1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 /*!
41     \class QGraphicsItem
42     \brief The QGraphicsItem class is the base class for all graphical
43     items in a QGraphicsScene.
44     \since 4.2
45 
46     \ingroup graphicsview-api
47     \inmodule QtWidgets
48 
49     It provides a light-weight foundation for writing your own custom items.
50     This includes defining the item's geometry, collision detection, its
51     painting implementation and item interaction through its event handlers.
52     QGraphicsItem is part of the \l{Graphics View Framework}
53 
54     \image graphicsview-items.png
55 
56     For convenience, Qt provides a set of standard graphics items for the most
57     common shapes. These are:
58 
59     \list
60     \li QGraphicsEllipseItem provides an ellipse item
61     \li QGraphicsLineItem provides a line item
62     \li QGraphicsPathItem provides an arbitrary path item
63     \li QGraphicsPixmapItem provides a pixmap item
64     \li QGraphicsPolygonItem provides a polygon item
65     \li QGraphicsRectItem provides a rectangular item
66     \li QGraphicsSimpleTextItem provides a simple text label item
67     \li QGraphicsTextItem provides an advanced text browser item
68     \endlist
69 
70     All of an item's geometric information is based on its local coordinate
71     system. The item's position, pos(), is the only function that does not
72     operate in local coordinates, as it returns a position in parent
73     coordinates. \l {The Graphics View Coordinate System} describes the coordinate
74     system in detail.
75 
76     You can set whether an item should be visible (i.e., drawn, and accepting
77     events), by calling setVisible(). Hiding an item will also hide its
78     children. Similarly, you can enable or disable an item by calling
79     setEnabled(). If you disable an item, all its children will also be
80     disabled. By default, items are both visible and enabled. To toggle
81     whether an item is selected or not, first enable selection by setting
82     the ItemIsSelectable flag, and then call setSelected(). Normally,
83     selection is toggled by the scene, as a result of user interaction.
84 
85     To write your own graphics item, you first create a subclass of
86     QGraphicsItem, and then start by implementing its two pure virtual public
87     functions: boundingRect(), which returns an estimate of the area painted
88     by the item, and paint(), which implements the actual painting. For
89     example:
90 
91     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 0
92 
93     The boundingRect() function has many different purposes.
94     QGraphicsScene bases its item index on boundingRect(), and
95     QGraphicsView uses it both for culling invisible items, and for
96     determining the area that needs to be recomposed when drawing
97     overlapping items. In addition, QGraphicsItem's collision
98     detection mechanisms use boundingRect() to provide an efficient
99     cut-off. The fine grained collision algorithm in
100     collidesWithItem() is based on calling shape(), which returns an
101     accurate outline of the item's shape as a QPainterPath.
102 
103     QGraphicsScene expects all items boundingRect() and shape() to
104     remain unchanged unless it is notified. If you want to change an
105     item's geometry in any way, you must first call
106     prepareGeometryChange() to allow QGraphicsScene to update its
107     bookkeeping.
108 
109     Collision detection can be done in two ways:
110 
111     \list 1
112 
113     \li Reimplement shape() to return an accurate shape for your item,
114     and rely on the default implementation of collidesWithItem() to do
115     shape-shape intersection. This can be rather expensive if the
116     shapes are complex.
117 
118     \li Reimplement collidesWithItem() to provide your own custom item
119     and shape collision algorithm.
120 
121     \endlist
122 
123     The contains() function can be called to determine whether the item \e
124     contains a point or not. This function can also be reimplemented by the
125     item. The default behavior of contains() is based on calling shape().
126 
127     Items can contain other items, and also be contained by other items. All
128     items can have a parent item and a list of children. Unless the item has
129     no parent, its position is in \e parent coordinates (i.e., the parent's
130     local coordinates). Parent items propagate both their position and their
131     transformation to all children.
132 
133     \image graphicsview-parentchild.png
134 
135     \target Transformations
136     \section1 Transformations
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     \li The item's base transform is applied (transform())
167     \li The item's transformations list is applied in order (transformations())
168     \li The item is rotated relative to its transform origin point (rotation(), transformOriginPoint())
169     \li The item is scaled relative to its transform origin point (scale(), transformOriginPoint())
170     \endlist
171 
172     \section1 Painting
173 
174     The paint() function is called by QGraphicsView to paint the item's
175     contents. The item has no background or default fill of its own; whatever
176     is behind the item will shine through all areas that are not explicitly
177     painted in this function.  You can call update() to schedule a repaint,
178     optionally passing the rectangle that needs a repaint. Depending on
179     whether or not the item is visible in a view, the item may or may not be
180     repainted; there is no equivalent to QWidget::repaint() in QGraphicsItem.
181 
182     Items are painted by the view, starting with the parent items and then
183     drawing children, in ascending stacking order. You can set an item's
184     stacking order by calling setZValue(), and test it by calling
185     zValue(), where items with low z-values are painted before items with
186     high z-values. Stacking order applies to sibling items; parents are always
187     drawn before their children.
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     \li 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     \li You can call stackBefore() to reorder the list of children. This will
221     directly modify the insertion order.
222 
223     \li 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 
234     QGraphicsItem receives events from QGraphicsScene through the virtual
235     function sceneEvent(). This function distributes the most common events
236     to a set of convenience event handlers:
237 
238     \list
239     \li contextMenuEvent() handles context menu events
240     \li focusInEvent() and focusOutEvent() handle focus in and out events
241     \li hoverEnterEvent(), hoverMoveEvent(), and hoverLeaveEvent() handles
242     hover enter, move and leave events
243     \li inputMethodEvent() handles input events, for accessibility support
244     \li keyPressEvent() and keyReleaseEvent() handle key press and release events
245     \li mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and
246     mouseDoubleClickEvent() handles mouse press, move, release, click and
247     doubleclick events
248     \endlist
249 
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
259 
260     Sometimes it's useful to register custom data with an item, be it a custom
261     item, or a standard item. You can call setData() on any item to store data
262     in it using a key-value pair (the key being an integer, and the value is a
263     QVariant). To get custom data from an item, call data(). This
264     functionality is completely untouched by Qt itself; it is provided for the
265     user's convenience.
266 
267     \sa QGraphicsScene, QGraphicsView, {Graphics View Framework}
268 */
269 
270 /*!
271   \enum QGraphicsItem::anonymous
272 
273   The value returned by the virtual type() function in standard
274   graphics item classes in Qt. All such standard graphics item classes
275   in Qt are associated with a unique value for Type, e.g. the value
276   returned by QGraphicsPathItem::type() is 2.
277 
278   \value Type
279 
280     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 18
281 
282   \value UserType The lowest value returned by the virtual type()
283   function for custom subclasses of QGraphicsItem.
284 
285     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 1
286 */
287 
288 /*!
289   \enum QGraphicsPathItem::anonymous
290 
291   The value returned by the virtual type() function.
292 
293   \value Type A graphics path item
294 */
295 
296 /*!
297   \enum QGraphicsRectItem::anonymous
298 
299   The value returned by the virtual type() function.
300 
301   \value Type A graphics rect item
302 */
303 
304 /*!
305   \enum QGraphicsEllipseItem::anonymous
306 
307   The value returned by the virtual type() function.
308 
309   \value Type A graphics ellipse item
310 */
311 
312 /*!
313   \enum QGraphicsPolygonItem::anonymous
314 
315   The value returned by the virtual type() function.
316 
317   \value Type A graphics polygon item
318 */
319 
320 /*!
321   \enum QGraphicsPixmapItem::anonymous
322 
323   The value returned by the virtual type() function.
324 
325   \value Type A graphics pixmap item
326 */
327 
328 /*!
329   \enum QGraphicsTextItem::anonymous
330 
331   The value returned by the virtual type() function.
332 
333   \value Type A graphics text item
334 */
335 
336 /*!
337   \enum QGraphicsSimpleTextItem::anonymous
338 
339   The value returned by the virtual type() function.
340 
341   \value Type A graphics simple text item
342 */
343 
344 /*!
345   \enum QGraphicsItemGroup::anonymous
346 
347   The value returned by the virtual type() function.
348 
349   \value Type A graphics item group
350 */
351 
352 /*!
353   \enum QGraphicsLineItem::anonymous
354 
355   The value returned by the virtual type() function.
356 
357   \value Type A graphics line item
358 */
359 
360 /*!
361     \enum QGraphicsItem::GraphicsItemFlag
362 
363     This enum describes different flags that you can set on an item to
364     toggle different features in the item's behavior.
365 
366     All flags are disabled by default.
367 
368     \value ItemIsMovable The item supports interactive movement using
369     the mouse. By clicking on the item and then dragging, the item
370     will move together with the mouse cursor. If the item has
371     children, all children are also moved. If the item is part of a
372     selection, all selected items are also moved. This feature is
373     provided as a convenience through the base implementation of
374     QGraphicsItem's mouse event handlers.
375 
376     \value ItemIsSelectable The item supports selection. Enabling this
377     feature will enable setSelected() to toggle selection for the
378     item. It will also let the item be selected automatically as a
379     result of calling QGraphicsScene::setSelectionArea(), by clicking
380     on an item, or by using rubber band selection in QGraphicsView.
381 
382     \value ItemIsFocusable The item supports keyboard input focus (i.e., it is
383     an input item). Enabling this flag will allow the item to accept focus,
384     which again allows the delivery of key events to
385     QGraphicsItem::keyPressEvent() and QGraphicsItem::keyReleaseEvent().
386 
387     \value ItemClipsToShape The item clips to its own shape. The item cannot
388     draw or receive mouse, tablet, drag and drop or hover events outside its
389     shape. It is disabled by default. This behavior is enforced by
390     QGraphicsView::drawItems() or QGraphicsScene::drawItems(). This flag was
391     introduced in Qt 4.3.
392 
393     \value ItemClipsChildrenToShape The item clips the painting of all its
394     descendants to its own shape. Items that are either direct or indirect
395     children of this item cannot draw outside this item's shape. By default,
396     this flag is disabled; children can draw anywhere. This behavior is
397     enforced by QGraphicsView::drawItems() or
398     QGraphicsScene::drawItems(). This flag was introduced in Qt 4.3.
399     \note This flag is similar to ItemContainsChildrenInShape but in addition
400     enforces the containment by clipping the children.
401 
402     \value ItemIgnoresTransformations The item ignores inherited
403     transformations (i.e., its position is still anchored to its parent, but
404     the parent or view rotation, zoom or shear transformations are ignored).
405     This flag is useful for keeping text label items horizontal and unscaled,
406     so they will still be readable if the view is transformed.  When set, the
407     item's view geometry and scene geometry will be maintained separately. You
408     must call deviceTransform() to map coordinates and detect collisions in
409     the view. By default, this flag is disabled. This flag was introduced in
410     Qt 4.3. \note With this flag set you can still scale the item itself, and
411     that scale transformation will influence the item's children.
412 
413     \value ItemIgnoresParentOpacity The item ignores its parent's opacity. The
414     item's effective opacity is the same as its own; it does not combine with
415     the parent's opacity. This flags allows your item to keep its absolute
416     opacity even if the parent is semitransparent. This flag was introduced in
417     Qt 4.5.
418 
419     \value ItemDoesntPropagateOpacityToChildren The item doesn't propagate its
420     opacity to its children. This flag allows you to create a semitransparent
421     item that does not affect the opacity of its children. This flag was
422     introduced in Qt 4.5.
423 
424     \value ItemStacksBehindParent The item is stacked behind its parent. By
425     default, child items are stacked on top of the parent item. But setting
426     this flag, the child will be stacked behind it. This flag is useful for
427     drop shadow effects and for decoration objects that follow the parent
428     item's geometry without drawing on top of it. This flag was introduced
429     in Qt 4.5.
430 
431     \value ItemUsesExtendedStyleOption The item makes use of either
432     \l{QStyleOptionGraphicsItem::} {exposedRect} or
433     \l{QStyleOptionGraphicsItem::} {matrix} in
434     QStyleOptionGraphicsItem. By default, the
435     \l{QStyleOptionGraphicsItem::} {exposedRect} is initialized to the
436     item's boundingRect() and the
437     \l{QStyleOptionGraphicsItem::}{matrix} is untransformed.  You can
438     enable this flag for the style options to be set up with more
439     fine-grained values.  Note that
440     QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
441     and always initialized to 1. Use
442     QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need
443     a higher value. This flag was introduced in Qt 4.6.
444 
445     \value ItemHasNoContents The item does not paint anything (i.e., calling
446     paint() on the item has no effect). You should set this flag on items that
447     do not need to be painted to ensure that Graphics View avoids unnecessary
448     painting preparations. This flag was introduced in Qt 4.6.
449 
450     \value ItemSendsGeometryChanges The item enables itemChange()
451     notifications for ItemPositionChange, ItemPositionHasChanged,
452     ItemTransformChange, ItemTransformHasChanged, ItemRotationChange,
453     ItemRotationHasChanged, ItemScaleChange, ItemScaleHasChanged,
454     ItemTransformOriginPointChange, and ItemTransformOriginPointHasChanged. For
455     performance reasons, these notifications are disabled by default. You must
456     enable this flag to receive notifications for position and transform
457     changes. This flag was introduced in Qt 4.6.
458 
459     \value ItemAcceptsInputMethod The item supports input methods typically
460     used for Asian languages.
461     This flag was introduced in Qt 4.6.
462 
463     \value ItemNegativeZStacksBehindParent The item automatically
464     stacks behind it's parent if it's z-value is negative. This flag
465     enables setZValue() to toggle ItemStacksBehindParent. This flag
466     was introduced in Qt 4.6.
467 
468     \value ItemIsPanel The item is a panel. A panel provides activation and
469     contained focus handling. Only one panel can be active at a time (see
470     QGraphicsItem::isActive()). When no panel is active, QGraphicsScene
471     activates all non-panel items. Window items (i.e.,
472     QGraphicsItem::isWindow() returns \c true) are panels. This flag was
473     introduced in Qt 4.6.
474 
475     \omitvalue ItemIsFocusScope \omit Internal only (for now). \endomit
476 
477     \value ItemSendsScenePositionChanges The item enables itemChange()
478     notifications for ItemScenePositionHasChanged. For performance reasons,
479     these notifications are disabled by default. You must enable this flag
480     to receive notifications for scene position changes. This flag was
481     introduced in Qt 4.6.
482 
483     \omitvalue ItemStopsClickFocusPropagation \omit The item stops propagating
484     click focus to items underneath when being clicked on. This flag
485     allows you create a non-focusable item that can be clicked on without
486     changing the focus. \endomit
487 
488     \omitvalue ItemStopsFocusHandling \omit Same as
489     ItemStopsClickFocusPropagation, but also suppresses focus-out. This flag
490     allows you to completely take over focus handling.
491     This flag was introduced in Qt 4.7. \endomit
492 
493     \value ItemContainsChildrenInShape This flag indicates that all of the
494     item's direct or indirect children only draw within the item's shape.
495     Unlike ItemClipsChildrenToShape, this restriction is not enforced. Set
496     ItemContainsChildrenInShape when you manually assure that drawing
497     is bound to the item's shape and want to avoid the cost associated with
498     enforcing the clip. Setting this flag enables more efficient drawing and
499     collision detection. The flag is disabled by default.
500     \note If both this flag and ItemClipsChildrenToShape are set, the clip
501     will be enforced. This is equivalent to just setting
502     ItemClipsChildrenToShape.
503 
504     This flag was introduced in Qt 5.4.
505 */
506 
507 /*!
508     \enum QGraphicsItem::GraphicsItemChange
509 
510     This enum describes the state changes that are notified by
511     QGraphicsItem::itemChange(). The notifications are sent as the state
512     changes, and in some cases, adjustments can be made (see the documentation
513     for each change for details).
514 
515     Note: Be careful with calling functions on the QGraphicsItem itself inside
516     itemChange(), as certain function calls can lead to unwanted
517     recursion. For example, you cannot call setPos() in itemChange() on an
518     ItemPositionChange notification, as the setPos() function will again call
519     itemChange(ItemPositionChange). Instead, you can return the new, adjusted
520     position from itemChange().
521 
522     \value ItemEnabledChange The item's enabled state changes. If the item is
523     presently enabled, it will become disabled, and vice verca. The value
524     argument is the new enabled state (i.e., true or false). Do not call
525     setEnabled() in itemChange() as this notification is delivered. Instead,
526     you can return the new state from itemChange().
527 
528     \value ItemEnabledHasChanged The item's enabled state has changed. The
529     value argument is the new enabled state (i.e., true or false). Do not call
530     setEnabled() in itemChange() as this notification is delivered. The return
531     value is ignored.
532 
533     \value ItemMatrixChange The item's affine transformation matrix is
534     changing. This value is obsolete; you can use ItemTransformChange instead.
535 
536     \value ItemPositionChange The item's position changes. This notification
537     is sent if the ItemSendsGeometryChanges flag is enabled, and when the
538     item's local position changes, relative to its parent (i.e., as a result
539     of calling setPos() or moveBy()). The value argument is the new position
540     (i.e., a QPointF).  You can call pos() to get the original position. Do
541     not call setPos() or moveBy() in itemChange() as this notification is
542     delivered; instead, you can return the new, adjusted position from
543     itemChange(). After this notification, QGraphicsItem immediately sends the
544     ItemPositionHasChanged notification if the position changed.
545 
546     \value ItemPositionHasChanged The item's position has changed. This
547     notification is sent if the ItemSendsGeometryChanges flag is enabled, and
548     after the item's local position, relative to its parent, has changed. The
549     value argument is the new position (the same as pos()), and QGraphicsItem
550     ignores the return value for this notification (i.e., a read-only
551     notification).
552 
553     \value ItemTransformChange The item's transformation matrix changes. This
554     notification is sent if the ItemSendsGeometryChanges flag is enabled, and
555     when the item's local transformation matrix changes (i.e., as a result of
556     calling setTransform(). The value argument is the new matrix (i.e., a
557     QTransform); to get the old matrix, call transform(). Do not call
558     setTransform() or set any of the transformation properties in itemChange()
559     as this notification is delivered; instead, you can return the new matrix
560     from itemChange().  This notification is not sent if you change the
561     transformation properties.
562 
563     \value ItemTransformHasChanged The item's transformation matrix has
564     changed either because setTransform is called, or one of the
565     transformation properties is changed. This notification is sent if the
566     ItemSendsGeometryChanges flag is enabled, and after the item's local
567     transformation matrix has changed. The value argument is the new matrix
568     (same as transform()), and QGraphicsItem ignores the return value for this
569     notification (i.e., a read-only notification).
570 
571     \value ItemRotationChange The item's rotation property changes. This
572     notification is sent if the ItemSendsGeometryChanges flag is enabled, and
573     when the item's rotation property changes (i.e., as a result of calling
574     setRotation()). The value argument is the new rotation (i.e., a double);
575     to get the old rotation, call rotation(). Do not call setRotation() in
576     itemChange() as this notification is delivered; instead, you can return
577     the new rotation from itemChange().
578 
579     \value ItemRotationHasChanged The item's rotation property has changed.
580     This notification is sent if the ItemSendsGeometryChanges flag is enabled,
581     and after the item's rotation property has changed. The value argument is
582     the new rotation (i.e., a double), and QGraphicsItem ignores the return
583     value for this notification (i.e., a read-only notification). Do not call
584     setRotation() in itemChange() as this notification is delivered.
585 
586     \value ItemScaleChange The item's scale property changes. This notification
587     is sent if the ItemSendsGeometryChanges flag is enabled, and when the item's
588     scale property changes (i.e., as a result of calling setScale()). The value
589     argument is the new scale (i.e., a double); to get the old scale, call
590     scale(). Do not call setScale() in itemChange() as this notification is
591     delivered; instead, you can return the new scale from itemChange().
592 
593     \value ItemScaleHasChanged The item's scale property has changed. This
594     notification is sent if the ItemSendsGeometryChanges flag is enabled, and
595     after the item's scale property has changed. The value argument is the new
596     scale (i.e., a double), and QGraphicsItem ignores the return value for this
597     notification (i.e., a read-only notification). Do not call setScale() in
598     itemChange() as this notification is delivered.
599 
600     \value ItemTransformOriginPointChange The item's transform origin point
601     property changes. This notification is sent if the ItemSendsGeometryChanges
602     flag is enabled, and when the item's transform origin point property changes
603     (i.e., as a result of calling setTransformOriginPoint()). The value argument
604     is the new origin point (i.e., a QPointF); to get the old origin point, call
605     transformOriginPoint(). Do not call setTransformOriginPoint() in itemChange()
606     as this notification is delivered; instead, you can return the new transform
607     origin point from itemChange().
608 
609     \value ItemTransformOriginPointHasChanged The item's transform origin point
610     property has changed. This notification is sent if the ItemSendsGeometryChanges
611     flag is enabled, and after the item's transform origin point property has
612     changed. The value argument is the new origin point (i.e., a QPointF), and
613     QGraphicsItem ignores the return value for this notification (i.e., a read-only
614     notification). Do not call setTransformOriginPoint() in itemChange() as this
615     notification is delivered.
616 
617     \value ItemSelectedChange The item's selected state changes. If the item is
618     presently selected, it will become unselected, and vice verca. The value
619     argument is the new selected state (i.e., true or false). Do not call
620     setSelected() in itemChange() as this notification is delivered; instead, you
621     can return the new selected state from itemChange().
622 
623     \value ItemSelectedHasChanged The item's selected state has changed. The
624     value argument is the new selected state (i.e., true or false). Do not
625     call setSelected() in itemChange() as this notification is delivered. The
626     return value is ignored.
627 
628     \value ItemVisibleChange The item's visible state changes. If the item is
629     presently visible, it will become invisible, and vice verca. The value
630     argument is the new visible state (i.e., true or false). Do not call
631     setVisible() in itemChange() as this notification is delivered; instead,
632     you can return the new visible state from itemChange().
633 
634     \value ItemVisibleHasChanged The item's visible state has changed. The
635     value argument is the new visible state (i.e., true or false). Do not call
636     setVisible() in itemChange() as this notification is delivered. The return
637     value is ignored.
638 
639     \value ItemParentChange The item's parent changes. The value argument is
640     the new parent item (i.e., a QGraphicsItem pointer).  Do not call
641     setParentItem() in itemChange() as this notification is delivered;
642     instead, you can return the new parent from itemChange().
643 
644     \value ItemParentHasChanged The item's parent has changed. The value
645     argument is the new parent (i.e., a pointer to a QGraphicsItem). Do not
646     call setParentItem() in itemChange() as this notification is
647     delivered. The return value is ignored.
648 
649     \value ItemChildAddedChange A child is added to this item. The value
650     argument is the new child item (i.e., a QGraphicsItem pointer). Do not
651     pass this item to any item's setParentItem() function as this notification
652     is delivered. The return value is unused; you cannot adjust anything in
653     this notification. Note that the new child might not be fully constructed
654     when this notification is sent; calling pure virtual functions on
655     the child can lead to a crash.
656 
657     \value ItemChildRemovedChange A child is removed from this item. The value
658     argument is the child item that is about to be removed (i.e., a
659     QGraphicsItem pointer). The return value is unused; you cannot adjust
660     anything in this notification.
661 
662     \value ItemSceneChange The item is moved to a new scene. This notification is
663     also sent when the item is added to its initial scene, and when it is removed.
664     The item's scene() is the old scene, or \nullptr if the item has not been added
665     to a scene yet. The value argument is the new scene (i.e., a QGraphicsScene
666     pointer), or \nullptr if the item is removed from a scene. Do not
667     override this change by passing this item to QGraphicsScene::addItem() as this
668     notification is delivered; instead, you can return the new scene from
669     itemChange(). Use this feature with caution; objecting to a scene change can
670     quickly lead to unwanted recursion.
671 
672     \value ItemSceneHasChanged The item's scene has changed. The item's scene() is
673     the new scene. This notification is also sent when the item is added to its
674     initial scene, and when it is removed.The value argument is the new scene
675     (i.e., a pointer to a QGraphicsScene). Do not call setScene() in itemChange()
676     as this notification is delivered. The return value is ignored.
677 
678     \value ItemCursorChange The item's cursor changes. The value argument is
679     the new cursor (i.e., a QCursor). Do not call setCursor() in itemChange()
680     as this notification is delivered. Instead, you can return a new cursor
681     from itemChange().
682 
683     \value ItemCursorHasChanged The item's cursor has changed. The value
684     argument is the new cursor (i.e., a QCursor). Do not call setCursor() as
685     this notification is delivered. The return value is ignored.
686 
687     \value ItemToolTipChange The item's tooltip changes. The value argument is
688     the new tooltip (i.e., a QToolTip). Do not call setToolTip() in
689     itemChange() as this notification is delivered. Instead, you can return a
690     new tooltip from itemChange().
691 
692     \value ItemToolTipHasChanged The item's tooltip has changed. The value
693     argument is the new tooltip (i.e., a QToolTip). Do not call setToolTip()
694     as this notification is delivered. The return value is ignored.
695 
696     \value ItemFlagsChange The item's flags change. The value argument is the
697     new flags (i.e., a quint32). Do not call setFlags() in itemChange() as
698     this notification is delivered. Instead, you can return the new flags from
699     itemChange().
700 
701     \value ItemFlagsHaveChanged The item's flags have changed. The value
702     argument is the new flags (i.e., a quint32). Do not call setFlags() in
703     itemChange() as this notification is delivered. The return value is
704     ignored.
705 
706     \value ItemZValueChange The item's Z-value changes. The value argument is
707     the new Z-value (i.e., a double). Do not call setZValue() in itemChange()
708     as this notification is delivered. Instead, you can return a new Z-value
709     from itemChange().
710 
711     \value ItemZValueHasChanged The item's Z-value has changed. The value
712     argument is the new Z-value (i.e., a double). Do not call setZValue() as
713     this notification is delivered. The return value is ignored.
714 
715     \value ItemOpacityChange The item's opacity changes. The value argument is
716     the new opacity (i.e., a double). Do not call setOpacity() in itemChange()
717     as this notification is delivered. Instead, you can return a new opacity
718     from itemChange().
719 
720     \value ItemOpacityHasChanged The item's opacity has changed. The value
721     argument is the new opacity (i.e., a double). Do not call setOpacity() as
722     this notification is delivered. The return value is ignored.
723 
724     \value ItemScenePositionHasChanged The item's scene position has changed.
725     This notification is sent if the ItemSendsScenePositionChanges flag is
726     enabled, and after the item's scene position has changed (i.e., the
727     position or transformation of the item itself or the position or
728     transformation of any ancestor has changed). The value argument is the
729     new scene position (the same as scenePos()), and QGraphicsItem ignores
730     the return value for this notification (i.e., a read-only notification).
731 */
732 
733 /*!
734     \enum QGraphicsItem::CacheMode
735     \since 4.4
736 
737     This enum describes QGraphicsItem's cache modes. Caching is used to speed
738     up rendering by allocating and rendering to an off-screen pixel buffer,
739     which can be reused when the item requires redrawing. For some paint
740     devices, the cache is stored directly in graphics memory, which makes
741     rendering very quick.
742 
743     \value NoCache The default; all item caching is
744     disabled. QGraphicsItem::paint() is called every time the item needs
745     redrawing.
746 
747     \value ItemCoordinateCache Caching is enabled for the item's logical
748     (local) coordinate system. QGraphicsItem creates an off-screen pixel
749     buffer with a configurable size / resolution that you can pass to
750     QGraphicsItem::setCacheMode(). Rendering quality will typically degrade,
751     depending on the resolution of the cache and the item transformation.  The
752     first time the item is redrawn, it will render itself into the cache, and
753     the cache is then reused for every subsequent expose. The cache is also
754     reused as the item is transformed. To adjust the resolution of the cache,
755     you can call setCacheMode() again.
756 
757     \value DeviceCoordinateCache Caching is enabled at the paint device level,
758     in device coordinates. This mode is for items that can move, but are not
759     rotated, scaled or sheared. If the item is transformed directly or
760     indirectly, the cache will be regenerated automatically. Unlike
761     ItemCoordinateCacheMode, DeviceCoordinateCache always renders at maximum
762     quality.
763 
764     \sa QGraphicsItem::setCacheMode()
765 */
766 
767 /*!
768     \enum QGraphicsItem::Extension
769     \internal
770 
771     Note: This is provided as a hook to avoid future problems related
772     to adding virtual functions. See also extension(),
773     supportsExtension() and setExtension().
774 */
775 
776 /*!
777     \enum QGraphicsItem::PanelModality
778     \since 4.6
779 
780     This enum specifies the behavior of a modal panel. A modal panel
781     is one that blocks input to other panels. Note that items that
782     are children of a modal panel are not blocked.
783 
784     The values are:
785 
786     \value NonModal The panel is not modal and does not block input to
787     other panels. This is the default value for panels.
788 
789     \value PanelModal The panel is modal to a single item hierarchy
790     and blocks input to its parent pane, all grandparent panels, and
791     all siblings of its parent and grandparent panels.
792 
793     \value SceneModal The window is modal to the entire scene and
794     blocks input to all panels.
795 
796     \sa QGraphicsItem::setPanelModality(), QGraphicsItem::panelModality(), QGraphicsItem::ItemIsPanel
797 */
798 
799 #include "qgraphicsitem.h"
800 
801 #include "qgraphicsscene.h"
802 #include "qgraphicsscene_p.h"
803 #include "qgraphicssceneevent.h"
804 #include "qgraphicsview.h"
805 #include "qgraphicswidget.h"
806 #include "qgraphicsproxywidget.h"
807 #include "qgraphicsscenebsptreeindex_p.h"
808 #include <QtCore/qbitarray.h>
809 #include <QtCore/qpoint.h>
810 #include <QtCore/qstack.h>
811 #include <QtCore/qtimer.h>
812 #include <QtCore/qvariant.h>
813 #include <QtCore/qvarlengtharray.h>
814 #include <QtCore/qnumeric.h>
815 #include <QtWidgets/qapplication.h>
816 #include <QtGui/qbitmap.h>
817 #include <QtGui/qpainter.h>
818 #include <QtGui/qpainterpath.h>
819 #include <QtGui/qpixmapcache.h>
820 #include <QtWidgets/qstyleoption.h>
821 #include <QtGui/qevent.h>
822 #include <QtGui/qinputmethod.h>
823 #if QT_CONFIG(graphicseffect)
824 #include <QtWidgets/qgraphicseffect.h>
825 #endif
826 
827 #include <private/qgraphicsitem_p.h>
828 #include <private/qgraphicswidget_p.h>
829 #include <private/qwidgettextcontrol_p.h>
830 #include <private/qtextdocumentlayout_p.h>
831 #include <private/qtextengine_p.h>
832 #include <private/qwidget_p.h>
833 #include <private/qapplication_p.h>
834 #include <private/qgesturemanager_p.h>
835 #include <private/qdebug_p.h>
836 
837 QT_BEGIN_NAMESPACE
838 
_q_adjustRect(QRect * rect)839 static inline void _q_adjustRect(QRect *rect)
840 {
841     Q_ASSERT(rect);
842     if (!rect->width())
843         rect->adjust(0, 0, 1, 0);
844     if (!rect->height())
845         rect->adjust(0, 0, 0, 1);
846 }
847 
848 /*
849     ### Move this into QGraphicsItemPrivate
850  */
851 class QGraphicsItemCustomDataStore
852 {
853 public:
854     QHash<const QGraphicsItem *, QMap<int, QVariant> > data;
855 };
Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore,qt_dataStore)856 Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
857 
858 /*!
859     \internal
860 
861     Returns a QPainterPath of \a path when stroked with the \a pen.
862     Ignoring dash pattern.
863 */
864 static QPainterPath qt_graphicsItem_shapeFromPath(const QPainterPath &path, const QPen &pen)
865 {
866     // We unfortunately need this hack as QPainterPathStroker will set a width of 1.0
867     // if we pass a value of 0.0 to QPainterPathStroker::setWidth()
868     const qreal penWidthZero = qreal(0.00000001);
869 
870     if (path == QPainterPath() || pen == Qt::NoPen)
871         return path;
872     QPainterPathStroker ps;
873     ps.setCapStyle(pen.capStyle());
874     if (pen.widthF() <= 0.0)
875         ps.setWidth(penWidthZero);
876     else
877         ps.setWidth(pen.widthF());
878     ps.setJoinStyle(pen.joinStyle());
879     ps.setMiterLimit(pen.miterLimit());
880     QPainterPath p = ps.createStroke(path);
881     p.addPath(path);
882     return p;
883 }
884 
885 /*!
886     \internal
887 */
QGraphicsItemPrivate()888 QGraphicsItemPrivate::QGraphicsItemPrivate()
889     : z(0),
890       opacity(1.),
891       scene(nullptr),
892       parent(nullptr),
893       transformData(nullptr),
894       graphicsEffect(nullptr),
895       index(-1),
896       siblingIndex(-1),
897       itemDepth(-1),
898       focusProxy(nullptr),
899       subFocusItem(nullptr),
900       focusScopeItem(nullptr),
901       imHints(Qt::ImhNone),
902       panelModality(QGraphicsItem::NonModal),
903       acceptedMouseButtons(0x1f),
904       visible(true),
905       explicitlyHidden(false),
906       enabled(true),
907       explicitlyDisabled(false),
908       selected(false),
909       acceptsHover(false),
910       acceptDrops(false),
911       isMemberOfGroup(false),
912       handlesChildEvents(false),
913       itemDiscovered(false),
914       hasCursor(false),
915       ancestorFlags(0),
916       cacheMode(0),
917       hasBoundingRegionGranularity(false),
918       isWidget(false),
919       dirty(false),
920       dirtyChildren(false),
921       localCollisionHack(false),
922       inSetPosHelper(false),
923       needSortChildren(false),
924       allChildrenDirty(false),
925       fullUpdatePending(false),
926       flags(0),
927       paintedViewBoundingRectsNeedRepaint(false),
928       dirtySceneTransform(true),
929       geometryChanged(true),
930       inDestructor(false),
931       isObject(false),
932       ignoreVisible(false),
933       ignoreOpacity(false),
934       acceptTouchEvents(false),
935       acceptedTouchBeginEvent(false),
936       filtersDescendantEvents(false),
937       sceneTransformTranslateOnly(false),
938       notifyBoundingRectChanged(false),
939       notifyInvalidated(false),
940       mouseSetsFocus(true),
941       explicitActivate(false),
942       wantsActive(false),
943       holesInSiblingIndex(false),
944       sequentialOrdering(true),
945       updateDueToGraphicsEffect(false),
946       scenePosDescendants(false),
947       pendingPolish(false),
948       mayHaveChildWithGraphicsEffect(false),
949       isDeclarativeItem(false),
950       sendParentChangeNotification(false),
951       dirtyChildrenBoundingRect(true),
952       globalStackingOrder(-1),
953       q_ptr(nullptr)
954 {
955 }
956 
957 /*!
958     \internal
959 */
~QGraphicsItemPrivate()960 QGraphicsItemPrivate::~QGraphicsItemPrivate()
961 {
962 }
963 
964 /*!
965     \internal
966 
967     Propagates the ancestor flag \a flag with value \a enabled to all this
968     item's children. If \a root is false, the flag is also set on this item
969     (default is true).
970 */
updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,AncestorFlag flag,bool enabled,bool root)971 void QGraphicsItemPrivate::updateAncestorFlag(QGraphicsItem::GraphicsItemFlag childFlag,
972                                            AncestorFlag flag, bool enabled, bool root)
973 {
974     Q_Q(QGraphicsItem);
975     if (root) {
976         // For root items only. This is the item that has either enabled or
977         // disabled \a childFlag, or has been reparented.
978         switch (int(childFlag)) {
979         case -2:
980             flag = AncestorFiltersChildEvents;
981             enabled = q->filtersChildEvents();
982             break;
983         case -1:
984             flag = AncestorHandlesChildEvents;
985             enabled = q->handlesChildEvents();
986             break;
987         case QGraphicsItem::ItemClipsChildrenToShape:
988             flag = AncestorClipsChildren;
989             enabled = flags & QGraphicsItem::ItemClipsChildrenToShape;
990             break;
991         case QGraphicsItem::ItemIgnoresTransformations:
992             flag = AncestorIgnoresTransformations;
993             enabled = flags & QGraphicsItem::ItemIgnoresTransformations;
994             break;
995         case QGraphicsItem::ItemContainsChildrenInShape:
996             flag = AncestorContainsChildren;
997             enabled = flags & QGraphicsItem::ItemContainsChildrenInShape;
998             break;
999         default:
1000             return;
1001         }
1002 
1003         if (parent) {
1004             // Inherit the enabled-state from our parents.
1005             if ((parent->d_ptr->ancestorFlags & flag)
1006                     || (int(parent->d_ptr->flags & childFlag) == childFlag)
1007                     || (int(childFlag) == -1 && parent->d_ptr->handlesChildEvents)
1008                     || (int(childFlag) == -2 && parent->d_ptr->filtersDescendantEvents)) {
1009                 enabled = true;
1010                 ancestorFlags |= flag;
1011             } else {
1012                 ancestorFlags &= ~flag;
1013             }
1014         } else {
1015             // Top-level root items don't have any ancestors, so there are no
1016             // ancestor flags either.
1017             ancestorFlags = 0;
1018         }
1019     } else {
1020         // Don't set or propagate the ancestor flag if it's already correct.
1021         if (((ancestorFlags & flag) && enabled) || (!(ancestorFlags & flag) && !enabled))
1022             return;
1023 
1024         // Set the flag.
1025         if (enabled)
1026             ancestorFlags |= flag;
1027         else
1028             ancestorFlags &= ~flag;
1029 
1030         // Don't process children if the item has the main flag set on itself.
1031         if ((int(childFlag) != -1 &&  int(flags & childFlag) == childFlag)
1032             || (int(childFlag) == -1 && handlesChildEvents)
1033             || (int(childFlag) == -2 && filtersDescendantEvents))
1034             return;
1035     }
1036 
1037     for (int i = 0; i < children.size(); ++i)
1038         children.at(i)->d_ptr->updateAncestorFlag(childFlag, flag, enabled, false);
1039 }
1040 
updateAncestorFlags()1041 void QGraphicsItemPrivate::updateAncestorFlags()
1042 {
1043     int flags = 0;
1044     if (parent) {
1045         // Inherit the parent's ancestor flags.
1046         QGraphicsItemPrivate *pd = parent->d_ptr.data();
1047         flags = pd->ancestorFlags;
1048 
1049         // Add in flags from the parent.
1050         if (pd->filtersDescendantEvents)
1051             flags |= AncestorFiltersChildEvents;
1052         if (pd->handlesChildEvents)
1053             flags |= AncestorHandlesChildEvents;
1054         if (pd->flags & QGraphicsItem::ItemClipsChildrenToShape)
1055             flags |= AncestorClipsChildren;
1056         if (pd->flags & QGraphicsItem::ItemIgnoresTransformations)
1057             flags |= AncestorIgnoresTransformations;
1058         if (pd->flags & QGraphicsItem::ItemContainsChildrenInShape)
1059             flags |= AncestorContainsChildren;
1060     }
1061 
1062     if (ancestorFlags == flags)
1063         return; // No change; stop propagation.
1064     ancestorFlags = flags;
1065 
1066     // Propagate to children recursively.
1067     for (int i = 0; i < children.size(); ++i)
1068         children.at(i)->d_ptr->updateAncestorFlags();
1069 }
1070 
1071 /*!
1072     \internal
1073 
1074     Propagates item group membership.
1075 */
setIsMemberOfGroup(bool enabled)1076 void QGraphicsItemPrivate::setIsMemberOfGroup(bool enabled)
1077 {
1078     Q_Q(QGraphicsItem);
1079     isMemberOfGroup = enabled;
1080     if (!qgraphicsitem_cast<QGraphicsItemGroup *>(q)) {
1081         foreach (QGraphicsItem *child, children)
1082             child->d_func()->setIsMemberOfGroup(enabled);
1083     }
1084 }
1085 
1086 /*!
1087     \internal
1088 
1089     Maps any item pos properties of \a event to \a item's coordinate system.
1090 */
remapItemPos(QEvent * event,QGraphicsItem * item)1091 void QGraphicsItemPrivate::remapItemPos(QEvent *event, QGraphicsItem *item)
1092 {
1093     Q_Q(QGraphicsItem);
1094     switch (event->type()) {
1095     case QEvent::GraphicsSceneMouseMove:
1096     case QEvent::GraphicsSceneMousePress:
1097     case QEvent::GraphicsSceneMouseRelease:
1098     case QEvent::GraphicsSceneMouseDoubleClick: {
1099         QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
1100         mouseEvent->setPos(item->mapFromItem(q, mouseEvent->pos()));
1101         mouseEvent->setLastPos(item->mapFromItem(q, mouseEvent->pos()));
1102         for (int i = 0x1; i <= 0x10; i <<= 1) {
1103             if (mouseEvent->buttons() & i) {
1104                 Qt::MouseButton button = Qt::MouseButton(i);
1105                 mouseEvent->setButtonDownPos(button, item->mapFromItem(q, mouseEvent->buttonDownPos(button)));
1106             }
1107         }
1108         break;
1109     }
1110     case QEvent::GraphicsSceneWheel: {
1111         QGraphicsSceneWheelEvent *wheelEvent = static_cast<QGraphicsSceneWheelEvent *>(event);
1112         wheelEvent->setPos(item->mapFromItem(q, wheelEvent->pos()));
1113         break;
1114     }
1115     case QEvent::GraphicsSceneContextMenu: {
1116         QGraphicsSceneContextMenuEvent *contextEvent = static_cast<QGraphicsSceneContextMenuEvent *>(event);
1117         contextEvent->setPos(item->mapFromItem(q, contextEvent->pos()));
1118         break;
1119     }
1120     case QEvent::GraphicsSceneHoverMove: {
1121         QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
1122         hoverEvent->setPos(item->mapFromItem(q, hoverEvent->pos()));
1123         break;
1124     }
1125     default:
1126         break;
1127     }
1128 }
1129 
1130 /*!
1131     \internal
1132 
1133     Maps the point \a pos from scene to item coordinates. If \a view is passed and the item
1134     is untransformable, this function will correctly map \a pos from the scene using the
1135     view's transformation.
1136 */
1137 
genericMapFromSceneTransform(const QWidget * viewport) const1138 QTransform QGraphicsItemPrivate::genericMapFromSceneTransform(const QWidget *viewport) const
1139 {
1140     Q_Q(const QGraphicsItem);
1141     if (!itemIsUntransformable())
1142        return sceneTransform.inverted();
1143     const QGraphicsView *view = viewport
1144         ? qobject_cast<QGraphicsView *>(viewport->parentWidget())
1145         : nullptr;
1146     if (view == nullptr)
1147         return sceneTransform.inverted();
1148     // ### More ping pong than needed.
1149     const QTransform viewportTransform = view->viewportTransform();
1150     return viewportTransform * q->deviceTransform(viewportTransform).inverted();
1151 }
1152 
genericMapFromScene(const QPointF & pos,const QWidget * viewport) const1153 QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos,
1154                                                   const QWidget *viewport) const
1155 {
1156     return genericMapFromSceneTransform(viewport).map(pos);
1157 }
1158 
1159 /*!
1160     \internal
1161 
1162     Combines this item's position and transform onto \a transform.
1163 
1164     If you need to change this function (e.g., adding more transformation
1165     modes / options), make sure to change all places marked with COMBINE.
1166 */
combineTransformToParent(QTransform * x,const QTransform * viewTransform) const1167 void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const
1168 {
1169     // COMBINE
1170     if (viewTransform && itemIsUntransformable()) {
1171         *x = q_ptr->deviceTransform(*viewTransform);
1172     } else {
1173         if (transformData)
1174             *x *= transformData->computedFullTransform();
1175         if (!pos.isNull())
1176             *x *= QTransform::fromTranslate(pos.x(), pos.y());
1177     }
1178 }
1179 
1180 /*!
1181     \internal
1182 
1183     Combines this item's position and transform onto \a transform.
1184 
1185     If you need to change this function (e.g., adding more transformation
1186     modes / options), make sure to change QGraphicsItem::deviceTransform() as
1187     well.
1188 */
combineTransformFromParent(QTransform * x,const QTransform * viewTransform) const1189 void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const
1190 {
1191     // COMBINE
1192     if (viewTransform && itemIsUntransformable()) {
1193         *x = q_ptr->deviceTransform(*viewTransform);
1194     } else {
1195         x->translate(pos.x(), pos.y());
1196         if (transformData)
1197             *x = transformData->computedFullTransform(x);
1198     }
1199 }
1200 
updateSceneTransformFromParent()1201 void QGraphicsItemPrivate::updateSceneTransformFromParent()
1202 {
1203     if (parent) {
1204         Q_ASSERT(!parent->d_ptr->dirtySceneTransform);
1205         if (parent->d_ptr->sceneTransformTranslateOnly) {
1206             sceneTransform = QTransform::fromTranslate(parent->d_ptr->sceneTransform.dx() + pos.x(),
1207                                                        parent->d_ptr->sceneTransform.dy() + pos.y());
1208         } else {
1209             sceneTransform = parent->d_ptr->sceneTransform;
1210             sceneTransform.translate(pos.x(), pos.y());
1211         }
1212         if (transformData) {
1213             sceneTransform = transformData->computedFullTransform(&sceneTransform);
1214             sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
1215         } else {
1216             sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly;
1217         }
1218     } else if (!transformData) {
1219         sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
1220         sceneTransformTranslateOnly = 1;
1221     } else if (transformData->onlyTransform) {
1222         sceneTransform = transformData->transform;
1223         if (!pos.isNull())
1224             sceneTransform *= QTransform::fromTranslate(pos.x(), pos.y());
1225         sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
1226     } else if (pos.isNull()) {
1227         sceneTransform = transformData->computedFullTransform();
1228         sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
1229     } else {
1230         sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
1231         sceneTransform = transformData->computedFullTransform(&sceneTransform);
1232         sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
1233     }
1234     dirtySceneTransform = 0;
1235 }
1236 
1237 /*!
1238     \internal
1239 
1240     Make sure not to trigger any pure virtual function calls (e.g.,
1241     prepareGeometryChange) if the item is in its destructor, i.e.
1242     inDestructor is 1.
1243 */
setParentItemHelper(QGraphicsItem * newParent,const QVariant * newParentVariant,const QVariant * thisPointerVariant)1244 void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent, const QVariant *newParentVariant,
1245                                                const QVariant *thisPointerVariant)
1246 {
1247     Q_Q(QGraphicsItem);
1248     if (newParent == parent)
1249         return;
1250 
1251     if (isWidget)
1252         static_cast<QGraphicsWidgetPrivate *>(this)->fixFocusChainBeforeReparenting((newParent &&
1253                                                         newParent->isWidget()) ? static_cast<QGraphicsWidget *>(newParent) : nullptr,
1254                                                         scene);
1255     if (scene) {
1256         // Deliver the change to the index
1257         if (scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
1258             scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParent);
1259 
1260         // Disable scene pos notifications for old ancestors
1261         if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
1262             scene->d_func()->setScenePosItemEnabled(q, false);
1263     }
1264 
1265     if (subFocusItem && parent) {
1266         // Make sure none of the old parents point to this guy.
1267         subFocusItem->d_ptr->clearSubFocus(parent);
1268     }
1269 
1270     // We anticipate geometry changes. If the item is deleted, it will be
1271     // removed from the index at a later stage, and the whole scene will be
1272     // updated.
1273     if (!inDestructor)
1274         q_ptr->prepareGeometryChange();
1275 
1276     if (parent) {
1277         // Remove from current parent
1278         parent->d_ptr->removeChild(q);
1279         if (thisPointerVariant)
1280             parent->itemChange(QGraphicsItem::ItemChildRemovedChange, *thisPointerVariant);
1281     }
1282 
1283     // Update toplevelitem list. If this item is being deleted, its parent
1284     // will be 0 but we don't want to register/unregister it in the TLI list.
1285     if (scene && !inDestructor) {
1286         if (parent && !newParent) {
1287             scene->d_func()->registerTopLevelItem(q);
1288         } else if (!parent && newParent) {
1289             scene->d_func()->unregisterTopLevelItem(q);
1290         }
1291     }
1292 
1293     // Ensure any last parent focus scope does not point to this item or any of
1294     // its descendents.
1295     QGraphicsItem *p = parent;
1296     QGraphicsItem *parentFocusScopeItem = nullptr;
1297     while (p) {
1298         if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
1299             // If this item's focus scope's focus scope item points
1300             // to this item or a descendent, then clear it.
1301             QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
1302             if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
1303                 parentFocusScopeItem = fsi;
1304                 p->d_ptr->focusScopeItem = nullptr;
1305                 fsi->d_ptr->focusScopeItemChange(false);
1306             }
1307             break;
1308         }
1309         p = p->d_ptr->parent;
1310     }
1311 
1312     // Update graphics effect optimization flag
1313     if (newParent && (graphicsEffect || mayHaveChildWithGraphicsEffect))
1314         newParent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
1315 
1316     // Update focus scope item ptr in new scope.
1317     QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem;
1318     if (newFocusScopeItem && newParent) {
1319         QGraphicsItem *p = newParent;
1320         while (p) {
1321             if (p->d_ptr->flags & QGraphicsItem::ItemIsFocusScope) {
1322                 if (subFocusItem && subFocusItem != q_ptr) {
1323                     // Find the subFocusItem's topmost focus scope within the new parent's focusscope
1324                     QGraphicsItem *ancestorScope = nullptr;
1325                     QGraphicsItem *p2 = subFocusItem->d_ptr->parent;
1326                     while (p2 && p2 != p) {
1327                         if (p2->d_ptr->flags & QGraphicsItem::ItemIsFocusScope)
1328                             ancestorScope = p2;
1329                         if (p2->d_ptr->flags & QGraphicsItem::ItemIsPanel)
1330                             break;
1331                         if (p2 == q_ptr)
1332                             break;
1333                         p2 = p2->d_ptr->parent;
1334                     }
1335                     if (ancestorScope)
1336                         newFocusScopeItem = ancestorScope;
1337                 }
1338 
1339                 p->d_ptr->focusScopeItem = newFocusScopeItem;
1340                 newFocusScopeItem->d_ptr->focusScopeItemChange(true);
1341                 // Ensure the new item is no longer the subFocusItem. The
1342                 // only way to set focus on a child of a focus scope is
1343                 // by setting focus on the scope itself.
1344                 if (subFocusItem && !p->focusItem())
1345                     subFocusItem->d_ptr->clearSubFocus();
1346                 break;
1347             }
1348             p = p->d_ptr->parent;
1349         }
1350     }
1351 
1352     // Resolve depth.
1353     invalidateDepthRecursively();
1354 
1355     if ((parent = newParent)) {
1356         if (parent->d_func()->scene && parent->d_func()->scene != scene) {
1357             // Move this item to its new parent's scene
1358             parent->d_func()->scene->addItem(q);
1359         } else if (!parent->d_func()->scene && scene) {
1360             // Remove this item from its former scene
1361             scene->removeItem(q);
1362         }
1363 
1364         parent->d_ptr->addChild(q);
1365         if (thisPointerVariant)
1366             parent->itemChange(QGraphicsItem::ItemChildAddedChange, *thisPointerVariant);
1367         if (scene) {
1368             // Re-enable scene pos notifications for new ancestors
1369             if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
1370                 scene->d_func()->setScenePosItemEnabled(q, true);
1371         }
1372 
1373         // Propagate dirty flags to the new parent
1374         markParentDirty(/*updateBoundingRect=*/true);
1375 
1376         // Inherit ancestor flags from the new parent.
1377         updateAncestorFlags();
1378 
1379         // Update item visible / enabled.
1380         if (parent->d_ptr->visible != visible) {
1381             if (!parent->d_ptr->visible || !explicitlyHidden)
1382                 setVisibleHelper(parent->d_ptr->visible, /* explicit = */ false, /* update = */ false);
1383         }
1384         if (parent->isEnabled() != enabled) {
1385             if (!parent->d_ptr->enabled || !explicitlyDisabled)
1386                 setEnabledHelper(parent->d_ptr->enabled, /* explicit = */ false, /* update = */ false);
1387         }
1388 
1389         // Auto-activate if visible and the parent is active.
1390         if (visible && parent->isActive())
1391             q->setActive(true);
1392     } else {
1393         // Inherit ancestor flags from the new parent.
1394         updateAncestorFlags();
1395 
1396         if (!inDestructor) {
1397             // Update item visible / enabled.
1398             if (!visible && !explicitlyHidden)
1399                 setVisibleHelper(true, /* explicit = */ false);
1400             if (!enabled && !explicitlyDisabled)
1401                 setEnabledHelper(true, /* explicit = */ false);
1402         }
1403     }
1404 
1405     dirtySceneTransform = 1;
1406     if (!inDestructor && (transformData || (newParent && newParent->d_ptr->transformData)))
1407         transformChanged();
1408 
1409     // Restore the sub focus chain.
1410     if (subFocusItem) {
1411         subFocusItem->d_ptr->setSubFocus(newParent);
1412         if (parent && parent->isActive())
1413             subFocusItem->setFocus();
1414     }
1415 
1416     // Deliver post-change notification
1417     if (newParentVariant)
1418         q->itemChange(QGraphicsItem::ItemParentHasChanged, *newParentVariant);
1419 
1420     if (isObject)
1421         emit static_cast<QGraphicsObject *>(q)->parentChanged();
1422 }
1423 
1424 /*!
1425     \internal
1426 
1427     Returns the bounding rect of this item's children (excluding itself).
1428 */
childrenBoundingRectHelper(QTransform * x,QRectF * rect,QGraphicsItem * topMostEffectItem)1429 void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect, QGraphicsItem *topMostEffectItem)
1430 {
1431     Q_Q(QGraphicsItem);
1432 
1433     QRectF childrenRect;
1434     QRectF *result = rect;
1435     rect = &childrenRect;
1436     const bool setTopMostEffectItem = !topMostEffectItem;
1437 
1438     for (int i = 0; i < children.size(); ++i) {
1439         QGraphicsItem *child = children.at(i);
1440         QGraphicsItemPrivate *childd = child->d_ptr.data();
1441         if (setTopMostEffectItem)
1442             topMostEffectItem = child;
1443         bool hasPos = !childd->pos.isNull();
1444         if (hasPos || childd->transformData) {
1445             // COMBINE
1446             QTransform matrix = childd->transformToParent();
1447             if (x)
1448                 matrix *= *x;
1449             *rect |= matrix.mapRect(child->d_ptr->effectiveBoundingRect(topMostEffectItem));
1450             if (!childd->children.isEmpty())
1451                 childd->childrenBoundingRectHelper(&matrix, rect, topMostEffectItem);
1452         } else {
1453             if (x)
1454                 *rect |= x->mapRect(child->d_ptr->effectiveBoundingRect(topMostEffectItem));
1455             else
1456                 *rect |= child->d_ptr->effectiveBoundingRect(topMostEffectItem);
1457             if (!childd->children.isEmpty())
1458                 childd->childrenBoundingRectHelper(x, rect, topMostEffectItem);
1459         }
1460     }
1461 
1462     if (flags & QGraphicsItem::ItemClipsChildrenToShape){
1463         if (x)
1464             *rect &= x->mapRect(q->boundingRect());
1465         else
1466             *rect &= q->boundingRect();
1467     }
1468 
1469     *result |= *rect;
1470 }
1471 
initStyleOption(QStyleOptionGraphicsItem * option,const QTransform & worldTransform,const QRegion & exposedRegion,bool allItems) const1472 void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
1473                                            const QRegion &exposedRegion, bool allItems) const
1474 {
1475     Q_ASSERT(option);
1476     Q_Q(const QGraphicsItem);
1477 
1478     // Initialize standard QStyleOption values.
1479     const QRectF brect = q->boundingRect();
1480     option->state = QStyle::State_None;
1481     option->rect = brect.toRect();
1482     option->levelOfDetail = 1;
1483     option->exposedRect = brect;
1484 
1485     // Style animations require a QObject-based animation target.
1486     // If a plain QGraphicsItem is used to draw animated controls,
1487     // QStyle is let to send animation updates to the whole scene.
1488     option->styleObject = q_ptr->toGraphicsObject();
1489     if (!option->styleObject)
1490         option->styleObject = scene;
1491 
1492     if (selected)
1493         option->state |= QStyle::State_Selected;
1494     if (enabled)
1495         option->state |= QStyle::State_Enabled;
1496     if (q->hasFocus())
1497         option->state |= QStyle::State_HasFocus;
1498     if (scene) {
1499         if (scene->d_func()->hoverItems.contains(q_ptr))
1500             option->state |= QStyle::State_MouseOver;
1501         if (q == scene->mouseGrabberItem())
1502             option->state |= QStyle::State_Sunken;
1503     }
1504 
1505     if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption))
1506         return;
1507 
1508     // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect).
1509     option->matrix = worldTransform.toAffine(); //### discards perspective
1510 
1511     if (!allItems) {
1512         // Determine the item's exposed area
1513         option->exposedRect = QRectF();
1514         const QTransform reverseMap = worldTransform.inverted();
1515         for (const QRect &exposedRect : exposedRegion) {
1516             option->exposedRect |= reverseMap.mapRect(QRectF(exposedRect));
1517             if (option->exposedRect.contains(brect))
1518                 break;
1519         }
1520         option->exposedRect &= brect;
1521     }
1522 }
1523 
1524 /*!
1525     \internal
1526 
1527     Empty all cached pixmaps from the pixmap cache.
1528 */
purge()1529 void QGraphicsItemCache::purge()
1530 {
1531     QPixmapCache::remove(key);
1532     key = QPixmapCache::Key();
1533     const auto &constDeviceData = deviceData; // avoid detach
1534     for (const auto &data : constDeviceData)
1535         QPixmapCache::remove(data.key);
1536     deviceData.clear();
1537     allExposed = true;
1538     exposed.clear();
1539 }
1540 
1541 /*!
1542     Constructs a QGraphicsItem with the given \a parent item.
1543     It does not modify the parent object returned by QObject::parent().
1544 
1545     If \a parent is \nullptr, you can add the item to a scene by calling
1546     QGraphicsScene::addItem(). The item will then become a top-level item.
1547 
1548     \sa QGraphicsScene::addItem(), setParentItem()
1549 */
QGraphicsItem(QGraphicsItem * parent)1550 QGraphicsItem::QGraphicsItem(QGraphicsItem *parent)
1551     : d_ptr(new QGraphicsItemPrivate)
1552 {
1553     d_ptr->q_ptr = this;
1554     setParentItem(parent);
1555 }
1556 
1557 /*!
1558     \internal
1559 */
QGraphicsItem(QGraphicsItemPrivate & dd,QGraphicsItem * parent)1560 QGraphicsItem::QGraphicsItem(QGraphicsItemPrivate &dd, QGraphicsItem *parent)
1561     : d_ptr(&dd)
1562 {
1563     d_ptr->q_ptr = this;
1564     setParentItem(parent);
1565 }
1566 
1567 /*!
1568     Destroys the QGraphicsItem and all its children. If this item is currently
1569     associated with a scene, the item will be removed from the scene before it
1570     is deleted.
1571 
1572     \note It is more efficient to remove the item from the QGraphicsScene before
1573     destroying the item.
1574 */
~QGraphicsItem()1575 QGraphicsItem::~QGraphicsItem()
1576 {
1577     if (d_ptr->isObject) {
1578         QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
1579         QObjectPrivate *p = QObjectPrivate::get(o);
1580         p->wasDeleted = true;
1581         if (p->declarativeData) {
1582             p->wasDeleted = true; // needed, so that destroying the declarative data does the right thing
1583             if (static_cast<QAbstractDeclarativeDataImpl*>(p->declarativeData)->ownedByQml1) {
1584                 if (QAbstractDeclarativeData::destroyed_qml1)
1585                     QAbstractDeclarativeData::destroyed_qml1(p->declarativeData, o);
1586             } else {
1587                 if (QAbstractDeclarativeData::destroyed)
1588                     QAbstractDeclarativeData::destroyed(p->declarativeData, o);
1589             }
1590             p->declarativeData = nullptr;
1591             p->wasDeleted = false;
1592         }
1593     }
1594 
1595     d_ptr->inDestructor = 1;
1596     d_ptr->removeExtraItemCache();
1597 
1598 #ifndef QT_NO_GESTURES
1599     if (d_ptr->isObject && !d_ptr->gestureContext.isEmpty()) {
1600         QGraphicsObject *o = static_cast<QGraphicsObject *>(this);
1601         if (QGestureManager *manager = QGestureManager::instance(QGestureManager::DontForceCreation)) {
1602             const auto types  = d_ptr->gestureContext.keys(); // FIXME: iterate over the map directly?
1603             for (Qt::GestureType type : types)
1604                 manager->cleanupCachedGestures(o, type);
1605         }
1606     }
1607 #endif
1608 
1609     clearFocus();
1610     setFocusProxy(nullptr);
1611 
1612     // Update focus scope item ptr.
1613     QGraphicsItem *p = d_ptr->parent;
1614     while (p) {
1615         if (p->flags() & ItemIsFocusScope) {
1616             if (p->d_ptr->focusScopeItem == this)
1617                 p->d_ptr->focusScopeItem = nullptr;
1618             break;
1619         }
1620         p = p->d_ptr->parent;
1621     }
1622 
1623     if (!d_ptr->children.isEmpty()) {
1624         while (!d_ptr->children.isEmpty())
1625             delete d_ptr->children.first();
1626         Q_ASSERT(d_ptr->children.isEmpty());
1627     }
1628 
1629     if (d_ptr->scene) {
1630         d_ptr->scene->d_func()->removeItemHelper(this);
1631     } else {
1632         d_ptr->resetFocusProxy();
1633         setParentItem(nullptr);
1634     }
1635 
1636 #if QT_CONFIG(graphicseffect)
1637     delete d_ptr->graphicsEffect;
1638 #endif // QT_CONFIG(graphicseffect)
1639     if (d_ptr->transformData) {
1640         for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) {
1641             QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i);
1642             static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = nullptr;
1643             delete t;
1644         }
1645     }
1646     delete d_ptr->transformData;
1647 
1648     if (QGraphicsItemCustomDataStore *dataStore = qt_dataStore())
1649         dataStore->data.remove(this);
1650 }
1651 
1652 /*!
1653     Returns the current scene for the item, or \nullptr if the item is
1654     not stored in a scene.
1655 
1656     To add or move an item to a scene, call QGraphicsScene::addItem().
1657 */
scene() const1658 QGraphicsScene *QGraphicsItem::scene() const
1659 {
1660     return d_ptr->scene;
1661 }
1662 
1663 /*!
1664     Returns a pointer to this item's item group, or \nullptr if this
1665     item is not  member of a group.
1666 
1667     \sa QGraphicsItemGroup, QGraphicsScene::createItemGroup()
1668 */
group() const1669 QGraphicsItemGroup *QGraphicsItem::group() const
1670 {
1671     if (!d_ptr->isMemberOfGroup)
1672         return nullptr;
1673     QGraphicsItem *parent = const_cast<QGraphicsItem *>(this);
1674     while ((parent = parent->d_ptr->parent)) {
1675         if (QGraphicsItemGroup *group = qgraphicsitem_cast<QGraphicsItemGroup *>(parent))
1676             return group;
1677     }
1678     // Unreachable; if d_ptr->isMemberOfGroup is != 0, then one parent of this
1679     // item is a group item.
1680     return nullptr;
1681 }
1682 
1683 /*!
1684     Adds this item to the item group \a group. If \a group is \nullptr, this item is
1685     removed from any current group and added as a child of the previous
1686     group's parent.
1687 
1688     \sa group(), QGraphicsScene::createItemGroup()
1689 */
setGroup(QGraphicsItemGroup * group)1690 void QGraphicsItem::setGroup(QGraphicsItemGroup *group)
1691 {
1692     if (!group) {
1693         if (QGraphicsItemGroup *group = this->group())
1694             group->removeFromGroup(this);
1695     } else {
1696         group->addToGroup(this);
1697     }
1698 }
1699 
1700 /*!
1701     Returns a pointer to this item's parent item. If this item does not have a
1702     parent, \nullptr is returned.
1703 
1704     \sa setParentItem(), childItems()
1705 */
parentItem() const1706 QGraphicsItem *QGraphicsItem::parentItem() const
1707 {
1708     return d_ptr->parent;
1709 }
1710 
1711 /*!
1712     Returns this item's top-level item. The top-level item is the item's
1713     topmost ancestor item whose parent is \nullptr. If an item has no
1714     parent, its own pointer is returned (i.e., a top-level item is its
1715     own top-level item).
1716 
1717     \sa parentItem()
1718 */
topLevelItem() const1719 QGraphicsItem *QGraphicsItem::topLevelItem() const
1720 {
1721     QGraphicsItem *parent = const_cast<QGraphicsItem *>(this);
1722     while (QGraphicsItem *grandPa = parent->parentItem())
1723         parent = grandPa;
1724     return parent;
1725 }
1726 
1727 /*!
1728     \since 4.6
1729 
1730     Returns a pointer to the item's parent, cast to a QGraphicsObject. Returns
1731     \nullptr if the parent item is not a QGraphicsObject.
1732 
1733     \sa parentItem(), childItems()
1734 */
parentObject() const1735 QGraphicsObject *QGraphicsItem::parentObject() const
1736 {
1737     QGraphicsItem *p = d_ptr->parent;
1738     return (p && p->d_ptr->isObject) ? static_cast<QGraphicsObject *>(p) : nullptr;
1739 }
1740 
1741 /*!
1742     \since 4.4
1743 
1744     Returns a pointer to the item's parent widget. The item's parent widget is
1745     the closest parent item that is a widget.
1746 
1747     \sa parentItem(), childItems()
1748 */
parentWidget() const1749 QGraphicsWidget *QGraphicsItem::parentWidget() const
1750 {
1751     QGraphicsItem *p = parentItem();
1752     while (p && !p->isWidget())
1753         p = p->parentItem();
1754     return (p && p->isWidget()) ? static_cast<QGraphicsWidget *>(p) : nullptr;
1755 }
1756 
1757 /*!
1758     \since 4.4
1759 
1760     Returns a pointer to the item's top level widget (i.e., the item's
1761     ancestor whose parent is \nullptr, or whose parent is not a widget), or
1762     \nullptr if this item does not have a top level widget. If the item
1763     is its own top level  widget, this function returns a pointer to the
1764     item itself.
1765 */
topLevelWidget() const1766 QGraphicsWidget *QGraphicsItem::topLevelWidget() const
1767 {
1768     if (const QGraphicsWidget *p = parentWidget())
1769         return p->topLevelWidget();
1770     return isWidget() ? static_cast<QGraphicsWidget *>(const_cast<QGraphicsItem *>(this)) : nullptr;
1771 }
1772 
1773 /*!
1774     \since 4.4
1775 
1776     Returns the item's window, or \nullptr if this item does not have a
1777     window. If the item is a window, it will return itself.  Otherwise
1778     it will return the closest ancestor that is a window.
1779 
1780     \sa QGraphicsWidget::isWindow()
1781 */
window() const1782 QGraphicsWidget *QGraphicsItem::window() const
1783 {
1784     QGraphicsItem *p = panel();
1785     if (p && p->isWindow())
1786         return static_cast<QGraphicsWidget *>(p);
1787     return nullptr;
1788 }
1789 
1790 /*!
1791     \since 4.6
1792 
1793     Returns the item's panel, or \nullptr if this item does not have a
1794     panel. If the item is a panel, it will return itself. Otherwise it
1795     will return the closest ancestor that is a panel.
1796 
1797     \sa isPanel(), ItemIsPanel
1798 */
panel() const1799 QGraphicsItem *QGraphicsItem::panel() const
1800 {
1801     if (d_ptr->flags & ItemIsPanel)
1802         return const_cast<QGraphicsItem *>(this);
1803     return d_ptr->parent ? d_ptr->parent->panel() : nullptr;
1804 }
1805 
1806 /*!
1807   \since 4.6
1808 
1809   Return the graphics item cast to a QGraphicsObject, if the class is actually a
1810   graphics object, 0 otherwise.
1811 */
toGraphicsObject()1812 QGraphicsObject *QGraphicsItem::toGraphicsObject()
1813 {
1814     return d_ptr->isObject ? static_cast<QGraphicsObject *>(this) : nullptr;
1815 }
1816 
1817 /*!
1818   \since 4.6
1819 
1820   Return the graphics item cast to a QGraphicsObject, if the class is actually a
1821   graphics object, 0 otherwise.
1822 */
toGraphicsObject() const1823 const QGraphicsObject *QGraphicsItem::toGraphicsObject() const
1824 {
1825     return d_ptr->isObject ? static_cast<const QGraphicsObject *>(this) : nullptr;
1826 }
1827 
1828 /*!
1829   Sets this item's parent item to \a newParent. If this item already
1830   has a parent, it is first removed from the previous parent. If \a
1831   newParent is 0, this item will become a top-level item.
1832 
1833   Note that this implicitly adds this graphics item to the scene of
1834   the parent. You should not \l{QGraphicsScene::addItem()}{add} the
1835   item to the scene yourself.
1836 
1837   The behavior when calling this function on an item that is an ancestor of
1838   \a newParent is undefined.
1839 
1840   \sa parentItem(), childItems()
1841 */
setParentItem(QGraphicsItem * newParent)1842 void QGraphicsItem::setParentItem(QGraphicsItem *newParent)
1843 {
1844     if (newParent == this) {
1845         qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
1846         return;
1847     }
1848     if (newParent == d_ptr->parent)
1849         return;
1850 
1851     const QVariant newParentVariant(itemChange(QGraphicsItem::ItemParentChange,
1852                                                QVariant::fromValue<QGraphicsItem *>(newParent)));
1853     newParent = qvariant_cast<QGraphicsItem *>(newParentVariant);
1854     if (newParent == d_ptr->parent)
1855         return;
1856 
1857     const QVariant thisPointerVariant(QVariant::fromValue<QGraphicsItem *>(this));
1858     d_ptr->setParentItemHelper(newParent, &newParentVariant, &thisPointerVariant);
1859 }
1860 
1861 /*!
1862     \fn QList<QGraphicsItem *> QGraphicsItem::children() const
1863     \obsolete
1864 
1865     Use childItems() instead.
1866 
1867     \sa setParentItem()
1868 */
1869 
1870 /*!
1871     \since 4.4
1872 
1873     Returns a list of this item's children.
1874 
1875     The items are sorted by stacking order. This takes into account both the
1876     items' insertion order and their Z-values.
1877 
1878     \sa setParentItem(), zValue(), {QGraphicsItem#Sorting}{Sorting}
1879 */
childItems() const1880 QList<QGraphicsItem *> QGraphicsItem::childItems() const
1881 {
1882     const_cast<QGraphicsItem *>(this)->d_ptr->ensureSortedChildren();
1883     return d_ptr->children;
1884 }
1885 
1886 /*!
1887     \since 4.4
1888     Returns \c true if this item is a widget (i.e., QGraphicsWidget); otherwise,
1889     returns \c false.
1890 */
isWidget() const1891 bool QGraphicsItem::isWidget() const
1892 {
1893     return d_ptr->isWidget;
1894 }
1895 
1896 /*!
1897     \since 4.4
1898     Returns \c true if the item is a QGraphicsWidget window, otherwise returns
1899     false.
1900 
1901     \sa QGraphicsWidget::windowFlags()
1902 */
isWindow() const1903 bool QGraphicsItem::isWindow() const
1904 {
1905     return d_ptr->isWidget && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
1906 }
1907 
1908 /*!
1909     \since 4.6
1910     Returns \c true if the item is a panel; otherwise returns \c false.
1911 
1912     \sa QGraphicsItem::panel(), ItemIsPanel
1913 */
isPanel() const1914 bool QGraphicsItem::isPanel() const
1915 {
1916     return d_ptr->flags & ItemIsPanel;
1917 }
1918 
1919 /*!
1920     Returns this item's flags. The flags describe what configurable features
1921     of the item are enabled and not. For example, if the flags include
1922     ItemIsFocusable, the item can accept input focus.
1923 
1924     By default, no flags are enabled.
1925 
1926     \sa setFlags(), setFlag()
1927 */
flags() const1928 QGraphicsItem::GraphicsItemFlags QGraphicsItem::flags() const
1929 {
1930     return GraphicsItemFlags(d_ptr->flags);
1931 }
1932 
1933 /*!
1934     If \a enabled is true, the item flag \a flag is enabled; otherwise, it is
1935     disabled.
1936 
1937     \sa flags(), setFlags()
1938 */
setFlag(GraphicsItemFlag flag,bool enabled)1939 void QGraphicsItem::setFlag(GraphicsItemFlag flag, bool enabled)
1940 {
1941     if (enabled)
1942         setFlags(GraphicsItemFlags(d_ptr->flags) | flag);
1943     else
1944         setFlags(GraphicsItemFlags(d_ptr->flags) & ~flag);
1945 }
1946 
1947 /*!
1948     Sets the item flags to \a flags. All flags in \a flags are enabled; all
1949     flags not in \a flags are disabled.
1950 
1951     If the item had focus and \a flags does not enable ItemIsFocusable, the
1952     item loses focus as a result of calling this function. Similarly, if the
1953     item was selected, and \a flags does not enabled ItemIsSelectable, the
1954     item is automatically unselected.
1955 
1956     By default, no flags are enabled. (QGraphicsWidget enables the
1957     ItemSendsGeometryChanges flag by default in order to track position
1958     changes.)
1959 
1960     \sa flags(), setFlag()
1961 */
setFlags(GraphicsItemFlags flags)1962 void QGraphicsItem::setFlags(GraphicsItemFlags flags)
1963 {
1964     // Notify change and check for adjustment.
1965     if (quint32(d_ptr->flags) == quint32(flags))
1966         return;
1967     flags = GraphicsItemFlags(itemChange(ItemFlagsChange, quint32(flags)).toUInt());
1968     if (quint32(d_ptr->flags) == quint32(flags))
1969         return;
1970     if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex)
1971         d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, &flags);
1972 
1973     // Flags that alter the geometry of the item (or its children).
1974     const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
1975     bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
1976     if (fullUpdate)
1977         d_ptr->updatePaintedViewBoundingRects(/*children=*/true);
1978 
1979     // Keep the old flags to compare the diff.
1980     GraphicsItemFlags oldFlags = GraphicsItemFlags(d_ptr->flags);
1981 
1982     // Update flags.
1983     d_ptr->flags = flags;
1984 
1985     if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) {
1986         // Clear focus on the item if it has focus when the focusable flag
1987         // is unset.
1988         clearFocus();
1989     }
1990 
1991     if (!(d_ptr->flags & ItemIsSelectable) && isSelected()) {
1992         // Unselect the item if it is selected when the selectable flag is
1993         // unset.
1994         setSelected(false);
1995     }
1996 
1997     if ((flags & ItemClipsChildrenToShape) != (oldFlags & ItemClipsChildrenToShape)) {
1998         // Item children clipping changes. Propagate the ancestor flag to
1999         // all children.
2000         d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
2001         // The childrenBoundingRect is clipped to the boundingRect in case of ItemClipsChildrenToShape,
2002         // which means we have to invalidate the cached childrenBoundingRect whenever this flag changes.
2003         d_ptr->dirtyChildrenBoundingRect = 1;
2004         d_ptr->markParentDirty(true);
2005     }
2006 
2007     if ((flags & ItemContainsChildrenInShape) != (oldFlags & ItemContainsChildrenInShape)) {
2008         // Item children containtment changes. Propagate the ancestor flag to all children.
2009         d_ptr->updateAncestorFlag(ItemContainsChildrenInShape);
2010     }
2011 
2012     if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) {
2013         // Item children clipping changes. Propagate the ancestor flag to
2014         // all children.
2015         d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
2016     }
2017 
2018     if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
2019         // NB! We change the flags directly here, so we must also update d_ptr->flags.
2020         // Note that this has do be done before the ItemStacksBehindParent check
2021         // below; otherwise we will loose the change.
2022 
2023         // Update stack-behind.
2024         if (d_ptr->z < qreal(0.0))
2025             flags |= ItemStacksBehindParent;
2026         else
2027             flags &= ~ItemStacksBehindParent;
2028         d_ptr->flags = flags;
2029     }
2030 
2031     if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
2032         // NB! This check has to come after the ItemNegativeZStacksBehindParent
2033         // check above. Be careful.
2034 
2035         // Ensure child item sorting is up to date when toggling this flag.
2036         if (d_ptr->parent)
2037             d_ptr->parent->d_ptr->needSortChildren = 1;
2038         else if (d_ptr->scene)
2039             d_ptr->scene->d_func()->needSortTopLevelItems = 1;
2040     }
2041 
2042     if ((flags & ItemAcceptsInputMethod) != (oldFlags & ItemAcceptsInputMethod)) {
2043         // Update input method sensitivity in any views.
2044         if (d_ptr->scene)
2045             d_ptr->scene->d_func()->updateInputMethodSensitivityInViews();
2046     }
2047 
2048     if ((flags & ItemIsPanel) != (oldFlags & ItemIsPanel)) {
2049         bool becomesPanel = (flags & ItemIsPanel);
2050         if ((d_ptr->panelModality != NonModal) && d_ptr->scene) {
2051             // update the panel's modal state
2052             if (becomesPanel)
2053                 d_ptr->scene->d_func()->enterModal(this);
2054             else
2055                 d_ptr->scene->d_func()->leaveModal(this);
2056         }
2057         if (d_ptr->isWidget && (becomesPanel || parentWidget())) {
2058             QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this);
2059             QGraphicsWidget *focusFirst = w;
2060             QGraphicsWidget *focusLast = w;
2061             for (;;) {
2062                 QGraphicsWidget *test = focusLast->d_func()->focusNext;
2063                 if (!w->isAncestorOf(test) || test == w)
2064                     break;
2065                 focusLast = test;
2066             }
2067 
2068             if (becomesPanel) {
2069                 // unlink own widgets from focus chain
2070                 QGraphicsWidget *beforeMe = w->d_func()->focusPrev;
2071                 QGraphicsWidget *afterMe = focusLast->d_func()->focusNext;
2072                 beforeMe->d_func()->focusNext = afterMe;
2073                 afterMe->d_func()->focusPrev = beforeMe;
2074                 focusFirst->d_func()->focusPrev = focusLast;
2075                 focusLast->d_func()->focusNext = focusFirst;
2076                 if (!isAncestorOf(focusFirst->d_func()->focusNext))
2077                     focusFirst->d_func()->focusNext = w;
2078             } else if (QGraphicsWidget *pw = parentWidget()) {
2079                 // link up own widgets to focus chain
2080                 QGraphicsWidget *beforeMe = pw;
2081                 QGraphicsWidget *afterMe = pw->d_func()->focusNext;
2082                 beforeMe->d_func()->focusNext = w;
2083                 afterMe->d_func()->focusPrev = focusLast;
2084                 w->d_func()->focusPrev = beforeMe;
2085                 focusLast->d_func()->focusNext = afterMe;
2086             }
2087         }
2088     }
2089 
2090     if (d_ptr->scene) {
2091         if ((flags & ItemSendsScenePositionChanges) != (oldFlags & ItemSendsScenePositionChanges)) {
2092             if (flags & ItemSendsScenePositionChanges)
2093                 d_ptr->scene->d_func()->registerScenePosItem(this);
2094             else
2095                 d_ptr->scene->d_func()->unregisterScenePosItem(this);
2096         }
2097         d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
2098     }
2099 
2100     // Notify change.
2101     itemChange(ItemFlagsHaveChanged, quint32(flags));
2102 }
2103 
2104 /*!
2105     \since 4.4
2106     Returns the cache mode for this item. The default mode is NoCache (i.e.,
2107     cache is disabled and all painting is immediate).
2108 
2109     \sa setCacheMode()
2110 */
cacheMode() const2111 QGraphicsItem::CacheMode QGraphicsItem::cacheMode() const
2112 {
2113     return QGraphicsItem::CacheMode(d_ptr->cacheMode);
2114 }
2115 
2116 /*!
2117     \since 4.4
2118     Sets the item's cache mode to \a mode.
2119 
2120     The optional \a logicalCacheSize argument is used only by
2121     ItemCoordinateCache mode, and describes the resolution of the cache
2122     buffer; if \a logicalCacheSize is (100, 100), QGraphicsItem will fit the
2123     item into 100x100 pixels in graphics memory, regardless of the logical
2124     size of the item itself. By default QGraphicsItem uses the size of
2125     boundingRect(). For all other cache modes than ItemCoordinateCache, \a
2126     logicalCacheSize is ignored.
2127 
2128     Caching can speed up rendering if your item spends a significant time
2129     redrawing itself. In some cases the cache can also slow down rendering, in
2130     particular when the item spends less time redrawing than QGraphicsItem
2131     spends redrawing from the cache.
2132 
2133     When caching is enabled, an item's paint() function will generally draw into an
2134     offscreen pixmap cache; for any subsequent
2135     repaint requests, the Graphics View framework will redraw from the
2136     cache. This approach works particularly well with QGLWidget, which stores
2137     all the cache as OpenGL textures.
2138 
2139     Be aware that QPixmapCache's cache limit may need to be changed to obtain
2140     optimal performance.
2141 
2142     You can read more about the different cache modes in the CacheMode
2143     documentation.
2144 
2145     \note Enabling caching does not imply that the item's paint() function will be
2146     called only in response to an explicit update() call. For instance, under
2147     memory pressure, Qt may decide to drop some of the cache information;
2148     in such cases an item's paint() function will be called even if there
2149     was no update() call (that is, exactly as if there were no caching enabled).
2150 
2151     \sa CacheMode, QPixmapCache::setCacheLimit()
2152 */
setCacheMode(CacheMode mode,const QSize & logicalCacheSize)2153 void QGraphicsItem::setCacheMode(CacheMode mode, const QSize &logicalCacheSize)
2154 {
2155     CacheMode lastMode = CacheMode(d_ptr->cacheMode);
2156     d_ptr->cacheMode = mode;
2157     bool noVisualChange = (mode == NoCache && lastMode == NoCache)
2158                           || (mode == NoCache && lastMode == DeviceCoordinateCache)
2159                           || (mode == DeviceCoordinateCache && lastMode == NoCache)
2160                           || (mode == DeviceCoordinateCache && lastMode == DeviceCoordinateCache);
2161     if (mode == NoCache) {
2162         d_ptr->removeExtraItemCache();
2163     } else {
2164         QGraphicsItemCache *cache = d_ptr->extraItemCache();
2165 
2166         // Reset old cache
2167         cache->purge();
2168 
2169         if (mode == ItemCoordinateCache) {
2170             if (lastMode == mode && cache->fixedSize == logicalCacheSize)
2171                 noVisualChange = true;
2172             cache->fixedSize = logicalCacheSize;
2173         }
2174     }
2175     if (!noVisualChange)
2176         update();
2177 }
2178 
2179 /*!
2180     \since 4.6
2181 
2182     Returns the modality for this item.
2183 */
panelModality() const2184 QGraphicsItem::PanelModality QGraphicsItem::panelModality() const
2185 {
2186     return d_ptr->panelModality;
2187 }
2188 
2189 /*!
2190     \since 4.6
2191 
2192     Sets the modality for this item to \a panelModality.
2193 
2194     Changing the modality of a visible item takes effect immediately.
2195 */
setPanelModality(PanelModality panelModality)2196 void QGraphicsItem::setPanelModality(PanelModality panelModality)
2197 {
2198     if (d_ptr->panelModality == panelModality)
2199         return;
2200 
2201     PanelModality previousModality = d_ptr->panelModality;
2202     bool enterLeaveModal = (isPanel() && d_ptr->scene && isVisible());
2203     if (enterLeaveModal && panelModality == NonModal)
2204         d_ptr->scene->d_func()->leaveModal(this);
2205     d_ptr->panelModality = panelModality;
2206     if (enterLeaveModal && d_ptr->panelModality != NonModal)
2207         d_ptr->scene->d_func()->enterModal(this, previousModality);
2208 }
2209 
2210 /*!
2211     \since 4.6
2212 
2213     Returns \c true if this item is blocked by a modal panel, false otherwise. If \a blockingPanel is
2214     non-zero, \a blockingPanel will be set to the modal panel that is blocking this item. If this
2215     item is not blocked, \a blockingPanel will not be set by this function.
2216 
2217     This function always returns \c false for items not in a scene.
2218 
2219     \sa panelModality(), setPanelModality(), PanelModality
2220 */
isBlockedByModalPanel(QGraphicsItem ** blockingPanel) const2221 bool QGraphicsItem::isBlockedByModalPanel(QGraphicsItem **blockingPanel) const
2222 {
2223     if (!d_ptr->scene)
2224         return false;
2225 
2226 
2227     QGraphicsItem *dummy = nullptr;
2228     if (!blockingPanel)
2229         blockingPanel = &dummy;
2230 
2231     const QGraphicsScenePrivate *scene_d = d_ptr->scene->d_func();
2232     if (scene_d->modalPanels.isEmpty())
2233         return false;
2234 
2235     // ###
2236     if (!scene_d->popupWidgets.isEmpty() && scene_d->popupWidgets.first() == this)
2237         return false;
2238 
2239     for (int i = 0; i < scene_d->modalPanels.count(); ++i) {
2240         QGraphicsItem *modalPanel = scene_d->modalPanels.at(i);
2241         if (modalPanel->panelModality() == QGraphicsItem::SceneModal) {
2242             // Scene modal panels block all non-descendents.
2243             if (modalPanel != this && !modalPanel->isAncestorOf(this)) {
2244                 *blockingPanel = modalPanel;
2245                 return true;
2246             }
2247         } else {
2248             // Window modal panels block ancestors and siblings/cousins.
2249             if (modalPanel != this
2250                 && !modalPanel->isAncestorOf(this)
2251                 && commonAncestorItem(modalPanel)) {
2252                 *blockingPanel = modalPanel;
2253                 return true;
2254             }
2255         }
2256     }
2257     return false;
2258 }
2259 
2260 #ifndef QT_NO_TOOLTIP
2261 /*!
2262     Returns the item's tool tip, or an empty QString if no tool tip has been
2263     set.
2264 
2265     \sa setToolTip(), QToolTip
2266 */
toolTip() const2267 QString QGraphicsItem::toolTip() const
2268 {
2269     return d_ptr->extra(QGraphicsItemPrivate::ExtraToolTip).toString();
2270 }
2271 
2272 /*!
2273     Sets the item's tool tip to \a toolTip. If \a toolTip is empty, the item's
2274     tool tip is cleared.
2275 
2276     \sa toolTip(), QToolTip
2277 */
setToolTip(const QString & toolTip)2278 void QGraphicsItem::setToolTip(const QString &toolTip)
2279 {
2280     const QVariant toolTipVariant(itemChange(ItemToolTipChange, toolTip));
2281     d_ptr->setExtra(QGraphicsItemPrivate::ExtraToolTip, toolTipVariant.toString());
2282     itemChange(ItemToolTipHasChanged, toolTipVariant);
2283 }
2284 #endif // QT_NO_TOOLTIP
2285 
2286 #ifndef QT_NO_CURSOR
2287 /*!
2288     Returns the current cursor shape for the item. The mouse cursor
2289     will assume this shape when it's over this item.
2290     See the \l{Qt::CursorShape}{list of predefined cursor objects} for a
2291     range of useful shapes.
2292 
2293     An editor item might want to use an I-beam cursor:
2294 
2295     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 2
2296 
2297     If no cursor has been set, the cursor of the item beneath is used.
2298 
2299     \sa setCursor(), hasCursor(), unsetCursor(), QWidget::cursor,
2300     QApplication::overrideCursor()
2301 */
cursor() const2302 QCursor QGraphicsItem::cursor() const
2303 {
2304     return qvariant_cast<QCursor>(d_ptr->extra(QGraphicsItemPrivate::ExtraCursor));
2305 }
2306 
2307 /*!
2308     Sets the current cursor shape for the item to \a cursor. The mouse cursor
2309     will assume this shape when it's over this item.
2310     See the \l{Qt::CursorShape}{list of predefined cursor objects} for a
2311     range of useful shapes.
2312 
2313     An editor item might want to use an I-beam cursor:
2314 
2315     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 3
2316 
2317     If no cursor has been set, the cursor of the item beneath is used.
2318 
2319     \sa cursor(), hasCursor(), unsetCursor(), QWidget::cursor,
2320     QApplication::overrideCursor()
2321 */
setCursor(const QCursor & cursor)2322 void QGraphicsItem::setCursor(const QCursor &cursor)
2323 {
2324     const QVariant cursorVariant(itemChange(ItemCursorChange, QVariant::fromValue<QCursor>(cursor)));
2325     d_ptr->setExtra(QGraphicsItemPrivate::ExtraCursor, qvariant_cast<QCursor>(cursorVariant));
2326     d_ptr->hasCursor = 1;
2327     if (d_ptr->scene) {
2328         d_ptr->scene->d_func()->allItemsUseDefaultCursor = false;
2329         const auto views = d_ptr->scene->views();
2330         for (QGraphicsView *view : views) {
2331             view->viewport()->setMouseTracking(true);
2332             // Note: Some of this logic is duplicated in QGraphicsView's mouse events.
2333             if (view->underMouse()) {
2334                 const QPoint viewPoint = view->mapFromGlobal(QCursor::pos());
2335                 const QPointF cursorPos = mapFromScene(view->mapToScene(viewPoint));
2336                 // the cursor can only change if the current item is under the mouse
2337                 if (boundingRect().contains(cursorPos)) {
2338                     const auto itemsUnderCursor = view->items(viewPoint);
2339                     for (QGraphicsItem *itemUnderCursor : itemsUnderCursor) {
2340                         if (itemUnderCursor->hasCursor()) {
2341                             QMetaObject::invokeMethod(view, "_q_setViewportCursor",
2342                                                       Q_ARG(QCursor, itemUnderCursor->cursor()));
2343                             break;
2344                         }
2345                     }
2346                 }
2347                 break;
2348             }
2349         }
2350     }
2351     itemChange(ItemCursorHasChanged, cursorVariant);
2352 }
2353 
2354 /*!
2355     Returns \c true if this item has a cursor set; otherwise, false is returned.
2356 
2357     By default, items don't have any cursor set. cursor() will return a
2358     standard pointing arrow cursor.
2359 
2360     \sa unsetCursor()
2361 */
hasCursor() const2362 bool QGraphicsItem::hasCursor() const
2363 {
2364     return d_ptr->hasCursor;
2365 }
2366 
2367 /*!
2368     Clears the cursor from this item.
2369 
2370     \sa hasCursor(), setCursor()
2371 */
unsetCursor()2372 void QGraphicsItem::unsetCursor()
2373 {
2374     if (!d_ptr->hasCursor)
2375         return;
2376     d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraCursor);
2377     d_ptr->hasCursor = 0;
2378     if (d_ptr->scene) {
2379         const auto views = d_ptr->scene->views();
2380         for (QGraphicsView *view : views) {
2381             if (view->underMouse() && view->itemAt(view->mapFromGlobal(QCursor::pos())) == this) {
2382                 QMetaObject::invokeMethod(view, "_q_unsetViewportCursor");
2383                 break;
2384             }
2385         }
2386     }
2387 }
2388 
2389 #endif // QT_NO_CURSOR
2390 
2391 /*!
2392    Returns \c true if the item is visible; otherwise, false is returned.
2393 
2394    Note that the item's general visibility is unrelated to whether or not it
2395    is actually being visualized by a QGraphicsView.
2396 
2397    \sa setVisible()
2398 */
isVisible() const2399 bool QGraphicsItem::isVisible() const
2400 {
2401     return d_ptr->visible;
2402 }
2403 
2404 /*!
2405     \since 4.4
2406     Returns \c true if the item is visible to \a parent; otherwise, false is
2407     returned. \a parent can be \nullptr, in which case this function will return
2408     whether the item is visible to the scene or not.
2409 
2410     An item may not be visible to its ancestors even if isVisible() is true. It
2411     may also be visible to its ancestors even if isVisible() is false. If
2412     any ancestor is hidden, the item itself will be implicitly hidden, in which
2413     case this function will return false.
2414 
2415     \sa isVisible(), setVisible()
2416 */
isVisibleTo(const QGraphicsItem * parent) const2417 bool QGraphicsItem::isVisibleTo(const QGraphicsItem *parent) const
2418 {
2419     const QGraphicsItem *p = this;
2420     if (d_ptr->explicitlyHidden)
2421         return false;
2422     do {
2423         if (p == parent)
2424             return true;
2425         if (p->d_ptr->explicitlyHidden)
2426             return false;
2427     } while ((p = p->d_ptr->parent));
2428     return parent == nullptr;
2429 }
2430 
2431 /*!
2432     \internal
2433 
2434     Sets this item's visibility to \a newVisible. If \a explicitly is true,
2435     this item will be "explicitly" \a newVisible; otherwise, it.. will not be.
2436 */
setVisibleHelper(bool newVisible,bool explicitly,bool update,bool hiddenByPanel)2437 void QGraphicsItemPrivate::setVisibleHelper(bool newVisible, bool explicitly,
2438                                             bool update, bool hiddenByPanel)
2439 {
2440     Q_Q(QGraphicsItem);
2441 
2442     // Update explicit bit.
2443     if (explicitly)
2444         explicitlyHidden = newVisible ? 0 : 1;
2445 
2446     // Check if there's nothing to do.
2447     if (visible == quint32(newVisible))
2448         return;
2449 
2450     // Don't show child if parent is not visible
2451     if (parent && newVisible && !parent->d_ptr->visible)
2452         return;
2453 
2454     // Modify the property.
2455     const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange,
2456                                                        quint32(newVisible)));
2457     newVisible = newVisibleVariant.toBool();
2458     if (visible == quint32(newVisible))
2459         return;
2460     visible = newVisible;
2461 
2462     // Schedule redrawing
2463     if (update) {
2464         QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
2465         if (c)
2466             c->purge();
2467         if (scene) {
2468 #if QT_CONFIG(graphicseffect)
2469             invalidateParentGraphicsEffectsRecursively();
2470 #endif // QT_CONFIG(graphicseffect)
2471             scene->d_func()->markDirty(q_ptr, QRectF(), /*invalidateChildren=*/false, /*force=*/true);
2472         }
2473     }
2474 
2475     // Certain properties are dropped as an item becomes invisible.
2476     bool hasFocus = q_ptr->hasFocus();
2477     if (!newVisible) {
2478         if (scene) {
2479             if (scene->d_func()->mouseGrabberItems.contains(q))
2480                 q->ungrabMouse();
2481             if (scene->d_func()->keyboardGrabberItems.contains(q))
2482                 q->ungrabKeyboard();
2483             if (q->isPanel() && panelModality != QGraphicsItem::NonModal)
2484                 scene->d_func()->leaveModal(q_ptr);
2485         }
2486         if (hasFocus && scene) {
2487             // Hiding the focus item or the closest non-panel ancestor of the focus item
2488             QGraphicsItem *focusItem = scene->focusItem();
2489             bool clear = true;
2490             if (isWidget && !focusItem->isPanel()) {
2491                 do {
2492                     if (focusItem == q_ptr) {
2493                         clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
2494                         break;
2495                     }
2496                 } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
2497             }
2498             if (clear)
2499                 clearFocusHelper(/* giveFocusToParent = */ false, hiddenByPanel);
2500         }
2501         if (q_ptr->isSelected())
2502             q_ptr->setSelected(false);
2503     } else {
2504         geometryChanged = 1;
2505         paintedViewBoundingRectsNeedRepaint = 1;
2506         if (scene) {
2507             if (isWidget) {
2508                 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
2509                 if (widget->windowType() == Qt::Popup)
2510                     scene->d_func()->addPopup(widget);
2511             }
2512             if (q->isPanel() && panelModality != QGraphicsItem::NonModal) {
2513                 scene->d_func()->enterModal(q_ptr);
2514             }
2515         }
2516     }
2517 
2518     // Update children with explicitly = false.
2519     const bool updateChildren = update && !((flags & QGraphicsItem::ItemClipsChildrenToShape
2520                                              || flags & QGraphicsItem::ItemContainsChildrenInShape)
2521                                             && !(flags & QGraphicsItem::ItemHasNoContents));
2522     foreach (QGraphicsItem *child, children) {
2523         if (!newVisible || !child->d_ptr->explicitlyHidden)
2524             child->d_ptr->setVisibleHelper(newVisible, false, updateChildren, hiddenByPanel);
2525     }
2526 
2527     // Update activation
2528     if (scene && q->isPanel()) {
2529         if (newVisible) {
2530             if (parent && parent->isActive())
2531                 q->setActive(true);
2532         } else {
2533             if (q->isActive())
2534                 scene->setActivePanel(parent);
2535         }
2536     }
2537 
2538     // Enable subfocus
2539     if (scene) {
2540         if (newVisible) {
2541             // Item is shown
2542             QGraphicsItem *p = parent;
2543             bool done = false;
2544             while (p) {
2545                 if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
2546                     QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
2547                     if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
2548                         done = true;
2549                         while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible())
2550                             fsi = fsi->d_ptr->focusScopeItem;
2551                         fsi->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
2552                                                    /* focusFromHide = */ false);
2553                     }
2554                     break;
2555                 }
2556                 p = p->d_ptr->parent;
2557             }
2558             if (!done) {
2559                 QGraphicsItem *fi = subFocusItem;
2560                 if (fi && fi != scene->focusItem()) {
2561                     scene->setFocusItem(fi);
2562                 } else if (flags & QGraphicsItem::ItemIsFocusScope &&
2563                            !scene->focusItem() &&
2564                            q->isAncestorOf(scene->d_func()->lastFocusItem)) {
2565                     q_ptr->setFocus();
2566                 }
2567             }
2568         } else {
2569             // Item is hidden
2570             if (hasFocus) {
2571                 QGraphicsItem *p = parent;
2572                 while (p) {
2573                     if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
2574                         if (p->d_ptr->visible) {
2575                             p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ true,
2576                                                      /* focusFromHide = */ true);
2577                         }
2578                         break;
2579                     }
2580                     p = p->d_ptr->parent;
2581                 }
2582             }
2583         }
2584     }
2585 
2586     // Deliver post-change notification.
2587     q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant);
2588 
2589     if (isObject)
2590         emit static_cast<QGraphicsObject *>(q_ptr)->visibleChanged();
2591 }
2592 
2593 /*!
2594     If \a visible is true, the item is made visible. Otherwise, the item is
2595     made invisible. Invisible items are not painted, nor do they receive any
2596     events. In particular, mouse events pass right through invisible items,
2597     and are delivered to any item that may be behind. Invisible items are also
2598     unselectable, they cannot take input focus, and are not detected by
2599     QGraphicsScene's item location functions.
2600 
2601     If an item becomes invisible while grabbing the mouse, (i.e., while it is
2602     receiving mouse events,) it will automatically lose the mouse grab, and
2603     the grab is not regained by making the item visible again; it must receive
2604     a new mouse press to regain the mouse grab.
2605 
2606     Similarly, an invisible item cannot have focus, so if the item has focus
2607     when it becomes invisible, it will lose focus, and the focus is not
2608     regained by simply making the item visible again.
2609 
2610     If you hide a parent item, all its children will also be hidden. If you
2611     show a parent item, all children will be shown, unless they have been
2612     explicitly hidden (i.e., if you call setVisible(false) on a child, it will
2613     not be reshown even if its parent is hidden, and then shown again).
2614 
2615     Items are visible by default; it is unnecessary to call
2616     setVisible() on a new item.
2617 
2618     \note An item with opacity set to 0 will still be considered visible,
2619     although it will be treated like an invisible item: mouse events will pass
2620     through it, it will not be included in the items returned by
2621     QGraphicsView::items(), and so on. However, the item will retain the focus.
2622 
2623     \sa isVisible(), show(), hide(), setOpacity()
2624 */
setVisible(bool visible)2625 void QGraphicsItem::setVisible(bool visible)
2626 {
2627     d_ptr->setVisibleHelper(visible,
2628                             /* explicit = */ true,
2629                             /* update = */ true,
2630                             /* hiddenByPanel = */ isPanel());
2631 }
2632 
2633 /*!
2634     \fn void QGraphicsItem::hide()
2635 
2636     Hides the item (items are visible by default).
2637 
2638     This convenience function is equivalent to calling \c setVisible(false).
2639 
2640     \sa show(), setVisible()
2641 */
2642 
2643 /*!
2644     \fn void QGraphicsItem::show()
2645 
2646     Shows the item (items are visible by default).
2647 
2648     This convenience function is equivalent to calling \c setVisible(true).
2649 
2650     \sa hide(), setVisible()
2651 */
2652 
2653 /*!
2654     Returns \c true if the item is enabled; otherwise, false is returned.
2655 
2656     \sa setEnabled()
2657 */
isEnabled() const2658 bool QGraphicsItem::isEnabled() const
2659 {
2660     return d_ptr->enabled;
2661 }
2662 
2663 /*!
2664     \internal
2665 
2666     Sets this item's visibility to \a newEnabled. If \a explicitly is true,
2667     this item will be "explicitly" \a newEnabled; otherwise, it.. will not be.
2668 */
setEnabledHelper(bool newEnabled,bool explicitly,bool update)2669 void QGraphicsItemPrivate::setEnabledHelper(bool newEnabled, bool explicitly, bool update)
2670 {
2671     // Update explicit bit.
2672     if (explicitly)
2673         explicitlyDisabled = newEnabled ? 0 : 1;
2674 
2675     // Check if there's nothing to do.
2676     if (enabled == quint32(newEnabled))
2677         return;
2678 
2679     // Certain properties are dropped when an item is disabled.
2680     if (!newEnabled) {
2681         if (scene && scene->mouseGrabberItem() == q_ptr)
2682             q_ptr->ungrabMouse();
2683         if (q_ptr->hasFocus()) {
2684             // Disabling the closest non-panel ancestor of the focus item
2685             // causes focus to pop to the next item, otherwise it's cleared.
2686             QGraphicsItem *focusItem = scene->focusItem();
2687             bool clear = true;
2688             if (isWidget && !focusItem->isPanel() && q_ptr->isAncestorOf(focusItem)) {
2689                 do {
2690                     if (focusItem == q_ptr) {
2691                         clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(true);
2692                         break;
2693                     }
2694                 } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
2695             }
2696             if (clear)
2697                 q_ptr->clearFocus();
2698         }
2699         if (q_ptr->isSelected())
2700             q_ptr->setSelected(false);
2701     }
2702 
2703     // Modify the property.
2704     const QVariant newEnabledVariant(q_ptr->itemChange(QGraphicsItem::ItemEnabledChange,
2705                                                        quint32(newEnabled)));
2706     enabled = newEnabledVariant.toBool();
2707 
2708     // Schedule redraw.
2709     if (update)
2710         q_ptr->update();
2711 
2712     foreach (QGraphicsItem *child, children) {
2713         if (!newEnabled || !child->d_ptr->explicitlyDisabled)
2714             child->d_ptr->setEnabledHelper(newEnabled, /* explicitly = */ false);
2715     }
2716 
2717     // Deliver post-change notification.
2718     q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant);
2719 
2720     if (isObject)
2721         emit static_cast<QGraphicsObject *>(q_ptr)->enabledChanged();
2722 }
2723 
2724 /*!
2725     If \a enabled is true, the item is enabled; otherwise, it is disabled.
2726 
2727     Disabled items are visible, but they do not receive any events, and cannot
2728     take focus nor be selected. Mouse events are discarded; they are not
2729     propagated unless the item is also invisible, or if it does not accept
2730     mouse events (see acceptedMouseButtons()). A disabled item cannot become the
2731     mouse grabber, and as a result of this, an item loses the grab if it
2732     becomes disabled when grabbing the mouse, just like it loses focus if it
2733     had focus when it was disabled.
2734 
2735     Disabled items are traditionally drawn using grayed-out colors (see \l
2736     QPalette::Disabled).
2737 
2738     If you disable a parent item, all its children will also be disabled. If
2739     you enable a parent item, all children will be enabled, unless they have
2740     been explicitly disabled (i.e., if you call setEnabled(false) on a child,
2741     it will not be reenabled if its parent is disabled, and then enabled
2742     again).
2743 
2744     Items are enabled by default.
2745 
2746     \note If you install an event filter, you can still intercept events
2747     before they are delivered to items; this mechanism disregards the item's
2748     enabled state.
2749 
2750     \sa isEnabled()
2751 */
setEnabled(bool enabled)2752 void QGraphicsItem::setEnabled(bool enabled)
2753 {
2754     d_ptr->setEnabledHelper(enabled, /* explicitly = */ true);
2755 }
2756 
2757 /*!
2758     Returns \c true if this item is selected; otherwise, false is returned.
2759 
2760     Items that are in a group inherit the group's selected state.
2761 
2762     Items are not selected by default.
2763 
2764     \sa setSelected(), QGraphicsScene::setSelectionArea()
2765 */
isSelected() const2766 bool QGraphicsItem::isSelected() const
2767 {
2768     if (QGraphicsItemGroup *group = this->group())
2769         return group->isSelected();
2770     return d_ptr->selected;
2771 }
2772 
2773 /*!
2774     If \a selected is true and this item is selectable, this item is selected;
2775     otherwise, it is unselected.
2776 
2777     If the item is in a group, the whole group's selected state is toggled by
2778     this function. If the group is selected, all items in the group are also
2779     selected, and if the group is not selected, no item in the group is
2780     selected.
2781 
2782     Only visible, enabled, selectable items can be selected.  If \a selected
2783     is true and this item is either invisible or disabled or unselectable,
2784     this function does nothing.
2785 
2786     By default, items cannot be selected. To enable selection, set the
2787     ItemIsSelectable flag.
2788 
2789     This function is provided for convenience, allowing individual toggling of
2790     the selected state of an item. However, a more common way of selecting
2791     items is to call QGraphicsScene::setSelectionArea(), which will call this
2792     function for all visible, enabled, and selectable items within a specified
2793     area on the scene.
2794 
2795     \sa isSelected(), QGraphicsScene::selectedItems()
2796 */
setSelected(bool selected)2797 void QGraphicsItem::setSelected(bool selected)
2798 {
2799     if (QGraphicsItemGroup *group = this->group()) {
2800         group->setSelected(selected);
2801         return;
2802     }
2803 
2804     if (!(d_ptr->flags & ItemIsSelectable) || !d_ptr->enabled || !d_ptr->visible)
2805         selected = false;
2806     if (d_ptr->selected == selected)
2807         return;
2808     const QVariant newSelectedVariant(itemChange(ItemSelectedChange, quint32(selected)));
2809     bool newSelected = newSelectedVariant.toBool();
2810     if (d_ptr->selected == newSelected)
2811         return;
2812     d_ptr->selected = newSelected;
2813 
2814     update();
2815     if (d_ptr->scene) {
2816         QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
2817         if (selected) {
2818             sceneD->selectedItems << this;
2819         } else {
2820             // QGraphicsScene::selectedItems() lazily pulls out all items that are
2821             // no longer selected.
2822         }
2823         if (!sceneD->selectionChanging)
2824             emit d_ptr->scene->selectionChanged();
2825     }
2826 
2827     // Deliver post-change notification.
2828     itemChange(QGraphicsItem::ItemSelectedHasChanged, newSelectedVariant);
2829 }
2830 
2831 /*!
2832     \since 4.5
2833 
2834     Returns this item's local opacity, which is between 0.0 (transparent) and
2835     1.0 (opaque). This value is combined with parent and ancestor values into
2836     the effectiveOpacity(). The effective opacity decides how the item is
2837     rendered and also affects its visibility when queried by functions such as
2838     QGraphicsView::items().
2839 
2840     The opacity property decides the state of the painter passed to the
2841     paint() function. If the item is cached, i.e., ItemCoordinateCache or
2842     DeviceCoordinateCache, the effective property will be applied to the item's
2843     cache as it is rendered.
2844 
2845     The default opacity is 1.0; fully opaque.
2846 
2847     \sa setOpacity(), paint(), ItemIgnoresParentOpacity,
2848     ItemDoesntPropagateOpacityToChildren
2849 */
opacity() const2850 qreal QGraphicsItem::opacity() const
2851 {
2852     return d_ptr->opacity;
2853 }
2854 
2855 /*!
2856     \since 4.5
2857 
2858     Returns this item's \e effective opacity, which is between 0.0
2859     (transparent) and 1.0 (opaque). This value is a combination of this item's
2860     local opacity, and its parent and ancestors' opacities. The effective
2861     opacity decides how the item is rendered.
2862 
2863     \sa opacity(), setOpacity(), paint(), ItemIgnoresParentOpacity,
2864     ItemDoesntPropagateOpacityToChildren
2865 */
effectiveOpacity() const2866 qreal QGraphicsItem::effectiveOpacity() const
2867 {
2868     return d_ptr->effectiveOpacity();
2869 }
2870 
2871 /*!
2872     \since 4.5
2873 
2874     Sets this item's local \a opacity, between 0.0 (transparent) and 1.0
2875     (opaque). The item's local opacity is combined with parent and ancestor
2876     opacities into the effectiveOpacity().
2877 
2878     By default, opacity propagates from parent to child, so if a parent's
2879     opacity is 0.5 and the child is also 0.5, the child's effective opacity
2880     will be 0.25.
2881 
2882     The opacity property decides the state of the painter passed to the
2883     paint() function. If the item is cached, i.e., ItemCoordinateCache or
2884     DeviceCoordinateCache, the effective property will be applied to the
2885     item's cache as it is rendered.
2886 
2887     There are two item flags that affect how the item's opacity is combined
2888     with the parent: ItemIgnoresParentOpacity and
2889     ItemDoesntPropagateOpacityToChildren.
2890 
2891     \note Setting the opacity of an item to 0 will not make the item invisible
2892     (according to isVisible()), but the item will be treated like an invisible
2893     one. See the documentation of setVisible() for more information.
2894 
2895     \sa opacity(), effectiveOpacity(), setVisible()
2896 */
setOpacity(qreal opacity)2897 void QGraphicsItem::setOpacity(qreal opacity)
2898 {
2899     // Notify change.
2900     const QVariant newOpacityVariant(itemChange(ItemOpacityChange, opacity));
2901 
2902     // Normalized opacity
2903     qreal newOpacity = qBound(qreal(0), newOpacityVariant.toReal(), qreal(1));
2904 
2905     // No change? Done.
2906     if (newOpacity == d_ptr->opacity)
2907         return;
2908 
2909     bool wasFullyTransparent = d_ptr->isOpacityNull();
2910     d_ptr->opacity = newOpacity;
2911 
2912     // Notify change.
2913     itemChange(ItemOpacityHasChanged, newOpacityVariant);
2914 
2915     // Update.
2916     if (d_ptr->scene) {
2917 #if QT_CONFIG(graphicseffect)
2918         d_ptr->invalidateParentGraphicsEffectsRecursively();
2919         if (!(d_ptr->flags & ItemDoesntPropagateOpacityToChildren))
2920             d_ptr->invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::OpacityChanged);
2921 #endif // QT_CONFIG(graphicseffect)
2922         d_ptr->scene->d_func()->markDirty(this, QRectF(),
2923                                           /*invalidateChildren=*/true,
2924                                           /*force=*/false,
2925                                           /*ignoreOpacity=*/d_ptr->isOpacityNull());
2926         if (wasFullyTransparent)
2927             d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
2928     }
2929 
2930     if (d_ptr->isObject)
2931         emit static_cast<QGraphicsObject *>(this)->opacityChanged();
2932 }
2933 
2934 /*!
2935     Returns a pointer to this item's effect if it has one; otherwise \nullptr.
2936 
2937     \since 4.6
2938 */
2939 #if QT_CONFIG(graphicseffect)
graphicsEffect() const2940 QGraphicsEffect *QGraphicsItem::graphicsEffect() const
2941 {
2942     return d_ptr->graphicsEffect;
2943 }
2944 
2945 /*!
2946     Sets \a effect as the item's effect. If there already is an effect installed
2947     on this item, QGraphicsItem will delete the existing effect before installing
2948     the new \a effect. You can delete an existing effect by calling
2949     setGraphicsEffect(\nullptr).
2950 
2951     If \a effect is the installed effect on a different item, setGraphicsEffect() will remove
2952     the effect from the item and install it on this item.
2953 
2954     QGraphicsItem takes ownership of \a effect.
2955 
2956     \note This function will apply the effect on itself and all its children.
2957 
2958     \since 4.6
2959 */
setGraphicsEffect(QGraphicsEffect * effect)2960 void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
2961 {
2962     if (d_ptr->graphicsEffect == effect)
2963         return;
2964 
2965     if (d_ptr->graphicsEffect) {
2966         delete d_ptr->graphicsEffect;
2967         d_ptr->graphicsEffect = nullptr;
2968     } else if (d_ptr->parent) {
2969         d_ptr->parent->d_ptr->updateChildWithGraphicsEffectFlagRecursively();
2970     }
2971 
2972     if (effect) {
2973         // Set new effect.
2974         QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this);
2975         QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
2976         d_ptr->graphicsEffect = effect;
2977         effect->d_func()->setGraphicsEffectSource(source);
2978         prepareGeometryChange();
2979     }
2980 }
2981 #endif // QT_CONFIG(graphicseffect)
2982 
updateChildWithGraphicsEffectFlagRecursively()2983 void QGraphicsItemPrivate::updateChildWithGraphicsEffectFlagRecursively()
2984 {
2985 #if QT_CONFIG(graphicseffect)
2986     QGraphicsItemPrivate *itemPrivate = this;
2987     do {
2988         // parent chain already notified?
2989         if (itemPrivate->mayHaveChildWithGraphicsEffect)
2990             return;
2991         itemPrivate->mayHaveChildWithGraphicsEffect = 1;
2992     } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : nullptr));
2993 #endif
2994 }
2995 
2996 /*!
2997     \internal
2998     \since 4.6
2999     Returns the effective bounding rect of the given item space rect.
3000     If the item has no effect, the rect is returned unmodified.
3001     If the item has an effect, the effective rect can be extend beyond the
3002     item's bounding rect, depending on the effect.
3003 
3004     \sa boundingRect()
3005 */
effectiveBoundingRect(const QRectF & rect) const3006 QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const
3007 {
3008 #if QT_CONFIG(graphicseffect)
3009     Q_Q(const QGraphicsItem);
3010     QGraphicsEffect *effect = graphicsEffect;
3011     if (scene && effect && effect->isEnabled()) {
3012         if (scene->d_func()->views.isEmpty())
3013             return effect->boundingRectFor(rect);
3014         QRectF sceneRect = q->mapRectToScene(rect);
3015         QRectF sceneEffectRect;
3016         const auto views = scene->views();
3017         for (QGraphicsView *view : views) {
3018             QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect);
3019             QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect();
3020             sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect);
3021         }
3022         return q->mapRectFromScene(sceneEffectRect);
3023     }
3024 #endif // QT_CONFIG(graphicseffect)
3025     return rect;
3026 }
3027 
3028 /*!
3029     \internal
3030     \since 4.6
3031     Returns the effective bounding rect of the item.
3032     If the item has no effect, this is the same as the item's bounding rect.
3033     If the item has an effect, the effective rect can be larger than the item's
3034     bouding rect, depending on the effect.
3035 
3036     \sa boundingRect()
3037 */
effectiveBoundingRect(QGraphicsItem * topMostEffectItem) const3038 QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectItem) const
3039 {
3040 #if QT_CONFIG(graphicseffect)
3041     Q_Q(const QGraphicsItem);
3042     QRectF brect = effectiveBoundingRect(q_ptr->boundingRect());
3043     if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
3044         || ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren
3045         || topMostEffectItem == q)
3046         return brect;
3047 
3048     const QGraphicsItem *effectParent = parent;
3049     while (effectParent) {
3050         QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect;
3051         if (scene && effect && effect->isEnabled()) {
3052             const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect);
3053             const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace);
3054             brect = effectParent->mapRectToItem(q, effectRectInParentSpace);
3055         }
3056         if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
3057             || effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren
3058             || topMostEffectItem == effectParent) {
3059             return brect;
3060         }
3061         effectParent = effectParent->d_ptr->parent;
3062     }
3063 
3064     return brect;
3065 #else //QT_CONFIG(graphicseffect)
3066     Q_UNUSED(topMostEffectItem);
3067     return q_ptr->boundingRect();
3068 #endif // QT_CONFIG(graphicseffect)
3069 
3070 }
3071 
3072 /*!
3073     \internal
3074     \since 4.6
3075     Returns the effective bounding rect of this item in scene coordinates,
3076     by combining sceneTransform() with boundingRect(), taking into account
3077     the effect that the item might have.
3078 
3079     If the item has no effect, this is the same as sceneBoundingRect().
3080 
3081     \sa effectiveBoundingRect(), sceneBoundingRect()
3082 */
sceneEffectiveBoundingRect() const3083 QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const
3084 {
3085     // Find translate-only offset
3086     // COMBINE
3087     QPointF offset;
3088     const QGraphicsItem *parentItem = q_ptr;
3089     const QGraphicsItemPrivate *itemd;
3090     do {
3091         itemd = parentItem->d_ptr.data();
3092         if (itemd->transformData)
3093             break;
3094         offset += itemd->pos;
3095     } while ((parentItem = itemd->parent));
3096 
3097     QRectF br = effectiveBoundingRect();
3098     br.translate(offset);
3099     return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
3100 }
3101 
3102 /*!
3103    Returns \c true if this item can accept drag and drop events; otherwise,
3104    returns \c false. By default, items do not accept drag and drop events; items
3105    are transparent to drag and drop.
3106 
3107    \sa setAcceptDrops()
3108 */
acceptDrops() const3109 bool QGraphicsItem::acceptDrops() const
3110 {
3111     return d_ptr->acceptDrops;
3112 }
3113 
3114 /*!
3115     If \a on is true, this item will accept drag and drop events; otherwise,
3116     it is transparent for drag and drop events. By default, items do not
3117     accept drag and drop events.
3118 
3119     \sa acceptDrops()
3120 */
setAcceptDrops(bool on)3121 void QGraphicsItem::setAcceptDrops(bool on)
3122 {
3123     d_ptr->acceptDrops = on;
3124 }
3125 
3126 /*!
3127     Returns the mouse buttons that this item accepts mouse events for.  By
3128     default, all mouse buttons are accepted.
3129 
3130     If an item accepts a mouse button, it will become the mouse
3131     grabber item when a mouse press event is delivered for that mouse
3132     button. However, if the item does not accept the button,
3133     QGraphicsScene will forward the mouse events to the first item
3134     beneath it that does.
3135 
3136     \sa setAcceptedMouseButtons(), mousePressEvent()
3137 */
acceptedMouseButtons() const3138 Qt::MouseButtons QGraphicsItem::acceptedMouseButtons() const
3139 {
3140     return Qt::MouseButtons(d_ptr->acceptedMouseButtons);
3141 }
3142 
3143 /*!
3144     Sets the mouse \a buttons that this item accepts mouse events for.
3145 
3146     By default, all mouse buttons are accepted. If an item accepts a
3147     mouse button, it will become the mouse grabber item when a mouse
3148     press event is delivered for that button. However, if the item
3149     does not accept the mouse button, QGraphicsScene will forward the
3150     mouse events to the first item beneath it that does.
3151 
3152     To disable mouse events for an item (i.e., make it transparent for mouse
3153     events), call setAcceptedMouseButtons(0).
3154 
3155     \sa acceptedMouseButtons(), mousePressEvent()
3156 */
setAcceptedMouseButtons(Qt::MouseButtons buttons)3157 void QGraphicsItem::setAcceptedMouseButtons(Qt::MouseButtons buttons)
3158 {
3159     if (Qt::MouseButtons(d_ptr->acceptedMouseButtons) != buttons) {
3160         if (buttons == 0 && d_ptr->scene && d_ptr->scene->mouseGrabberItem() == this
3161             && d_ptr->scene->d_func()->lastMouseGrabberItemHasImplicitMouseGrab) {
3162             ungrabMouse();
3163         }
3164         d_ptr->acceptedMouseButtons = quint32(buttons);
3165     }
3166 }
3167 
3168 /*!
3169     \since 4.4
3170 
3171     Returns \c true if an item accepts hover events
3172     (QGraphicsSceneHoverEvent); otherwise, returns \c false. By default,
3173     items do not accept hover events.
3174 
3175     \sa setAcceptedMouseButtons()
3176 */
acceptHoverEvents() const3177 bool QGraphicsItem::acceptHoverEvents() const
3178 {
3179     return d_ptr->acceptsHover;
3180 }
3181 
3182 /*!
3183     \fn bool QGraphicsItem::acceptsHoverEvents() const
3184     \obsolete
3185 
3186     Call acceptHoverEvents() instead.
3187 */
3188 
3189 /*!
3190     \since 4.4
3191 
3192     If \a enabled is true, this item will accept hover events;
3193     otherwise, it will ignore them. By default, items do not accept
3194     hover events.
3195 
3196     Hover events are delivered when there is no current mouse grabber
3197     item.  They are sent when the mouse cursor enters an item, when it
3198     moves around inside the item, and when the cursor leaves an
3199     item. Hover events are commonly used to highlight an item when
3200     it's entered, and for tracking the mouse cursor as it hovers over
3201     the item (equivalent to QWidget::mouseTracking).
3202 
3203     Parent items receive hover enter events before their children, and
3204     leave events after their children. The parent does not receive a
3205     hover leave event if the cursor enters a child, though; the parent
3206     stays "hovered" until the cursor leaves its area, including its
3207     children's areas.
3208 
3209     If a parent item handles child events, it will receive hover move,
3210     drag move, and drop events as the cursor passes through its
3211     children, but it does not receive hover enter and hover leave, nor
3212     drag enter and drag leave events on behalf of its children.
3213 
3214     A QGraphicsWidget with window decorations will accept hover events
3215     regardless of the value of acceptHoverEvents().
3216 
3217     \sa acceptHoverEvents(), hoverEnterEvent(), hoverMoveEvent(),
3218     hoverLeaveEvent()
3219 */
setAcceptHoverEvents(bool enabled)3220 void QGraphicsItem::setAcceptHoverEvents(bool enabled)
3221 {
3222     if (d_ptr->acceptsHover == quint32(enabled))
3223         return;
3224     d_ptr->acceptsHover = quint32(enabled);
3225     if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) {
3226         d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false;
3227         d_ptr->scene->d_func()->enableMouseTrackingOnViews();
3228     }
3229 }
3230 
3231 /*!
3232     \fn void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
3233     \obsolete
3234 
3235     Use setAcceptHoverEvents(\a enabled) instead.
3236 */
3237 
3238 /*! \since 4.6
3239 
3240     Returns \c true if an item accepts \l{QTouchEvent}{touch events};
3241     otherwise, returns \c false. By default, items do not accept touch events.
3242 
3243     \sa setAcceptTouchEvents()
3244 */
acceptTouchEvents() const3245 bool QGraphicsItem::acceptTouchEvents() const
3246 {
3247     return d_ptr->acceptTouchEvents;
3248 }
3249 
3250 /*!
3251     \since 4.6
3252 
3253     If \a enabled is true, this item will accept \l{QTouchEvent}{touch events};
3254     otherwise, it will ignore them. By default, items do not accept
3255     touch events.
3256 */
setAcceptTouchEvents(bool enabled)3257 void QGraphicsItem::setAcceptTouchEvents(bool enabled)
3258 {
3259     if (d_ptr->acceptTouchEvents == quint32(enabled))
3260         return;
3261     d_ptr->acceptTouchEvents = quint32(enabled);
3262     if (d_ptr->acceptTouchEvents && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreTouchEvents) {
3263         d_ptr->scene->d_func()->allItemsIgnoreTouchEvents = false;
3264         d_ptr->scene->d_func()->enableTouchEventsOnViews();
3265     }
3266 }
3267 
3268 /*!
3269     \since 4.6
3270 
3271     Returns \c true if this item filters child events (i.e., all events
3272     intended for any of its children are instead sent to this item);
3273     otherwise, false is returned.
3274 
3275     The default value is false; child events are not filtered.
3276 
3277     \sa setFiltersChildEvents()
3278 */
filtersChildEvents() const3279 bool QGraphicsItem::filtersChildEvents() const
3280 {
3281     return d_ptr->filtersDescendantEvents;
3282 }
3283 
3284 /*!
3285     \since 4.6
3286 
3287     If \a enabled is true, this item is set to filter all events for
3288     all its children (i.e., all events intented for any of its
3289     children are instead sent to this item); otherwise, if \a enabled
3290     is false, this item will only handle its own events. The default
3291     value is false.
3292 
3293     \sa filtersChildEvents()
3294 */
setFiltersChildEvents(bool enabled)3295 void QGraphicsItem::setFiltersChildEvents(bool enabled)
3296 {
3297     if (d_ptr->filtersDescendantEvents == enabled)
3298         return;
3299 
3300     d_ptr->filtersDescendantEvents = enabled;
3301     d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
3302 }
3303 
3304 /*!
3305     \obsolete
3306 
3307     Returns \c true if this item handles child events (i.e., all events
3308     intended for any of its children are instead sent to this item);
3309     otherwise, false is returned.
3310 
3311     This property is useful for item groups; it allows one item to
3312     handle events on behalf of its children, as opposed to its
3313     children handling their events individually.
3314 
3315     The default is to return false; children handle their own events.
3316     The exception for this is if the item is a QGraphicsItemGroup, then
3317     it defaults to return true.
3318 
3319     \sa setHandlesChildEvents()
3320 */
handlesChildEvents() const3321 bool QGraphicsItem::handlesChildEvents() const
3322 {
3323     return d_ptr->handlesChildEvents;
3324 }
3325 
3326 /*!
3327     \obsolete
3328 
3329     If \a enabled is true, this item is set to handle all events for
3330     all its children (i.e., all events intented for any of its
3331     children are instead sent to this item); otherwise, if \a enabled
3332     is false, this item will only handle its own events. The default
3333     value is false.
3334 
3335     This property is useful for item groups; it allows one item to
3336     handle events on behalf of its children, as opposed to its
3337     children handling their events individually.
3338 
3339     If a child item accepts hover events, its parent will receive
3340     hover move events as the cursor passes through the child, but it
3341     does not receive hover enter and hover leave events on behalf of
3342     its child.
3343 
3344     \sa handlesChildEvents()
3345 */
setHandlesChildEvents(bool enabled)3346 void QGraphicsItem::setHandlesChildEvents(bool enabled)
3347 {
3348     if (d_ptr->handlesChildEvents == enabled)
3349         return;
3350 
3351     d_ptr->handlesChildEvents = enabled;
3352     d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
3353 }
3354 /*!
3355     \since 4.6
3356     Returns \c true if this item is active; otherwise returns \c false.
3357 
3358     An item can only be active if the scene is active. An item is active
3359     if it is, or is a descendent of, an active panel. Items in non-active
3360     panels are not active.
3361 
3362     Items that are not part of a panel follow scene activation when the
3363     scene has no active panel.
3364 
3365     Only active items can gain input focus.
3366 
3367     \sa QGraphicsScene::isActive(), QGraphicsScene::activePanel(), panel(), isPanel()
3368 */
isActive() const3369 bool QGraphicsItem::isActive() const
3370 {
3371     if (!d_ptr->scene || !d_ptr->scene->isActive())
3372         return false;
3373     return panel() == d_ptr->scene->activePanel();
3374 }
3375 
3376 /*!
3377     \since 4.6
3378 
3379     If \a active is true, and the scene is active, this item's panel will be
3380     activated. Otherwise, the panel is deactivated.
3381 
3382     If the item is not part of an active scene, \a active will decide what
3383     happens to the panel when the scene becomes active or the item is added to
3384     the scene. If true, the item's panel will be activated when the item is
3385     either added to the scene or the scene is activated. Otherwise, the item
3386     will stay inactive independent of the scene's activated state.
3387 
3388     \sa isPanel(), QGraphicsScene::setActivePanel(), QGraphicsScene::isActive()
3389 */
setActive(bool active)3390 void QGraphicsItem::setActive(bool active)
3391 {
3392     d_ptr->explicitActivate = 1;
3393     d_ptr->wantsActive = active;
3394     if (d_ptr->scene) {
3395         if (active) {
3396             // Activate this item.
3397             d_ptr->scene->setActivePanel(this);
3398         } else {
3399             QGraphicsItem *activePanel = d_ptr->scene->activePanel();
3400             QGraphicsItem *thisPanel = panel();
3401             if (!activePanel || activePanel == thisPanel) {
3402                 // Deactivate this item, and reactivate the parent panel,
3403                 // or the last active panel (if any).
3404                 QGraphicsItem *nextToActivate = nullptr;
3405                 if (d_ptr->parent)
3406                     nextToActivate = d_ptr->parent->panel();
3407                 if (!nextToActivate)
3408                     nextToActivate = d_ptr->scene->d_func()->lastActivePanel;
3409                 if (nextToActivate == this || isAncestorOf(nextToActivate))
3410                     nextToActivate = nullptr;
3411                 d_ptr->scene->setActivePanel(nextToActivate);
3412             }
3413         }
3414     }
3415 }
3416 
3417 /*!
3418     Returns \c true if this item is active, and it or its \l{focusProxy()}{focus
3419     proxy} has keyboard input focus; otherwise, returns \c false.
3420 
3421     \sa focusItem(), setFocus(), QGraphicsScene::setFocusItem(), isActive()
3422 */
hasFocus() const3423 bool QGraphicsItem::hasFocus() const
3424 {
3425     if (!d_ptr->scene || !d_ptr->scene->isActive())
3426         return false;
3427 
3428     if (d_ptr->focusProxy)
3429         return d_ptr->focusProxy->hasFocus();
3430 
3431     if (d_ptr->scene->d_func()->focusItem != this)
3432         return false;
3433 
3434     return panel() == d_ptr->scene->d_func()->activePanel;
3435 }
3436 
3437 /*!
3438     Gives keyboard input focus to this item. The \a focusReason argument will
3439     be passed into any \l{QFocusEvent}{focus event} generated by this function;
3440     it is used to give an explanation of what caused the item to get focus.
3441 
3442     Only enabled items that set the ItemIsFocusable flag can accept keyboard
3443     focus.
3444 
3445     If this item is not visible, not active, or not associated with a scene,
3446     it will not gain immediate input focus. However, it will be registered as
3447     the preferred focus item for its subtree of items, should it later become
3448     visible.
3449 
3450     As a result of calling this function, this item will receive a
3451     \l{focusInEvent()}{focus in event} with \a focusReason. If another item
3452     already has focus, that item will first receive a \l{focusOutEvent()}
3453     {focus out event} indicating that it has lost input focus.
3454 
3455     \sa clearFocus(), hasFocus(), focusItem(), focusProxy()
3456 */
setFocus(Qt::FocusReason focusReason)3457 void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
3458 {
3459     d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromHide = */ false);
3460 }
3461 
3462 /*!
3463     \internal
3464 */
setFocusHelper(Qt::FocusReason focusReason,bool climb,bool focusFromHide)3465 void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb, bool focusFromHide)
3466 {
3467     // Disabled / unfocusable items cannot accept focus.
3468     if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable))
3469         return;
3470 
3471     // Find focus proxy.
3472     QGraphicsItem *f = q_ptr;
3473     while (f->d_ptr->focusProxy)
3474         f = f->d_ptr->focusProxy;
3475 
3476     // Return if it already has focus.
3477     if (scene && scene->focusItem() == f)
3478         return;
3479 
3480     // Update focus scope item ptr.
3481     QGraphicsItem *p = parent;
3482     while (p) {
3483         if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
3484             QGraphicsItem *oldFocusScopeItem = p->d_ptr->focusScopeItem;
3485             p->d_ptr->focusScopeItem = q_ptr;
3486             if (oldFocusScopeItem)
3487                 oldFocusScopeItem->d_ptr->focusScopeItemChange(false);
3488             focusScopeItemChange(true);
3489             if (!p->focusItem() && !focusFromHide) {
3490                 // Calling setFocus() on a child of a focus scope that does
3491                 // not have focus changes only the focus scope pointer,
3492                 // so that focus is restored the next time the scope gains
3493                 // focus.
3494                 return;
3495             }
3496             break;
3497         }
3498         p = p->d_ptr->parent;
3499     }
3500 
3501     if (climb) {
3502         while (f->d_ptr->focusScopeItem && f->d_ptr->focusScopeItem->isVisible())
3503             f = f->d_ptr->focusScopeItem;
3504     }
3505 
3506     // Update the child focus chain.
3507     QGraphicsItem *commonAncestor = nullptr;
3508     if (scene && scene->focusItem() && scene->focusItem()->panel() == q_ptr->panel()) {
3509         commonAncestor = scene->focusItem()->commonAncestorItem(f);
3510         scene->focusItem()->d_ptr->clearSubFocus(scene->focusItem(), commonAncestor);
3511     }
3512 
3513     f->d_ptr->setSubFocus(f, commonAncestor);
3514 
3515     // Update the scene's focus item.
3516     if (scene) {
3517         QGraphicsItem *p = q_ptr->panel();
3518         if ((!p && scene->isActive()) || (p && p->isActive())) {
3519             // Visible items immediately gain focus from scene.
3520             scene->d_func()->setFocusItemHelper(f, focusReason);
3521         }
3522     }
3523 }
3524 
3525 /*!
3526     Takes keyboard input focus from the item.
3527 
3528     If it has focus, a \l{focusOutEvent()}{focus out event} is sent to this
3529     item to tell it that it is about to lose the focus.
3530 
3531     Only items that set the ItemIsFocusable flag, or widgets that set an
3532     appropriate focus policy, can accept keyboard focus.
3533 
3534     \sa setFocus(), hasFocus(), QGraphicsWidget::focusPolicy
3535 */
clearFocus()3536 void QGraphicsItem::clearFocus()
3537 {
3538     d_ptr->clearFocusHelper(/* giveFocusToParent = */ true,
3539                             /* hiddenByParentPanel = */ false);
3540 }
3541 
3542 /*!
3543     \internal
3544 */
clearFocusHelper(bool giveFocusToParent,bool hiddenByParentPanel)3545 void QGraphicsItemPrivate::clearFocusHelper(bool giveFocusToParent, bool hiddenByParentPanel)
3546 {
3547     QGraphicsItem *subFocusItem = q_ptr;
3548     if (flags & QGraphicsItem::ItemIsFocusScope) {
3549         while (subFocusItem->d_ptr->focusScopeItem)
3550             subFocusItem = subFocusItem->d_ptr->focusScopeItem;
3551     }
3552 
3553     if (giveFocusToParent) {
3554         // Pass focus to the closest parent focus scope
3555         if (!inDestructor) {
3556             QGraphicsItem *p = parent;
3557             while (p) {
3558                 if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
3559                     if (p->d_ptr->focusScopeItem == q_ptr) {
3560                         p->d_ptr->focusScopeItem = nullptr;
3561                         if (!subFocusItem->hasFocus()) //if it has focus, focusScopeItemChange is called elsewhere
3562                             focusScopeItemChange(false);
3563                     }
3564                     if (subFocusItem->hasFocus())
3565                         p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false,
3566                                                  /* focusFromHide = */ false);
3567                     return;
3568                 }
3569                 p = p->d_ptr->parent;
3570             }
3571         }
3572     }
3573 
3574     if (subFocusItem->hasFocus()) {
3575         // Invisible items with focus must explicitly clear subfocus.
3576         if (!hiddenByParentPanel)
3577             clearSubFocus(q_ptr);
3578 
3579         // If this item has the scene's input focus, clear it.
3580         scene->setFocusItem(nullptr);
3581     }
3582 }
3583 
3584 /*!
3585     \since 4.6
3586 
3587     Returns this item's focus proxy, or \nullptr if this item has no
3588     focus proxy.
3589 
3590     \sa setFocusProxy(), setFocus(), hasFocus()
3591 */
focusProxy() const3592 QGraphicsItem *QGraphicsItem::focusProxy() const
3593 {
3594     return d_ptr->focusProxy;
3595 }
3596 
3597 /*!
3598     \since 4.6
3599 
3600     Sets the item's focus proxy to \a item.
3601 
3602     If an item has a focus proxy, the focus proxy will receive
3603     input focus when the item gains input focus. The item itself
3604     will still have focus (i.e., hasFocus() will return true),
3605     but only the focus proxy will receive the keyboard input.
3606 
3607     A focus proxy can itself have a focus proxy, and so on. In
3608     such case, keyboard input will be handled by the outermost
3609     focus proxy.
3610 
3611     The focus proxy \a item must belong to the same scene as
3612     this item.
3613 
3614     \sa focusProxy(), setFocus(), hasFocus()
3615 */
setFocusProxy(QGraphicsItem * item)3616 void QGraphicsItem::setFocusProxy(QGraphicsItem *item)
3617 {
3618     if (item == d_ptr->focusProxy)
3619         return;
3620     if (item == this) {
3621         qWarning("QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
3622         return;
3623     }
3624     if (item) {
3625         if (item->d_ptr->scene != d_ptr->scene) {
3626             qWarning("QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
3627             return;
3628         }
3629         for (QGraphicsItem *f = item->focusProxy(); f != nullptr; f = f->focusProxy()) {
3630             if (f == this) {
3631                 qWarning("QGraphicsItem::setFocusProxy: %p is already in the focus proxy chain", item);
3632                 return;
3633             }
3634         }
3635     }
3636 
3637     QGraphicsItem *lastFocusProxy = d_ptr->focusProxy;
3638     if (lastFocusProxy)
3639         lastFocusProxy->d_ptr->focusProxyRefs.removeOne(&d_ptr->focusProxy);
3640     d_ptr->focusProxy = item;
3641     if (item)
3642         item->d_ptr->focusProxyRefs << &d_ptr->focusProxy;
3643 }
3644 
3645 /*!
3646     \since 4.6
3647 
3648     If this item, a child or descendant of this item currently has input
3649     focus, this function will return a pointer to that item. If
3650     no descendant has input focus, \nullptr is returned.
3651 
3652     \sa hasFocus(), setFocus(), QWidget::focusWidget()
3653 */
focusItem() const3654 QGraphicsItem *QGraphicsItem::focusItem() const
3655 {
3656     return d_ptr->subFocusItem;
3657 }
3658 
3659 /*!
3660     \internal
3661 
3662     Returns this item's focus scope item.
3663 */
focusScopeItem() const3664 QGraphicsItem *QGraphicsItem::focusScopeItem() const
3665 {
3666     return d_ptr->focusScopeItem;
3667 }
3668 
3669 /*!
3670     \since 4.4
3671     Grabs the mouse input.
3672 
3673     This item will receive all mouse events for the scene until any of the
3674     following events occurs:
3675 
3676     \list
3677     \li The item becomes invisible
3678     \li The item is removed from the scene
3679     \li The item is deleted
3680     \li The item call ungrabMouse()
3681     \li Another item calls grabMouse(); the item will regain the mouse grab
3682     when the other item calls ungrabMouse().
3683     \endlist
3684 
3685     When an item gains the mouse grab, it receives a QEvent::GrabMouse
3686     event. When it loses the mouse grab, it receives a QEvent::UngrabMouse
3687     event. These events can be used to detect when your item gains or loses
3688     the mouse grab through other means than receiving mouse button events.
3689 
3690     It is almost never necessary to explicitly grab the mouse in Qt, as Qt
3691     grabs and releases it sensibly. In particular, Qt grabs the mouse when you
3692     press a mouse button, and keeps the mouse grabbed until you release the
3693     last mouse button. Also, Qt::Popup widgets implicitly call grabMouse()
3694     when shown, and ungrabMouse() when hidden.
3695 
3696     Note that only visible items can grab mouse input. Calling grabMouse() on
3697     an invisible item has no effect.
3698 
3699     Keyboard events are not affected.
3700 
3701     \sa QGraphicsScene::mouseGrabberItem(), ungrabMouse(), grabKeyboard()
3702 */
grabMouse()3703 void QGraphicsItem::grabMouse()
3704 {
3705     if (!d_ptr->scene) {
3706         qWarning("QGraphicsItem::grabMouse: cannot grab mouse without scene");
3707         return;
3708     }
3709     if (!d_ptr->visible) {
3710         qWarning("QGraphicsItem::grabMouse: cannot grab mouse while invisible");
3711         return;
3712     }
3713     d_ptr->scene->d_func()->grabMouse(this);
3714 }
3715 
3716 /*!
3717     \since 4.4
3718     Releases the mouse grab.
3719 
3720     \sa grabMouse(), ungrabKeyboard()
3721 */
ungrabMouse()3722 void QGraphicsItem::ungrabMouse()
3723 {
3724     if (!d_ptr->scene) {
3725         qWarning("QGraphicsItem::ungrabMouse: cannot ungrab mouse without scene");
3726         return;
3727     }
3728     d_ptr->scene->d_func()->ungrabMouse(this);
3729 }
3730 
3731 /*!
3732     \since 4.4
3733     Grabs the keyboard input.
3734 
3735     The item will receive all keyboard input to the scene until one of the
3736     following events occur:
3737 
3738     \list
3739     \li The item becomes invisible
3740     \li The item is removed from the scene
3741     \li The item is deleted
3742     \li The item calls ungrabKeyboard()
3743     \li Another item calls grabKeyboard(); the item will regain the keyboard grab
3744     when the other item calls ungrabKeyboard().
3745     \endlist
3746 
3747     When an item gains the keyboard grab, it receives a QEvent::GrabKeyboard
3748     event. When it loses the keyboard grab, it receives a
3749     QEvent::UngrabKeyboard event. These events can be used to detect when your
3750     item gains or loses the keyboard grab through other means than gaining
3751     input focus.
3752 
3753     It is almost never necessary to explicitly grab the keyboard in Qt, as Qt
3754     grabs and releases it sensibly. In particular, Qt grabs the keyboard when
3755     your item gains input focus, and releases it when your item loses input
3756     focus, or when the item is hidden.
3757 
3758     Note that only visible items can grab keyboard input. Calling
3759     grabKeyboard() on an invisible item has no effect.
3760 
3761     Keyboard events are not affected.
3762 
3763     \sa ungrabKeyboard(), grabMouse(), setFocus()
3764 */
grabKeyboard()3765 void QGraphicsItem::grabKeyboard()
3766 {
3767     if (!d_ptr->scene) {
3768         qWarning("QGraphicsItem::grabKeyboard: cannot grab keyboard without scene");
3769         return;
3770     }
3771     if (!d_ptr->visible) {
3772         qWarning("QGraphicsItem::grabKeyboard: cannot grab keyboard while invisible");
3773         return;
3774     }
3775     d_ptr->scene->d_func()->grabKeyboard(this);
3776 }
3777 
3778 /*!
3779     \since 4.4
3780     Releases the keyboard grab.
3781 
3782     \sa grabKeyboard(), ungrabMouse()
3783 */
ungrabKeyboard()3784 void QGraphicsItem::ungrabKeyboard()
3785 {
3786     if (!d_ptr->scene) {
3787         qWarning("QGraphicsItem::ungrabKeyboard: cannot ungrab keyboard without scene");
3788         return;
3789     }
3790     d_ptr->scene->d_func()->ungrabKeyboard(this);
3791 }
3792 
3793 /*!
3794     Returns the position of the item in parent coordinates. If the item has no
3795     parent, its position is given in scene coordinates.
3796 
3797     The position of the item describes its origin (local coordinate
3798     (0, 0)) in parent coordinates; this function returns the same as
3799     mapToParent(0, 0).
3800 
3801     For convenience, you can also call scenePos() to determine the
3802     item's position in scene coordinates, regardless of its parent.
3803 
3804     \sa x(), y(), setPos(), transform(), {The Graphics View Coordinate System}
3805 */
pos() const3806 QPointF QGraphicsItem::pos() const
3807 {
3808     return d_ptr->pos;
3809 }
3810 
3811 /*!
3812     \fn QGraphicsItem::x() const
3813 
3814     This convenience function is equivalent to calling pos().x().
3815 
3816     \sa y()
3817 */
3818 
3819 /*!
3820     \since 4.6
3821 
3822     Set's the \a x coordinate of the item's position. Equivalent to
3823     calling setPos(x, y()).
3824 
3825     \sa x(), setPos()
3826 */
setX(qreal x)3827 void QGraphicsItem::setX(qreal x)
3828 {
3829     if (d_ptr->inDestructor)
3830         return;
3831 
3832     if (qIsNaN(x))
3833         return;
3834 
3835     setPos(QPointF(x, d_ptr->pos.y()));
3836 }
3837 
3838 /*!
3839     \fn QGraphicsItem::y() const
3840 
3841     This convenience function is equivalent to calling pos().y().
3842 
3843     \sa x()
3844 */
3845 
3846 /*!
3847     \since 4.6
3848 
3849     Set's the \a y coordinate of the item's position. Equivalent to
3850     calling setPos(x(), y).
3851 
3852     \sa x(), setPos()
3853 */
setY(qreal y)3854 void QGraphicsItem::setY(qreal y)
3855 {
3856     if (d_ptr->inDestructor)
3857         return;
3858 
3859     if (qIsNaN(y))
3860         return;
3861 
3862     setPos(QPointF(d_ptr->pos.x(), y));
3863 }
3864 
3865 /*!
3866     Returns the item's position in scene coordinates. This is
3867     equivalent to calling \c mapToScene(0, 0).
3868 
3869     \sa pos(), sceneTransform(), {The Graphics View Coordinate System}
3870 */
scenePos() const3871 QPointF QGraphicsItem::scenePos() const
3872 {
3873     return mapToScene(0, 0);
3874 }
3875 
3876 /*!
3877     \internal
3878 
3879     Sets the position \a pos.
3880 */
setPosHelper(const QPointF & pos)3881 void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
3882 {
3883     Q_Q(QGraphicsItem);
3884     inSetPosHelper = 1;
3885     if (scene)
3886         q->prepareGeometryChange();
3887     QPointF oldPos = this->pos;
3888     this->pos = pos;
3889     dirtySceneTransform = 1;
3890     inSetPosHelper = 0;
3891     if (isObject) {
3892         if (pos.x() != oldPos.x())
3893             emit static_cast<QGraphicsObject *>(q_ptr)->xChanged();
3894         if (pos.y() != oldPos.y())
3895             emit static_cast<QGraphicsObject *>(q_ptr)->yChanged();
3896     }
3897 }
3898 
3899 /*!
3900     \internal
3901 
3902     Sets the transform \a transform.
3903 */
setTransformHelper(const QTransform & transform)3904 void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform)
3905 {
3906     q_ptr->prepareGeometryChange();
3907     transformData->transform = transform;
3908     dirtySceneTransform = 1;
3909     transformChanged();
3910 }
3911 
3912 /*!
3913     Sets the position of the item to \a pos, which is in parent
3914     coordinates.  For items with no parent, \a pos is in scene
3915     coordinates.
3916 
3917     The position of the item describes its origin (local coordinate
3918     (0, 0)) in parent coordinates.
3919 
3920     \sa pos(), scenePos(), {The Graphics View Coordinate System}
3921 */
setPos(const QPointF & pos)3922 void QGraphicsItem::setPos(const QPointF &pos)
3923 {
3924     if (d_ptr->pos == pos)
3925         return;
3926 
3927     if (d_ptr->inDestructor)
3928         return;
3929 
3930     // Update and repositition.
3931     if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
3932         d_ptr->setPosHelper(pos);
3933         if (d_ptr->isWidget)
3934             static_cast<QGraphicsWidget *>(this)->d_func()->setGeometryFromSetPos();
3935         if (d_ptr->scenePosDescendants)
3936             d_ptr->sendScenePosChange();
3937         return;
3938     }
3939 
3940     // Notify the item that the position is changing.
3941     const QVariant newPosVariant(itemChange(ItemPositionChange, QVariant::fromValue<QPointF>(pos)));
3942     QPointF newPos = newPosVariant.toPointF();
3943     if (newPos == d_ptr->pos)
3944         return;
3945 
3946     // Update and repositition.
3947     d_ptr->setPosHelper(newPos);
3948 
3949     // Send post-notification.
3950     itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
3951     d_ptr->sendScenePosChange();
3952 }
3953 
3954 /*!
3955     \fn void QGraphicsItem::setPos(qreal x, qreal y)
3956     \overload
3957 
3958     This convenience function is equivalent to calling setPos(QPointF(\a x, \a
3959     y)).
3960 */
3961 
3962 /*!
3963     \fn void QGraphicsItem::moveBy(qreal dx, qreal dy)
3964 
3965     Moves the item by \a dx points horizontally, and \a dy point
3966     vertically. This function is equivalent to calling setPos(pos() +
3967     QPointF(\a dx, \a dy)).
3968 */
3969 
3970 /*!
3971     If this item is part of a scene that is viewed by a QGraphicsView, this
3972     convenience function will attempt to scroll the view to ensure that \a
3973     rect is visible inside the view's viewport. If \a rect is a null rect (the
3974     default), QGraphicsItem will default to the item's bounding rect. \a xmargin
3975     and \a ymargin are the number of pixels the view should use for margins.
3976 
3977     If the specified rect cannot be reached, the contents are scrolled to the
3978     nearest valid position.
3979 
3980     If this item is not viewed by a QGraphicsView, this function does nothing.
3981 
3982     \sa QGraphicsView::ensureVisible()
3983 */
ensureVisible(const QRectF & rect,int xmargin,int ymargin)3984 void QGraphicsItem::ensureVisible(const QRectF &rect, int xmargin, int ymargin)
3985 {
3986     if (d_ptr->scene) {
3987         QRectF sceneRect;
3988         if (!rect.isNull())
3989             sceneRect = sceneTransform().mapRect(rect);
3990         else
3991             sceneRect = sceneBoundingRect();
3992         foreach (QGraphicsView *view, d_ptr->scene->d_func()->views)
3993             view->ensureVisible(sceneRect, xmargin, ymargin);
3994     }
3995 }
3996 
3997 /*!
3998     \fn void QGraphicsItem::ensureVisible(qreal x, qreal y, qreal w, qreal h,
3999     int xmargin = 50, int ymargin = 50)
4000 
4001     This convenience function is equivalent to calling
4002     ensureVisible(QRectF(\a x, \a y, \a w, \a h), \a xmargin, \a ymargin).
4003 */
4004 
4005 #if QT_DEPRECATED_SINCE(5, 13)
4006 /*!
4007     \obsolete
4008 
4009     Returns the item's affine transformation matrix. This is a subset or the
4010     item's full transformation matrix, and might not represent the item's full
4011     transformation.
4012 
4013     Use transform() instead.
4014 
4015     \sa setTransform(), sceneTransform()
4016 */
matrix() const4017 QMatrix QGraphicsItem::matrix() const
4018 {
4019     return transform().toAffine();
4020 }
4021 #endif
4022 
4023 /*!
4024     \since 4.3
4025 
4026     Returns this item's transformation matrix.
4027 
4028     The transformation matrix is combined with the item's rotation(), scale()
4029     and transformations() into a combined transformations for the item.
4030 
4031     The default transformation matrix is an identity matrix.
4032 
4033     \sa setTransform(), sceneTransform()
4034 */
transform() const4035 QTransform QGraphicsItem::transform() const
4036 {
4037     if (!d_ptr->transformData)
4038         return QTransform();
4039     return d_ptr->transformData->transform;
4040 }
4041 
4042 /*!
4043     \since 4.6
4044 
4045     Returns the clockwise rotation, in degrees, around the Z axis. The default
4046     value is 0 (i.e., the item is not rotated).
4047 
4048     The rotation is combined with the item's scale(), transform() and
4049     transformations() to map the item's coordinate system to the parent item.
4050 
4051     \sa setRotation(), transformOriginPoint(), {Transformations}
4052 */
rotation() const4053 qreal QGraphicsItem::rotation() const
4054 {
4055     if (!d_ptr->transformData)
4056         return 0;
4057     return d_ptr->transformData->rotation;
4058 }
4059 
4060 /*!
4061     \since 4.6
4062 
4063     Sets the clockwise rotation \a angle, in degrees, around the Z axis. The
4064     default value is 0 (i.e., the item is not rotated). Assigning a negative
4065     value will rotate the item counter-clockwise. Normally the rotation angle
4066     is in the range (-360, 360), but it's also possible to assign values
4067     outside of this range (e.g., a rotation of 370 degrees is the same as a
4068     rotation of 10 degrees).
4069 
4070     The item is rotated around its transform origin point, which by default
4071     is (0, 0). You can select a different transformation origin by calling
4072     setTransformOriginPoint().
4073 
4074     The rotation is combined with the item's scale(), transform() and
4075     transformations() to map the item's coordinate system to the parent item.
4076 
4077     \sa rotation(), setTransformOriginPoint(), {Transformations}
4078 */
setRotation(qreal angle)4079 void QGraphicsItem::setRotation(qreal angle)
4080 {
4081     prepareGeometryChange();
4082     qreal newRotation = angle;
4083 
4084     if (d_ptr->flags & ItemSendsGeometryChanges) {
4085         // Notify the item that the rotation is changing.
4086         const QVariant newRotationVariant(itemChange(ItemRotationChange, angle));
4087         newRotation = newRotationVariant.toReal();
4088     }
4089 
4090     if (!d_ptr->transformData)
4091         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4092 
4093     if (d_ptr->transformData->rotation == newRotation)
4094         return;
4095 
4096     d_ptr->transformData->rotation = newRotation;
4097     d_ptr->transformData->onlyTransform = false;
4098     d_ptr->dirtySceneTransform = 1;
4099 
4100     // Send post-notification.
4101     if (d_ptr->flags & ItemSendsGeometryChanges)
4102         itemChange(ItemRotationHasChanged, newRotation);
4103 
4104     if (d_ptr->isObject)
4105         emit static_cast<QGraphicsObject *>(this)->rotationChanged();
4106 
4107     d_ptr->transformChanged();
4108 }
4109 
4110 /*!
4111     \since 4.6
4112 
4113     Returns the scale factor of the item. The default scale factor is 1.0
4114     (i.e., the item is not scaled).
4115 
4116     The scale is combined with the item's rotation(), transform() and
4117     transformations() to map the item's coordinate system to the parent item.
4118 
4119     \sa setScale(), rotation(), {Transformations}
4120 */
scale() const4121 qreal QGraphicsItem::scale() const
4122 {
4123     if (!d_ptr->transformData)
4124         return 1.;
4125     return d_ptr->transformData->scale;
4126 }
4127 
4128 /*!
4129     \since 4.6
4130 
4131     Sets the scale \a factor of the item. The default scale factor is 1.0
4132     (i.e., the item is not scaled). A scale factor of 0.0 will collapse the
4133     item to a single point. If you provide a negative scale factor, the
4134     item will be flipped and mirrored (i.e., rotated 180 degrees).
4135 
4136     The item is scaled around its transform origin point, which by default
4137     is (0, 0). You can select a different transformation origin by calling
4138     setTransformOriginPoint().
4139 
4140     The scale is combined with the item's rotation(), transform() and
4141     transformations() to map the item's coordinate system to the parent item.
4142 
4143     \sa scale(), setTransformOriginPoint(), {Transformations Example}
4144 */
setScale(qreal factor)4145 void QGraphicsItem::setScale(qreal factor)
4146 {
4147     prepareGeometryChange();
4148     qreal newScale = factor;
4149 
4150     if (d_ptr->flags & ItemSendsGeometryChanges) {
4151         // Notify the item that the scale is changing.
4152         const QVariant newScaleVariant(itemChange(ItemScaleChange, factor));
4153         newScale = newScaleVariant.toReal();
4154     }
4155 
4156     if (!d_ptr->transformData)
4157         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4158 
4159     if (d_ptr->transformData->scale == newScale)
4160         return;
4161 
4162     d_ptr->transformData->scale = newScale;
4163     d_ptr->transformData->onlyTransform = false;
4164     d_ptr->dirtySceneTransform = 1;
4165 
4166     // Send post-notification.
4167     if (d_ptr->flags & ItemSendsGeometryChanges)
4168         itemChange(ItemScaleHasChanged, newScale);
4169 
4170     if (d_ptr->isObject)
4171         emit static_cast<QGraphicsObject *>(this)->scaleChanged();
4172 
4173     d_ptr->transformChanged();
4174 }
4175 
4176 
4177 /*!
4178     \since 4.6
4179 
4180     Returns a list of graphics transforms that currently apply to this item.
4181 
4182     QGraphicsTransform is for applying and controlling a chain of individual
4183     transformation operations on an item. It's particularly useful in
4184     animations, where each transform operation needs to be interpolated
4185     independently, or differently.
4186 
4187     The transformations are combined with the item's rotation(), scale() and
4188     transform() to map the item's coordinate system to the parent item.
4189 
4190     \sa scale(), rotation(), transformOriginPoint(), {Transformations}
4191 */
transformations() const4192 QList<QGraphicsTransform *> QGraphicsItem::transformations() const
4193 {
4194     if (!d_ptr->transformData)
4195         return QList<QGraphicsTransform *>();
4196     return d_ptr->transformData->graphicsTransforms;
4197 }
4198 
4199 /*!
4200     \since 4.6
4201 
4202     Sets a list of graphics \a transformations (QGraphicsTransform) that
4203     currently apply to this item.
4204 
4205     If all you want is to rotate or scale an item, you should call setRotation()
4206     or setScale() instead. If you want to set an arbitrary transformation on
4207     an item, you can call setTransform().
4208 
4209     QGraphicsTransform is for applying and controlling a chain of individual
4210     transformation operations on an item. It's particularly useful in
4211     animations, where each transform operation needs to be interpolated
4212     independently, or differently.
4213 
4214     The transformations are combined with the item's rotation(), scale() and
4215     transform() to map the item's coordinate system to the parent item.
4216 
4217     \sa scale(), setTransformOriginPoint(), {Transformations}
4218 */
setTransformations(const QList<QGraphicsTransform * > & transformations)4219 void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transformations)
4220 {
4221     prepareGeometryChange();
4222     if (!d_ptr->transformData)
4223         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4224     d_ptr->transformData->graphicsTransforms = transformations;
4225     for (int i = 0; i < transformations.size(); ++i)
4226         transformations.at(i)->d_func()->setItem(this);
4227     d_ptr->transformData->onlyTransform = false;
4228     d_ptr->dirtySceneTransform = 1;
4229     d_ptr->transformChanged();
4230 }
4231 
4232 /*!
4233     \internal
4234 */
prependGraphicsTransform(QGraphicsTransform * t)4235 void QGraphicsItemPrivate::prependGraphicsTransform(QGraphicsTransform *t)
4236 {
4237     if (!transformData)
4238         transformData = new QGraphicsItemPrivate::TransformData;
4239     if (!transformData->graphicsTransforms.contains(t))
4240         transformData->graphicsTransforms.prepend(t);
4241 
4242     Q_Q(QGraphicsItem);
4243     t->d_func()->setItem(q);
4244     transformData->onlyTransform = false;
4245     dirtySceneTransform = 1;
4246     transformChanged();
4247 }
4248 
4249 /*!
4250     \internal
4251 */
appendGraphicsTransform(QGraphicsTransform * t)4252 void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t)
4253 {
4254     if (!transformData)
4255         transformData = new QGraphicsItemPrivate::TransformData;
4256     if (!transformData->graphicsTransforms.contains(t))
4257         transformData->graphicsTransforms.append(t);
4258 
4259     Q_Q(QGraphicsItem);
4260     t->d_func()->setItem(q);
4261     transformData->onlyTransform = false;
4262     dirtySceneTransform = 1;
4263     transformChanged();
4264 }
4265 
4266 /*!
4267     \since 4.6
4268 
4269     Returns the origin point for the transformation in item coordinates.
4270 
4271     The default is QPointF(0,0).
4272 
4273     \sa setTransformOriginPoint(), {Transformations}
4274 */
transformOriginPoint() const4275 QPointF QGraphicsItem::transformOriginPoint() const
4276 {
4277     if (!d_ptr->transformData)
4278         return QPointF(0,0);
4279     return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin);
4280 }
4281 
4282 /*!
4283     \since 4.6
4284 
4285     Sets the \a origin point for the transformation in item coordinates.
4286 
4287     \sa transformOriginPoint(), {Transformations}
4288 */
setTransformOriginPoint(const QPointF & origin)4289 void QGraphicsItem::setTransformOriginPoint(const QPointF &origin)
4290 {
4291     prepareGeometryChange();
4292     QPointF newOrigin = origin;
4293 
4294     if (d_ptr->flags & ItemSendsGeometryChanges) {
4295         // Notify the item that the origin point is changing.
4296         const QVariant newOriginVariant(itemChange(ItemTransformOriginPointChange,
4297                                                    QVariant::fromValue<QPointF>(origin)));
4298         newOrigin = newOriginVariant.toPointF();
4299     }
4300 
4301     if (!d_ptr->transformData)
4302         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4303 
4304     if (d_ptr->transformData->xOrigin == newOrigin.x()
4305         && d_ptr->transformData->yOrigin == newOrigin.y()) {
4306         return;
4307     }
4308 
4309     d_ptr->transformData->xOrigin = newOrigin.x();
4310     d_ptr->transformData->yOrigin = newOrigin.y();
4311     d_ptr->transformData->onlyTransform = false;
4312     d_ptr->dirtySceneTransform = 1;
4313 
4314     // Send post-notification.
4315     if (d_ptr->flags & ItemSendsGeometryChanges)
4316         itemChange(ItemTransformOriginPointHasChanged, QVariant::fromValue<QPointF>(newOrigin));
4317 }
4318 
4319 /*!
4320     \fn void QGraphicsItem::setTransformOriginPoint(qreal x, qreal y)
4321 
4322     \since 4.6
4323     \overload
4324 
4325     Sets the origin point for the transformation in item coordinates.
4326     This is equivalent to calling setTransformOriginPoint(QPointF(\a x, \a y)).
4327 
4328     \sa setTransformOriginPoint(), {Transformations}
4329 */
4330 
4331 
4332 #if QT_DEPRECATED_SINCE(5, 13)
4333 /*!
4334     \obsolete
4335 
4336     Use sceneTransform() instead.
4337 
4338     \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
4339 */
sceneMatrix() const4340 QMatrix QGraphicsItem::sceneMatrix() const
4341 {
4342     d_ptr->ensureSceneTransform();
4343     return d_ptr->sceneTransform.toAffine();
4344 }
4345 #endif
4346 
4347 /*!
4348     \since 4.3
4349 
4350     Returns this item's scene transformation matrix. This matrix can be used
4351     to map coordinates and geometrical shapes from this item's local
4352     coordinate system to the scene's coordinate system. To map coordinates
4353     from the scene, you must first invert the returned matrix.
4354 
4355     Example:
4356 
4357     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 4
4358 
4359     Unlike transform(), which returns only an item's local transformation, this
4360     function includes the item's (and any parents') position, and all the transfomation properties.
4361 
4362     \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations}
4363 */
sceneTransform() const4364 QTransform QGraphicsItem::sceneTransform() const
4365 {
4366     d_ptr->ensureSceneTransform();
4367     return d_ptr->sceneTransform;
4368 }
4369 
4370 /*!
4371     \since 4.3
4372 
4373     Returns this item's device transformation matrix, using \a
4374     viewportTransform to map from scene to device coordinates. This matrix can
4375     be used to map coordinates and geometrical shapes from this item's local
4376     coordinate system to the viewport's (or any device's) coordinate
4377     system. To map coordinates from the viewport, you must first invert the
4378     returned matrix.
4379 
4380     Example:
4381 
4382     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 5
4383 
4384     This function is the same as combining this item's scene transform with
4385     the view's viewport transform, but it also understands the
4386     ItemIgnoresTransformations flag. The device transform can be used to do
4387     accurate coordinate mapping (and collision detection) for untransformable
4388     items.
4389 
4390     \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate
4391     System}, itemTransform()
4392 */
deviceTransform(const QTransform & viewportTransform) const4393 QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const
4394 {
4395     // Ensure we return the standard transform if we're not untransformable.
4396     if (!d_ptr->itemIsUntransformable()) {
4397         d_ptr->ensureSceneTransform();
4398         return d_ptr->sceneTransform * viewportTransform;
4399     }
4400 
4401     // Find the topmost item that ignores view transformations.
4402     const QGraphicsItem *untransformedAncestor = this;
4403     QList<const QGraphicsItem *> parents;
4404     while (untransformedAncestor && ((untransformedAncestor->d_ptr->ancestorFlags
4405                                      & QGraphicsItemPrivate::AncestorIgnoresTransformations))) {
4406         parents.prepend(untransformedAncestor);
4407         untransformedAncestor = untransformedAncestor->parentItem();
4408     }
4409 
4410     if (!untransformedAncestor) {
4411         // Assert in debug mode, continue in release.
4412         Q_ASSERT_X(untransformedAncestor, "QGraphicsItem::deviceTransform",
4413                    "Invalid object structure!");
4414         return QTransform();
4415     }
4416 
4417     // Determine the inherited origin. Find the parent of the topmost untransformable.
4418     // Use its scene transform to map the position of the untransformable. Then use
4419     // that viewport position as the anchoring point for the untransformable subtree.
4420     QGraphicsItem *parentOfUntransformedAncestor = untransformedAncestor->parentItem();
4421     QTransform inheritedMatrix;
4422     if (parentOfUntransformedAncestor)
4423         inheritedMatrix = parentOfUntransformedAncestor->sceneTransform();
4424     QPointF mappedPoint = (inheritedMatrix * viewportTransform).map(untransformedAncestor->pos());
4425 
4426     // COMBINE
4427     QTransform matrix = QTransform::fromTranslate(mappedPoint.x(), mappedPoint.y());
4428     if (untransformedAncestor->d_ptr->transformData)
4429         matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(&matrix);
4430 
4431     // Then transform and translate all children.
4432     for (int i = 0; i < parents.size(); ++i) {
4433         const QGraphicsItem *parent = parents.at(i);
4434         parent->d_ptr->combineTransformFromParent(&matrix);
4435     }
4436 
4437     return matrix;
4438 }
4439 
4440 /*!
4441     \since 4.5
4442 
4443     Returns a QTransform that maps coordinates from this item to \a other. If
4444     \a ok is not null, and if there is no such transform, the boolean pointed
4445     to by \a ok will be set to false; otherwise it will be set to true.
4446 
4447     This transform provides an alternative to the mapToItem() or mapFromItem()
4448     functions, by returning the appropriate transform so that you can map
4449     shapes and coordinates yourself. It also helps you write more efficient
4450     code when repeatedly mapping between the same two items.
4451 
4452     \note In rare circumstances, there is no transform that maps between two
4453     items.
4454 
4455     \sa mapToItem(), mapFromItem(), deviceTransform()
4456 */
itemTransform(const QGraphicsItem * other,bool * ok) const4457 QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) const
4458 {
4459     // Catch simple cases first.
4460     if (other == nullptr) {
4461         qWarning("QGraphicsItem::itemTransform: null pointer passed");
4462         return QTransform();
4463     }
4464     if (other == this) {
4465         if (ok)
4466             *ok = true;
4467         return QTransform();
4468     }
4469 
4470     QGraphicsItem *parent = d_ptr->parent;
4471     const QGraphicsItem *otherParent = other->d_ptr->parent;
4472 
4473     // This is other's child
4474     if (parent == other) {
4475         if (ok)
4476             *ok = true;
4477         QTransform x;
4478         d_ptr->combineTransformFromParent(&x);
4479         return x;
4480     }
4481 
4482     // This is other's parent
4483     if (otherParent == this) {
4484         const QPointF &otherPos = other->d_ptr->pos;
4485         if (other->d_ptr->transformData) {
4486             QTransform otherToParent;
4487             other->d_ptr->combineTransformFromParent(&otherToParent);
4488             return otherToParent.inverted(ok);
4489         }
4490         if (ok)
4491             *ok = true;
4492         return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
4493     }
4494 
4495     // Siblings
4496     if (parent == otherParent) {
4497         // COMBINE
4498         const QPointF &itemPos = d_ptr->pos;
4499         const QPointF &otherPos = other->d_ptr->pos;
4500         if (!d_ptr->transformData && !other->d_ptr->transformData) {
4501             QPointF delta = itemPos - otherPos;
4502             if (ok)
4503                 *ok = true;
4504             return QTransform::fromTranslate(delta.x(), delta.y());
4505         }
4506 
4507         QTransform itemToParent;
4508         d_ptr->combineTransformFromParent(&itemToParent);
4509         QTransform otherToParent;
4510         other->d_ptr->combineTransformFromParent(&otherToParent);
4511         return itemToParent * otherToParent.inverted(ok);
4512     }
4513 
4514     // Find the closest common ancestor. If the two items don't share an
4515     // ancestor, then the only way is to combine their scene transforms.
4516     const QGraphicsItem *commonAncestor = commonAncestorItem(other);
4517     if (!commonAncestor) {
4518         d_ptr->ensureSceneTransform();
4519         other->d_ptr->ensureSceneTransform();
4520         return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(ok);
4521     }
4522 
4523     // If the two items are cousins (in sibling branches), map both to the
4524     // common ancestor, and combine the two transforms.
4525     bool cousins = other != commonAncestor && this != commonAncestor;
4526     if (cousins) {
4527         bool good = false;
4528         QTransform thisToScene = itemTransform(commonAncestor, &good);
4529         QTransform otherToScene(Qt::Uninitialized);
4530         if (good)
4531             otherToScene = other->itemTransform(commonAncestor, &good);
4532         if (!good) {
4533             if (ok)
4534                 *ok = false;
4535             return QTransform();
4536         }
4537         return thisToScene * otherToScene.inverted(ok);
4538     }
4539 
4540     // One is an ancestor of the other; walk the chain.
4541     bool parentOfOther = isAncestorOf(other);
4542     const QGraphicsItem *child = parentOfOther ? other : this;
4543     const QGraphicsItem *root = parentOfOther ? this : other;
4544 
4545     QTransform x;
4546     const QGraphicsItem *p = child;
4547     do {
4548         p->d_ptr.data()->combineTransformToParent(&x);
4549     } while ((p = p->d_ptr->parent) && p != root);
4550     if (parentOfOther)
4551         return x.inverted(ok);
4552     if (ok)
4553         *ok = true;
4554     return x;
4555 }
4556 
4557 #if QT_DEPRECATED_SINCE(5, 13)
4558 QT_WARNING_PUSH
4559 QT_WARNING_DISABLE_DEPRECATED
4560 /*!
4561     \obsolete
4562 
4563     Sets the item's affine transformation matrix. This is a subset or the
4564     item's full transformation matrix, and might not represent the item's full
4565     transformation.
4566 
4567     Use setTransform() instead.
4568 
4569     \sa transform(), {The Graphics View Coordinate System}
4570 */
setMatrix(const QMatrix & matrix,bool combine)4571 void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
4572 {
4573     if (!d_ptr->transformData)
4574         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4575 
4576     QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix));
4577     if (d_ptr->transformData->transform == newTransform)
4578         return;
4579 
4580     // Update and set the new transformation.
4581     if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
4582         d_ptr->setTransformHelper(newTransform);
4583         return;
4584     }
4585 
4586     // Notify the item that the transformation matrix is changing.
4587     const QVariant newMatrixVariant = QVariant::fromValue<QMatrix>(newTransform.toAffine());
4588     newTransform = QTransform(qvariant_cast<QMatrix>(itemChange(ItemMatrixChange, newMatrixVariant)));
4589     if (d_ptr->transformData->transform == newTransform)
4590         return;
4591 
4592     // Update and set the new transformation.
4593     d_ptr->setTransformHelper(newTransform);
4594 
4595     // Send post-notification.
4596     itemChange(ItemTransformHasChanged, QVariant::fromValue<QTransform>(newTransform));
4597 }
4598 QT_WARNING_POP
4599 #endif
4600 
4601 /*!
4602     \since 4.3
4603 
4604     Sets the item's current transformation matrix to \a matrix.
4605 
4606     If \a combine is true, then \a matrix is combined with the current matrix;
4607     otherwise, \a matrix \e replaces the current matrix. \a combine is false
4608     by default.
4609 
4610     To simplify interaction with items using a transformed view, QGraphicsItem
4611     provides mapTo... and mapFrom... functions that can translate between
4612     items' and the scene's coordinates. For example, you can call mapToScene()
4613     to map an item coordiate to a scene coordinate, or mapFromScene() to map
4614     from scene coordinates to item coordinates.
4615 
4616     The transformation matrix is combined with the item's rotation(), scale()
4617     and transformations() into a combined transformation that maps the item's
4618     coordinate system to its parent.
4619 
4620     \sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations}
4621 */
setTransform(const QTransform & matrix,bool combine)4622 void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
4623 {
4624     if (!d_ptr->transformData)
4625         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4626 
4627     QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix);
4628     if (d_ptr->transformData->transform == newTransform)
4629         return;
4630 
4631     // Update and set the new transformation.
4632     if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
4633         d_ptr->setTransformHelper(newTransform);
4634         if (d_ptr->scenePosDescendants)
4635             d_ptr->sendScenePosChange();
4636         return;
4637     }
4638 
4639     // Notify the item that the transformation matrix is changing.
4640     const QVariant newTransformVariant(itemChange(ItemTransformChange,
4641                                                   QVariant::fromValue<QTransform>(newTransform)));
4642     newTransform = qvariant_cast<QTransform>(newTransformVariant);
4643     if (d_ptr->transformData->transform == newTransform)
4644         return;
4645 
4646     // Update and set the new transformation.
4647     d_ptr->setTransformHelper(newTransform);
4648 
4649     // Send post-notification.
4650     itemChange(ItemTransformHasChanged, newTransformVariant);
4651     d_ptr->sendScenePosChange();
4652 }
4653 
4654 #if QT_DEPRECATED_SINCE(5, 13)
4655 /*!
4656     \obsolete
4657 
4658     Use resetTransform() instead.
4659 */
resetMatrix()4660 void QGraphicsItem::resetMatrix()
4661 {
4662     resetTransform();
4663 }
4664 #endif
4665 
4666 /*!
4667     \since 4.3
4668 
4669     Resets this item's transformation matrix to the identity matrix or
4670     all the transformation properties to their default values.
4671     This is equivalent to calling \c setTransform(QTransform()).
4672 
4673     \sa setTransform(), transform()
4674 */
resetTransform()4675 void QGraphicsItem::resetTransform()
4676 {
4677     setTransform(QTransform(), false);
4678 }
4679 
4680 /*!
4681     \fn void QGraphicsItem::rotate(qreal angle)
4682     \obsolete
4683 
4684     Use
4685 
4686     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 20
4687 
4688     instead.
4689 
4690     Rotates the current item transformation \a angle degrees clockwise around
4691     its origin. To translate around an arbitrary point (x, y), you need to
4692     combine translation and rotation with setTransform().
4693 
4694     Example:
4695 
4696     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 6
4697 
4698     \sa setTransform(), transform(), scale(), shear(), translate()
4699 */
4700 
4701 /*!
4702     \fn void QGraphicsItem::scale(qreal sx, qreal sy)
4703     \obsolete
4704 
4705     Use
4706 
4707     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 21
4708 
4709     instead.
4710 
4711     Scales the current item transformation by (\a sx, \a sy) around its
4712     origin. To scale from an arbitrary point (x, y), you need to combine
4713     translation and scaling with setTransform().
4714 
4715     Example:
4716 
4717     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 7
4718 
4719     \sa setTransform(), transform()
4720 */
4721 
4722 /*!
4723     \fn void QGraphicsItem::shear(qreal sh, qreal sv)
4724     \obsolete
4725 
4726     Use
4727 
4728     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 22
4729 
4730     instead.
4731 
4732     Shears the current item transformation by (\a sh, \a sv).
4733 
4734     \sa setTransform(), transform()
4735 */
4736 
4737 /*!
4738     \fn void QGraphicsItem::translate(qreal dx, qreal dy)
4739     \obsolete
4740 
4741     Use setPos() or setTransformOriginPoint() instead. For identical
4742     behavior, use
4743 
4744     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 23
4745 
4746     Translates the current item transformation by (\a dx, \a dy).
4747 
4748     If all you want is to move an item, you should call moveBy() or
4749     setPos() instead; this function changes the item's translation,
4750     which is conceptually separate from its position.
4751 
4752     \sa setTransform(), transform()
4753 */
4754 
4755 /*!
4756     This virtual function is called twice for all items by the
4757     QGraphicsScene::advance() slot. In the first phase, all items are called
4758     with \a phase == 0, indicating that items on the scene are about to
4759     advance, and then all items are called with \a phase == 1. Reimplement
4760     this function to update your item if you need simple scene-controlled
4761     animation.
4762 
4763     The default implementation does nothing.
4764 
4765     This function is intended for animations. An alternative is to
4766     multiple-inherit from QObject and QGraphicsItem and use the \l{The Animation
4767     Framework}{Animation Framework}.
4768 
4769     \sa QGraphicsScene::advance(), QTimeLine
4770 */
advance(int phase)4771 void QGraphicsItem::advance(int phase)
4772 {
4773     Q_UNUSED(phase);
4774 }
4775 
4776 /*!
4777     Returns the Z-value of the item. The Z-value affects the stacking order of
4778     sibling (neighboring) items.
4779 
4780     The default Z-value is 0.
4781 
4782     \sa setZValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
4783 */
zValue() const4784 qreal QGraphicsItem::zValue() const
4785 {
4786     return d_ptr->z;
4787 }
4788 
4789 /*!
4790     Sets the Z-value of the item to \a z. The Z value decides the stacking
4791     order of sibling (neighboring) items. A sibling item of high Z value will
4792     always be drawn on top of another sibling item with a lower Z value.
4793 
4794     If you restore the Z value, the item's insertion order will decide its
4795     stacking order.
4796 
4797     The Z-value does not affect the item's size in any way.
4798 
4799     The default Z-value is 0.
4800 
4801     \sa zValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
4802 */
setZValue(qreal z)4803 void QGraphicsItem::setZValue(qreal z)
4804 {
4805     const QVariant newZVariant(itemChange(ItemZValueChange, z));
4806     qreal newZ = newZVariant.toReal();
4807     if (newZ == d_ptr->z)
4808         return;
4809 
4810     if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
4811         // Z Value has changed, we have to notify the index.
4812         d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, &newZ);
4813     }
4814 
4815     d_ptr->z = newZ;
4816     if (d_ptr->parent)
4817         d_ptr->parent->d_ptr->needSortChildren = 1;
4818     else if (d_ptr->scene)
4819         d_ptr->scene->d_func()->needSortTopLevelItems = 1;
4820 
4821     if (d_ptr->scene)
4822         d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
4823 
4824     itemChange(ItemZValueHasChanged, newZVariant);
4825 
4826     if (d_ptr->flags & ItemNegativeZStacksBehindParent)
4827         setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
4828 
4829     if (d_ptr->isObject)
4830         emit static_cast<QGraphicsObject *>(this)->zChanged();
4831 }
4832 
4833 /*!
4834     \internal
4835 
4836     Ensures that the list of children is sorted by insertion order, and that
4837     the siblingIndexes are packed (no gaps), and start at 0.
4838 
4839     ### This function is almost identical to
4840     QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes().
4841 */
ensureSequentialSiblingIndex()4842 void QGraphicsItemPrivate::ensureSequentialSiblingIndex()
4843 {
4844     if (!sequentialOrdering) {
4845         std::sort(children.begin(), children.end(), insertionOrder);
4846         sequentialOrdering = 1;
4847         needSortChildren = 1;
4848     }
4849     if (holesInSiblingIndex) {
4850         holesInSiblingIndex = 0;
4851         for (int i = 0; i < children.size(); ++i)
4852             children[i]->d_ptr->siblingIndex = i;
4853     }
4854 }
4855 
4856 /*!
4857     \internal
4858 */
sendScenePosChange()4859 inline void QGraphicsItemPrivate::sendScenePosChange()
4860 {
4861     Q_Q(QGraphicsItem);
4862     if (scene) {
4863         if (flags & QGraphicsItem::ItemSendsScenePositionChanges)
4864             q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos());
4865         if (scenePosDescendants) {
4866             foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) {
4867                 if (q->isAncestorOf(item))
4868                     item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos());
4869             }
4870         }
4871     }
4872 }
4873 
4874 /*!
4875     \since 4.6
4876 
4877     Stacks this item before \a sibling, which must be a sibling item (i.e., the
4878     two items must share the same parent item, or must both be toplevel items).
4879     The \a sibling must have the same Z value as this item, otherwise calling
4880     this function will have no effect.
4881 
4882     By default, all sibling items are stacked by insertion order (i.e., the
4883     first item you add is drawn before the next item you add). If two items' Z
4884     values are different, then the item with the highest Z value is drawn on
4885     top. When the Z values are the same, the insertion order will decide the
4886     stacking order.
4887 
4888     \sa setZValue(), ItemStacksBehindParent, {QGraphicsItem#Sorting}{Sorting}
4889 */
stackBefore(const QGraphicsItem * sibling)4890 void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
4891 {
4892     if (sibling == this)
4893         return;
4894     if (!sibling || d_ptr->parent != sibling->parentItem()) {
4895         qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
4896         return;
4897     }
4898     QList<QGraphicsItem *> *siblings = d_ptr->parent
4899                                        ? &d_ptr->parent->d_ptr->children
4900                                        : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : nullptr);
4901     if (!siblings) {
4902         qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
4903         return;
4904     }
4905 
4906     // First, make sure that the sibling indexes have no holes. This also
4907     // marks the children list for sorting.
4908     if (d_ptr->parent)
4909         d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
4910     else
4911         d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
4912 
4913     // Only move items with the same Z value, and that need moving.
4914     int siblingIndex = sibling->d_ptr->siblingIndex;
4915     int myIndex = d_ptr->siblingIndex;
4916     if (myIndex >= siblingIndex) {
4917         siblings->move(myIndex, siblingIndex);
4918         // Fixup the insertion ordering.
4919         for (int i = 0; i < siblings->size(); ++i) {
4920             int &index = siblings->at(i)->d_ptr->siblingIndex;
4921             if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
4922                 ++index;
4923         }
4924         d_ptr->siblingIndex = siblingIndex;
4925         for (int i = 0; i < siblings->size(); ++i) {
4926             int &index = siblings->at(i)->d_ptr->siblingIndex;
4927             if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
4928                 siblings->at(i)->d_ptr->siblingOrderChange();
4929         }
4930         d_ptr->siblingOrderChange();
4931     }
4932 }
4933 
4934 /*!
4935     Returns the bounding rect of this item's descendants (i.e., its
4936     children, their children, etc.) in local coordinates. The
4937     rectangle will contain all descendants after they have been mapped
4938     to local coordinates. If the item has no children, this function
4939     returns an empty QRectF.
4940 
4941     This does not include this item's own bounding rect; it only returns
4942     its descendants' accumulated bounding rect. If you need to include this
4943     item's bounding rect, you can add boundingRect() to childrenBoundingRect()
4944     using QRectF::operator|().
4945 
4946     This function is linear in complexity; it determines the size of the
4947     returned bounding rect by iterating through all descendants.
4948 
4949     \sa boundingRect(), sceneBoundingRect()
4950 */
childrenBoundingRect() const4951 QRectF QGraphicsItem::childrenBoundingRect() const
4952 {
4953     if (!d_ptr->dirtyChildrenBoundingRect)
4954         return d_ptr->childrenBoundingRect;
4955 
4956     d_ptr->childrenBoundingRect = QRectF();
4957     d_ptr->childrenBoundingRectHelper(nullptr, &d_ptr->childrenBoundingRect, nullptr);
4958     d_ptr->dirtyChildrenBoundingRect = 0;
4959     return d_ptr->childrenBoundingRect;
4960 }
4961 
4962 /*!
4963     \fn virtual QRectF QGraphicsItem::boundingRect() const = 0
4964 
4965     This pure virtual function defines the outer bounds of the item as
4966     a rectangle; all painting must be restricted to inside an item's
4967     bounding rect. QGraphicsView uses this to determine whether the
4968     item requires redrawing.
4969 
4970     Although the item's shape can be arbitrary, the bounding rect is
4971     always rectangular, and it is unaffected by the items'
4972     transformation.
4973 
4974     If you want to change the item's bounding rectangle, you must first call
4975     prepareGeometryChange(). This notifies the scene of the imminent change,
4976     so that it can update its item geometry index; otherwise, the scene will
4977     be unaware of the item's new geometry, and the results are undefined
4978     (typically, rendering artifacts are left within the view).
4979 
4980     Reimplement this function to let QGraphicsView determine what
4981     parts of the widget, if any, need to be redrawn.
4982 
4983     Note: For shapes that paint an outline / stroke, it is important
4984     to include half the pen width in the bounding rect. It is not
4985     necessary to compensate for antialiasing, though.
4986 
4987     Example:
4988 
4989     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 8
4990 
4991     \sa boundingRegion(), shape(), contains(), {The Graphics View Coordinate
4992     System}, prepareGeometryChange()
4993 */
4994 
4995 /*!
4996     Returns the bounding rect of this item in scene coordinates, by combining
4997     sceneTransform() with boundingRect().
4998 
4999     \sa boundingRect(), {The Graphics View Coordinate System}
5000 */
sceneBoundingRect() const5001 QRectF QGraphicsItem::sceneBoundingRect() const
5002 {
5003     // Find translate-only offset
5004     // COMBINE
5005     QPointF offset;
5006     const QGraphicsItem *parentItem = this;
5007     const QGraphicsItemPrivate *itemd;
5008     do {
5009         itemd = parentItem->d_ptr.data();
5010         if (itemd->transformData)
5011             break;
5012         offset += itemd->pos;
5013     } while ((parentItem = itemd->parent));
5014 
5015     QRectF br = boundingRect();
5016     br.translate(offset);
5017     if (!parentItem)
5018         return br;
5019     if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) {
5020         br.translate(parentItem->d_ptr->sceneTransform.dx(), parentItem->d_ptr->sceneTransform.dy());
5021         return br;
5022     }
5023     return parentItem->d_ptr->sceneTransform.mapRect(br);
5024 }
5025 
5026 /*!
5027     Returns the shape of this item as a QPainterPath in local
5028     coordinates. The shape is used for many things, including collision
5029     detection, hit tests, and for the QGraphicsScene::items() functions.
5030 
5031     The default implementation calls boundingRect() to return a simple
5032     rectangular shape, but subclasses can reimplement this function to return
5033     a more accurate shape for non-rectangular items. For example, a round item
5034     may choose to return an elliptic shape for better collision detection. For
5035     example:
5036 
5037     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 9
5038 
5039     The outline of a shape can vary depending on the width and style of the
5040     pen used when drawing. If you want to include this outline in the item's
5041     shape, you can create a shape from the stroke using QPainterPathStroker.
5042 
5043     This function is called by the default implementations of contains() and
5044     collidesWithPath().
5045 
5046     \sa boundingRect(), contains(), prepareGeometryChange(), QPainterPathStroker
5047 */
shape() const5048 QPainterPath QGraphicsItem::shape() const
5049 {
5050     QPainterPath path;
5051     path.addRect(boundingRect());
5052     return path;
5053 }
5054 
5055 /*!
5056     Returns \c true if this item is clipped. An item is clipped if it has either
5057     set the \l ItemClipsToShape flag, or if it or any of its ancestors has set
5058     the \l ItemClipsChildrenToShape flag.
5059 
5060     Clipping affects the item's appearance (i.e., painting), as well as mouse
5061     and hover event delivery.
5062 
5063     \sa clipPath(), shape(), setFlags()
5064 */
isClipped() const5065 bool QGraphicsItem::isClipped() const
5066 {
5067     Q_D(const QGraphicsItem);
5068     return (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
5069         || (d->flags & QGraphicsItem::ItemClipsToShape);
5070 }
5071 
5072 /*!
5073     \since 4.5
5074 
5075     Returns this item's clip path, or an empty QPainterPath if this item is
5076     not clipped. The clip path constrains the item's appearance and
5077     interaction (i.e., restricts the area the item can draw within and receive
5078     events for).
5079 
5080     You can enable clipping by setting the ItemClipsToShape or
5081     ItemClipsChildrenToShape flags. The item's clip path is calculated by
5082     intersecting all clipping ancestors' shapes. If the item sets
5083     ItemClipsToShape, the final clip is intersected with the item's own shape.
5084 
5085     \note Clipping introduces a performance penalty for all items involved;
5086     you should generally avoid using clipping if you can (e.g., if your items
5087     always draw inside boundingRect() or shape() boundaries, clipping is not
5088     necessary).
5089 
5090     \sa isClipped(), shape(), setFlags()
5091 */
clipPath() const5092 QPainterPath QGraphicsItem::clipPath() const
5093 {
5094     Q_D(const QGraphicsItem);
5095     if (!isClipped())
5096         return QPainterPath();
5097 
5098     const QRectF thisBoundingRect(boundingRect());
5099     if (thisBoundingRect.isEmpty())
5100         return QPainterPath();
5101 
5102     QPainterPath clip;
5103     // Start with the item's bounding rect.
5104     clip.addRect(thisBoundingRect);
5105 
5106     if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
5107         const QGraphicsItem *parent = this;
5108         const QGraphicsItem *lastParent = this;
5109 
5110         // Intersect any in-between clips starting at the top and moving downwards.
5111         while ((parent = parent->d_ptr->parent)) {
5112             if (parent->d_ptr->flags & ItemClipsChildrenToShape) {
5113                 // Map clip to the current parent and intersect with its shape/clipPath
5114                 clip = lastParent->itemTransform(parent).map(clip);
5115                 clip = clip.intersected(parent->shape());
5116                 if (clip.isEmpty())
5117                     return clip;
5118                 lastParent = parent;
5119             }
5120 
5121             if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
5122                 break;
5123         }
5124 
5125         if (lastParent != this) {
5126             // Map clip back to the item's transform.
5127             // ### what if itemtransform fails
5128             clip = lastParent->itemTransform(this).map(clip);
5129         }
5130     }
5131 
5132     if (d->flags & ItemClipsToShape)
5133         clip = clip.intersected(shape());
5134 
5135     return clip;
5136 }
5137 
5138 /*!
5139     Returns \c true if this item contains \a point, which is in local
5140     coordinates; otherwise, false is returned. It is most often called from
5141     QGraphicsView to determine what item is under the cursor, and for that
5142     reason, the implementation of this function should be as light-weight as
5143     possible.
5144 
5145     By default, this function calls shape(), but you can reimplement it in a
5146     subclass to provide a (perhaps more efficient) implementation.
5147 
5148     \sa shape(), boundingRect(), collidesWithPath()
5149 */
contains(const QPointF & point) const5150 bool QGraphicsItem::contains(const QPointF &point) const
5151 {
5152     return isClipped() ? clipPath().contains(point) : shape().contains(point);
5153 }
5154 
5155 /*!
5156 
5157     Returns \c true if this item collides with \a other; otherwise
5158     returns \c false.
5159 
5160     The \a mode is applied to \a other, and the resulting shape or
5161     bounding rectangle is then compared to this item's shape. The
5162     default value for \a mode is Qt::IntersectsItemShape; \a other
5163     collides with this item if it either intersects, contains, or is
5164     contained by this item's shape (see Qt::ItemSelectionMode for
5165     details).
5166 
5167     The default implementation is based on shape intersection, and it calls
5168     shape() on both items. Because the complexity of arbitrary shape-shape
5169     intersection grows with an order of magnitude when the shapes are complex,
5170     this operation can be noticably time consuming. You have the option of
5171     reimplementing this function in a subclass of QGraphicsItem to provide a
5172     custom algorithm. This allows you to make use of natural constraints in
5173     the shapes of your own items, in order to improve the performance of the
5174     collision detection. For instance, two untransformed perfectly circular
5175     items' collision can be determined very efficiently by comparing their
5176     positions and radii.
5177 
5178     Keep in mind that when reimplementing this function and calling shape() or
5179     boundingRect() on \a other, the returned coordinates must be mapped to
5180     this item's coordinate system before any intersection can take place.
5181 
5182     \sa contains(), shape()
5183 */
collidesWithItem(const QGraphicsItem * other,Qt::ItemSelectionMode mode) const5184 bool QGraphicsItem::collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode) const
5185 {
5186     if (other == this)
5187         return true;
5188     if (!other)
5189         return false;
5190     // The items share the same clip if their closest clipper is the same, or
5191     // if one clips the other.
5192     bool clips = (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
5193     bool otherClips = (other->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
5194     if (clips || otherClips) {
5195         const QGraphicsItem *closestClipper = isAncestorOf(other) ? this : parentItem();
5196         while (closestClipper && !(closestClipper->flags() & ItemClipsChildrenToShape))
5197             closestClipper = closestClipper->parentItem();
5198         const QGraphicsItem *otherClosestClipper = other->isAncestorOf(this) ? other : other->parentItem();
5199         while (otherClosestClipper && !(otherClosestClipper->flags() & ItemClipsChildrenToShape))
5200             otherClosestClipper = otherClosestClipper->parentItem();
5201         if (closestClipper == otherClosestClipper) {
5202             d_ptr->localCollisionHack = 1;
5203             bool res = collidesWithPath(mapFromItem(other, other->shape()), mode);
5204             d_ptr->localCollisionHack = 0;
5205             return res;
5206         }
5207     }
5208 
5209     QPainterPath otherShape = other->isClipped() ? other->clipPath() : other->shape();
5210     return collidesWithPath(mapFromItem(other, otherShape), mode);
5211 }
5212 
5213 /*!
5214     Returns \c true if this item collides with \a path.
5215 
5216     The collision is determined by \a mode. The default value for \a mode is
5217     Qt::IntersectsItemShape; \a path collides with this item if it either
5218     intersects, contains, or is contained by this item's shape.
5219 
5220     Note that this function checks whether the item's shape or
5221     bounding rectangle (depending on \a mode) is contained within \a
5222     path, and not whether \a path is contained within the items shape
5223     or bounding rectangle.
5224 
5225     \sa collidesWithItem(), contains(), shape()
5226 */
collidesWithPath(const QPainterPath & path,Qt::ItemSelectionMode mode) const5227 bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode mode) const
5228 {
5229     if (path.isEmpty()) {
5230         // No collision with empty paths.
5231         return false;
5232     }
5233 
5234     QRectF rectA(boundingRect());
5235     _q_adjustRect(&rectA);
5236     QRectF rectB(path.controlPointRect());
5237     _q_adjustRect(&rectB);
5238     if (!rectA.intersects(rectB)) {
5239         // This we can determine efficiently. If the two rects neither
5240         // intersect nor contain eachother, then the two items do not collide.
5241         return false;
5242     }
5243 
5244     // For further testing, we need this item's shape or bounding rect.
5245     QPainterPath thisShape;
5246     if (mode == Qt::IntersectsItemShape || mode == Qt::ContainsItemShape)
5247         thisShape = (isClipped() && !d_ptr->localCollisionHack) ? clipPath() : shape();
5248     else
5249         thisShape.addRect(rectA);
5250 
5251     if (thisShape == QPainterPath()) {
5252         // Empty shape? No collision.
5253         return false;
5254     }
5255 
5256     // Use QPainterPath boolean operations to determine the collision, O(N*logN).
5257     if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
5258         return path.intersects(thisShape);
5259     return path.contains(thisShape);
5260 }
5261 
5262 /*!
5263     Returns a list of all items that collide with this item.
5264 
5265     The way collisions are detected is determined by applying \a mode
5266     to items that are compared to this item, i.e., each item's shape
5267     or bounding rectangle is checked against this item's shape. The
5268     default value for \a mode is Qt::IntersectsItemShape.
5269 
5270     \sa collidesWithItem()
5271 */
collidingItems(Qt::ItemSelectionMode mode) const5272 QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const
5273 {
5274     if (d_ptr->scene)
5275         return d_ptr->scene->collidingItems(this, mode);
5276     return QList<QGraphicsItem *>();
5277 }
5278 
5279 /*!
5280     \internal
5281 
5282     Item obscurity helper function.
5283 
5284     Returns \c true if the subrect \a rect of \a item's bounding rect is obscured
5285     by \a other (i.e., \a other's opaque area covers \a item's \a rect
5286     completely. \a other is assumed to already be "on top of" \a item
5287     wrt. stacking order.
5288 */
qt_QGraphicsItem_isObscured(const QGraphicsItem * item,const QGraphicsItem * other,const QRectF & rect)5289 static bool qt_QGraphicsItem_isObscured(const QGraphicsItem *item,
5290                                         const QGraphicsItem *other,
5291                                         const QRectF &rect)
5292 {
5293     return other->mapToItem(item, other->opaqueArea()).contains(rect);
5294 }
5295 
5296 /*!
5297     \overload
5298     \since 4.3
5299 
5300     Returns \c true if \a rect is completely obscured by the opaque shape of any
5301     of colliding items above it (i.e., with a higher Z value than this item).
5302 
5303     \sa opaqueArea()
5304 */
isObscured(const QRectF & rect) const5305 bool QGraphicsItem::isObscured(const QRectF &rect) const
5306 {
5307     Q_D(const QGraphicsItem);
5308     if (!d->scene)
5309         return false;
5310 
5311     QRectF br = boundingRect();
5312     QRectF testRect = rect.isNull() ? br : rect;
5313 
5314     const auto items = d->scene->items(mapToScene(br), Qt::IntersectsItemBoundingRect);
5315     for (QGraphicsItem *item : items) {
5316         if (item == this)
5317             break;
5318         if (qt_QGraphicsItem_isObscured(this, item, testRect))
5319             return true;
5320     }
5321     return false;
5322 }
5323 
5324 /*!
5325     \fn bool QGraphicsItem::isObscured(qreal x, qreal y, qreal w, qreal h) const
5326     \overload
5327     \since 4.3
5328 
5329     This convenience function is equivalent to calling isObscured(QRectF(\a x, \a y, \a w, \a h)).
5330 */
5331 
5332 /*!
5333     Returns \c true if this item's bounding rect is completely obscured by the
5334     opaque shape of \a item.
5335 
5336     The base implementation maps \a item's opaqueArea() to this item's
5337     coordinate system, and then checks if this item's boundingRect() is fully
5338     contained within the mapped shape.
5339 
5340     You can reimplement this function to provide a custom algorithm for
5341     determining whether this item is obscured by \a item.
5342 
5343     \sa opaqueArea(), isObscured()
5344 */
isObscuredBy(const QGraphicsItem * item) const5345 bool QGraphicsItem::isObscuredBy(const QGraphicsItem *item) const
5346 {
5347     if (!item)
5348         return false;
5349     return qt_closestItemFirst(item, this)
5350         && qt_QGraphicsItem_isObscured(this, item, boundingRect());
5351 }
5352 
5353 /*!
5354     This virtual function returns a shape representing the area where this
5355     item is opaque. An area is opaque if it is filled using an opaque brush or
5356     color (i.e., not transparent).
5357 
5358     This function is used by isObscuredBy(), which is called by underlying
5359     items to determine if they are obscured by this item.
5360 
5361     The default implementation returns an empty QPainterPath, indicating that
5362     this item is completely transparent and does not obscure any other items.
5363 
5364     \sa isObscuredBy(), isObscured(), shape()
5365 */
opaqueArea() const5366 QPainterPath QGraphicsItem::opaqueArea() const
5367 {
5368     return QPainterPath();
5369 }
5370 
5371 /*!
5372     \since 4.4
5373 
5374     Returns the bounding region for this item. The coordinate space of the
5375     returned region depends on \a itemToDeviceTransform. If you pass an
5376     identity QTransform as a parameter, this function will return a local
5377     coordinate region.
5378 
5379     The bounding region describes a coarse outline of the item's visual
5380     contents. Although it's expensive to calculate, it's also more precise
5381     than boundingRect(), and it can help to avoid unnecessary repainting when
5382     an item is updated. This is particularly efficient for thin items (e.g.,
5383     lines or simple polygons). You can tune the granularity for the bounding
5384     region by calling setBoundingRegionGranularity(). The default granularity
5385     is 0; in which the item's bounding region is the same as its bounding
5386     rect.
5387 
5388     \a itemToDeviceTransform is the transformation from item coordinates to
5389     device coordinates. If you want this function to return a QRegion in scene
5390     coordinates, you can pass sceneTransform() as an argument.
5391 
5392     \sa boundingRegionGranularity()
5393 */
boundingRegion(const QTransform & itemToDeviceTransform) const5394 QRegion QGraphicsItem::boundingRegion(const QTransform &itemToDeviceTransform) const
5395 {
5396     // ### Ideally we would have a better way to generate this region,
5397     // preferably something in the lines of QPainterPath::toRegion(QTransform)
5398     // coupled with a way to generate a painter path from a set of painter
5399     // operations (e.g., QPicture::toPainterPath() or so). The current
5400     // approach generates a bitmap with the size of the item's bounding rect
5401     // in device coordinates, scaled by b.r.granularity, then paints the item
5402     // into the bitmap, converts the result to a QRegion and scales the region
5403     // back to device space with inverse granularity.
5404     qreal granularity = boundingRegionGranularity();
5405     QRect deviceRect = itemToDeviceTransform.mapRect(boundingRect()).toRect();
5406     _q_adjustRect(&deviceRect);
5407     if (granularity == 0.0)
5408         return QRegion(deviceRect);
5409 
5410     int pad = 1;
5411     QSize bitmapSize(qMax(1, int(deviceRect.width() * granularity) + pad * 2),
5412                      qMax(1, int(deviceRect.height() * granularity) + pad * 2));
5413     QImage mask(bitmapSize, QImage::Format_ARGB32_Premultiplied);
5414     mask.fill(0);
5415     QPainter p(&mask);
5416     p.setRenderHints(QPainter::Antialiasing);
5417 
5418     // Transform painter (### this code is from QGraphicsScene::drawItemHelper
5419     // and doesn't work properly with perspective transformations).
5420     QPointF viewOrigo = itemToDeviceTransform.map(QPointF(0,  0));
5421     QPointF offset = viewOrigo - deviceRect.topLeft();
5422     p.scale(granularity, granularity);
5423     p.translate(offset);
5424     p.translate(pad, pad);
5425     p.setWorldTransform(itemToDeviceTransform, true);
5426     p.translate(itemToDeviceTransform.inverted().map(QPointF(0, 0)));
5427 
5428     // Render
5429     QStyleOptionGraphicsItem option;
5430     const_cast<QGraphicsItem *>(this)->paint(&p, &option, nullptr);
5431     p.end();
5432 
5433     // Transform QRegion back to device space
5434     QTransform unscale = QTransform::fromScale(1 / granularity, 1 / granularity);
5435     QRegion r;
5436     QBitmap colorMask = QBitmap::fromImage(mask.createMaskFromColor(0));
5437     for (const QRect &rect : QRegion(colorMask)) {
5438         QRect xrect = unscale.mapRect(rect).translated(deviceRect.topLeft() - QPoint(pad, pad));
5439         r += xrect.adjusted(-1, -1, 1, 1) & deviceRect;
5440     }
5441     return r;
5442 }
5443 
5444 /*!
5445     \since 4.4
5446 
5447     Returns the item's bounding region granularity; a value between and
5448     including 0 and 1. The default value is 0 (i.e., the lowest granularity,
5449     where the bounding region corresponds to the item's bounding rectangle).
5450 
5451 \omit
5452 ### NOTE
5453 \endomit
5454 
5455     \sa setBoundingRegionGranularity()
5456 */
boundingRegionGranularity() const5457 qreal QGraphicsItem::boundingRegionGranularity() const
5458 {
5459     return d_ptr->hasBoundingRegionGranularity
5460         ? qvariant_cast<qreal>(d_ptr->extra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity))
5461         : 0;
5462 }
5463 
5464 /*!
5465     \since 4.4
5466     Sets the bounding region granularity to \a granularity; a value between
5467     and including 0 and 1. The default value is 0 (i.e., the lowest
5468     granularity, where the bounding region corresponds to the item's bounding
5469     rectangle).
5470 
5471     The granularity is used by boundingRegion() to calculate how fine the
5472     bounding region of the item should be. The highest achievable granularity
5473     is 1, where boundingRegion() will return the finest outline possible for
5474     the respective device (e.g., for a QGraphicsView viewport, this gives you
5475     a pixel-perfect bounding region). The lowest possible granularity is
5476     0. The value of \a granularity describes the ratio between device
5477     resolution and the resolution of the bounding region (e.g., a value of
5478     0.25 will provide a region where each chunk corresponds to 4x4 device
5479     units / pixels).
5480 
5481     \sa boundingRegionGranularity()
5482 */
setBoundingRegionGranularity(qreal granularity)5483 void QGraphicsItem::setBoundingRegionGranularity(qreal granularity)
5484 {
5485     if (granularity < 0.0 || granularity > 1.0) {
5486         qWarning("QGraphicsItem::setBoundingRegionGranularity: invalid granularity %g", granularity);
5487         return;
5488     }
5489     if (granularity == 0.0) {
5490         d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity);
5491         d_ptr->hasBoundingRegionGranularity = 0;
5492         return;
5493     }
5494     d_ptr->hasBoundingRegionGranularity = 1;
5495     d_ptr->setExtra(QGraphicsItemPrivate::ExtraBoundingRegionGranularity,
5496                     QVariant::fromValue<qreal>(granularity));
5497 }
5498 
5499 /*!
5500     \fn virtual void QGraphicsItem::paint(QPainter *painter, const
5501     QStyleOptionGraphicsItem *option, QWidget *widget = 0) = 0
5502 
5503     This function, which is usually called by QGraphicsView, paints the
5504     contents of an item in local coordinates.
5505 
5506     Reimplement this function in a QGraphicsItem subclass to provide the
5507     item's painting implementation, using \a painter. The \a option parameter
5508     provides style options for the item, such as its state, exposed area and
5509     its level-of-detail hints. The \a widget argument is optional. If
5510     provided, it points to the widget that is being painted on; otherwise, it
5511     is 0. For cached painting, \a widget is always 0.
5512 
5513     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 10
5514 
5515     The painter's pen is 0-width by default, and its pen is initialized to the
5516     QPalette::Text brush from the paint device's palette. The brush is
5517     initialized to QPalette::Window.
5518 
5519     Make sure to constrain all painting inside the boundaries of
5520     boundingRect() to avoid rendering artifacts (as QGraphicsView does not
5521     clip the painter for you). In particular, when QPainter renders the
5522     outline of a shape using an assigned QPen, half of the outline will be
5523     drawn outside, and half inside, the shape you're rendering (e.g., with a
5524     pen width of 2 units, you must draw outlines 1 unit inside
5525     boundingRect()). QGraphicsItem does not support use of cosmetic pens with
5526     a non-zero width.
5527 
5528     All painting is done in local coordinates.
5529 
5530     \note It is mandatory that an item will always redraw itself in the exact
5531     same way, unless update() was called; otherwise visual artifacts may
5532     occur. In other words, two subsequent calls to paint() must always produce
5533     the same output, unless update() was called between them.
5534 
5535     \note Enabling caching for an item does not guarantee that paint()
5536     will be invoked only once by the Graphics View framework,
5537     even without any explicit call to update(). See the documentation of
5538     setCacheMode() for more details.
5539 
5540     \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
5541 */
5542 
5543 /*!
5544     \internal
5545     Returns \c true if we can discard an update request; otherwise false.
5546 */
discardUpdateRequest(bool ignoreVisibleBit,bool ignoreDirtyBit,bool ignoreOpacity) const5547 bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit,
5548                                                 bool ignoreOpacity) const
5549 {
5550     // No scene, or if the scene is updating everything, means we have nothing
5551     // to do. The only exception is if the scene tracks the growing scene rect.
5552     return !scene
5553            || (!visible && !ignoreVisibleBit && !this->ignoreVisible)
5554            || (!ignoreDirtyBit && fullUpdatePending)
5555            || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
5556 }
5557 
5558 /*!
5559     \internal
5560 */
depth() const5561 int QGraphicsItemPrivate::depth() const
5562 {
5563     if (itemDepth == -1)
5564         const_cast<QGraphicsItemPrivate *>(this)->resolveDepth();
5565 
5566     return itemDepth;
5567 }
5568 
5569 /*!
5570     \internal
5571 */
5572 #if QT_CONFIG(graphicseffect)
invalidateParentGraphicsEffectsRecursively()5573 void QGraphicsItemPrivate::invalidateParentGraphicsEffectsRecursively()
5574 {
5575     QGraphicsItemPrivate *itemPrivate = this;
5576     do {
5577         if (itemPrivate->graphicsEffect) {
5578             itemPrivate->notifyInvalidated = 1;
5579 
5580             if (!itemPrivate->updateDueToGraphicsEffect)
5581                 static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
5582         }
5583     } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : nullptr));
5584 }
5585 
invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)5586 void QGraphicsItemPrivate::invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)
5587 {
5588     if (!mayHaveChildWithGraphicsEffect)
5589         return;
5590 
5591     for (int i = 0; i < children.size(); ++i) {
5592         QGraphicsItemPrivate *childPrivate = children.at(i)->d_ptr.data();
5593         if (reason == OpacityChanged && (childPrivate->flags & QGraphicsItem::ItemIgnoresParentOpacity))
5594             continue;
5595         if (childPrivate->graphicsEffect) {
5596             childPrivate->notifyInvalidated = 1;
5597             static_cast<QGraphicsItemEffectSourcePrivate *>(childPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
5598         }
5599 
5600         childPrivate->invalidateChildGraphicsEffectsRecursively(reason);
5601     }
5602 }
5603 #endif // QT_CONFIG(graphicseffect)
5604 
5605 /*!
5606     \internal
5607 */
invalidateDepthRecursively()5608 void QGraphicsItemPrivate::invalidateDepthRecursively()
5609 {
5610     if (itemDepth == -1)
5611         return;
5612 
5613     itemDepth = -1;
5614     for (int i = 0; i < children.size(); ++i)
5615         children.at(i)->d_ptr->invalidateDepthRecursively();
5616 }
5617 
5618 /*!
5619     \internal
5620 
5621     Resolves the stacking depth of this object and all its ancestors.
5622 */
resolveDepth()5623 void QGraphicsItemPrivate::resolveDepth()
5624 {
5625     if (!parent)
5626         itemDepth = 0;
5627     else {
5628         if (parent->d_ptr->itemDepth == -1)
5629             parent->d_ptr->resolveDepth();
5630         itemDepth = parent->d_ptr->itemDepth + 1;
5631     }
5632 }
5633 
5634 /*!
5635     \internal
5636 
5637     ### This function is almost identical to
5638     QGraphicsScenePrivate::registerTopLevelItem().
5639 */
addChild(QGraphicsItem * child)5640 void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
5641 {
5642     // Remove all holes from the sibling index list. Now the max index
5643     // number is equal to the size of the children list.
5644     ensureSequentialSiblingIndex();
5645     needSortChildren = 1; // ### maybe 0
5646     child->d_ptr->siblingIndex = children.size();
5647     children.append(child);
5648     if (isObject)
5649         emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
5650 }
5651 
5652 /*!
5653     \internal
5654 
5655     ### This function is almost identical to
5656     QGraphicsScenePrivate::unregisterTopLevelItem().
5657 */
removeChild(QGraphicsItem * child)5658 void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
5659 {
5660     // When removing elements in the middle of the children list,
5661     // there will be a "gap" in the list of sibling indexes (0,1,3,4).
5662     if (!holesInSiblingIndex)
5663         holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1;
5664     if (sequentialOrdering && !holesInSiblingIndex)
5665         children.removeAt(child->d_ptr->siblingIndex);
5666     else
5667         children.removeOne(child);
5668     // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because
5669     // the child is not guaranteed to be at the index after the list is sorted.
5670     // (see ensureSortedChildren()).
5671     child->d_ptr->siblingIndex = -1;
5672     if (isObject)
5673         emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
5674 }
5675 
5676 /*!
5677     \internal
5678 */
maybeExtraItemCache() const5679 QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
5680 {
5681     return (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
5682 }
5683 
5684 /*!
5685     \internal
5686 */
extraItemCache() const5687 QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
5688 {
5689     QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
5690     if (!c) {
5691         QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
5692         c = new QGraphicsItemCache;
5693         that->setExtra(ExtraCacheData, QVariant::fromValue<void *>(c));
5694     }
5695     return c;
5696 }
5697 
5698 /*!
5699     \internal
5700 */
removeExtraItemCache()5701 void QGraphicsItemPrivate::removeExtraItemCache()
5702 {
5703     QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(extra(ExtraCacheData));
5704     if (c) {
5705         c->purge();
5706         delete c;
5707     }
5708     unsetExtra(ExtraCacheData);
5709 }
5710 
updatePaintedViewBoundingRects(bool updateChildren)5711 void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren)
5712 {
5713     if (!scene)
5714         return;
5715 
5716     for (int i = 0; i < scene->d_func()->views.size(); ++i) {
5717         QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func();
5718         QRect rect = paintedViewBoundingRects.value(viewPrivate->viewport);
5719         rect.translate(viewPrivate->dirtyScrollOffset);
5720         viewPrivate->updateRect(rect);
5721     }
5722 
5723     if (updateChildren) {
5724         for (int i = 0; i < children.size(); ++i)
5725             children.at(i)->d_ptr->updatePaintedViewBoundingRects(true);
5726     }
5727 }
5728 
5729 // Traverses all the ancestors up to the top-level and updates the pointer to
5730 // always point to the top-most item that has a dirty scene transform.
5731 // It then backtracks to the top-most dirty item and start calculating the
5732 // scene transform by combining the item's transform (+pos) with the parent's
5733 // cached scene transform (which we at this point know for sure is valid).
ensureSceneTransformRecursive(QGraphicsItem ** topMostDirtyItem)5734 void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
5735 {
5736     Q_ASSERT(topMostDirtyItem);
5737 
5738     if (dirtySceneTransform)
5739         *topMostDirtyItem = q_ptr;
5740 
5741     if (parent)
5742         parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
5743 
5744     if (*topMostDirtyItem == q_ptr) {
5745         if (!dirtySceneTransform)
5746             return; // OK, neither my ancestors nor I have dirty scene transforms.
5747         *topMostDirtyItem = nullptr;
5748     } else if (*topMostDirtyItem) {
5749         return; // Continue backtrack.
5750     }
5751 
5752     // This item and all its descendants have dirty scene transforms.
5753     // We're about to validate this item's scene transform, so we have to
5754     // invalidate all the children; otherwise there's no way for the descendants
5755     // to detect that the ancestor has changed.
5756     invalidateChildrenSceneTransform();
5757 
5758     // COMBINE my transform with the parent's scene transform.
5759     updateSceneTransformFromParent();
5760     Q_ASSERT(!dirtySceneTransform);
5761 }
5762 
5763 /*!
5764     \internal
5765 */
setSubFocus(QGraphicsItem * rootItem,QGraphicsItem * stopItem)5766 void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
5767 {
5768     // Update focus child chain. Stop at panels, or if this item
5769     // is hidden, stop at the first item with a visible parent.
5770     QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
5771     if (parent->panel() != q_ptr->panel())
5772         return;
5773 
5774     do {
5775         // Clear any existing ancestor's subFocusItem.
5776         if (parent != q_ptr && parent->d_ptr->subFocusItem) {
5777             if (parent->d_ptr->subFocusItem == q_ptr)
5778                 break;
5779             parent->d_ptr->subFocusItem->d_ptr->clearSubFocus(nullptr, stopItem);
5780         }
5781         parent->d_ptr->subFocusItem = q_ptr;
5782         parent->d_ptr->subFocusItemChange();
5783     } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible));
5784 
5785     if (scene && !scene->isActive()) {
5786         scene->d_func()->passiveFocusItem = subFocusItem;
5787         scene->d_func()->lastFocusItem = subFocusItem;
5788     }
5789 }
5790 
5791 /*!
5792     \internal
5793 */
clearSubFocus(QGraphicsItem * rootItem,QGraphicsItem * stopItem)5794 void QGraphicsItemPrivate::clearSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
5795 {
5796     // Reset sub focus chain.
5797     QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
5798     do {
5799         if (parent->d_ptr->subFocusItem != q_ptr)
5800             break;
5801         parent->d_ptr->subFocusItem = nullptr;
5802         if (parent != stopItem && !parent->isAncestorOf(stopItem))
5803             parent->d_ptr->subFocusItemChange();
5804     } while (!parent->isPanel() && (parent = parent->d_ptr->parent));
5805 }
5806 
5807 /*!
5808     \internal
5809 
5810     Sets the focusProxy pointer to \nullptr for all items that have this item as their
5811     focusProxy.
5812 */
resetFocusProxy()5813 void QGraphicsItemPrivate::resetFocusProxy()
5814 {
5815     for (int i = 0; i < focusProxyRefs.size(); ++i)
5816         *focusProxyRefs.at(i) = nullptr;
5817     focusProxyRefs.clear();
5818 }
5819 
5820 /*!
5821     \internal
5822 
5823     Subclasses can reimplement this function to be notified when subFocusItem
5824     changes.
5825 */
subFocusItemChange()5826 void QGraphicsItemPrivate::subFocusItemChange()
5827 {
5828 }
5829 
5830 /*!
5831     \internal
5832 
5833     Subclasses can reimplement this function to be notified when an item
5834     becomes a focusScopeItem (or is no longer a focusScopeItem).
5835 */
focusScopeItemChange(bool isSubFocusItem)5836 void QGraphicsItemPrivate::focusScopeItemChange(bool isSubFocusItem)
5837 {
5838     Q_UNUSED(isSubFocusItem);
5839 }
5840 
5841 /*!
5842     \internal
5843 
5844     Subclasses can reimplement this function to be notified when its
5845     siblingIndex order is changed.
5846 */
siblingOrderChange()5847 void QGraphicsItemPrivate::siblingOrderChange()
5848 {
5849 }
5850 
5851 /*!
5852     \internal
5853 
5854     Tells us if it is a proxy widget
5855 */
isProxyWidget() const5856 bool QGraphicsItemPrivate::isProxyWidget() const
5857 {
5858     return false;
5859 }
5860 
5861 /*!
5862     Schedules a redraw of the area covered by \a rect in this item. You can
5863     call this function whenever your item needs to be redrawn, such as if it
5864     changes appearance or size.
5865 
5866     This function does not cause an immediate paint; instead it schedules a
5867     paint request that is processed by QGraphicsView after control reaches the
5868     event loop. The item will only be redrawn if it is visible in any
5869     associated view.
5870 
5871     As a side effect of the item being repainted, other items that overlap the
5872     area \a rect may also be repainted.
5873 
5874     If the item is invisible (i.e., isVisible() returns \c false), this function
5875     does nothing.
5876 
5877     \sa paint(), boundingRect()
5878 */
update(const QRectF & rect)5879 void QGraphicsItem::update(const QRectF &rect)
5880 {
5881     if (rect.isEmpty() && !rect.isNull())
5882         return;
5883 
5884     // Make sure we notify effects about invalidated source.
5885 #if QT_CONFIG(graphicseffect)
5886     d_ptr->invalidateParentGraphicsEffectsRecursively();
5887 #endif // QT_CONFIG(graphicseffect)
5888 
5889     if (CacheMode(d_ptr->cacheMode) != NoCache) {
5890         // Invalidate cache.
5891         QGraphicsItemCache *cache = d_ptr->extraItemCache();
5892         if (!cache->allExposed) {
5893             if (rect.isNull()) {
5894                 cache->allExposed = true;
5895                 cache->exposed.clear();
5896             } else {
5897                 cache->exposed.append(rect);
5898             }
5899         }
5900         // Only invalidate cache; item is already dirty.
5901         if (d_ptr->fullUpdatePending)
5902             return;
5903     }
5904 
5905     if (d_ptr->scene)
5906         d_ptr->scene->d_func()->markDirty(this, rect);
5907 }
5908 
5909 /*!
5910     \since 4.4
5911     Scrolls the contents of \a rect by \a dx, \a dy. If \a rect is a null rect
5912     (the default), the item's bounding rect is scrolled.
5913 
5914     Scrolling provides a fast alternative to simply redrawing when the
5915     contents of the item (or parts of the item) are shifted vertically or
5916     horizontally. Depending on the current transformation and the capabilities
5917     of the paint device (i.e., the viewport), this operation may consist of
5918     simply moving pixels from one location to another using memmove(). In most
5919     cases this is faster than rerendering the entire area.
5920 
5921     After scrolling, the item will issue an update for the newly exposed
5922     areas. If scrolling is not supported (e.g., you are rendering to an OpenGL
5923     viewport, which does not benefit from scroll optimizations), this function
5924     is equivalent to calling update(\a rect).
5925 
5926     \b{Note:} Scrolling is only supported when QGraphicsItem::ItemCoordinateCache
5927     is enabled; in all other cases calling this function is equivalent to calling
5928     update(\a rect). If you for sure know that the item is opaque and not overlapped
5929     by other items, you can map the \a rect to viewport coordinates and scroll the
5930     viewport.
5931 
5932     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 19
5933 
5934     \sa boundingRect()
5935 */
scroll(qreal dx,qreal dy,const QRectF & rect)5936 void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
5937 {
5938     Q_D(QGraphicsItem);
5939     if (dx == 0.0 && dy == 0.0)
5940         return;
5941     if (!d->scene)
5942         return;
5943 
5944     // Accelerated scrolling means moving pixels from one location to another
5945     // and only redraw the newly exposed area. The following requirements must
5946     // be fulfilled in order to do that:
5947     //
5948     // 1) Item is opaque.
5949     // 2) Item is not overlapped by other items.
5950     //
5951     // There's (yet) no way to detect whether an item is opaque or not, which means
5952     // we cannot do accelerated scrolling unless the cache is enabled. In case of using
5953     // DeviceCoordinate cache we also have to take the device transform into account in
5954     // order to determine whether we can do accelerated scrolling or not. That's left out
5955     // for simplicity here, but it is definitely something we can consider in the future
5956     // as a performance improvement.
5957     if (d->cacheMode != QGraphicsItem::ItemCoordinateCache
5958         || !qFuzzyIsNull(dx - int(dx)) || !qFuzzyIsNull(dy - int(dy))) {
5959         update(rect);
5960         return;
5961     }
5962 
5963     QGraphicsItemCache *cache = d->extraItemCache();
5964     if (cache->allExposed || cache->fixedSize.isValid()) {
5965         // Cache is either invalidated or item is scaled (see QGraphicsItem::setCacheMode).
5966         update(rect);
5967         return;
5968     }
5969 
5970     // Find pixmap in cache.
5971     QPixmap cachedPixmap;
5972     if (!QPixmapCache::find(cache->key, &cachedPixmap)) {
5973         update(rect);
5974         return;
5975     }
5976 
5977     QRect scrollRect = (rect.isNull() ? boundingRect() : rect).toAlignedRect();
5978     if (!scrollRect.intersects(cache->boundingRect))
5979         return; // Nothing to scroll.
5980 
5981     // Remove from cache to avoid deep copy when modifying.
5982     QPixmapCache::remove(cache->key);
5983 
5984     QRegion exposed;
5985     cachedPixmap.scroll(dx, dy, scrollRect.translated(-cache->boundingRect.topLeft()), &exposed);
5986 
5987     // Reinsert into cache.
5988     cache->key = QPixmapCache::insert(cachedPixmap);
5989 
5990     // Translate the existing expose.
5991     for (int i = 0; i < cache->exposed.size(); ++i) {
5992         QRectF &e = cache->exposed[i];
5993         if (!rect.isNull() && !e.intersects(rect))
5994             continue;
5995         e.translate(dx, dy);
5996     }
5997 
5998     // Append newly exposed areas. Note that the exposed region is currently
5999     // in pixmap coordinates, so we have to translate it to item coordinates.
6000     exposed.translate(cache->boundingRect.topLeft());
6001     for (const QRect &exposedRect : exposed)
6002         cache->exposed += exposedRect;
6003 
6004     // Trigger update. This will redraw the newly exposed area and make sure
6005     // the pixmap is re-blitted in case there are overlapping items.
6006     d->scene->d_func()->markDirty(this, rect);
6007 }
6008 
6009 /*!
6010     \fn void QGraphicsItem::update(qreal x, qreal y, qreal width, qreal height)
6011     \overload
6012 
6013     This convenience function is equivalent to calling update(QRectF(\a x, \a
6014     y, \a width, \a height)).
6015 */
6016 
6017 /*!
6018     Maps the point \a point, which is in this item's coordinate system, to \a
6019     item's coordinate system, and returns the mapped coordinate.
6020 
6021     If \a item is \nullptr, this function returns the same as mapToScene().
6022 
6023     \sa itemTransform(), mapToParent(), mapToScene(), transform(), mapFromItem(), {The Graphics
6024     View Coordinate System}
6025 */
mapToItem(const QGraphicsItem * item,const QPointF & point) const6026 QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point) const
6027 {
6028     if (item)
6029         return itemTransform(item).map(point);
6030     return mapToScene(point);
6031 }
6032 
6033 /*!
6034     \fn QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y) const
6035     \overload
6036 
6037     This convenience function is equivalent to calling mapToItem(\a item,
6038     QPointF(\a x, \a y)).
6039 */
6040 
6041 /*!
6042     Maps the point \a point, which is in this item's coordinate system, to its
6043     parent's coordinate system, and returns the mapped coordinate. If the item
6044     has no parent, \a point will be mapped to the scene's coordinate system.
6045 
6046     \sa mapToItem(), mapToScene(), transform(), mapFromParent(), {The Graphics
6047     View Coordinate System}
6048 */
mapToParent(const QPointF & point) const6049 QPointF QGraphicsItem::mapToParent(const QPointF &point) const
6050 {
6051     // COMBINE
6052     if (!d_ptr->transformData)
6053         return point + d_ptr->pos;
6054     return d_ptr->transformToParent().map(point);
6055 }
6056 
6057 /*!
6058     \fn QPointF QGraphicsItem::mapToParent(qreal x, qreal y) const
6059     \overload
6060 
6061     This convenience function is equivalent to calling mapToParent(QPointF(\a
6062     x, \a y)).
6063 */
6064 
6065 /*!
6066     Maps the point \a point, which is in this item's coordinate system, to the
6067     scene's coordinate system, and returns the mapped coordinate.
6068 
6069     \sa mapToItem(), mapToParent(), transform(), mapFromScene(), {The Graphics
6070     View Coordinate System}
6071 */
mapToScene(const QPointF & point) const6072 QPointF QGraphicsItem::mapToScene(const QPointF &point) const
6073 {
6074     if (d_ptr->hasTranslateOnlySceneTransform())
6075         return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy());
6076     return d_ptr->sceneTransform.map(point);
6077 }
6078 
6079 /*!
6080     \fn QPointF QGraphicsItem::mapToScene(qreal x, qreal y) const
6081     \overload
6082 
6083     This convenience function is equivalent to calling mapToScene(QPointF(\a
6084     x, \a y)).
6085 */
6086 
6087 /*!
6088     Maps the rectangle \a rect, which is in this item's coordinate system, to
6089     \a item's coordinate system, and returns the mapped rectangle as a polygon.
6090 
6091     If \a item is \nullptr, this function returns the same as mapToScene().
6092 
6093     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6094     Graphics View Coordinate System}
6095 */
mapToItem(const QGraphicsItem * item,const QRectF & rect) const6096 QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect) const
6097 {
6098     if (item)
6099         return itemTransform(item).map(rect);
6100     return mapToScene(rect);
6101 }
6102 
6103 /*!
6104     \fn QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6105     \since 4.3
6106 
6107     This convenience function is equivalent to calling mapToItem(item, QRectF(\a x, \a y, \a w, \a h)).
6108 */
6109 
6110 /*!
6111     Maps the rectangle \a rect, which is in this item's coordinate system, to
6112     its parent's coordinate system, and returns the mapped rectangle as a
6113     polygon. If the item has no parent, \a rect will be mapped to the scene's
6114     coordinate system.
6115 
6116     \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6117     Coordinate System}
6118 */
mapToParent(const QRectF & rect) const6119 QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
6120 {
6121     // COMBINE
6122     if (!d_ptr->transformData)
6123         return rect.translated(d_ptr->pos);
6124     return d_ptr->transformToParent().map(rect);
6125 }
6126 
6127 /*!
6128     \fn QPolygonF QGraphicsItem::mapToParent(qreal x, qreal y, qreal w, qreal h) const
6129     \since 4.3
6130 
6131     This convenience function is equivalent to calling mapToParent(QRectF(\a x, \a y, \a w, \a h)).
6132 */
6133 
6134 /*!
6135     Maps the rectangle \a rect, which is in this item's coordinate system, to
6136     the scene's coordinate system, and returns the mapped rectangle as a polygon.
6137 
6138     \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6139     Coordinate System}
6140 */
mapToScene(const QRectF & rect) const6141 QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const
6142 {
6143     if (d_ptr->hasTranslateOnlySceneTransform())
6144         return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
6145     return d_ptr->sceneTransform.map(rect);
6146 }
6147 
6148 /*!
6149     \fn QPolygonF QGraphicsItem::mapToScene(qreal x, qreal y, qreal w, qreal h) const
6150     \since 4.3
6151 
6152     This convenience function is equivalent to calling mapToScene(QRectF(\a x, \a y, \a w, \a h)).
6153 */
6154 
6155 /*!
6156     \since 4.5
6157 
6158     Maps the rectangle \a rect, which is in this item's coordinate system, to
6159     \a item's coordinate system, and returns the mapped rectangle as a new
6160     rectangle (i.e., the bounding rectangle of the resulting polygon).
6161 
6162     If \a item is \nullptr, this function returns the same as mapRectToScene().
6163 
6164     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6165     Graphics View Coordinate System}
6166 */
mapRectToItem(const QGraphicsItem * item,const QRectF & rect) const6167 QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rect) const
6168 {
6169     if (item)
6170         return itemTransform(item).mapRect(rect);
6171     return mapRectToScene(rect);
6172 }
6173 
6174 /*!
6175     \fn QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6176     \since 4.5
6177 
6178     This convenience function is equivalent to calling mapRectToItem(item, QRectF(\a x, \a y, \a w, \a h)).
6179 */
6180 
6181 /*!
6182     \since 4.5
6183 
6184     Maps the rectangle \a rect, which is in this item's coordinate system, to
6185     its parent's coordinate system, and returns the mapped rectangle as a new
6186     rectangle (i.e., the bounding rectangle of the resulting polygon).
6187 
6188     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6189     Graphics View Coordinate System}
6190 */
mapRectToParent(const QRectF & rect) const6191 QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
6192 {
6193     // COMBINE
6194     if (!d_ptr->transformData)
6195         return rect.translated(d_ptr->pos);
6196     return d_ptr->transformToParent().mapRect(rect);
6197 }
6198 
6199 /*!
6200     \fn QRectF QGraphicsItem::mapRectToParent(qreal x, qreal y, qreal w, qreal h) const
6201     \since 4.5
6202 
6203     This convenience function is equivalent to calling mapRectToParent(QRectF(\a x, \a y, \a w, \a h)).
6204 */
6205 
6206 /*!
6207     \since 4.5
6208 
6209     Maps the rectangle \a rect, which is in this item's coordinate system, to
6210     the scene coordinate system, and returns the mapped rectangle as a new
6211     rectangle (i.e., the bounding rectangle of the resulting polygon).
6212 
6213     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6214     Graphics View Coordinate System}
6215 */
mapRectToScene(const QRectF & rect) const6216 QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const
6217 {
6218     if (d_ptr->hasTranslateOnlySceneTransform())
6219         return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
6220     return d_ptr->sceneTransform.mapRect(rect);
6221 }
6222 
6223 /*!
6224     \fn QRectF QGraphicsItem::mapRectToScene(qreal x, qreal y, qreal w, qreal h) const
6225     \since 4.5
6226 
6227     This convenience function is equivalent to calling mapRectToScene(QRectF(\a x, \a y, \a w, \a h)).
6228 */
6229 
6230 /*!
6231     \since 4.5
6232 
6233     Maps the rectangle \a rect, which is in \a item's coordinate system, to
6234     this item's coordinate system, and returns the mapped rectangle as a new
6235     rectangle (i.e., the bounding rectangle of the resulting polygon).
6236 
6237     If \a item is \nullptr, this function returns the same as mapRectFromScene().
6238 
6239     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6240     Graphics View Coordinate System}
6241 */
mapRectFromItem(const QGraphicsItem * item,const QRectF & rect) const6242 QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &rect) const
6243 {
6244     if (item)
6245         return item->itemTransform(this).mapRect(rect);
6246     return mapRectFromScene(rect);
6247 }
6248 
6249 /*!
6250     \fn QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6251     \since 4.5
6252 
6253     This convenience function is equivalent to calling mapRectFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
6254 */
6255 
6256 /*!
6257     \since 4.5
6258 
6259     Maps the rectangle \a rect, which is in this item's parent's coordinate
6260     system, to this item's coordinate system, and returns the mapped rectangle
6261     as a new rectangle (i.e., the bounding rectangle of the resulting
6262     polygon).
6263 
6264     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6265     Graphics View Coordinate System}
6266 */
mapRectFromParent(const QRectF & rect) const6267 QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
6268 {
6269     // COMBINE
6270     if (!d_ptr->transformData)
6271         return rect.translated(-d_ptr->pos);
6272     return d_ptr->transformToParent().inverted().mapRect(rect);
6273 }
6274 
6275 /*!
6276     \fn QRectF QGraphicsItem::mapRectFromParent(qreal x, qreal y, qreal w, qreal h) const
6277     \since 4.5
6278 
6279     This convenience function is equivalent to calling mapRectFromParent(QRectF(\a x, \a y, \a w, \a h)).
6280 */
6281 
6282 /*!
6283     \since 4.5
6284 
6285     Maps the rectangle \a rect, which is in scene coordinates, to this item's
6286     coordinate system, and returns the mapped rectangle as a new rectangle
6287     (i.e., the bounding rectangle of the resulting polygon).
6288 
6289     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6290     Graphics View Coordinate System}
6291 */
mapRectFromScene(const QRectF & rect) const6292 QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const
6293 {
6294     if (d_ptr->hasTranslateOnlySceneTransform())
6295         return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
6296     return d_ptr->sceneTransform.inverted().mapRect(rect);
6297 }
6298 
6299 /*!
6300     \fn QRectF QGraphicsItem::mapRectFromScene(qreal x, qreal y, qreal w, qreal h) const
6301     \since 4.5
6302 
6303     This convenience function is equivalent to calling mapRectFromScene(QRectF(\a x, \a y, \a w, \a h)).
6304 */
6305 
6306 /*!
6307     Maps the polygon \a polygon, which is in this item's coordinate system, to
6308     \a item's coordinate system, and returns the mapped polygon.
6309 
6310     If \a item is \nullptr, this function returns the same as mapToScene().
6311 
6312     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6313     Graphics View Coordinate System}
6314 */
mapToItem(const QGraphicsItem * item,const QPolygonF & polygon) const6315 QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &polygon) const
6316 {
6317     if (item)
6318         return itemTransform(item).map(polygon);
6319     return mapToScene(polygon);
6320 }
6321 
6322 /*!
6323     Maps the polygon \a polygon, which is in this item's coordinate system, to
6324     its parent's coordinate system, and returns the mapped polygon. If the
6325     item has no parent, \a polygon will be mapped to the scene's coordinate
6326     system.
6327 
6328     \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6329     Coordinate System}
6330 */
mapToParent(const QPolygonF & polygon) const6331 QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
6332 {
6333     // COMBINE
6334     if (!d_ptr->transformData)
6335         return polygon.translated(d_ptr->pos);
6336     return d_ptr->transformToParent().map(polygon);
6337 }
6338 
6339 /*!
6340     Maps the polygon \a polygon, which is in this item's coordinate system, to
6341     the scene's coordinate system, and returns the mapped polygon.
6342 
6343     \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6344     Coordinate System}
6345 */
mapToScene(const QPolygonF & polygon) const6346 QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const
6347 {
6348     if (d_ptr->hasTranslateOnlySceneTransform())
6349         return polygon.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
6350     return d_ptr->sceneTransform.map(polygon);
6351 }
6352 
6353 /*!
6354     Maps the path \a path, which is in this item's coordinate system, to
6355     \a item's coordinate system, and returns the mapped path.
6356 
6357     If \a item is \nullptr, this function returns the same as mapToScene().
6358 
6359     \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6360     Graphics View Coordinate System}
6361 */
mapToItem(const QGraphicsItem * item,const QPainterPath & path) const6362 QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterPath &path) const
6363 {
6364     if (item)
6365         return itemTransform(item).map(path);
6366     return mapToScene(path);
6367 }
6368 
6369 /*!
6370     Maps the path \a path, which is in this item's coordinate system, to
6371     its parent's coordinate system, and returns the mapped path. If the
6372     item has no parent, \a path will be mapped to the scene's coordinate
6373     system.
6374 
6375     \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6376     Coordinate System}
6377 */
mapToParent(const QPainterPath & path) const6378 QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
6379 {
6380     // COMBINE
6381     if (!d_ptr->transformData)
6382         return path.translated(d_ptr->pos);
6383     return d_ptr->transformToParent().map(path);
6384 }
6385 
6386 /*!
6387     Maps the path \a path, which is in this item's coordinate system, to
6388     the scene's coordinate system, and returns the mapped path.
6389 
6390     \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6391     Coordinate System}
6392 */
mapToScene(const QPainterPath & path) const6393 QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const
6394 {
6395     if (d_ptr->hasTranslateOnlySceneTransform())
6396         return path.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
6397     return d_ptr->sceneTransform.map(path);
6398 }
6399 
6400 /*!
6401     Maps the point \a point, which is in \a item's coordinate system, to this
6402     item's coordinate system, and returns the mapped coordinate.
6403 
6404     If \a item is \nullptr, this function returns the same as mapFromScene().
6405 
6406     \sa itemTransform(), mapFromParent(), mapFromScene(), transform(), mapToItem(), {The Graphics
6407     View Coordinate System}
6408 */
mapFromItem(const QGraphicsItem * item,const QPointF & point) const6409 QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &point) const
6410 {
6411     if (item)
6412         return item->itemTransform(this).map(point);
6413     return mapFromScene(point);
6414 }
6415 
6416 /*!
6417     \fn QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y) const
6418     \overload
6419 
6420     This convenience function is equivalent to calling mapFromItem(\a item,
6421     QPointF(\a x, \a y)).
6422 */
6423 
6424 /*!
6425     Maps the point \a point, which is in this item's parent's coordinate
6426     system, to this item's coordinate system, and returns the mapped
6427     coordinate.
6428 
6429     \sa mapFromItem(), mapFromScene(), transform(), mapToParent(), {The Graphics
6430     View Coordinate System}
6431 */
mapFromParent(const QPointF & point) const6432 QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
6433 {
6434     // COMBINE
6435     if (d_ptr->transformData)
6436         return d_ptr->transformToParent().inverted().map(point);
6437     return point - d_ptr->pos;
6438 }
6439 
6440 /*!
6441     \fn QPointF QGraphicsItem::mapFromParent(qreal x, qreal y) const
6442     \overload
6443 
6444     This convenience function is equivalent to calling
6445     mapFromParent(QPointF(\a x, \a y)).
6446 */
6447 
6448 /*!
6449     Maps the point \a point, which is in this item's scene's coordinate
6450     system, to this item's coordinate system, and returns the mapped
6451     coordinate.
6452 
6453     \sa mapFromItem(), mapFromParent(), transform(), mapToScene(), {The Graphics
6454     View Coordinate System}
6455 */
mapFromScene(const QPointF & point) const6456 QPointF QGraphicsItem::mapFromScene(const QPointF &point) const
6457 {
6458     if (d_ptr->hasTranslateOnlySceneTransform())
6459         return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy());
6460     return d_ptr->sceneTransform.inverted().map(point);
6461 }
6462 
6463 /*!
6464     \fn QPointF QGraphicsItem::mapFromScene(qreal x, qreal y) const
6465     \overload
6466 
6467     This convenience function is equivalent to calling mapFromScene(QPointF(\a
6468     x, \a y)).
6469 */
6470 
6471 /*!
6472     Maps the rectangle \a rect, which is in \a item's coordinate system, to
6473     this item's coordinate system, and returns the mapped rectangle as a
6474     polygon.
6475 
6476     If \a item is \nullptr, this function returns the same as mapFromScene()
6477 
6478     \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The Graphics View Coordinate
6479     System}
6480 */
mapFromItem(const QGraphicsItem * item,const QRectF & rect) const6481 QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &rect) const
6482 {
6483     if (item)
6484         return item->itemTransform(this).map(rect);
6485     return mapFromScene(rect);
6486 }
6487 
6488 /*!
6489     \fn QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6490     \since 4.3
6491 
6492     This convenience function is equivalent to calling mapFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
6493 */
6494 
6495 /*!
6496     Maps the rectangle \a rect, which is in this item's parent's coordinate
6497     system, to this item's coordinate system, and returns the mapped rectangle
6498     as a polygon.
6499 
6500     \sa mapToParent(), mapFromItem(), transform(), {The Graphics View Coordinate
6501     System}
6502 */
mapFromParent(const QRectF & rect) const6503 QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
6504 {
6505     // COMBINE
6506     if (!d_ptr->transformData)
6507         return rect.translated(-d_ptr->pos);
6508     return d_ptr->transformToParent().inverted().map(rect);
6509 }
6510 
6511 /*!
6512     \fn QPolygonF QGraphicsItem::mapFromParent(qreal x, qreal y, qreal w, qreal h) const
6513     \since 4.3
6514 
6515     This convenience function is equivalent to calling mapFromItem(QRectF(\a x, \a y, \a w, \a h)).
6516 */
6517 
6518 /*!
6519     Maps the rectangle \a rect, which is in this item's scene's coordinate
6520     system, to this item's coordinate system, and returns the mapped rectangle
6521     as a polygon.
6522 
6523     \sa mapToScene(), mapFromItem(), transform(), {The Graphics View Coordinate
6524     System}
6525 */
mapFromScene(const QRectF & rect) const6526 QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const
6527 {
6528     if (d_ptr->hasTranslateOnlySceneTransform())
6529         return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
6530     return d_ptr->sceneTransform.inverted().map(rect);
6531 }
6532 
6533 /*!
6534     \fn QPolygonF QGraphicsItem::mapFromScene(qreal x, qreal y, qreal w, qreal h) const
6535     \since 4.3
6536 
6537     This convenience function is equivalent to calling mapFromScene(QRectF(\a x, \a y, \a w, \a h)).
6538 */
6539 
6540 /*!
6541     Maps the polygon \a polygon, which is in \a item's coordinate system, to
6542     this item's coordinate system, and returns the mapped polygon.
6543 
6544     If \a item is \nullptr, this function returns the same as mapFromScene().
6545 
6546     \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The
6547     Graphics View Coordinate System}
6548 */
mapFromItem(const QGraphicsItem * item,const QPolygonF & polygon) const6549 QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF &polygon) const
6550 {
6551     if (item)
6552         return item->itemTransform(this).map(polygon);
6553     return mapFromScene(polygon);
6554 }
6555 
6556 /*!
6557     Maps the polygon \a polygon, which is in this item's parent's coordinate
6558     system, to this item's coordinate system, and returns the mapped polygon.
6559 
6560     \sa mapToParent(), mapToItem(), transform(), {The Graphics View Coordinate
6561     System}
6562 */
mapFromParent(const QPolygonF & polygon) const6563 QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
6564 {
6565     // COMBINE
6566     if (!d_ptr->transformData)
6567         return polygon.translated(-d_ptr->pos);
6568     return d_ptr->transformToParent().inverted().map(polygon);
6569 }
6570 
6571 /*!
6572     Maps the polygon \a polygon, which is in this item's scene's coordinate
6573     system, to this item's coordinate system, and returns the mapped polygon.
6574 
6575     \sa mapToScene(), mapFromParent(), transform(), {The Graphics View Coordinate
6576     System}
6577 */
mapFromScene(const QPolygonF & polygon) const6578 QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const
6579 {
6580     if (d_ptr->hasTranslateOnlySceneTransform())
6581         return polygon.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
6582     return d_ptr->sceneTransform.inverted().map(polygon);
6583 }
6584 
6585 /*!
6586     Maps the path \a path, which is in \a item's coordinate system, to
6587     this item's coordinate system, and returns the mapped path.
6588 
6589     If \a item is \nullptr, this function returns the same as mapFromScene().
6590 
6591     \sa itemTransform(), mapFromParent(), mapFromScene(), mapToItem(), {The
6592     Graphics View Coordinate System}
6593 */
mapFromItem(const QGraphicsItem * item,const QPainterPath & path) const6594 QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainterPath &path) const
6595 {
6596     if (item)
6597         return item->itemTransform(this).map(path);
6598     return mapFromScene(path);
6599 }
6600 
6601 /*!
6602     Maps the path \a path, which is in this item's parent's coordinate
6603     system, to this item's coordinate system, and returns the mapped path.
6604 
6605     \sa mapFromScene(), mapFromItem(), mapToParent(), {The Graphics View
6606     Coordinate System}
6607 */
mapFromParent(const QPainterPath & path) const6608 QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
6609 {
6610     // COMBINE
6611     if (!d_ptr->transformData)
6612             return path.translated(-d_ptr->pos);
6613     return d_ptr->transformToParent().inverted().map(path);
6614 }
6615 
6616 /*!
6617     Maps the path \a path, which is in this item's scene's coordinate
6618     system, to this item's coordinate system, and returns the mapped path.
6619 
6620     \sa mapFromParent(), mapFromItem(), mapToScene(), {The Graphics View
6621     Coordinate System}
6622 */
mapFromScene(const QPainterPath & path) const6623 QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const
6624 {
6625     if (d_ptr->hasTranslateOnlySceneTransform())
6626         return path.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
6627     return d_ptr->sceneTransform.inverted().map(path);
6628 }
6629 
6630 /*!
6631     Returns \c true if this item is an ancestor of \a child (i.e., if this item
6632     is \a child's parent, or one of \a child's parent's ancestors).
6633 
6634     \sa parentItem()
6635 */
isAncestorOf(const QGraphicsItem * child) const6636 bool QGraphicsItem::isAncestorOf(const QGraphicsItem *child) const
6637 {
6638     if (!child || child == this)
6639         return false;
6640     if (child->d_ptr->depth() < d_ptr->depth())
6641         return false;
6642     const QGraphicsItem *ancestor = child;
6643     while ((ancestor = ancestor->d_ptr->parent)) {
6644         if (ancestor == this)
6645             return true;
6646     }
6647     return false;
6648 }
6649 
6650 /*!
6651     \since 4.4
6652 
6653     Returns the closest common ancestor item of this item and \a other,
6654     or \nullptr if either \a other is \nullptr, or there is no common ancestor.
6655 
6656     \sa isAncestorOf()
6657 */
commonAncestorItem(const QGraphicsItem * other) const6658 QGraphicsItem *QGraphicsItem::commonAncestorItem(const QGraphicsItem *other) const
6659 {
6660     if (!other)
6661         return nullptr;
6662     if (other == this)
6663         return const_cast<QGraphicsItem *>(this);
6664     const QGraphicsItem *thisw = this;
6665     const QGraphicsItem *otherw = other;
6666     int thisDepth = d_ptr->depth();
6667     int otherDepth = other->d_ptr->depth();
6668     while (thisDepth > otherDepth) {
6669         thisw = thisw->d_ptr->parent;
6670         --thisDepth;
6671     }
6672     while (otherDepth > thisDepth) {
6673         otherw = otherw->d_ptr->parent;
6674         --otherDepth;
6675     }
6676     while (thisw && thisw != otherw) {
6677         thisw = thisw->d_ptr->parent;
6678         otherw = otherw->d_ptr->parent;
6679     }
6680     return const_cast<QGraphicsItem *>(thisw);
6681 }
6682 
6683 /*!
6684     \since 4.4
6685     Returns \c true if this item is currently under the mouse cursor in one of
6686     the views; otherwise, false is returned.
6687 
6688     \sa QGraphicsScene::views(), QCursor::pos()
6689 */
isUnderMouse() const6690 bool QGraphicsItem::isUnderMouse() const
6691 {
6692     Q_D(const QGraphicsItem);
6693     if (!d->scene)
6694         return false;
6695 
6696     QPoint cursorPos = QCursor::pos();
6697     const auto views = d->scene->views();
6698     for (QGraphicsView *view : views) {
6699         if (contains(mapFromScene(view->mapToScene(view->mapFromGlobal(cursorPos)))))
6700             return true;
6701     }
6702     return false;
6703 }
6704 
6705 /*!
6706     Returns this item's custom data for the key \a key as a QVariant.
6707 
6708     Custom item data is useful for storing arbitrary properties in any
6709     item. Example:
6710 
6711     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 11
6712 
6713     Qt does not use this feature for storing data; it is provided solely
6714     for the convenience of the user.
6715 
6716     \sa setData()
6717 */
data(int key) const6718 QVariant QGraphicsItem::data(int key) const
6719 {
6720     QGraphicsItemCustomDataStore *store = qt_dataStore();
6721     if (!store->data.contains(this))
6722         return QVariant();
6723     return store->data.value(this).value(key);
6724 }
6725 
6726 /*!
6727     Sets this item's custom data for the key \a key to \a value.
6728 
6729     Custom item data is useful for storing arbitrary properties for any
6730     item. Qt does not use this feature for storing data; it is provided solely
6731     for the convenience of the user.
6732 
6733     \sa data()
6734 */
setData(int key,const QVariant & value)6735 void QGraphicsItem::setData(int key, const QVariant &value)
6736 {
6737     qt_dataStore()->data[this][key] = value;
6738 }
6739 
6740 /*!
6741     \fn T qgraphicsitem_cast(QGraphicsItem *item)
6742     \relates QGraphicsItem
6743     \since 4.2
6744 
6745     Returns the given \a item cast to type T if \a item is of type T;
6746     otherwise, \nullptr is returned.
6747 
6748     \note To make this function work correctly with custom items, reimplement
6749     the \l{QGraphicsItem::}{type()} function for each custom QGraphicsItem
6750     subclass.
6751 
6752     \sa QGraphicsItem::type(), QGraphicsItem::UserType
6753 */
6754 
6755 /*!
6756     Returns the type of an item as an int. All standard graphicsitem classes
6757     are associated with a unique value; see QGraphicsItem::Type. This type
6758     information is used by qgraphicsitem_cast() to distinguish between types.
6759 
6760     The default implementation (in QGraphicsItem) returns UserType.
6761 
6762     To enable use of qgraphicsitem_cast() with a custom item, reimplement this
6763     function and declare a Type enum value equal to your custom item's type.
6764     Custom items must return a value larger than or equal to UserType (65536).
6765 
6766     For example:
6767 
6768     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 1
6769 
6770     \sa UserType
6771 */
type() const6772 int QGraphicsItem::type() const
6773 {
6774     return (int)UserType;
6775 }
6776 
6777 /*!
6778     Installs an event filter for this item on \a filterItem, causing
6779     all events for this item to first pass through \a filterItem's
6780     sceneEventFilter() function.
6781 
6782     To filter another item's events, install this item as an event filter
6783     for the other item. Example:
6784 
6785     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 12
6786 
6787     An item can only filter events for other items in the same
6788     scene. Also, an item cannot filter its own events; instead, you
6789     can reimplement sceneEvent() directly.
6790 
6791     Items must belong to a scene for scene event filters to be installed and
6792     used.
6793 
6794     \sa removeSceneEventFilter(), sceneEventFilter(), sceneEvent()
6795 */
installSceneEventFilter(QGraphicsItem * filterItem)6796 void QGraphicsItem::installSceneEventFilter(QGraphicsItem *filterItem)
6797 {
6798     if (!d_ptr->scene) {
6799         qWarning("QGraphicsItem::installSceneEventFilter: event filters can only be installed"
6800                  " on items in a scene.");
6801         return;
6802     }
6803     if (d_ptr->scene != filterItem->scene()) {
6804         qWarning("QGraphicsItem::installSceneEventFilter: event filters can only be installed"
6805                  " on items in the same scene.");
6806         return;
6807     }
6808     d_ptr->scene->d_func()->installSceneEventFilter(this, filterItem);
6809 }
6810 
6811 /*!
6812     Removes an event filter on this item from \a filterItem.
6813 
6814     \sa installSceneEventFilter()
6815 */
removeSceneEventFilter(QGraphicsItem * filterItem)6816 void QGraphicsItem::removeSceneEventFilter(QGraphicsItem *filterItem)
6817 {
6818     if (!d_ptr->scene || d_ptr->scene != filterItem->scene())
6819         return;
6820     d_ptr->scene->d_func()->removeSceneEventFilter(this, filterItem);
6821 }
6822 
6823 /*!
6824     Filters events for the item \a watched. \a event is the filtered
6825     event.
6826 
6827     Reimplementing this function in a subclass makes it possible
6828     for the item to be used as an event filter for other items,
6829     intercepting all the events sent to those items before they are
6830     able to respond.
6831 
6832     Reimplementations must return true to prevent further processing of
6833     a given event, ensuring that it will not be delivered to the watched
6834     item, or return false to indicate that the event should be propagated
6835     further by the event system.
6836 
6837     \sa installSceneEventFilter()
6838 */
sceneEventFilter(QGraphicsItem * watched,QEvent * event)6839 bool QGraphicsItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
6840 {
6841     Q_UNUSED(watched);
6842     Q_UNUSED(event);
6843     return false;
6844 }
6845 
6846 /*!
6847     This virtual function receives events to this item. Reimplement
6848     this function to intercept events before they are dispatched to
6849     the specialized event handlers contextMenuEvent(), focusInEvent(),
6850     focusOutEvent(), hoverEnterEvent(), hoverMoveEvent(),
6851     hoverLeaveEvent(), keyPressEvent(), keyReleaseEvent(),
6852     mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(), and
6853     mouseDoubleClickEvent().
6854 
6855     Returns \c true if the event was recognized and handled; otherwise, (e.g., if
6856     the event type was not recognized,) false is returned.
6857 
6858     \a event is the intercepted event.
6859 */
sceneEvent(QEvent * event)6860 bool QGraphicsItem::sceneEvent(QEvent *event)
6861 {
6862     if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents) {
6863         if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave
6864             || event->type() == QEvent::DragEnter || event->type() == QEvent::DragLeave) {
6865             // Hover enter and hover leave events for children are ignored;
6866             // hover move events are forwarded.
6867             return true;
6868         }
6869 
6870         QGraphicsItem *handler = this;
6871         do {
6872             handler = handler->d_ptr->parent;
6873             Q_ASSERT(handler);
6874         } while (handler->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents);
6875         // Forward the event to the closest parent that handles child
6876         // events, mapping existing item-local coordinates to its
6877         // coordinate system.
6878         d_ptr->remapItemPos(event, handler);
6879         handler->sceneEvent(event);
6880         return true;
6881     }
6882 
6883     if (event->type() == QEvent::FocusOut) {
6884         focusOutEvent(static_cast<QFocusEvent *>(event));
6885         return true;
6886     }
6887 
6888     if (!d_ptr->visible) {
6889         // Eaten
6890         return true;
6891     }
6892 
6893     switch (event->type()) {
6894     case QEvent::FocusIn:
6895         focusInEvent(static_cast<QFocusEvent *>(event));
6896         break;
6897     case QEvent::GraphicsSceneContextMenu:
6898         contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
6899         break;
6900     case QEvent::GraphicsSceneDragEnter:
6901         dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
6902         break;
6903     case QEvent::GraphicsSceneDragMove:
6904         dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
6905         break;
6906     case QEvent::GraphicsSceneDragLeave:
6907         dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
6908         break;
6909     case QEvent::GraphicsSceneDrop:
6910         dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
6911         break;
6912     case QEvent::GraphicsSceneHoverEnter:
6913         hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
6914         break;
6915     case QEvent::GraphicsSceneHoverMove:
6916         hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
6917         break;
6918     case QEvent::GraphicsSceneHoverLeave:
6919         hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
6920         break;
6921     case QEvent::GraphicsSceneMouseMove:
6922         mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
6923         break;
6924     case QEvent::GraphicsSceneMousePress:
6925         mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
6926         break;
6927     case QEvent::GraphicsSceneMouseRelease:
6928         mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
6929         break;
6930     case QEvent::GraphicsSceneMouseDoubleClick:
6931         mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
6932         break;
6933     case QEvent::GraphicsSceneWheel:
6934         wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
6935         break;
6936     case QEvent::KeyPress: {
6937         QKeyEvent *k = static_cast<QKeyEvent *>(event);
6938         if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
6939             if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
6940                 bool res = false;
6941                 if (k->key() == Qt::Key_Backtab
6942                     || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
6943                     if (d_ptr->isWidget) {
6944                         res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(false);
6945                     } else if (d_ptr->scene) {
6946                         res = d_ptr->scene->focusNextPrevChild(false);
6947                     }
6948                 } else if (k->key() == Qt::Key_Tab) {
6949                     if (d_ptr->isWidget) {
6950                         res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(true);
6951                     } else if (d_ptr->scene) {
6952                         res = d_ptr->scene->focusNextPrevChild(true);
6953                     }
6954                 }
6955                 if (!res)
6956                     event->ignore();
6957                 return true;
6958             }
6959         }
6960         keyPressEvent(static_cast<QKeyEvent *>(event));
6961         break;
6962     }
6963     case QEvent::KeyRelease:
6964         keyReleaseEvent(static_cast<QKeyEvent *>(event));
6965         break;
6966     case QEvent::InputMethod:
6967         inputMethodEvent(static_cast<QInputMethodEvent *>(event));
6968         break;
6969     case QEvent::WindowActivate:
6970     case QEvent::WindowDeactivate:
6971         // Propagate panel activation.
6972         if (d_ptr->scene) {
6973             for (int i = 0; i < d_ptr->children.size(); ++i) {
6974                 QGraphicsItem *child = d_ptr->children.at(i);
6975                 if (child->isVisible() && !child->isPanel()) {
6976                     if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
6977                         d_ptr->scene->sendEvent(child, event);
6978                 }
6979             }
6980         }
6981         break;
6982     default:
6983         return false;
6984     }
6985 
6986     return true;
6987 }
6988 
6989 /*!
6990     This event handler can be reimplemented in a subclass to process context
6991     menu events. The \a event parameter contains details about the event to
6992     be handled.
6993 
6994     If you ignore the event (i.e., by calling QEvent::ignore()), \a event
6995     will propagate to any item beneath this item. If no items accept the
6996     event, it will be ignored by the scene and propagate to the view.
6997 
6998     It's common to open a QMenu in response to receiving a context menu
6999     event. Example:
7000 
7001     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 13
7002 
7003     The default implementation ignores the event.
7004 
7005     \sa sceneEvent()
7006 */
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)7007 void QGraphicsItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
7008 {
7009     event->ignore();
7010 }
7011 
7012 /*!
7013     This event handler, for event \a event, can be reimplemented to receive
7014     drag enter events for this item. Drag enter events are generated as the
7015     cursor enters the item's area.
7016 
7017     By accepting the event (i.e., by calling QEvent::accept()), the item will
7018     accept drop events, in addition to receiving drag move and drag
7019     leave. Otherwise, the event will be ignored and propagate to the item
7020     beneath. If the event is accepted, the item will receive a drag move event
7021     before control goes back to the event loop.
7022 
7023     A common implementation of dragEnterEvent accepts or ignores \a event
7024     depending on the associated mime data in \a event. Example:
7025 
7026     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 14
7027 
7028     Items do not receive drag and drop events by default; to enable this
7029     feature, call \c setAcceptDrops(true).
7030 
7031     The default implementation does nothing.
7032 
7033     \sa dropEvent(), dragMoveEvent(), dragLeaveEvent()
7034 */
dragEnterEvent(QGraphicsSceneDragDropEvent * event)7035 void QGraphicsItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
7036 {
7037     Q_D(QGraphicsItem);
7038     // binary compatibility workaround between 4.4 and 4.5
7039     if (d->isProxyWidget())
7040         static_cast<QGraphicsProxyWidget*>(this)->dragEnterEvent(event);
7041 }
7042 
7043 /*!
7044     This event handler, for event \a event, can be reimplemented to receive
7045     drag leave events for this item. Drag leave events are generated as the
7046     cursor leaves the item's area. Most often you will not need to reimplement
7047     this function, but it can be useful for resetting state in your item
7048     (e.g., highlighting).
7049 
7050     Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7051 
7052     Items do not receive drag and drop events by default; to enable this
7053     feature, call \c setAcceptDrops(true).
7054 
7055     The default implementation does nothing.
7056 
7057     \sa dragEnterEvent(), dropEvent(), dragMoveEvent()
7058 */
dragLeaveEvent(QGraphicsSceneDragDropEvent * event)7059 void QGraphicsItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
7060 {
7061     Q_D(QGraphicsItem);
7062     // binary compatibility workaround between 4.4 and 4.5
7063     if (d->isProxyWidget())
7064         static_cast<QGraphicsProxyWidget*>(this)->dragLeaveEvent(event);
7065 }
7066 
7067 /*!
7068     This event handler, for event \a event, can be reimplemented to receive
7069     drag move events for this item. Drag move events are generated as the
7070     cursor moves around inside the item's area. Most often you will not need
7071     to reimplement this function; it is used to indicate that only parts of
7072     the item can accept drops.
7073 
7074     Calling QEvent::ignore() or QEvent::accept() on \a event toggles whether
7075     or not the item will accept drops at the position from the event. By
7076     default, \a event is accepted, indicating that the item allows drops at
7077     the specified position.
7078 
7079     Items do not receive drag and drop events by default; to enable this
7080     feature, call \c setAcceptDrops(true).
7081 
7082     The default implementation does nothing.
7083 
7084     \sa dropEvent(), dragEnterEvent(), dragLeaveEvent()
7085 */
dragMoveEvent(QGraphicsSceneDragDropEvent * event)7086 void QGraphicsItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
7087 {
7088     Q_D(QGraphicsItem);
7089     // binary compatibility workaround between 4.4 and 4.5
7090     if (d->isProxyWidget())
7091         static_cast<QGraphicsProxyWidget*>(this)->dragMoveEvent(event);
7092 }
7093 
7094 /*!
7095     This event handler, for event \a event, can be reimplemented to receive
7096     drop events for this item. Items can only receive drop events if the last
7097     drag move event was accepted.
7098 
7099     Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7100 
7101     Items do not receive drag and drop events by default; to enable this
7102     feature, call \c setAcceptDrops(true).
7103 
7104     The default implementation does nothing.
7105 
7106     \sa dragEnterEvent(), dragMoveEvent(), dragLeaveEvent()
7107 */
dropEvent(QGraphicsSceneDragDropEvent * event)7108 void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event)
7109 {
7110     Q_D(QGraphicsItem);
7111     // binary compatibility workaround between 4.4 and 4.5
7112     if (d->isProxyWidget())
7113         static_cast<QGraphicsProxyWidget*>(this)->dropEvent(event);
7114 }
7115 
7116 /*!
7117     This event handler, for event \a event, can be reimplemented to receive
7118     focus in events for this item. The default implementation calls
7119     ensureVisible().
7120 
7121     \sa focusOutEvent(), sceneEvent(), setFocus()
7122 */
focusInEvent(QFocusEvent * event)7123 void QGraphicsItem::focusInEvent(QFocusEvent *event)
7124 {
7125     Q_UNUSED(event);
7126     update();
7127 }
7128 
7129 /*!
7130     This event handler, for event \a event, can be reimplemented to receive
7131     focus out events for this item. The default implementation does nothing.
7132 
7133     \sa focusInEvent(), sceneEvent(), setFocus()
7134 */
focusOutEvent(QFocusEvent * event)7135 void QGraphicsItem::focusOutEvent(QFocusEvent *event)
7136 {
7137     Q_UNUSED(event);
7138     update();
7139 }
7140 
7141 /*!
7142     This event handler, for event \a event, can be reimplemented to receive
7143     hover enter events for this item. The default implementation calls
7144     update(); otherwise it does nothing.
7145 
7146     Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7147 
7148     \sa hoverMoveEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
7149 */
hoverEnterEvent(QGraphicsSceneHoverEvent * event)7150 void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
7151 {
7152     Q_UNUSED(event);
7153     update();
7154 }
7155 
7156 /*!
7157     This event handler, for event \a event, can be reimplemented to receive
7158     hover move events for this item. The default implementation does nothing.
7159 
7160     Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7161 
7162     \sa hoverEnterEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
7163 */
hoverMoveEvent(QGraphicsSceneHoverEvent * event)7164 void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7165 {
7166     Q_UNUSED(event);
7167 }
7168 
7169 /*!
7170     This event handler, for event \a event, can be reimplemented to receive
7171     hover leave events for this item. The default implementation calls
7172     update(); otherwise it does nothing.
7173 
7174     Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7175 
7176     \sa hoverEnterEvent(), hoverMoveEvent(), sceneEvent(), setAcceptHoverEvents()
7177 */
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)7178 void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
7179 {
7180     Q_UNUSED(event);
7181     update();
7182 }
7183 
7184 /*!
7185     This event handler, for event \a event, can be reimplemented to
7186     receive key press events for this item. The default implementation
7187     ignores the event. If you reimplement this handler, the event will by
7188     default be accepted.
7189 
7190     Note that key events are only received for items that set the
7191     ItemIsFocusable flag, and that have keyboard input focus.
7192 
7193     \sa keyReleaseEvent(), setFocus(), QGraphicsScene::setFocusItem(),
7194     sceneEvent()
7195 */
keyPressEvent(QKeyEvent * event)7196 void QGraphicsItem::keyPressEvent(QKeyEvent *event)
7197 {
7198     event->ignore();
7199 }
7200 
7201 /*!
7202     This event handler, for event \a event, can be reimplemented to receive
7203     key release events for this item. The default implementation
7204     ignores the event. If you reimplement this handler, the event will by
7205     default be accepted.
7206 
7207     Note that key events are only received for items that set the
7208     ItemIsFocusable flag, and that have keyboard input focus.
7209 
7210     \sa keyPressEvent(), setFocus(), QGraphicsScene::setFocusItem(),
7211     sceneEvent()
7212 */
keyReleaseEvent(QKeyEvent * event)7213 void QGraphicsItem::keyReleaseEvent(QKeyEvent *event)
7214 {
7215     event->ignore();
7216 }
7217 
7218 /*!
7219     This event handler, for event \a event, can be reimplemented to
7220     receive mouse press events for this item. Mouse press events are
7221     only delivered to items that accept the mouse button that is
7222     pressed. By default, an item accepts all mouse buttons, but you
7223     can change this by calling setAcceptedMouseButtons().
7224 
7225     The mouse press event decides which item should become the mouse
7226     grabber (see QGraphicsScene::mouseGrabberItem()). If you do not
7227     reimplement this function, the press event will propagate to any
7228     topmost item beneath this item, and no other mouse events will be
7229     delivered to this item.
7230 
7231     If you do reimplement this function, \a event will by default be
7232     accepted (see QEvent::accept()), and this item is then the mouse
7233     grabber. This allows the item to receive future move, release and
7234     doubleclick events. If you call QEvent::ignore() on \a event, this
7235     item will lose the mouse grab, and \a event will propagate to any
7236     topmost item beneath. No further mouse events will be delivered to
7237     this item unless a new mouse press event is received.
7238 
7239     The default implementation handles basic item interaction, such as
7240     selection and moving. If you want to keep the base implementation
7241     when reimplementing this function, call
7242     QGraphicsItem::mousePressEvent() in your reimplementation.
7243 
7244     The event is \l{QEvent::ignore()}d for items that are neither
7245     \l{QGraphicsItem::ItemIsMovable}{movable} nor
7246     \l{QGraphicsItem::ItemIsSelectable}{selectable}.
7247 
7248     \sa mouseMoveEvent(), mouseReleaseEvent(),
7249     mouseDoubleClickEvent(), sceneEvent()
7250 */
mousePressEvent(QGraphicsSceneMouseEvent * event)7251 void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
7252 {
7253     if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
7254         bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
7255         if (!multiSelect) {
7256             if (!d_ptr->selected) {
7257                 if (QGraphicsScene *scene = d_ptr->scene) {
7258                     ++scene->d_func()->selectionChanging;
7259                     scene->clearSelection();
7260                     --scene->d_func()->selectionChanging;
7261                 }
7262                 setSelected(true);
7263             }
7264         }
7265     } else if (!(flags() & ItemIsMovable)) {
7266         event->ignore();
7267     }
7268     if (d_ptr->isWidget) {
7269         // Qt::Popup closes when you click outside.
7270         QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this);
7271         if ((w->windowFlags() & Qt::Popup) == Qt::Popup) {
7272             event->accept();
7273             if (!w->rect().contains(event->pos()))
7274                 w->close();
7275         }
7276     }
7277 }
7278 
_qt_movableAncestorIsSelected(const QGraphicsItem * item)7279 bool _qt_movableAncestorIsSelected(const QGraphicsItem *item)
7280 {
7281     const QGraphicsItem *parent = item->parentItem();
7282     return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(parent));
7283 }
7284 
movableAncestorIsSelected(const QGraphicsItem * item)7285 bool QGraphicsItemPrivate::movableAncestorIsSelected(const QGraphicsItem *item)
7286 {
7287     const QGraphicsItem *parent = item->d_ptr->parent;
7288     return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(parent));
7289 }
7290 
7291 /*!
7292     This event handler, for event \a event, can be reimplemented to
7293     receive mouse move events for this item. If you do receive this
7294     event, you can be certain that this item also received a mouse
7295     press event, and that this item is the current mouse grabber.
7296 
7297     Calling QEvent::ignore() or QEvent::accept() on \a event has no
7298     effect.
7299 
7300     The default implementation handles basic item interaction, such as
7301     selection and moving. If you want to keep the base implementation
7302     when reimplementing this function, call
7303     QGraphicsItem::mouseMoveEvent() in your reimplementation.
7304 
7305     Please note that mousePressEvent() decides which graphics item it
7306     is that receives mouse events. See the mousePressEvent()
7307     description for details.
7308 
7309     \sa mousePressEvent(), mouseReleaseEvent(),
7310     mouseDoubleClickEvent(), sceneEvent()
7311 */
mouseMoveEvent(QGraphicsSceneMouseEvent * event)7312 void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
7313 {
7314     if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
7315         // Determine the list of items that need to be moved.
7316         QList<QGraphicsItem *> selectedItems;
7317         QHash<QGraphicsItem *, QPointF> initialPositions;
7318         if (d_ptr->scene) {
7319             selectedItems = d_ptr->scene->selectedItems();
7320             initialPositions = d_ptr->scene->d_func()->movingItemsInitialPositions;
7321             if (initialPositions.isEmpty()) {
7322                 for (QGraphicsItem *item : qAsConst(selectedItems))
7323                     initialPositions[item] = item->pos();
7324                 initialPositions[this] = pos();
7325             }
7326             d_ptr->scene->d_func()->movingItemsInitialPositions = initialPositions;
7327         }
7328 
7329         // Find the active view.
7330         QGraphicsView *view = nullptr;
7331         if (event->widget())
7332             view = qobject_cast<QGraphicsView *>(event->widget()->parentWidget());
7333 
7334         // Move all selected items
7335         int i = 0;
7336         bool movedMe = false;
7337         while (i <= selectedItems.size()) {
7338             QGraphicsItem *item = nullptr;
7339             if (i < selectedItems.size())
7340                 item = selectedItems.at(i);
7341             else
7342                 item = this;
7343             if (item == this) {
7344                 // Slightly clumsy-looking way to ensure that "this" is part
7345                 // of the list of items to move, this is to avoid allocations
7346                 // (appending this item to the list of selected items causes a
7347                 // detach).
7348                 if (movedMe)
7349                     break;
7350                 movedMe = true;
7351             }
7352 
7353             if ((item->flags() & ItemIsMovable) && !QGraphicsItemPrivate::movableAncestorIsSelected(item)) {
7354                 QPointF currentParentPos;
7355                 QPointF buttonDownParentPos;
7356                 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations) {
7357                     // Items whose ancestors ignore transformations need to
7358                     // map screen coordinates to local coordinates, then map
7359                     // those to the parent.
7360                     QTransform viewToItemTransform = (item->deviceTransform(view->viewportTransform())).inverted();
7361                     currentParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->screenPos()))));
7362                     buttonDownParentPos = mapToParent(viewToItemTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton)))));
7363                 } else if (item->flags() & ItemIgnoresTransformations) {
7364                     // Root items that ignore transformations need to
7365                     // calculate their diff by mapping viewport coordinates
7366                     // directly to parent coordinates.
7367                     // COMBINE
7368                     QTransform itemTransform;
7369                     if (item->d_ptr->transformData)
7370                         itemTransform = item->d_ptr->transformData->computedFullTransform();
7371                     itemTransform.translate(item->d_ptr->pos.x(), item->d_ptr->pos.y());
7372                     QTransform viewToParentTransform = itemTransform
7373                                                        * (item->sceneTransform() * view->viewportTransform()).inverted();
7374                     currentParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->screenPos())));
7375                     buttonDownParentPos = viewToParentTransform.map(QPointF(view->mapFromGlobal(event->buttonDownScreenPos(Qt::LeftButton))));
7376                 } else {
7377                     // All other items simply map from the scene.
7378                     currentParentPos = item->mapToParent(item->mapFromScene(event->scenePos()));
7379                     buttonDownParentPos = item->mapToParent(item->mapFromScene(event->buttonDownScenePos(Qt::LeftButton)));
7380                 }
7381 
7382                 item->setPos(initialPositions.value(item) + currentParentPos - buttonDownParentPos);
7383 
7384                 if (item->flags() & ItemIsSelectable)
7385                     item->setSelected(true);
7386             }
7387             ++i;
7388         }
7389 
7390     } else {
7391         event->ignore();
7392     }
7393 }
7394 
7395 /*!
7396     This event handler, for event \a event, can be reimplemented to
7397     receive mouse release events for this item.
7398 
7399     Calling QEvent::ignore() or QEvent::accept() on \a event has no
7400     effect.
7401 
7402     The default implementation handles basic item interaction, such as
7403     selection and moving. If you want to keep the base implementation
7404     when reimplementing this function, call
7405     QGraphicsItem::mouseReleaseEvent() in your reimplementation.
7406 
7407     Please note that mousePressEvent() decides which graphics item it
7408     is that receives mouse events. See the mousePressEvent()
7409     description for details.
7410 
7411     \sa mousePressEvent(), mouseMoveEvent(), mouseDoubleClickEvent(),
7412     sceneEvent()
7413 */
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)7414 void QGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
7415 {
7416     if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
7417         bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
7418         if (event->scenePos() == event->buttonDownScenePos(Qt::LeftButton)) {
7419             // The item didn't move
7420             if (multiSelect) {
7421                 setSelected(!isSelected());
7422             } else {
7423                 bool selectionChanged = false;
7424                 if (QGraphicsScene *scene = d_ptr->scene) {
7425                     ++scene->d_func()->selectionChanging;
7426                     // Clear everything but this item. Bypass
7427                     // QGraphicsScene::clearSelection()'s default behavior by
7428                     // temporarily removing this item from the selection list.
7429                     if (d_ptr->selected) {
7430                         scene->d_func()->selectedItems.remove(this);
7431                         foreach (QGraphicsItem *item, scene->d_func()->selectedItems) {
7432                             if (item->isSelected()) {
7433                                 selectionChanged = true;
7434                                 break;
7435                             }
7436                         }
7437                     }
7438                     scene->clearSelection();
7439                     if (d_ptr->selected)
7440                         scene->d_func()->selectedItems.insert(this);
7441                     --scene->d_func()->selectionChanging;
7442                     if (selectionChanged)
7443                         emit d_ptr->scene->selectionChanged();
7444                 }
7445                 setSelected(true);
7446             }
7447         }
7448     }
7449     if (d_ptr->scene && !event->buttons())
7450         d_ptr->scene->d_func()->movingItemsInitialPositions.clear();
7451 }
7452 
7453 /*!
7454     This event handler, for event \a event, can be reimplemented to
7455     receive mouse doubleclick events for this item.
7456 
7457     When doubleclicking an item, the item will first receive a mouse
7458     press event, followed by a release event (i.e., a click), then a
7459     doubleclick event, and finally a release event.
7460 
7461     Calling QEvent::ignore() or QEvent::accept() on \a event has no
7462     effect.
7463 
7464     The default implementation calls mousePressEvent(). If you want to
7465     keep the base implementation when reimplementing this function,
7466     call QGraphicsItem::mouseDoubleClickEvent() in your
7467     reimplementation.
7468 
7469     Note that an item will not receive double click events if it is
7470     neither \l {QGraphicsItem::ItemIsSelectable}{selectable} nor
7471     \l{QGraphicsItem::ItemIsMovable}{movable} (single mouse clicks are
7472     ignored in this case, and that stops the generation of double
7473     clicks).
7474 
7475     \sa mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), sceneEvent()
7476 */
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)7477 void QGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
7478 {
7479     mousePressEvent(event);
7480 }
7481 
7482 /*!
7483     This event handler, for event \a event, can be reimplemented to receive
7484     wheel events for this item. If you reimplement this function, \a event
7485     will be accepted by default.
7486 
7487     If you ignore the event, (i.e., by calling QEvent::ignore(),) it will
7488     propagate to any item beneath this item. If no items accept the event, it
7489     will be ignored by the scene, and propagate to the view (e.g., the view's
7490     vertical scroll bar).
7491 
7492     The default implementation ignores the event.
7493 
7494     \sa sceneEvent()
7495 */
wheelEvent(QGraphicsSceneWheelEvent * event)7496 void QGraphicsItem::wheelEvent(QGraphicsSceneWheelEvent *event)
7497 {
7498     event->ignore();
7499 }
7500 
7501 /*!
7502     This event handler, for event \a event, can be reimplemented to receive
7503     input method events for this item. The default implementation ignores the
7504     event.
7505 
7506     \sa inputMethodQuery(), sceneEvent()
7507 */
inputMethodEvent(QInputMethodEvent * event)7508 void QGraphicsItem::inputMethodEvent(QInputMethodEvent *event)
7509 {
7510     event->ignore();
7511 }
7512 
7513 /*!
7514     This method is only relevant for input items. It is used by the
7515     input method to query a set of properties of the item to be able
7516     to support complex input method operations, such as support for
7517     surrounding text and reconversions. \a query specifies which
7518     property is queried.
7519 
7520     \sa inputMethodEvent(), QInputMethodEvent
7521 */
inputMethodQuery(Qt::InputMethodQuery query) const7522 QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
7523 {
7524     Q_UNUSED(query);
7525     return QVariant();
7526 }
7527 
7528 /*!
7529     Returns the current input method hints of this item.
7530 
7531     Input method hints are only relevant for input items.
7532     The hints are used by the input method to indicate how it should operate.
7533     For example, if the Qt::ImhNumbersOnly flag is set, the input method may change
7534     its visual components to reflect that only numbers can be entered.
7535 
7536     The effect may vary between input method implementations.
7537 
7538     \since 4.6
7539 
7540     \sa setInputMethodHints(), inputMethodQuery()
7541 */
inputMethodHints() const7542 Qt::InputMethodHints QGraphicsItem::inputMethodHints() const
7543 {
7544     Q_D(const QGraphicsItem);
7545     return d->imHints;
7546 }
7547 
7548 /*!
7549     Sets the current input method hints of this item to \a hints.
7550 
7551     \since 4.6
7552 
7553     \sa inputMethodHints(), inputMethodQuery()
7554 */
setInputMethodHints(Qt::InputMethodHints hints)7555 void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints)
7556 {
7557     Q_D(QGraphicsItem);
7558     d->imHints = hints;
7559     if (!hasFocus())
7560         return;
7561     d->scene->d_func()->updateInputMethodSensitivityInViews();
7562     QWidget *fw = QApplication::focusWidget();
7563     if (!fw)
7564         return;
7565     QGuiApplication::inputMethod()->update(Qt::ImHints);
7566 }
7567 
7568 /*!
7569     Updates the item's micro focus.
7570 
7571     \since 4.7
7572 
7573     \sa QInputMethod
7574 */
updateMicroFocus()7575 void QGraphicsItem::updateMicroFocus()
7576 {
7577 }
7578 
7579 /*!
7580     This virtual function is called by QGraphicsItem to notify custom items
7581     that some part of the item's state changes. By reimplementing this
7582     function, you can react to a change, and in some cases (depending on \a
7583     change), adjustments can be made.
7584 
7585     \a change is the parameter of the item that is changing. \a value is the
7586     new value; the type of the value depends on \a change.
7587 
7588     Example:
7589 
7590     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 15
7591 
7592     The default implementation does nothing, and returns \a value.
7593 
7594     Note: Certain QGraphicsItem functions cannot be called in a
7595     reimplementation of this function; see the GraphicsItemChange
7596     documentation for details.
7597 
7598     \sa GraphicsItemChange
7599 */
itemChange(GraphicsItemChange change,const QVariant & value)7600 QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
7601 {
7602     Q_UNUSED(change);
7603     return value;
7604 }
7605 
7606 /*!
7607     \internal
7608 
7609     Note: This is provided as a hook to avoid future problems related
7610     to adding virtual functions.
7611 */
supportsExtension(Extension extension) const7612 bool QGraphicsItem::supportsExtension(Extension extension) const
7613 {
7614     Q_UNUSED(extension);
7615     return false;
7616 }
7617 
7618 /*!
7619     \internal
7620 
7621     Note: This is provided as a hook to avoid future problems related
7622     to adding virtual functions.
7623 */
setExtension(Extension extension,const QVariant & variant)7624 void QGraphicsItem::setExtension(Extension extension, const QVariant &variant)
7625 {
7626     Q_UNUSED(extension);
7627     Q_UNUSED(variant);
7628 }
7629 
7630 /*!
7631     \internal
7632 
7633     Note: This is provided as a hook to avoid future problems related
7634     to adding virtual functions.
7635 */
extension(const QVariant & variant) const7636 QVariant QGraphicsItem::extension(const QVariant &variant) const
7637 {
7638     Q_UNUSED(variant);
7639     return QVariant();
7640 }
7641 
7642 /*!
7643     \internal
7644 
7645     Adds this item to the scene's index. Called in conjunction with
7646     removeFromIndex() to ensure the index bookkeeping is correct when
7647     the item's position, transformation or shape changes.
7648 */
addToIndex()7649 void QGraphicsItem::addToIndex()
7650 {
7651     if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
7652         || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
7653         // ### add to child index only if applicable
7654         return;
7655     }
7656     if (d_ptr->scene)
7657         d_ptr->scene->d_func()->index->addItem(this);
7658 }
7659 
7660 /*!
7661     \internal
7662 
7663     Removes this item from the scene's index. Called in conjunction
7664     with addToIndex() to ensure the index bookkeeping is correct when
7665     the item's position, transformation or shape changes.
7666 */
removeFromIndex()7667 void QGraphicsItem::removeFromIndex()
7668 {
7669     if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
7670         || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
7671         // ### remove from child index only if applicable
7672         return;
7673     }
7674     if (d_ptr->scene)
7675         d_ptr->scene->d_func()->index->removeItem(this);
7676 }
7677 
7678 /*!
7679     Prepares the item for a geometry change. Call this function before
7680     changing the bounding rect of an item to keep QGraphicsScene's index up to
7681     date.
7682 
7683     prepareGeometryChange() will call update() if this is necessary.
7684 
7685     Example:
7686 
7687     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 16
7688 
7689     \sa boundingRect()
7690 */
prepareGeometryChange()7691 void QGraphicsItem::prepareGeometryChange()
7692 {
7693     if (d_ptr->inDestructor)
7694         return;
7695     if (d_ptr->scene) {
7696         d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
7697         d_ptr->geometryChanged = 1;
7698         d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
7699         d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper;
7700 
7701         QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
7702         scenePrivate->index->prepareBoundingRectChange(this);
7703         scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true, /*force=*/false,
7704                                 /*ignoreOpacity=*/ false, /*removingItemFromScene=*/ false,
7705                                 /*updateBoundingRect=*/true);
7706 
7707         // For compatibility reasons, we have to update the item's old geometry
7708         // if someone is connected to the changed signal or the scene has no views.
7709         // Note that this has to be done *after* markDirty to ensure that
7710         // _q_processDirtyItems is called before _q_emitUpdated.
7711         if (scenePrivate->isSignalConnected(scenePrivate->changedSignalIndex)
7712             || scenePrivate->views.isEmpty()) {
7713             if (d_ptr->hasTranslateOnlySceneTransform()) {
7714                 d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
7715                                                                d_ptr->sceneTransform.dy()));
7716             } else {
7717                 d_ptr->scene->update(d_ptr->sceneTransform.mapRect(boundingRect()));
7718             }
7719         }
7720     }
7721 
7722     d_ptr->markParentDirty(/*updateBoundingRect=*/true);
7723 }
7724 
7725 /*!
7726     \internal
7727 
7728     Highlights \a item as selected.
7729 
7730     NOTE: This function is a duplicate of qt_graphicsItem_highlightSelected() in
7731           qgraphicssvgitem.cpp!
7732 */
qt_graphicsItem_highlightSelected(QGraphicsItem * item,QPainter * painter,const QStyleOptionGraphicsItem * option)7733 static void qt_graphicsItem_highlightSelected(
7734     QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
7735 {
7736     const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
7737     if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
7738         return;
7739 
7740     const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
7741     if (qMin(mbrect.width(), mbrect.height()) < qreal(1.0))
7742         return;
7743 
7744     qreal itemPenWidth;
7745     switch (item->type()) {
7746         case QGraphicsEllipseItem::Type:
7747             itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
7748             break;
7749         case QGraphicsPathItem::Type:
7750             itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
7751             break;
7752         case QGraphicsPolygonItem::Type:
7753             itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
7754             break;
7755         case QGraphicsRectItem::Type:
7756             itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
7757             break;
7758         case QGraphicsSimpleTextItem::Type:
7759             itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
7760             break;
7761         case QGraphicsLineItem::Type:
7762             itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
7763             break;
7764         default:
7765             itemPenWidth = 1.0;
7766     }
7767     const qreal pad = itemPenWidth / 2;
7768 
7769     const qreal penWidth = 0; // cosmetic pen
7770 
7771     const QColor fgcolor = option->palette.windowText().color();
7772     const QColor bgcolor( // ensure good contrast against fgcolor
7773         fgcolor.red()   > 127 ? 0 : 255,
7774         fgcolor.green() > 127 ? 0 : 255,
7775         fgcolor.blue()  > 127 ? 0 : 255);
7776 
7777     painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
7778     painter->setBrush(Qt::NoBrush);
7779     painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
7780 
7781     painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
7782     painter->setBrush(Qt::NoBrush);
7783     painter->drawRect(item->boundingRect().adjusted(pad, pad, -pad, -pad));
7784 }
7785 
7786 /*!
7787     \class QGraphicsObject
7788     \brief The QGraphicsObject class provides a base class for all graphics items that
7789     require signals, slots and properties.
7790     \since 4.6
7791     \ingroup graphicsview-api
7792     \inmodule QtWidgets
7793 
7794     The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms.
7795     It maps many of QGraphicsItem's basic setters and getters to properties and adds notification
7796     signals for many of them.
7797 
7798     \section1 Parents and Children
7799 
7800     Each graphics object can be constructed with a parent item. This ensures that the
7801     item will be destroyed when its parent item is destroyed. Although QGraphicsObject
7802     inherits from both QObject and QGraphicsItem, you should use the functions provided
7803     by QGraphicsItem, \e not QObject, to manage the relationships between parent and
7804     child items.
7805 
7806     The relationships between items can be explored using the parentItem() and childItems()
7807     functions. In the hierarchy of items in a scene, the parentObject() and parentWidget()
7808     functions are the equivalent of the QWidget::parent() and QWidget::parentWidget()
7809     functions for QWidget subclasses.
7810 
7811     \sa QGraphicsWidget
7812 */
7813 
7814 /*!
7815     Constructs a QGraphicsObject with \a parent.
7816 */
QGraphicsObject(QGraphicsItem * parent)7817 QGraphicsObject::QGraphicsObject(QGraphicsItem *parent)
7818         : QGraphicsItem(parent)
7819 {
7820     QGraphicsItem::d_ptr->isObject = true;
7821 }
7822 
7823 /*!
7824   \internal
7825 */
QGraphicsObject(QGraphicsItemPrivate & dd,QGraphicsItem * parent)7826 QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent)
7827     : QGraphicsItem(dd, parent)
7828 {
7829     QGraphicsItem::d_ptr->isObject = true;
7830 }
7831 
7832 /*!
7833   Destructor.
7834 */
~QGraphicsObject()7835 QGraphicsObject::~QGraphicsObject()
7836 {
7837 }
7838 
7839 /*!
7840   \reimp
7841 */
event(QEvent * ev)7842 bool QGraphicsObject::event(QEvent *ev)
7843 {
7844     if (ev->type() == QEvent::StyleAnimationUpdate) {
7845         if (isVisible()) {
7846             ev->accept();
7847             update();
7848         }
7849         return true;
7850     }
7851     return QObject::event(ev);
7852 }
7853 
7854 #ifndef QT_NO_GESTURES
7855 /*!
7856     Subscribes the graphics object to the given \a gesture with specific \a flags.
7857 
7858     \sa ungrabGesture(), QGestureEvent
7859 */
grabGesture(Qt::GestureType gesture,Qt::GestureFlags flags)7860 void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
7861 {
7862     bool contains = QGraphicsItem::d_ptr->gestureContext.contains(gesture);
7863     QGraphicsItem::d_ptr->gestureContext.insert(gesture, flags);
7864     if (!contains && QGraphicsItem::d_ptr->scene)
7865         QGraphicsItem::d_ptr->scene->d_func()->grabGesture(this, gesture);
7866 }
7867 
7868 /*!
7869     Unsubscribes the graphics object from the given \a gesture.
7870 
7871     \sa grabGesture(), QGestureEvent
7872 */
ungrabGesture(Qt::GestureType gesture)7873 void QGraphicsObject::ungrabGesture(Qt::GestureType gesture)
7874 {
7875     if (QGraphicsItem::d_ptr->gestureContext.remove(gesture) && QGraphicsItem::d_ptr->scene)
7876         QGraphicsItem::d_ptr->scene->d_func()->ungrabGesture(this, gesture);
7877 }
7878 #endif // QT_NO_GESTURES
7879 
7880 /*!
7881     Updates the item's micro focus. This is slot for convenience.
7882 
7883     \since 4.7
7884 
7885     \sa QInputMethod
7886 */
updateMicroFocus()7887 void QGraphicsObject::updateMicroFocus()
7888 {
7889     QGraphicsItem::updateMicroFocus();
7890 }
7891 
children_append(QDeclarativeListProperty<QGraphicsObject> * list,QGraphicsObject * item)7892 void QGraphicsItemPrivate::children_append(QDeclarativeListProperty<QGraphicsObject> *list, QGraphicsObject *item)
7893 {
7894     if (item) {
7895         QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(list->object);
7896         if (QGraphicsItemPrivate::get(graphicsObject)->sendParentChangeNotification) {
7897             item->setParentItem(graphicsObject);
7898         } else {
7899             QGraphicsItemPrivate::get(item)->setParentItemHelper(graphicsObject, nullptr, nullptr);
7900         }
7901     }
7902 }
7903 
children_count(QDeclarativeListProperty<QGraphicsObject> * list)7904 int QGraphicsItemPrivate::children_count(QDeclarativeListProperty<QGraphicsObject> *list)
7905 {
7906     QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
7907     return d->children.count();
7908 }
7909 
children_at(QDeclarativeListProperty<QGraphicsObject> * list,int index)7910 QGraphicsObject *QGraphicsItemPrivate::children_at(QDeclarativeListProperty<QGraphicsObject> *list, int index)
7911 {
7912     QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
7913     if (index >= 0 && index < d->children.count())
7914         return d->children.at(index)->toGraphicsObject();
7915     else
7916         return nullptr;
7917 }
7918 
children_clear(QDeclarativeListProperty<QGraphicsObject> * list)7919 void QGraphicsItemPrivate::children_clear(QDeclarativeListProperty<QGraphicsObject> *list)
7920 {
7921     QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(static_cast<QGraphicsObject *>(list->object));
7922     int childCount = d->children.count();
7923     if (d->sendParentChangeNotification) {
7924         for (int index = 0; index < childCount; index++)
7925             d->children.at(0)->setParentItem(nullptr);
7926     } else {
7927         for (int index = 0; index < childCount; index++)
7928             QGraphicsItemPrivate::get(d->children.at(0))->setParentItemHelper(nullptr, nullptr, nullptr);
7929     }
7930 }
7931 
7932 /*!
7933     Returns a list of this item's children.
7934 
7935     The items are sorted by stacking order. This takes into account both the
7936     items' insertion order and their Z-values.
7937 
7938 */
childrenList()7939 QDeclarativeListProperty<QGraphicsObject> QGraphicsItemPrivate::childrenList()
7940 {
7941     Q_Q(QGraphicsItem);
7942     if (isObject) {
7943         QGraphicsObject *that = static_cast<QGraphicsObject *>(q);
7944         return QDeclarativeListProperty<QGraphicsObject>(that, &children, children_append,
7945                                                          children_count, children_at, children_clear);
7946     } else {
7947         //QGraphicsItem is not supported for this property
7948         return QDeclarativeListProperty<QGraphicsObject>();
7949     }
7950 }
7951 
7952 /*!
7953   \internal
7954   Returns the width of the item
7955   Reimplemented by QGraphicsWidget
7956 */
width() const7957 qreal QGraphicsItemPrivate::width() const
7958 {
7959     return 0;
7960 }
7961 
7962 /*!
7963   \internal
7964   Set the width of the item
7965   Reimplemented by QGraphicsWidget
7966 */
setWidth(qreal w)7967 void QGraphicsItemPrivate::setWidth(qreal w)
7968 {
7969     Q_UNUSED(w);
7970 }
7971 
7972 /*!
7973   \internal
7974   Reset the width of the item
7975   Reimplemented by QGraphicsWidget
7976 */
resetWidth()7977 void QGraphicsItemPrivate::resetWidth()
7978 {
7979 }
7980 
7981 /*!
7982   \internal
7983   Returns the height of the item
7984   Reimplemented by QGraphicsWidget
7985 */
height() const7986 qreal QGraphicsItemPrivate::height() const
7987 {
7988     return 0;
7989 }
7990 
7991 /*!
7992   \internal
7993   Set the height of the item
7994   Reimplemented by QGraphicsWidget
7995 */
setHeight(qreal h)7996 void QGraphicsItemPrivate::setHeight(qreal h)
7997 {
7998     Q_UNUSED(h);
7999 }
8000 
8001 /*!
8002   \internal
8003   Reset the height of the item
8004   Reimplemented by QGraphicsWidget
8005 */
resetHeight()8006 void QGraphicsItemPrivate::resetHeight()
8007 {
8008 }
8009 
8010 /*!
8011     \property QGraphicsObject::children
8012     \since 4.7
8013     \internal
8014 */
8015 
8016 /*!
8017     \property QGraphicsObject::width
8018     \since 4.7
8019     \internal
8020 */
8021 
8022 /*!
8023     \property QGraphicsObject::height
8024     \since 4.7
8025     \internal
8026 */
8027 
8028 /*!
8029   \property QGraphicsObject::parent
8030   \brief the parent of the item
8031 
8032   \note The item's parent is set independently of the parent object returned
8033   by QObject::parent().
8034 
8035   \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject()
8036 */
8037 
8038 /*!
8039   \property QGraphicsObject::opacity
8040   \brief the opacity of the item
8041 
8042   \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity()
8043 */
8044 
8045 /*!
8046   \fn QGraphicsObject::opacityChanged()
8047 
8048   This signal gets emitted whenever the opacity of the item changes
8049 
8050   \sa QGraphicsItem::opacity()
8051 */
8052 
8053 /*!
8054   \fn QGraphicsObject::parentChanged()
8055 
8056   This signal gets emitted whenever the parent of the item changes
8057 */
8058 
8059 /*!
8060   \property QGraphicsObject::pos
8061   \brief the position of the item
8062 
8063   Describes the items position.
8064 
8065   \sa QGraphicsItem::setPos(), QGraphicsItem::pos()
8066 */
8067 
8068 /*!
8069   \property QGraphicsObject::x
8070   \brief the x position of the item
8071 
8072   Describes the items x position.
8073 
8074   \sa QGraphicsItem::setX(), setPos()
8075 */
8076 
8077 /*!
8078   \fn QGraphicsObject::xChanged()
8079 
8080   This signal gets emitted whenever the x position of the item changes
8081 
8082   \sa pos()
8083 */
8084 
8085 /*!
8086   \property QGraphicsObject::y
8087   \brief the y position of the item
8088 
8089   Describes the items y position.
8090 
8091   \sa QGraphicsItem::setY(), setPos()
8092 */
8093 
8094 /*!
8095   \fn QGraphicsObject::yChanged()
8096 
8097   This signal gets emitted whenever the y position of the item changes.
8098 
8099   \sa pos()
8100 */
8101 
8102 /*!
8103   \property QGraphicsObject::z
8104   \brief the z value of the item
8105 
8106   Describes the items z value.
8107 
8108   \sa QGraphicsItem::setZValue(), zValue()
8109 */
8110 
8111 /*!
8112   \fn QGraphicsObject::zChanged()
8113 
8114   This signal gets emitted whenever the z value of the item changes.
8115 
8116   \sa pos()
8117 */
8118 
8119 /*!
8120   \property QGraphicsObject::rotation
8121   This property holds the rotation of the item in degrees.
8122 
8123   This specifies how many degrees to rotate the item around its transformOrigin.
8124   The default rotation is 0 degrees (i.e. not rotated at all).
8125 */
8126 
8127 /*!
8128   \fn QGraphicsObject::rotationChanged()
8129 
8130   This signal gets emitted whenever the roation of the item changes.
8131 */
8132 
8133 /*!
8134   \property QGraphicsObject::scale
8135   This property holds the scale of the item.
8136 
8137   A scale of less than 1 means the item will be displayed smaller than
8138   normal, and a scale of greater than 1 means the item will be
8139   displayed larger than normal.  A negative scale means the item will
8140   be mirrored.
8141 
8142   By default, items are displayed at a scale of 1 (i.e. at their
8143   normal size).
8144 
8145   Scaling is from the item's transformOrigin.
8146 */
8147 
8148 /*!
8149   \fn void QGraphicsObject::scaleChanged()
8150 
8151   This signal is emitted when the scale of the item changes.
8152 */
8153 
8154 
8155 /*!
8156   \property QGraphicsObject::enabled
8157   \brief whether the item is enabled or not
8158 
8159   This property is declared in QGraphicsItem.
8160 
8161   By default, this property is \c true.
8162 
8163   \sa QGraphicsItem::isEnabled(), QGraphicsItem::setEnabled()
8164 */
8165 
8166 /*!
8167   \fn void QGraphicsObject::enabledChanged()
8168 
8169   This signal gets emitted whenever the item get's enabled or disabled.
8170 
8171   \sa isEnabled()
8172 */
8173 
8174 /*!
8175   \property QGraphicsObject::visible
8176   \brief whether the item is visible or not
8177 
8178   This property is declared in QGraphicsItem.
8179 
8180   By default, this property is \c true.
8181 
8182   \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible()
8183 */
8184 
8185 /*!
8186   \fn QGraphicsObject::visibleChanged()
8187 
8188   This signal gets emitted whenever the visibility of the item changes
8189 
8190   \sa visible
8191 */
8192 
8193 /*!
8194   \property QGraphicsObject::transformOriginPoint
8195   \brief the transformation origin
8196 
8197   This property sets a specific point in the items coordiante system as the
8198   origin for scale and rotation.
8199 
8200   \sa scale, rotation, QGraphicsItem::transformOriginPoint()
8201 */
8202 
8203 /*!
8204     \fn void QGraphicsObject::widthChanged()
8205     \internal
8206 */
8207 
8208 /*!
8209     \fn void QGraphicsObject::heightChanged()
8210     \internal
8211 */
8212 
8213 /*!
8214 
8215   \fn QGraphicsObject::childrenChanged()
8216 
8217   This signal gets emitted whenever the children list changes
8218   \internal
8219 */
8220 
8221 /*!
8222   \property QGraphicsObject::effect
8223   \since 4.7
8224   \brief the effect attached to this item
8225 
8226   \sa QGraphicsItem::setGraphicsEffect(), QGraphicsItem::graphicsEffect()
8227 */
8228 
8229 /*!
8230     \class QAbstractGraphicsShapeItem
8231     \brief The QAbstractGraphicsShapeItem class provides a common base for
8232     all path items.
8233     \since 4.2
8234     \ingroup graphicsview-api
8235     \inmodule QtWidgets
8236 
8237     This class does not fully implement an item by itself; in particular, it
8238     does not implement boundingRect() and paint(), which are inherited by
8239     QGraphicsItem.
8240 
8241     You can subclass this item to provide a simple base implementation of
8242     accessors for the item's pen and brush.
8243 
8244     \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPathItem,
8245     QGraphicsPolygonItem, QGraphicsTextItem, QGraphicsLineItem,
8246     QGraphicsPixmapItem, {Graphics View Framework}
8247 */
8248 
8249 class QAbstractGraphicsShapeItemPrivate : public QGraphicsItemPrivate
8250 {
8251     Q_DECLARE_PUBLIC(QAbstractGraphicsShapeItem)
8252 public:
8253 
8254     QBrush brush;
8255     QPen pen;
8256 
8257     // Cached bounding rectangle
8258     mutable QRectF boundingRect;
8259 };
8260 
8261 /*!
8262     Constructs a QAbstractGraphicsShapeItem. \a parent is passed to
8263     QGraphicsItem's constructor.
8264 */
QAbstractGraphicsShapeItem(QGraphicsItem * parent)8265 QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QGraphicsItem *parent)
8266     : QGraphicsItem(*new QAbstractGraphicsShapeItemPrivate, parent)
8267 {
8268 }
8269 
8270 /*!
8271     \internal
8272 */
QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate & dd,QGraphicsItem * parent)8273 QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate &dd, QGraphicsItem *parent)
8274     : QGraphicsItem(dd, parent)
8275 {
8276 }
8277 
8278 /*!
8279     Destroys a QAbstractGraphicsShapeItem.
8280 */
~QAbstractGraphicsShapeItem()8281 QAbstractGraphicsShapeItem::~QAbstractGraphicsShapeItem()
8282 {
8283 }
8284 
8285 /*!
8286     Returns the item's pen. If no pen has been set, this function returns
8287     QPen(), a default black solid line pen with 1 width.
8288 */
pen() const8289 QPen QAbstractGraphicsShapeItem::pen() const
8290 {
8291     Q_D(const QAbstractGraphicsShapeItem);
8292     return d->pen;
8293 }
8294 
8295 /*!
8296     Sets the pen for this item to \a pen.
8297 
8298     The pen is used to draw the item's outline.
8299 
8300     \sa pen()
8301 */
setPen(const QPen & pen)8302 void QAbstractGraphicsShapeItem::setPen(const QPen &pen)
8303 {
8304     Q_D(QAbstractGraphicsShapeItem);
8305     if (d->pen == pen)
8306         return;
8307     prepareGeometryChange();
8308     d->pen = pen;
8309     d->boundingRect = QRectF();
8310     update();
8311 }
8312 
8313 /*!
8314     Returns the item's brush, or an empty brush if no brush has been set.
8315 
8316     \sa setBrush()
8317 */
brush() const8318 QBrush QAbstractGraphicsShapeItem::brush() const
8319 {
8320     Q_D(const QAbstractGraphicsShapeItem);
8321     return d->brush;
8322 }
8323 
8324 /*!
8325     Sets the item's brush to \a brush.
8326 
8327     The item's brush is used to fill the item.
8328 
8329     If you use a brush with a QGradient, the gradient
8330     is relative to the item's coordinate system.
8331 
8332     \sa brush()
8333 */
setBrush(const QBrush & brush)8334 void QAbstractGraphicsShapeItem::setBrush(const QBrush &brush)
8335 {
8336     Q_D(QAbstractGraphicsShapeItem);
8337     if (d->brush == brush)
8338         return;
8339     d->brush = brush;
8340     update();
8341 }
8342 
8343 /*!
8344     \reimp
8345 */
isObscuredBy(const QGraphicsItem * item) const8346 bool QAbstractGraphicsShapeItem::isObscuredBy(const QGraphicsItem *item) const
8347 {
8348     return QGraphicsItem::isObscuredBy(item);
8349 }
8350 
8351 /*!
8352     \reimp
8353 */
opaqueArea() const8354 QPainterPath QAbstractGraphicsShapeItem::opaqueArea() const
8355 {
8356     Q_D(const QAbstractGraphicsShapeItem);
8357     if (d->brush.isOpaque())
8358         return isClipped() ? clipPath() : shape();
8359     return QGraphicsItem::opaqueArea();
8360 }
8361 
8362 /*!
8363     \class QGraphicsPathItem
8364     \brief The QGraphicsPathItem class provides a path item that you
8365     can add to a QGraphicsScene.
8366     \since 4.2
8367     \ingroup graphicsview-api
8368     \inmodule QtWidgets
8369 
8370     To set the item's path, pass a QPainterPath to QGraphicsPathItem's
8371     constructor, or call the setPath() function. The path() function
8372     returns the current path.
8373 
8374     \image graphicsview-pathitem.png
8375 
8376     QGraphicsPathItem uses the path to provide a reasonable
8377     implementation of boundingRect(), shape(), and contains(). The
8378     paint() function draws the path using the item's associated pen
8379     and brush, which you can set by calling the setPen() and
8380     setBrush() functions.
8381 
8382     \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
8383     QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8384     View Framework}
8385 */
8386 
8387 class QGraphicsPathItemPrivate : public QAbstractGraphicsShapeItemPrivate
8388 {
8389     Q_DECLARE_PUBLIC(QGraphicsPathItem)
8390 public:
8391     QPainterPath path;
8392 };
8393 
8394 /*!
8395     Constructs a QGraphicsPath item using \a path as the default path. \a
8396     parent is passed to QAbstractGraphicsShapeItem's constructor.
8397 
8398     \sa QGraphicsScene::addItem()
8399 */
QGraphicsPathItem(const QPainterPath & path,QGraphicsItem * parent)8400 QGraphicsPathItem::QGraphicsPathItem(const QPainterPath &path,
8401                                      QGraphicsItem *parent)
8402     : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent)
8403 {
8404     if (!path.isEmpty())
8405         setPath(path);
8406 }
8407 
8408 /*!
8409     Constructs a QGraphicsPath. \a parent is passed to
8410     QAbstractGraphicsShapeItem's constructor.
8411 
8412     \sa QGraphicsScene::addItem()
8413 */
QGraphicsPathItem(QGraphicsItem * parent)8414 QGraphicsPathItem::QGraphicsPathItem(QGraphicsItem *parent)
8415     : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent)
8416 {
8417 }
8418 
8419 /*!
8420     Destroys the QGraphicsPathItem.
8421 */
~QGraphicsPathItem()8422 QGraphicsPathItem::~QGraphicsPathItem()
8423 {
8424 }
8425 
8426 /*!
8427     Returns the item's path as a QPainterPath. If no item has been set, an
8428     empty QPainterPath is returned.
8429 
8430     \sa setPath()
8431 */
path() const8432 QPainterPath QGraphicsPathItem::path() const
8433 {
8434     Q_D(const QGraphicsPathItem);
8435     return d->path;
8436 }
8437 
8438 /*!
8439     Sets the item's path to be the given \a path.
8440 
8441     \sa path()
8442 */
setPath(const QPainterPath & path)8443 void QGraphicsPathItem::setPath(const QPainterPath &path)
8444 {
8445     Q_D(QGraphicsPathItem);
8446     if (d->path == path)
8447         return;
8448     prepareGeometryChange();
8449     d->path = path;
8450     d->boundingRect = QRectF();
8451     update();
8452 }
8453 
8454 /*!
8455     \reimp
8456 */
boundingRect() const8457 QRectF QGraphicsPathItem::boundingRect() const
8458 {
8459     Q_D(const QGraphicsPathItem);
8460     if (d->boundingRect.isNull()) {
8461         qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
8462         if (pw == 0.0)
8463             d->boundingRect = d->path.controlPointRect();
8464         else {
8465             d->boundingRect = shape().controlPointRect();
8466         }
8467     }
8468     return d->boundingRect;
8469 }
8470 
8471 /*!
8472     \reimp
8473 */
shape() const8474 QPainterPath QGraphicsPathItem::shape() const
8475 {
8476     Q_D(const QGraphicsPathItem);
8477     return qt_graphicsItem_shapeFromPath(d->path, d->pen);
8478 }
8479 
8480 /*!
8481     \reimp
8482 */
contains(const QPointF & point) const8483 bool QGraphicsPathItem::contains(const QPointF &point) const
8484 {
8485     return QAbstractGraphicsShapeItem::contains(point);
8486 }
8487 
8488 /*!
8489     \reimp
8490 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)8491 void QGraphicsPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
8492                               QWidget *widget)
8493 {
8494     Q_D(QGraphicsPathItem);
8495     Q_UNUSED(widget);
8496     painter->setPen(d->pen);
8497     painter->setBrush(d->brush);
8498     painter->drawPath(d->path);
8499 
8500     if (option->state & QStyle::State_Selected)
8501         qt_graphicsItem_highlightSelected(this, painter, option);
8502 }
8503 
8504 /*!
8505     \reimp
8506 */
isObscuredBy(const QGraphicsItem * item) const8507 bool QGraphicsPathItem::isObscuredBy(const QGraphicsItem *item) const
8508 {
8509     return QAbstractGraphicsShapeItem::isObscuredBy(item);
8510 }
8511 
8512 /*!
8513     \reimp
8514 */
opaqueArea() const8515 QPainterPath QGraphicsPathItem::opaqueArea() const
8516 {
8517     return QAbstractGraphicsShapeItem::opaqueArea();
8518 }
8519 
8520 /*!
8521     \reimp
8522 */
type() const8523 int QGraphicsPathItem::type() const
8524 {
8525     return Type;
8526 }
8527 
8528 /*!
8529     \internal
8530 */
supportsExtension(Extension extension) const8531 bool QGraphicsPathItem::supportsExtension(Extension extension) const
8532 {
8533     Q_UNUSED(extension);
8534     return false;
8535 }
8536 
8537 /*!
8538     \internal
8539 */
setExtension(Extension extension,const QVariant & variant)8540 void QGraphicsPathItem::setExtension(Extension extension, const QVariant &variant)
8541 {
8542     Q_UNUSED(extension);
8543     Q_UNUSED(variant);
8544 }
8545 
8546 /*!
8547     \internal
8548 */
extension(const QVariant & variant) const8549 QVariant QGraphicsPathItem::extension(const QVariant &variant) const
8550 {
8551     Q_UNUSED(variant);
8552     return QVariant();
8553 }
8554 
8555 /*!
8556     \class QGraphicsRectItem
8557     \brief The QGraphicsRectItem class provides a rectangle item that you
8558     can add to a QGraphicsScene.
8559     \since 4.2
8560     \ingroup graphicsview-api
8561     \inmodule QtWidgets
8562 
8563     To set the item's rectangle, pass a QRectF to QGraphicsRectItem's
8564     constructor, or call the setRect() function. The rect() function
8565     returns the current rectangle.
8566 
8567     \image graphicsview-rectitem.png
8568 
8569     QGraphicsRectItem uses the rectangle and the pen width to provide
8570     a reasonable implementation of boundingRect(), shape(), and
8571     contains(). The paint() function draws the rectangle using the
8572     item's associated pen and brush, which you can set by calling the
8573     setPen() and setBrush() functions.
8574 
8575     \note The rendering of invalid rectangles, such as those with negative
8576     widths or heights, is undefined. If you cannot be sure that you are
8577     using valid rectangles (for example, if you are creating
8578     rectangles using data from an unreliable source) then you should
8579     use QRectF::normalized() to create normalized rectangles, and use
8580     those instead.
8581 
8582     \sa QGraphicsPathItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
8583     QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8584     View Framework}
8585 */
8586 
8587 class QGraphicsRectItemPrivate : public QAbstractGraphicsShapeItemPrivate
8588 {
8589     Q_DECLARE_PUBLIC(QGraphicsRectItem)
8590 public:
8591     QRectF rect;
8592 };
8593 
8594 /*!
8595     Constructs a QGraphicsRectItem, using \a rect as the default rectangle.
8596     \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8597 
8598     \sa QGraphicsScene::addItem()
8599 */
QGraphicsRectItem(const QRectF & rect,QGraphicsItem * parent)8600 QGraphicsRectItem::QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent)
8601     : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8602 {
8603     setRect(rect);
8604 }
8605 
8606 /*!
8607     \fn QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal width, qreal height,
8608                                      QGraphicsItem *parent)
8609 
8610     Constructs a QGraphicsRectItem with a default rectangle defined
8611     by (\a x, \a y) and the given \a width and \a height.
8612 
8613     \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8614 
8615     \sa QGraphicsScene::addItem()
8616 */
QGraphicsRectItem(qreal x,qreal y,qreal w,qreal h,QGraphicsItem * parent)8617 QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal w, qreal h,
8618                                      QGraphicsItem *parent)
8619     : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8620 {
8621     setRect(QRectF(x, y, w, h));
8622 }
8623 
8624 /*!
8625     Constructs a QGraphicsRectItem. \a parent is passed to
8626     QAbstractGraphicsShapeItem's constructor.
8627 
8628     \sa QGraphicsScene::addItem()
8629 */
QGraphicsRectItem(QGraphicsItem * parent)8630 QGraphicsRectItem::QGraphicsRectItem(QGraphicsItem *parent)
8631     : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8632 {
8633 }
8634 
8635 /*!
8636     Destroys the QGraphicsRectItem.
8637 */
~QGraphicsRectItem()8638 QGraphicsRectItem::~QGraphicsRectItem()
8639 {
8640 }
8641 
8642 /*!
8643     Returns the item's rectangle.
8644 
8645     \sa setRect()
8646 */
rect() const8647 QRectF QGraphicsRectItem::rect() const
8648 {
8649     Q_D(const QGraphicsRectItem);
8650     return d->rect;
8651 }
8652 
8653 /*!
8654     \fn void QGraphicsRectItem::setRect(const QRectF &rectangle)
8655 
8656     Sets the item's rectangle to be the given \a rectangle.
8657 
8658     \sa rect()
8659 */
setRect(const QRectF & rect)8660 void QGraphicsRectItem::setRect(const QRectF &rect)
8661 {
8662     Q_D(QGraphicsRectItem);
8663     if (d->rect == rect)
8664         return;
8665     prepareGeometryChange();
8666     d->rect = rect;
8667     d->boundingRect = QRectF();
8668     update();
8669 }
8670 
8671 /*!
8672     \fn void QGraphicsRectItem::setRect(qreal x, qreal y, qreal width, qreal height)
8673     \fn void QGraphicsEllipseItem::setRect(qreal x, qreal y, qreal width, qreal height)
8674 
8675     Sets the item's rectangle to the rectangle defined by (\a x, \a y)
8676     and the given \a width and \a height.
8677 
8678     This convenience function is equivalent to calling \c
8679     {setRect(QRectF(x, y, width, height))}
8680 
8681     \sa rect()
8682 */
8683 
8684 /*!
8685     \reimp
8686 */
boundingRect() const8687 QRectF QGraphicsRectItem::boundingRect() const
8688 {
8689     Q_D(const QGraphicsRectItem);
8690     if (d->boundingRect.isNull()) {
8691         qreal halfpw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF() / 2;
8692         d->boundingRect = d->rect;
8693         if (halfpw > 0.0)
8694             d->boundingRect.adjust(-halfpw, -halfpw, halfpw, halfpw);
8695     }
8696     return d->boundingRect;
8697 }
8698 
8699 /*!
8700     \reimp
8701 */
shape() const8702 QPainterPath QGraphicsRectItem::shape() const
8703 {
8704     Q_D(const QGraphicsRectItem);
8705     QPainterPath path;
8706     path.addRect(d->rect);
8707     return qt_graphicsItem_shapeFromPath(path, d->pen);
8708 }
8709 
8710 /*!
8711     \reimp
8712 */
contains(const QPointF & point) const8713 bool QGraphicsRectItem::contains(const QPointF &point) const
8714 {
8715     return QAbstractGraphicsShapeItem::contains(point);
8716 }
8717 
8718 /*!
8719     \reimp
8720 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)8721 void QGraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
8722                               QWidget *widget)
8723 {
8724     Q_D(QGraphicsRectItem);
8725     Q_UNUSED(widget);
8726     painter->setPen(d->pen);
8727     painter->setBrush(d->brush);
8728     painter->drawRect(d->rect);
8729 
8730     if (option->state & QStyle::State_Selected)
8731         qt_graphicsItem_highlightSelected(this, painter, option);
8732 }
8733 
8734 /*!
8735     \reimp
8736 */
isObscuredBy(const QGraphicsItem * item) const8737 bool QGraphicsRectItem::isObscuredBy(const QGraphicsItem *item) const
8738 {
8739     return QAbstractGraphicsShapeItem::isObscuredBy(item);
8740 }
8741 
8742 /*!
8743     \reimp
8744 */
opaqueArea() const8745 QPainterPath QGraphicsRectItem::opaqueArea() const
8746 {
8747     return QAbstractGraphicsShapeItem::opaqueArea();
8748 }
8749 
8750 /*!
8751     \reimp
8752 */
type() const8753 int QGraphicsRectItem::type() const
8754 {
8755     return Type;
8756 }
8757 
8758 /*!
8759     \internal
8760 */
supportsExtension(Extension extension) const8761 bool QGraphicsRectItem::supportsExtension(Extension extension) const
8762 {
8763     Q_UNUSED(extension);
8764     return false;
8765 }
8766 
8767 /*!
8768     \internal
8769 */
setExtension(Extension extension,const QVariant & variant)8770 void QGraphicsRectItem::setExtension(Extension extension, const QVariant &variant)
8771 {
8772     Q_UNUSED(extension);
8773     Q_UNUSED(variant);
8774 }
8775 
8776 /*!
8777     \internal
8778 */
extension(const QVariant & variant) const8779 QVariant QGraphicsRectItem::extension(const QVariant &variant) const
8780 {
8781     Q_UNUSED(variant);
8782     return QVariant();
8783 }
8784 
8785 /*!
8786     \class QGraphicsEllipseItem
8787     \brief The QGraphicsEllipseItem class provides an ellipse item that you
8788     can add to a QGraphicsScene.
8789     \since 4.2
8790     \ingroup graphicsview-api
8791     \inmodule QtWidgets
8792 
8793     QGraphicsEllipseItem respresents an ellipse with a fill and an outline,
8794     and you can also use it for ellipse segments (see startAngle(),
8795     spanAngle()).
8796 
8797     \table
8798         \row
8799             \li \inlineimage graphicsview-ellipseitem.png
8800             \li \inlineimage graphicsview-ellipseitem-pie.png
8801     \endtable
8802 
8803     To set the item's ellipse, pass a QRectF to QGraphicsEllipseItem's
8804     constructor, or call setRect(). The rect() function returns the
8805     current ellipse geometry.
8806 
8807     QGraphicsEllipseItem uses the rect and the pen width to provide a
8808     reasonable implementation of boundingRect(), shape(), and contains(). The
8809     paint() function draws the ellipse using the item's associated pen and
8810     brush, which you can set by calling setPen() and setBrush().
8811 
8812     \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsPolygonItem,
8813     QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8814     View Framework}
8815 */
8816 
8817 class QGraphicsEllipseItemPrivate : public QAbstractGraphicsShapeItemPrivate
8818 {
8819     Q_DECLARE_PUBLIC(QGraphicsEllipseItem)
8820 public:
QGraphicsEllipseItemPrivate()8821     inline QGraphicsEllipseItemPrivate()
8822         : startAngle(0), spanAngle(360 * 16)
8823     { }
8824 
8825     QRectF rect;
8826     int startAngle;
8827     int spanAngle;
8828 };
8829 
8830 /*!
8831     Constructs a QGraphicsEllipseItem using \a rect as the default rectangle.
8832     \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8833 
8834     \sa QGraphicsScene::addItem()
8835 */
QGraphicsEllipseItem(const QRectF & rect,QGraphicsItem * parent)8836 QGraphicsEllipseItem::QGraphicsEllipseItem(const QRectF &rect, QGraphicsItem *parent)
8837     : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8838 {
8839     setRect(rect);
8840 }
8841 
8842 /*!
8843     \fn QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent)
8844     \since 4.3
8845 
8846     Constructs a QGraphicsEllipseItem using the rectangle defined by (\a x, \a
8847     y) and the given \a width and \a height, as the default rectangle. \a
8848     parent is passed to QAbstractGraphicsShapeItem's constructor.
8849 
8850     \sa QGraphicsScene::addItem()
8851 */
QGraphicsEllipseItem(qreal x,qreal y,qreal w,qreal h,QGraphicsItem * parent)8852 QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h,
8853                                            QGraphicsItem *parent)
8854     : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8855 {
8856     setRect(x,y,w,h);
8857 }
8858 
8859 
8860 
8861 /*!
8862     Constructs a QGraphicsEllipseItem. \a parent is passed to
8863     QAbstractGraphicsShapeItem's constructor.
8864 
8865     \sa QGraphicsScene::addItem()
8866 */
QGraphicsEllipseItem(QGraphicsItem * parent)8867 QGraphicsEllipseItem::QGraphicsEllipseItem(QGraphicsItem *parent)
8868     : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8869 {
8870 }
8871 
8872 /*!
8873     Destroys the QGraphicsEllipseItem.
8874 */
~QGraphicsEllipseItem()8875 QGraphicsEllipseItem::~QGraphicsEllipseItem()
8876 {
8877 }
8878 
8879 /*!
8880     Returns the item's ellipse geometry as a QRectF.
8881 
8882     \sa setRect(), QPainter::drawEllipse()
8883 */
rect() const8884 QRectF QGraphicsEllipseItem::rect() const
8885 {
8886     Q_D(const QGraphicsEllipseItem);
8887     return d->rect;
8888 }
8889 
8890 /*!
8891     Sets the item's ellipse geometry to \a rect. The rectangle's left edge
8892     defines the left edge of the ellipse, and the rectangle's top edge
8893     describes the top of the ellipse. The height and width of the rectangle
8894     describe the height and width of the ellipse.
8895 
8896     \sa rect(), QPainter::drawEllipse()
8897 */
setRect(const QRectF & rect)8898 void QGraphicsEllipseItem::setRect(const QRectF &rect)
8899 {
8900     Q_D(QGraphicsEllipseItem);
8901     if (d->rect == rect)
8902         return;
8903     prepareGeometryChange();
8904     d->rect = rect;
8905     d->boundingRect = QRectF();
8906     update();
8907 }
8908 
8909 /*!
8910     Returns the start angle for an ellipse segment in 16ths of a degree. This
8911     angle is used together with spanAngle() for representing an ellipse
8912     segment (a pie). By default, the start angle is 0.
8913 
8914     \sa setStartAngle(), spanAngle()
8915 */
startAngle() const8916 int QGraphicsEllipseItem::startAngle() const
8917 {
8918     Q_D(const QGraphicsEllipseItem);
8919     return d->startAngle;
8920 }
8921 
8922 /*!
8923     Sets the start angle for an ellipse segment to \a angle, which is in 16ths
8924     of a degree. This angle is used together with spanAngle() for representing
8925     an ellipse segment (a pie). By default, the start angle is 0.
8926 
8927     \sa startAngle(), setSpanAngle(), QPainter::drawPie()
8928 */
setStartAngle(int angle)8929 void QGraphicsEllipseItem::setStartAngle(int angle)
8930 {
8931     Q_D(QGraphicsEllipseItem);
8932     if (angle != d->startAngle) {
8933         prepareGeometryChange();
8934         d->boundingRect = QRectF();
8935         d->startAngle = angle;
8936         update();
8937     }
8938 }
8939 
8940 /*!
8941     Returns the span angle of an ellipse segment in 16ths of a degree. This
8942     angle is used together with startAngle() for representing an ellipse
8943     segment (a pie). By default, this function returns 5760 (360 * 16, a full
8944     ellipse).
8945 
8946     \sa setSpanAngle(), startAngle()
8947 */
spanAngle() const8948 int QGraphicsEllipseItem::spanAngle() const
8949 {
8950     Q_D(const QGraphicsEllipseItem);
8951     return d->spanAngle;
8952 }
8953 
8954 /*!
8955     Sets the span angle for an ellipse segment to \a angle, which is in 16ths
8956     of a degree. This angle is used together with startAngle() to represent an
8957     ellipse segment (a pie). By default, the span angle is 5760 (360 * 16, a
8958     full ellipse).
8959 
8960     \sa spanAngle(), setStartAngle(), QPainter::drawPie()
8961 */
setSpanAngle(int angle)8962 void QGraphicsEllipseItem::setSpanAngle(int angle)
8963 {
8964     Q_D(QGraphicsEllipseItem);
8965     if (angle != d->spanAngle) {
8966         prepareGeometryChange();
8967         d->boundingRect = QRectF();
8968         d->spanAngle = angle;
8969         update();
8970     }
8971 }
8972 
8973 /*!
8974     \reimp
8975 */
boundingRect() const8976 QRectF QGraphicsEllipseItem::boundingRect() const
8977 {
8978     Q_D(const QGraphicsEllipseItem);
8979     if (d->boundingRect.isNull()) {
8980         qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
8981         if (pw == 0.0 && d->spanAngle == 360 * 16)
8982             d->boundingRect = d->rect;
8983         else
8984             d->boundingRect = shape().controlPointRect();
8985     }
8986     return d->boundingRect;
8987 }
8988 
8989 /*!
8990     \reimp
8991 */
shape() const8992 QPainterPath QGraphicsEllipseItem::shape() const
8993 {
8994     Q_D(const QGraphicsEllipseItem);
8995     QPainterPath path;
8996     if (d->rect.isNull())
8997         return path;
8998     if (d->spanAngle != 360 * 16) {
8999         path.moveTo(d->rect.center());
9000         path.arcTo(d->rect, d->startAngle / 16.0, d->spanAngle / 16.0);
9001     } else {
9002         path.addEllipse(d->rect);
9003     }
9004 
9005     return qt_graphicsItem_shapeFromPath(path, d->pen);
9006 }
9007 
9008 /*!
9009     \reimp
9010 */
contains(const QPointF & point) const9011 bool QGraphicsEllipseItem::contains(const QPointF &point) const
9012 {
9013     return QAbstractGraphicsShapeItem::contains(point);
9014 }
9015 
9016 /*!
9017     \reimp
9018 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)9019 void QGraphicsEllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
9020                                  QWidget *widget)
9021 {
9022     Q_D(QGraphicsEllipseItem);
9023     Q_UNUSED(widget);
9024     painter->setPen(d->pen);
9025     painter->setBrush(d->brush);
9026     if ((d->spanAngle != 0) && (qAbs(d->spanAngle) % (360 * 16) == 0))
9027         painter->drawEllipse(d->rect);
9028     else
9029         painter->drawPie(d->rect, d->startAngle, d->spanAngle);
9030 
9031     if (option->state & QStyle::State_Selected)
9032         qt_graphicsItem_highlightSelected(this, painter, option);
9033 }
9034 
9035 /*!
9036     \reimp
9037 */
isObscuredBy(const QGraphicsItem * item) const9038 bool QGraphicsEllipseItem::isObscuredBy(const QGraphicsItem *item) const
9039 {
9040     return QAbstractGraphicsShapeItem::isObscuredBy(item);
9041 }
9042 
9043 /*!
9044     \reimp
9045 */
opaqueArea() const9046 QPainterPath QGraphicsEllipseItem::opaqueArea() const
9047 {
9048     return QAbstractGraphicsShapeItem::opaqueArea();
9049 }
9050 
9051 /*!
9052     \reimp
9053 */
type() const9054 int QGraphicsEllipseItem::type() const
9055 {
9056     return Type;
9057 }
9058 
9059 
9060 /*!
9061     \internal
9062 */
supportsExtension(Extension extension) const9063 bool QGraphicsEllipseItem::supportsExtension(Extension extension) const
9064 {
9065     Q_UNUSED(extension);
9066     return false;
9067 }
9068 
9069 /*!
9070     \internal
9071 */
setExtension(Extension extension,const QVariant & variant)9072 void QGraphicsEllipseItem::setExtension(Extension extension, const QVariant &variant)
9073 {
9074     Q_UNUSED(extension);
9075     Q_UNUSED(variant);
9076 }
9077 
9078 /*!
9079     \internal
9080 */
extension(const QVariant & variant) const9081 QVariant QGraphicsEllipseItem::extension(const QVariant &variant) const
9082 {
9083     Q_UNUSED(variant);
9084     return QVariant();
9085 }
9086 
9087 /*!
9088     \class QGraphicsPolygonItem
9089     \brief The QGraphicsPolygonItem class provides a polygon item that you
9090     can add to a QGraphicsScene.
9091     \since 4.2
9092     \ingroup graphicsview-api
9093     \inmodule QtWidgets
9094 
9095     To set the item's polygon, pass a QPolygonF to
9096     QGraphicsPolygonItem's constructor, or call the setPolygon()
9097     function. The polygon() function returns the current polygon.
9098 
9099     \image graphicsview-polygonitem.png
9100 
9101     QGraphicsPolygonItem uses the polygon and the pen width to provide
9102     a reasonable implementation of boundingRect(), shape(), and
9103     contains(). The paint() function draws the polygon using the
9104     item's associated pen and brush, which you can set by calling the
9105     setPen() and setBrush() functions.
9106 
9107     \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9108     QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
9109     View Framework}
9110 */
9111 
9112 class QGraphicsPolygonItemPrivate : public QAbstractGraphicsShapeItemPrivate
9113 {
9114     Q_DECLARE_PUBLIC(QGraphicsPolygonItem)
9115 public:
QGraphicsPolygonItemPrivate()9116     inline QGraphicsPolygonItemPrivate()
9117         : fillRule(Qt::OddEvenFill)
9118     { }
9119 
9120     QPolygonF polygon;
9121     Qt::FillRule fillRule;
9122 };
9123 
9124 /*!
9125     Constructs a QGraphicsPolygonItem with \a polygon as the default
9126     polygon. \a parent is passed to QAbstractGraphicsShapeItem's constructor.
9127 
9128     \sa QGraphicsScene::addItem()
9129 */
QGraphicsPolygonItem(const QPolygonF & polygon,QGraphicsItem * parent)9130 QGraphicsPolygonItem::QGraphicsPolygonItem(const QPolygonF &polygon, QGraphicsItem *parent)
9131     : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent)
9132 {
9133     setPolygon(polygon);
9134 }
9135 
9136 /*!
9137     Constructs a QGraphicsPolygonItem. \a parent is passed to
9138     QAbstractGraphicsShapeItem's constructor.
9139 
9140     \sa QGraphicsScene::addItem()
9141 */
QGraphicsPolygonItem(QGraphicsItem * parent)9142 QGraphicsPolygonItem::QGraphicsPolygonItem(QGraphicsItem *parent)
9143     : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent)
9144 {
9145 }
9146 
9147 /*!
9148     Destroys the QGraphicsPolygonItem.
9149 */
~QGraphicsPolygonItem()9150 QGraphicsPolygonItem::~QGraphicsPolygonItem()
9151 {
9152 }
9153 
9154 /*!
9155     Returns the item's polygon, or an empty polygon if no polygon
9156     has been set.
9157 
9158     \sa setPolygon()
9159 */
polygon() const9160 QPolygonF QGraphicsPolygonItem::polygon() const
9161 {
9162     Q_D(const QGraphicsPolygonItem);
9163     return d->polygon;
9164 }
9165 
9166 /*!
9167     Sets the item's polygon to be the given \a polygon.
9168 
9169     \sa polygon()
9170 */
setPolygon(const QPolygonF & polygon)9171 void QGraphicsPolygonItem::setPolygon(const QPolygonF &polygon)
9172 {
9173     Q_D(QGraphicsPolygonItem);
9174     if (d->polygon == polygon)
9175         return;
9176     prepareGeometryChange();
9177     d->polygon = polygon;
9178     d->boundingRect = QRectF();
9179     update();
9180 }
9181 
9182 /*!
9183      Returns the fill rule of the polygon. The default fill rule is
9184      Qt::OddEvenFill.
9185 
9186      \sa setFillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
9187 */
fillRule() const9188 Qt::FillRule QGraphicsPolygonItem::fillRule() const
9189 {
9190      Q_D(const QGraphicsPolygonItem);
9191      return d->fillRule;
9192 }
9193 
9194 /*!
9195      Sets the fill rule of the polygon to \a rule. The default fill rule is
9196      Qt::OddEvenFill.
9197 
9198      \sa fillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
9199 */
setFillRule(Qt::FillRule rule)9200 void QGraphicsPolygonItem::setFillRule(Qt::FillRule rule)
9201 {
9202      Q_D(QGraphicsPolygonItem);
9203      if (rule != d->fillRule) {
9204          d->fillRule = rule;
9205          update();
9206      }
9207 }
9208 
9209 /*!
9210     \reimp
9211 */
boundingRect() const9212 QRectF QGraphicsPolygonItem::boundingRect() const
9213 {
9214     Q_D(const QGraphicsPolygonItem);
9215     if (d->boundingRect.isNull()) {
9216         qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
9217         if (pw == 0.0)
9218             d->boundingRect = d->polygon.boundingRect();
9219         else
9220             d->boundingRect = shape().controlPointRect();
9221     }
9222     return d->boundingRect;
9223 }
9224 
9225 /*!
9226     \reimp
9227 */
shape() const9228 QPainterPath QGraphicsPolygonItem::shape() const
9229 {
9230     Q_D(const QGraphicsPolygonItem);
9231     QPainterPath path;
9232     path.addPolygon(d->polygon);
9233     return qt_graphicsItem_shapeFromPath(path, d->pen);
9234 }
9235 
9236 /*!
9237     \reimp
9238 */
contains(const QPointF & point) const9239 bool QGraphicsPolygonItem::contains(const QPointF &point) const
9240 {
9241     return QAbstractGraphicsShapeItem::contains(point);
9242 }
9243 
9244 /*!
9245     \reimp
9246 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)9247 void QGraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
9248 {
9249     Q_D(QGraphicsPolygonItem);
9250     Q_UNUSED(widget);
9251     painter->setPen(d->pen);
9252     painter->setBrush(d->brush);
9253     painter->drawPolygon(d->polygon, d->fillRule);
9254 
9255     if (option->state & QStyle::State_Selected)
9256         qt_graphicsItem_highlightSelected(this, painter, option);
9257 }
9258 
9259 /*!
9260     \reimp
9261 */
isObscuredBy(const QGraphicsItem * item) const9262 bool QGraphicsPolygonItem::isObscuredBy(const QGraphicsItem *item) const
9263 {
9264     return QAbstractGraphicsShapeItem::isObscuredBy(item);
9265 }
9266 
9267 /*!
9268     \reimp
9269 */
opaqueArea() const9270 QPainterPath QGraphicsPolygonItem::opaqueArea() const
9271 {
9272     return QAbstractGraphicsShapeItem::opaqueArea();
9273 }
9274 
9275 /*!
9276     \reimp
9277 */
type() const9278 int QGraphicsPolygonItem::type() const
9279 {
9280     return Type;
9281 }
9282 
9283 /*!
9284     \internal
9285 */
supportsExtension(Extension extension) const9286 bool QGraphicsPolygonItem::supportsExtension(Extension extension) const
9287 {
9288     Q_UNUSED(extension);
9289     return false;
9290 }
9291 
9292 /*!
9293     \internal
9294 */
setExtension(Extension extension,const QVariant & variant)9295 void QGraphicsPolygonItem::setExtension(Extension extension, const QVariant &variant)
9296 {
9297     Q_UNUSED(extension);
9298     Q_UNUSED(variant);
9299 }
9300 
9301 /*!
9302     \internal
9303 */
extension(const QVariant & variant) const9304 QVariant QGraphicsPolygonItem::extension(const QVariant &variant) const
9305 {
9306     Q_UNUSED(variant);
9307     return QVariant();
9308 }
9309 
9310 /*!
9311     \class QGraphicsLineItem
9312     \brief The QGraphicsLineItem class provides a line item that you can add to a
9313     QGraphicsScene.
9314     \since 4.2
9315     \ingroup graphicsview-api
9316     \inmodule QtWidgets
9317 
9318     To set the item's line, pass a QLineF to QGraphicsLineItem's
9319     constructor, or call the setLine() function. The line() function
9320     returns the current line. By default the line is black with a
9321     width of 0, but you can change this by calling setPen().
9322 
9323     \image graphicsview-lineitem.png
9324 
9325     QGraphicsLineItem uses the line and the pen width to provide a reasonable
9326     implementation of boundingRect(), shape(), and contains(). The paint()
9327     function draws the line using the item's associated pen.
9328 
9329     \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9330     QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsPixmapItem,
9331     {Graphics View Framework}
9332 */
9333 
9334 class QGraphicsLineItemPrivate : public QGraphicsItemPrivate
9335 {
9336     Q_DECLARE_PUBLIC(QGraphicsLineItem)
9337 public:
9338     QLineF line;
9339     QPen pen;
9340 };
9341 
9342 /*!
9343     Constructs a QGraphicsLineItem, using \a line as the default line. \a
9344     parent is passed to QGraphicsItem's constructor.
9345 
9346     \sa QGraphicsScene::addItem()
9347 */
QGraphicsLineItem(const QLineF & line,QGraphicsItem * parent)9348 QGraphicsLineItem::QGraphicsLineItem(const QLineF &line, QGraphicsItem *parent)
9349     : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9350 {
9351     setLine(line);
9352 }
9353 
9354 /*!
9355     Constructs a QGraphicsLineItem, using the line between (\a x1, \a y1) and
9356     (\a x2, \a y2) as the default line.  \a parent is passed to
9357     QGraphicsItem's constructor.
9358 
9359     \sa QGraphicsScene::addItem()
9360 */
QGraphicsLineItem(qreal x1,qreal y1,qreal x2,qreal y2,QGraphicsItem * parent)9361 QGraphicsLineItem::QGraphicsLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent)
9362     : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9363 {
9364     setLine(x1, y1, x2, y2);
9365 }
9366 
9367 
9368 
9369 /*!
9370     Constructs a QGraphicsLineItem. \a parent is passed to QGraphicsItem's
9371     constructor.
9372 
9373     \sa QGraphicsScene::addItem()
9374 */
QGraphicsLineItem(QGraphicsItem * parent)9375 QGraphicsLineItem::QGraphicsLineItem(QGraphicsItem *parent)
9376     : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9377 {
9378 }
9379 
9380 /*!
9381     Destroys the QGraphicsLineItem.
9382 */
~QGraphicsLineItem()9383 QGraphicsLineItem::~QGraphicsLineItem()
9384 {
9385 }
9386 
9387 /*!
9388     Returns the item's pen, or a black solid 0-width pen if no pen has
9389     been set.
9390 
9391     \sa setPen()
9392 */
pen() const9393 QPen QGraphicsLineItem::pen() const
9394 {
9395     Q_D(const QGraphicsLineItem);
9396     return d->pen;
9397 }
9398 
9399 /*!
9400     Sets the item's pen to \a pen. If no pen is set, the line will be painted
9401     using a black solid 0-width pen.
9402 
9403     \sa pen()
9404 */
setPen(const QPen & pen)9405 void QGraphicsLineItem::setPen(const QPen &pen)
9406 {
9407     Q_D(QGraphicsLineItem);
9408     if (d->pen == pen)
9409         return;
9410     prepareGeometryChange();
9411     d->pen = pen;
9412     update();
9413 }
9414 
9415 /*!
9416     Returns the item's line, or a null line if no line has been set.
9417 
9418     \sa setLine()
9419 */
line() const9420 QLineF QGraphicsLineItem::line() const
9421 {
9422     Q_D(const QGraphicsLineItem);
9423     return d->line;
9424 }
9425 
9426 /*!
9427     Sets the item's line to be the given \a line.
9428 
9429     \sa line()
9430 */
setLine(const QLineF & line)9431 void QGraphicsLineItem::setLine(const QLineF &line)
9432 {
9433     Q_D(QGraphicsLineItem);
9434     if (d->line == line)
9435         return;
9436     prepareGeometryChange();
9437     d->line = line;
9438     update();
9439 }
9440 
9441 /*!
9442     \fn void QGraphicsLineItem::setLine(qreal x1, qreal y1, qreal x2, qreal y2)
9443     \overload
9444 
9445     Sets the item's line to be the line between (\a x1, \a y1) and (\a
9446     x2, \a y2).
9447 
9448     This is the same as calling \c {setLine(QLineF(x1, y1, x2, y2))}.
9449 */
9450 
9451 /*!
9452     \reimp
9453 */
boundingRect() const9454 QRectF QGraphicsLineItem::boundingRect() const
9455 {
9456     Q_D(const QGraphicsLineItem);
9457     if (d->pen.widthF() == 0.0) {
9458         const qreal x1 = d->line.p1().x();
9459         const qreal x2 = d->line.p2().x();
9460         const qreal y1 = d->line.p1().y();
9461         const qreal y2 = d->line.p2().y();
9462         qreal lx = qMin(x1, x2);
9463         qreal rx = qMax(x1, x2);
9464         qreal ty = qMin(y1, y2);
9465         qreal by = qMax(y1, y2);
9466         return QRectF(lx, ty, rx - lx, by - ty);
9467     }
9468     return shape().controlPointRect();
9469 }
9470 
9471 /*!
9472     \reimp
9473 */
shape() const9474 QPainterPath QGraphicsLineItem::shape() const
9475 {
9476     Q_D(const QGraphicsLineItem);
9477     QPainterPath path;
9478     if (d->line == QLineF())
9479         return path;
9480 
9481     path.moveTo(d->line.p1());
9482     path.lineTo(d->line.p2());
9483     return qt_graphicsItem_shapeFromPath(path, d->pen);
9484 }
9485 
9486 /*!
9487     \reimp
9488 */
contains(const QPointF & point) const9489 bool QGraphicsLineItem::contains(const QPointF &point) const
9490 {
9491     return QGraphicsItem::contains(point);
9492 }
9493 
9494 /*!
9495     \reimp
9496 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)9497 void QGraphicsLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
9498 {
9499     Q_D(QGraphicsLineItem);
9500     Q_UNUSED(widget);
9501     painter->setPen(d->pen);
9502     painter->drawLine(d->line);
9503 
9504     if (option->state & QStyle::State_Selected)
9505         qt_graphicsItem_highlightSelected(this, painter, option);
9506 }
9507 
9508 /*!
9509     \reimp
9510 */
isObscuredBy(const QGraphicsItem * item) const9511 bool QGraphicsLineItem::isObscuredBy(const QGraphicsItem *item) const
9512 {
9513     return QGraphicsItem::isObscuredBy(item);
9514 }
9515 
9516 /*!
9517     \reimp
9518 */
opaqueArea() const9519 QPainterPath QGraphicsLineItem::opaqueArea() const
9520 {
9521     return QGraphicsItem::opaqueArea();
9522 }
9523 
9524 /*!
9525     \reimp
9526 */
type() const9527 int QGraphicsLineItem::type() const
9528 {
9529     return Type;
9530 }
9531 
9532 /*!
9533     \internal
9534 */
supportsExtension(Extension extension) const9535 bool QGraphicsLineItem::supportsExtension(Extension extension) const
9536 {
9537     Q_UNUSED(extension);
9538     return false;
9539 }
9540 
9541 /*!
9542     \internal
9543 */
setExtension(Extension extension,const QVariant & variant)9544 void QGraphicsLineItem::setExtension(Extension extension, const QVariant &variant)
9545 {
9546     Q_UNUSED(extension);
9547     Q_UNUSED(variant);
9548 }
9549 
9550 /*!
9551     \internal
9552 */
extension(const QVariant & variant) const9553 QVariant QGraphicsLineItem::extension(const QVariant &variant) const
9554 {
9555     Q_UNUSED(variant);
9556     return QVariant();
9557 }
9558 
9559 /*!
9560     \class QGraphicsPixmapItem
9561     \brief The QGraphicsPixmapItem class provides a pixmap item that you can add to
9562     a QGraphicsScene.
9563     \since 4.2
9564     \ingroup graphicsview-api
9565     \inmodule QtWidgets
9566 
9567     To set the item's pixmap, pass a QPixmap to QGraphicsPixmapItem's
9568     constructor, or call the setPixmap() function. The pixmap()
9569     function returns the current pixmap.
9570 
9571     QGraphicsPixmapItem uses pixmap's optional alpha mask to provide a
9572     reasonable implementation of boundingRect(), shape(), and contains().
9573 
9574     \image graphicsview-pixmapitem.png
9575 
9576     The pixmap is drawn at the item's (0, 0) coordinate, as returned by
9577     offset(). You can change the drawing offset by calling setOffset().
9578 
9579     You can set the pixmap's transformation mode by calling
9580     setTransformationMode(). By default, Qt::FastTransformation is used, which
9581     provides fast, non-smooth scaling. Qt::SmoothTransformation enables
9582     QPainter::SmoothPixmapTransform on the painter, and the quality depends on
9583     the platform and viewport. The result is usually not as good as calling
9584     QPixmap::scale() directly. Call transformationMode() to get the current
9585     transformation mode for the item.
9586 
9587     \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9588     QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsLineItem,
9589     {Graphics View Framework}
9590 */
9591 
9592 /*!
9593     \enum QGraphicsPixmapItem::ShapeMode
9594 
9595     This enum describes how QGraphicsPixmapItem calculates its shape and
9596     opaque area.
9597 
9598     The default value is MaskShape.
9599 
9600     \value MaskShape The shape is determined by calling QPixmap::mask().
9601     This shape includes only the opaque pixels of the pixmap.
9602     Because the shape is more complex, however, it can be slower than the other modes,
9603     and uses more memory.
9604 
9605     \value BoundingRectShape The shape is determined by tracing the outline of
9606     the pixmap. This is the fastest shape mode, but it does not take into account
9607     any transparent areas on the pixmap.
9608 
9609     \value HeuristicMaskShape The shape is determine by calling
9610     QPixmap::createHeuristicMask().  The performance and memory consumption
9611     is similar to MaskShape.
9612 */
9613 extern QPainterPath qt_regionToPath(const QRegion &region);
9614 
9615 class QGraphicsPixmapItemPrivate : public QGraphicsItemPrivate
9616 {
9617     Q_DECLARE_PUBLIC(QGraphicsPixmapItem)
9618 public:
QGraphicsPixmapItemPrivate()9619     QGraphicsPixmapItemPrivate()
9620         : transformationMode(Qt::FastTransformation),
9621         shapeMode(QGraphicsPixmapItem::MaskShape),
9622         hasShape(false)
9623     {}
9624 
9625     QPixmap pixmap;
9626     Qt::TransformationMode transformationMode;
9627     QPointF offset;
9628     QGraphicsPixmapItem::ShapeMode shapeMode;
9629     QPainterPath shape;
9630     bool hasShape;
9631 
updateShape()9632     void updateShape()
9633     {
9634         shape = QPainterPath();
9635         switch (shapeMode) {
9636         case QGraphicsPixmapItem::MaskShape: {
9637             QBitmap mask = pixmap.mask();
9638             if (!mask.isNull()) {
9639                 shape = qt_regionToPath(QRegion(mask).translated(offset.toPoint()));
9640                 break;
9641             }
9642             Q_FALLTHROUGH();
9643         }
9644         case QGraphicsPixmapItem::BoundingRectShape:
9645             shape.addRect(QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
9646             break;
9647         case QGraphicsPixmapItem::HeuristicMaskShape:
9648 #ifndef QT_NO_IMAGE_HEURISTIC_MASK
9649             shape = qt_regionToPath(QRegion(pixmap.createHeuristicMask()).translated(offset.toPoint()));
9650 #else
9651             shape.addRect(QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
9652 #endif
9653             break;
9654         }
9655     }
9656 };
9657 
9658 /*!
9659     Constructs a QGraphicsPixmapItem, using \a pixmap as the default pixmap.
9660     \a parent is passed to QGraphicsItem's constructor.
9661 
9662     \sa QGraphicsScene::addItem()
9663 */
QGraphicsPixmapItem(const QPixmap & pixmap,QGraphicsItem * parent)9664 QGraphicsPixmapItem::QGraphicsPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent)
9665     : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent)
9666 {
9667     setPixmap(pixmap);
9668 }
9669 
9670 /*!
9671     Constructs a QGraphicsPixmapItem. \a parent is passed to QGraphicsItem's
9672     constructor.
9673 
9674     \sa QGraphicsScene::addItem()
9675 */
QGraphicsPixmapItem(QGraphicsItem * parent)9676 QGraphicsPixmapItem::QGraphicsPixmapItem(QGraphicsItem *parent)
9677     : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent)
9678 {
9679 }
9680 
9681 /*!
9682     Destroys the QGraphicsPixmapItem.
9683 */
~QGraphicsPixmapItem()9684 QGraphicsPixmapItem::~QGraphicsPixmapItem()
9685 {
9686 }
9687 
9688 /*!
9689     Sets the item's pixmap to \a pixmap.
9690 
9691     \sa pixmap()
9692 */
setPixmap(const QPixmap & pixmap)9693 void QGraphicsPixmapItem::setPixmap(const QPixmap &pixmap)
9694 {
9695     Q_D(QGraphicsPixmapItem);
9696     prepareGeometryChange();
9697     d->pixmap = pixmap;
9698     d->hasShape = false;
9699     update();
9700 }
9701 
9702 /*!
9703     Returns the item's pixmap, or an invalid QPixmap if no pixmap has been
9704     set.
9705 
9706     \sa setPixmap()
9707 */
pixmap() const9708 QPixmap QGraphicsPixmapItem::pixmap() const
9709 {
9710     Q_D(const QGraphicsPixmapItem);
9711     return d->pixmap;
9712 }
9713 
9714 /*!
9715     Returns the transformation mode of the pixmap. The default mode is
9716     Qt::FastTransformation, which provides quick transformation with no
9717     smoothing.
9718 
9719     \sa setTransformationMode()
9720 */
transformationMode() const9721 Qt::TransformationMode QGraphicsPixmapItem::transformationMode() const
9722 {
9723     Q_D(const QGraphicsPixmapItem);
9724     return d->transformationMode;
9725 }
9726 
9727 /*!
9728     Sets the pixmap item's transformation mode to \a mode, and toggles an
9729     update of the item. The default mode is Qt::FastTransformation, which
9730     provides quick transformation with no smoothing.
9731 
9732     Qt::SmoothTransformation enables QPainter::SmoothPixmapTransform on the
9733     painter, and the quality depends on the platform and viewport. The result
9734     is usually not as good as calling QPixmap::scale() directly.
9735 
9736     \sa transformationMode()
9737 */
setTransformationMode(Qt::TransformationMode mode)9738 void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode)
9739 {
9740     Q_D(QGraphicsPixmapItem);
9741     if (mode != d->transformationMode) {
9742         d->transformationMode = mode;
9743         update();
9744     }
9745 }
9746 
9747 /*!
9748     Returns the pixmap item's \e offset, which defines the point of the
9749     top-left corner of the pixmap, in local coordinates.
9750 
9751     \sa setOffset()
9752 */
offset() const9753 QPointF QGraphicsPixmapItem::offset() const
9754 {
9755     Q_D(const QGraphicsPixmapItem);
9756     return d->offset;
9757 }
9758 
9759 /*!
9760     Sets the pixmap item's offset to \a offset. QGraphicsPixmapItem will draw
9761     its pixmap using \a offset for its top-left corner.
9762 
9763     \sa offset()
9764 */
setOffset(const QPointF & offset)9765 void QGraphicsPixmapItem::setOffset(const QPointF &offset)
9766 {
9767     Q_D(QGraphicsPixmapItem);
9768     if (d->offset == offset)
9769         return;
9770     prepareGeometryChange();
9771     d->offset = offset;
9772     d->hasShape = false;
9773     update();
9774 }
9775 
9776 /*!
9777     \fn void QGraphicsPixmapItem::setOffset(qreal x, qreal y)
9778     \since 4.3
9779 
9780     This convenience function is equivalent to calling setOffset(QPointF(\a x, \a y)).
9781 */
9782 
9783 /*!
9784     \reimp
9785 */
boundingRect() const9786 QRectF QGraphicsPixmapItem::boundingRect() const
9787 {
9788     Q_D(const QGraphicsPixmapItem);
9789     if (d->pixmap.isNull())
9790         return QRectF();
9791     if (d->flags & ItemIsSelectable) {
9792         qreal pw = 1.0;
9793         return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio()).adjusted(-pw/2, -pw/2, pw/2, pw/2);
9794     } else {
9795         return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio());
9796     }
9797 }
9798 
9799 /*!
9800     \reimp
9801 */
shape() const9802 QPainterPath QGraphicsPixmapItem::shape() const
9803 {
9804     Q_D(const QGraphicsPixmapItem);
9805     if (!d->hasShape) {
9806         QGraphicsPixmapItemPrivate *thatD = const_cast<QGraphicsPixmapItemPrivate *>(d);
9807         thatD->updateShape();
9808         thatD->hasShape = true;
9809     }
9810     return d_func()->shape;
9811 }
9812 
9813 /*!
9814     \reimp
9815 */
contains(const QPointF & point) const9816 bool QGraphicsPixmapItem::contains(const QPointF &point) const
9817 {
9818     return QGraphicsItem::contains(point);
9819 }
9820 
9821 /*!
9822     \reimp
9823 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)9824 void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
9825                                 QWidget *widget)
9826 {
9827     Q_D(QGraphicsPixmapItem);
9828     Q_UNUSED(widget);
9829 
9830     painter->setRenderHint(QPainter::SmoothPixmapTransform,
9831                            (d->transformationMode == Qt::SmoothTransformation));
9832 
9833     painter->drawPixmap(d->offset, d->pixmap);
9834 
9835     if (option->state & QStyle::State_Selected)
9836         qt_graphicsItem_highlightSelected(this, painter, option);
9837 }
9838 
9839 /*!
9840     \reimp
9841 */
isObscuredBy(const QGraphicsItem * item) const9842 bool QGraphicsPixmapItem::isObscuredBy(const QGraphicsItem *item) const
9843 {
9844     return QGraphicsItem::isObscuredBy(item);
9845 }
9846 
9847 /*!
9848     \reimp
9849 */
opaqueArea() const9850 QPainterPath QGraphicsPixmapItem::opaqueArea() const
9851 {
9852     return shape();
9853 }
9854 
9855 /*!
9856     \reimp
9857 */
type() const9858 int QGraphicsPixmapItem::type() const
9859 {
9860     return Type;
9861 }
9862 
9863 /*!
9864     Returns the item's shape mode. The shape mode describes how
9865     QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
9866 
9867     \sa setShapeMode(), ShapeMode
9868 */
shapeMode() const9869 QGraphicsPixmapItem::ShapeMode QGraphicsPixmapItem::shapeMode() const
9870 {
9871     return d_func()->shapeMode;
9872 }
9873 
9874 /*!
9875     Sets the item's shape mode to \a mode. The shape mode describes how
9876     QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
9877 
9878     \sa shapeMode(), ShapeMode
9879 */
setShapeMode(ShapeMode mode)9880 void QGraphicsPixmapItem::setShapeMode(ShapeMode mode)
9881 {
9882     Q_D(QGraphicsPixmapItem);
9883     if (d->shapeMode == mode)
9884         return;
9885     d->shapeMode = mode;
9886     d->hasShape = false;
9887 }
9888 
9889 /*!
9890     \internal
9891 */
supportsExtension(Extension extension) const9892 bool QGraphicsPixmapItem::supportsExtension(Extension extension) const
9893 {
9894     Q_UNUSED(extension);
9895     return false;
9896 }
9897 
9898 /*!
9899     \internal
9900 */
setExtension(Extension extension,const QVariant & variant)9901 void QGraphicsPixmapItem::setExtension(Extension extension, const QVariant &variant)
9902 {
9903     Q_UNUSED(extension);
9904     Q_UNUSED(variant);
9905 }
9906 
9907 /*!
9908     \internal
9909 */
extension(const QVariant & variant) const9910 QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const
9911 {
9912     Q_UNUSED(variant);
9913     return QVariant();
9914 }
9915 
9916 /*!
9917     \class QGraphicsTextItem
9918     \brief The QGraphicsTextItem class provides a text item that you can add to
9919     a QGraphicsScene to display formatted text.
9920     \since 4.2
9921     \ingroup graphicsview-api
9922     \inmodule QtWidgets
9923 
9924     If you only need to show plain text in an item, consider using QGraphicsSimpleTextItem
9925     instead.
9926 
9927     To set the item's text, pass a QString to QGraphicsTextItem's
9928     constructor, or call setHtml()/setPlainText().
9929 
9930     QGraphicsTextItem uses the text's formatted size and the associated font
9931     to provide a reasonable implementation of boundingRect(), shape(),
9932     and contains(). You can set the font by calling setFont().
9933 
9934     It is possible to make the item editable by setting the Qt::TextEditorInteraction flag
9935     using setTextInteractionFlags().
9936 
9937     The item's preferred text width can be set using setTextWidth() and obtained
9938     using textWidth().
9939 
9940     \note In order to align HTML text in the center, the item's text width must be set.
9941     Otherwise, you can call adjustSize() after setting the item's text.
9942 
9943     \image graphicsview-textitem.png
9944 
9945     \note QGraphicsTextItem accepts \l{QGraphicsItem::acceptHoverEvents()}{hover events}
9946           by default. You can change this with \l{QGraphicsItem::}{setAcceptHoverEvents()}.
9947 
9948     \sa QGraphicsSimpleTextItem, QGraphicsPathItem, QGraphicsRectItem,
9949         QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
9950         QGraphicsLineItem, {Graphics View Framework}
9951 */
9952 
9953 class QGraphicsTextItemPrivate
9954 {
9955 public:
QGraphicsTextItemPrivate()9956     QGraphicsTextItemPrivate()
9957         : control(nullptr), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0)
9958     { }
9959 
9960     mutable QWidgetTextControl *control;
9961     QWidgetTextControl *textControl() const;
9962 
controlOffset() const9963     inline QPointF controlOffset() const
9964     { return QPointF(0., pageNumber * control->document()->pageSize().height()); }
sendControlEvent(QEvent * e)9965     inline void sendControlEvent(QEvent *e)
9966     { if (control) control->processEvent(e, controlOffset()); }
9967 
9968     void _q_updateBoundingRect(const QSizeF &);
9969     void _q_update(QRectF);
9970     void _q_ensureVisible(QRectF);
9971     bool _q_mouseOnEdge(QGraphicsSceneMouseEvent *);
9972 
9973     QRectF boundingRect;
9974     int pageNumber;
9975     bool useDefaultImpl;
9976     bool tabChangesFocus;
9977 
9978     uint clickCausedFocus : 1;
9979 
9980     QGraphicsTextItem *qq;
9981 };
9982 
9983 
9984 /*!
9985     Constructs a QGraphicsTextItem, using \a text as the default plain
9986     text. \a parent is passed to QGraphicsItem's constructor.
9987 
9988     \sa QGraphicsScene::addItem()
9989 */
QGraphicsTextItem(const QString & text,QGraphicsItem * parent)9990 QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent)
9991     : QGraphicsObject(*new QGraphicsItemPrivate, parent),
9992       dd(new QGraphicsTextItemPrivate)
9993 {
9994     dd->qq = this;
9995     if (!text.isEmpty())
9996         setPlainText(text);
9997     setAcceptDrops(true);
9998     setAcceptHoverEvents(true);
9999     setFlags(ItemUsesExtendedStyleOption);
10000 }
10001 
10002 /*!
10003     Constructs a QGraphicsTextItem. \a parent is passed to QGraphicsItem's
10004     constructor.
10005 
10006     \sa QGraphicsScene::addItem()
10007 */
QGraphicsTextItem(QGraphicsItem * parent)10008 QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent)
10009     : QGraphicsObject(*new QGraphicsItemPrivate, parent),
10010       dd(new QGraphicsTextItemPrivate)
10011 {
10012     dd->qq = this;
10013     setAcceptDrops(true);
10014     setAcceptHoverEvents(true);
10015     setFlag(ItemUsesExtendedStyleOption);
10016 }
10017 
10018 /*!
10019     Destroys the QGraphicsTextItem.
10020 */
~QGraphicsTextItem()10021 QGraphicsTextItem::~QGraphicsTextItem()
10022 {
10023     delete dd;
10024 }
10025 
10026 /*!
10027     Returns the item's text converted to HTML, or an empty QString if no text has been set.
10028 
10029     \sa setHtml()
10030 */
toHtml() const10031 QString QGraphicsTextItem::toHtml() const
10032 {
10033 #ifndef QT_NO_TEXTHTMLPARSER
10034     if (dd->control)
10035         return dd->control->toHtml();
10036 #endif
10037     return QString();
10038 }
10039 
10040 /*!
10041     Sets the item's text to \a text, assuming that text is HTML formatted. If
10042     the item has keyboard input focus, this function will also call
10043     ensureVisible() to ensure that the text is visible in all viewports.
10044 
10045     \sa toHtml(), hasFocus(), QGraphicsSimpleTextItem
10046 */
setHtml(const QString & text)10047 void QGraphicsTextItem::setHtml(const QString &text)
10048 {
10049     dd->textControl()->setHtml(text);
10050 }
10051 
10052 /*!
10053     Returns the item's text converted to plain text, or an empty QString if no text has been set.
10054 
10055     \sa setPlainText()
10056 */
toPlainText() const10057 QString QGraphicsTextItem::toPlainText() const
10058 {
10059     if (dd->control)
10060         return dd->control->toPlainText();
10061     return QString();
10062 }
10063 
10064 /*!
10065     Sets the item's text to \a text. If the item has keyboard input focus,
10066     this function will also call ensureVisible() to ensure that the text is
10067     visible in all viewports.
10068 
10069     \sa toHtml(), hasFocus()
10070 */
setPlainText(const QString & text)10071 void QGraphicsTextItem::setPlainText(const QString &text)
10072 {
10073     dd->textControl()->setPlainText(text);
10074 }
10075 
10076 /*!
10077     Returns the item's font, which is used to render the text.
10078 
10079     \sa setFont()
10080 */
font() const10081 QFont QGraphicsTextItem::font() const
10082 {
10083     if (!dd->control)
10084         return QFont();
10085     return dd->control->document()->defaultFont();
10086 }
10087 
10088 /*!
10089     Sets the font used to render the text item to \a font.
10090 
10091     \sa font()
10092 */
setFont(const QFont & font)10093 void QGraphicsTextItem::setFont(const QFont &font)
10094 {
10095     dd->textControl()->document()->setDefaultFont(font);
10096 }
10097 
10098 /*!
10099     Sets the color for unformatted text to \a col.
10100 */
setDefaultTextColor(const QColor & col)10101 void QGraphicsTextItem::setDefaultTextColor(const QColor &col)
10102 {
10103     QWidgetTextControl *c = dd->textControl();
10104     QPalette pal = c->palette();
10105     QColor old = pal.color(QPalette::Text);
10106     pal.setColor(QPalette::Text, col);
10107     c->setPalette(pal);
10108     if (old != col)
10109         update();
10110 }
10111 
10112 /*!
10113     Returns the default text color that is used for unformatted text.
10114 */
defaultTextColor() const10115 QColor QGraphicsTextItem::defaultTextColor() const
10116 {
10117     return dd->textControl()->palette().color(QPalette::Text);
10118 }
10119 
10120 /*!
10121     \reimp
10122 */
boundingRect() const10123 QRectF QGraphicsTextItem::boundingRect() const
10124 {
10125     return dd->boundingRect;
10126 }
10127 
10128 /*!
10129     \reimp
10130 */
shape() const10131 QPainterPath QGraphicsTextItem::shape() const
10132 {
10133     if (!dd->control)
10134         return QPainterPath();
10135     QPainterPath path;
10136     path.addRect(dd->boundingRect);
10137     return path;
10138 }
10139 
10140 /*!
10141     \reimp
10142 */
contains(const QPointF & point) const10143 bool QGraphicsTextItem::contains(const QPointF &point) const
10144 {
10145     return dd->boundingRect.contains(point);
10146 }
10147 
10148 /*!
10149     \reimp
10150 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)10151 void QGraphicsTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
10152                               QWidget *widget)
10153 {
10154     Q_UNUSED(widget);
10155     if (dd->control) {
10156         painter->save();
10157         QRectF r = option->exposedRect;
10158         painter->translate(-dd->controlOffset());
10159         r.translate(dd->controlOffset());
10160 
10161         QTextDocument *doc = dd->control->document();
10162         QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(doc->documentLayout());
10163 
10164         // the layout might need to expand the root frame to
10165         // the viewport if NoWrap is set
10166         if (layout)
10167             layout->setViewport(dd->boundingRect);
10168 
10169         dd->control->drawContents(painter, r);
10170 
10171         if (layout)
10172             layout->setViewport(QRect());
10173 
10174         painter->restore();
10175     }
10176 
10177     if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
10178         qt_graphicsItem_highlightSelected(this, painter, option);
10179 }
10180 
10181 /*!
10182     \reimp
10183 */
isObscuredBy(const QGraphicsItem * item) const10184 bool QGraphicsTextItem::isObscuredBy(const QGraphicsItem *item) const
10185 {
10186     return QGraphicsItem::isObscuredBy(item);
10187 }
10188 
10189 /*!
10190     \reimp
10191 */
opaqueArea() const10192 QPainterPath QGraphicsTextItem::opaqueArea() const
10193 {
10194     return QGraphicsItem::opaqueArea();
10195 }
10196 
10197 /*!
10198     \reimp
10199 */
type() const10200 int QGraphicsTextItem::type() const
10201 {
10202     return Type;
10203 }
10204 
10205 /*!
10206     Sets the preferred width for the item's text. If the actual text
10207     is wider than the specified width then it will be broken into
10208     multiple lines.
10209 
10210     If \a width is set to -1 then the text will not be broken into
10211     multiple lines unless it is enforced through an explicit line
10212     break or a new paragraph.
10213 
10214     The default value is -1.
10215 
10216     Note that QGraphicsTextItem keeps a QTextDocument internally,
10217     which is used to calculate the text width.
10218 
10219     \sa textWidth(), QTextDocument::setTextWidth()
10220 */
setTextWidth(qreal width)10221 void QGraphicsTextItem::setTextWidth(qreal width)
10222 {
10223     dd->textControl()->setTextWidth(width);
10224 }
10225 
10226 /*!
10227     Returns the text width.
10228 
10229     The width is calculated with the QTextDocument that
10230     QGraphicsTextItem keeps internally.
10231 
10232     \sa setTextWidth(), QTextDocument::textWidth()
10233 */
textWidth() const10234 qreal QGraphicsTextItem::textWidth() const
10235 {
10236     if (!dd->control)
10237         return -1;
10238     return dd->control->textWidth();
10239 }
10240 
10241 /*!
10242     Adjusts the text item to a reasonable size.
10243 */
adjustSize()10244 void QGraphicsTextItem::adjustSize()
10245 {
10246     if (dd->control)
10247         dd->control->adjustSize();
10248 }
10249 
10250 /*!
10251     Sets the text document \a document on the item.
10252 */
setDocument(QTextDocument * document)10253 void QGraphicsTextItem::setDocument(QTextDocument *document)
10254 {
10255     dd->textControl()->setDocument(document);
10256     dd->_q_updateBoundingRect(dd->control->size());
10257 }
10258 
10259 /*!
10260     Returns the item's text document.
10261 */
document() const10262 QTextDocument *QGraphicsTextItem::document() const
10263 {
10264     return dd->textControl()->document();
10265 }
10266 
10267 /*!
10268     \reimp
10269 */
sceneEvent(QEvent * event)10270 bool QGraphicsTextItem::sceneEvent(QEvent *event)
10271 {
10272     QEvent::Type t = event->type();
10273     if (!dd->tabChangesFocus && (t == QEvent::KeyPress || t == QEvent::KeyRelease)) {
10274         int k = ((QKeyEvent *)event)->key();
10275         if (k == Qt::Key_Tab || k == Qt::Key_Backtab) {
10276             dd->sendControlEvent(event);
10277             return true;
10278         }
10279     }
10280     bool result = QGraphicsItem::sceneEvent(event);
10281 
10282     // Ensure input context is updated.
10283     switch (event->type()) {
10284     case QEvent::ContextMenu:
10285     case QEvent::FocusIn:
10286     case QEvent::FocusOut:
10287     case QEvent::GraphicsSceneDragEnter:
10288     case QEvent::GraphicsSceneDragLeave:
10289     case QEvent::GraphicsSceneDragMove:
10290     case QEvent::GraphicsSceneDrop:
10291     case QEvent::GraphicsSceneHoverEnter:
10292     case QEvent::GraphicsSceneHoverLeave:
10293     case QEvent::GraphicsSceneHoverMove:
10294     case QEvent::GraphicsSceneMouseDoubleClick:
10295     case QEvent::GraphicsSceneMousePress:
10296     case QEvent::GraphicsSceneMouseMove:
10297     case QEvent::GraphicsSceneMouseRelease:
10298     case QEvent::KeyPress:
10299     case QEvent::KeyRelease:
10300         // Reset the focus widget's input context, regardless
10301         // of how this item gained or lost focus.
10302         if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
10303             QGuiApplication::inputMethod()->reset();
10304         } else {
10305             QGuiApplication::inputMethod()->update(Qt::ImQueryInput);
10306         }
10307         break;
10308     case QEvent::ShortcutOverride:
10309         dd->sendControlEvent(event);
10310         return true;
10311     default:
10312         break;
10313     }
10314 
10315     return result;
10316 }
10317 
10318 /*!
10319     \reimp
10320 */
mousePressEvent(QGraphicsSceneMouseEvent * event)10321 void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
10322 {
10323     if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable))
10324         && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
10325         // User left-pressed on edge of selectable/movable item, use
10326         // base impl.
10327         dd->useDefaultImpl = true;
10328     } else if (event->buttons() == event->button()
10329                && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
10330         // User pressed first button on non-interactive item.
10331         dd->useDefaultImpl = true;
10332     }
10333     if (dd->useDefaultImpl) {
10334         QGraphicsItem::mousePressEvent(event);
10335         if (!event->isAccepted())
10336             dd->useDefaultImpl = false;
10337         return;
10338     }
10339 
10340     dd->sendControlEvent(event);
10341 }
10342 
10343 /*!
10344     \reimp
10345 */
mouseMoveEvent(QGraphicsSceneMouseEvent * event)10346 void QGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
10347 {
10348     if (dd->useDefaultImpl) {
10349         QGraphicsItem::mouseMoveEvent(event);
10350         return;
10351     }
10352 
10353     dd->sendControlEvent(event);
10354 }
10355 
10356 /*!
10357     \reimp
10358 */
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)10359 void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
10360 {
10361     if (dd->useDefaultImpl) {
10362         QGraphicsItem::mouseReleaseEvent(event);
10363         if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
10364             && !event->buttons()) {
10365             // User released last button on non-interactive item.
10366             dd->useDefaultImpl = false;
10367         } else  if ((event->buttons() & Qt::LeftButton) == 0) {
10368             // User released the left button on an interactive item.
10369             dd->useDefaultImpl = false;
10370         }
10371         return;
10372     }
10373 
10374     QWidget *widget = event->widget();
10375     if (widget && (dd->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) {
10376         qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), dd->clickCausedFocus);
10377     }
10378     dd->clickCausedFocus = 0;
10379     dd->sendControlEvent(event);
10380 }
10381 
10382 /*!
10383     \reimp
10384 */
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)10385 void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
10386 {
10387     if (dd->useDefaultImpl) {
10388         QGraphicsItem::mouseDoubleClickEvent(event);
10389         return;
10390     }
10391 
10392     if (!hasFocus()) {
10393         QGraphicsItem::mouseDoubleClickEvent(event);
10394         return;
10395     }
10396 
10397     dd->sendControlEvent(event);
10398 }
10399 
10400 /*!
10401     \reimp
10402 */
contextMenuEvent(QGraphicsSceneContextMenuEvent * event)10403 void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
10404 {
10405     dd->sendControlEvent(event);
10406 }
10407 
10408 /*!
10409     \reimp
10410 */
keyPressEvent(QKeyEvent * event)10411 void QGraphicsTextItem::keyPressEvent(QKeyEvent *event)
10412 {
10413     dd->sendControlEvent(event);
10414 }
10415 
10416 /*!
10417     \reimp
10418 */
keyReleaseEvent(QKeyEvent * event)10419 void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event)
10420 {
10421     dd->sendControlEvent(event);
10422 }
10423 
10424 /*!
10425     \reimp
10426 */
focusInEvent(QFocusEvent * event)10427 void QGraphicsTextItem::focusInEvent(QFocusEvent *event)
10428 {
10429     dd->sendControlEvent(event);
10430     if (event->reason() == Qt::MouseFocusReason) {
10431         dd->clickCausedFocus = 1;
10432     }
10433     update();
10434 }
10435 
10436 /*!
10437     \reimp
10438 */
focusOutEvent(QFocusEvent * event)10439 void QGraphicsTextItem::focusOutEvent(QFocusEvent *event)
10440 {
10441     dd->sendControlEvent(event);
10442     update();
10443 }
10444 
10445 /*!
10446     \reimp
10447 */
dragEnterEvent(QGraphicsSceneDragDropEvent * event)10448 void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
10449 {
10450     dd->sendControlEvent(event);
10451 }
10452 
10453 /*!
10454     \reimp
10455 */
dragLeaveEvent(QGraphicsSceneDragDropEvent * event)10456 void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
10457 {
10458     dd->sendControlEvent(event);
10459 }
10460 
10461 /*!
10462     \reimp
10463 */
dragMoveEvent(QGraphicsSceneDragDropEvent * event)10464 void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
10465 {
10466     dd->sendControlEvent(event);
10467 }
10468 
10469 /*!
10470     \reimp
10471 */
dropEvent(QGraphicsSceneDragDropEvent * event)10472 void QGraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event)
10473 {
10474     dd->sendControlEvent(event);
10475 }
10476 
10477 /*!
10478     \reimp
10479 */
inputMethodEvent(QInputMethodEvent * event)10480 void QGraphicsTextItem::inputMethodEvent(QInputMethodEvent *event)
10481 {
10482     dd->sendControlEvent(event);
10483 }
10484 
10485 /*!
10486     \reimp
10487 */
hoverEnterEvent(QGraphicsSceneHoverEvent * event)10488 void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
10489 {
10490     dd->sendControlEvent(event);
10491 }
10492 
10493 /*!
10494     \reimp
10495 */
hoverMoveEvent(QGraphicsSceneHoverEvent * event)10496 void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
10497 {
10498     dd->sendControlEvent(event);
10499 }
10500 
10501 /*!
10502     \reimp
10503 */
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)10504 void QGraphicsTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
10505 {
10506     dd->sendControlEvent(event);
10507 }
10508 
10509 /*!
10510     \reimp
10511 */
inputMethodQuery(Qt::InputMethodQuery query) const10512 QVariant QGraphicsTextItem::inputMethodQuery(Qt::InputMethodQuery query) const
10513 {
10514     QVariant v;
10515     if (query == Qt::ImHints)
10516         v = int(inputMethodHints());
10517     else if (dd->control)
10518         v = dd->control->inputMethodQuery(query, QVariant());
10519     if (v.userType() == QMetaType::QRectF)
10520         v = v.toRectF().translated(-dd->controlOffset());
10521     else if (v.userType() == QMetaType::QPointF)
10522         v = v.toPointF() - dd->controlOffset();
10523     else if (v.userType() == QMetaType::QRect)
10524         v = v.toRect().translated(-dd->controlOffset().toPoint());
10525     else if (v.userType() == QMetaType::QPoint)
10526         v = v.toPoint() - dd->controlOffset().toPoint();
10527     return v;
10528 }
10529 
10530 /*!
10531     \internal
10532 */
supportsExtension(Extension extension) const10533 bool QGraphicsTextItem::supportsExtension(Extension extension) const
10534 {
10535     Q_UNUSED(extension);
10536     return false;
10537 }
10538 
10539 /*!
10540     \internal
10541 */
setExtension(Extension extension,const QVariant & variant)10542 void QGraphicsTextItem::setExtension(Extension extension, const QVariant &variant)
10543 {
10544     Q_UNUSED(extension);
10545     Q_UNUSED(variant);
10546 }
10547 
10548 /*!
10549     \internal
10550 */
extension(const QVariant & variant) const10551 QVariant QGraphicsTextItem::extension(const QVariant &variant) const
10552 {
10553     Q_UNUSED(variant);
10554     return QVariant();
10555 }
10556 
10557 /*!
10558     \internal
10559 */
_q_update(QRectF rect)10560 void QGraphicsTextItemPrivate::_q_update(QRectF rect)
10561 {
10562     if (rect.isValid()) {
10563         rect.translate(-controlOffset());
10564     } else {
10565         rect = boundingRect;
10566     }
10567     if (rect.intersects(boundingRect))
10568         qq->update(rect);
10569 }
10570 
10571 /*!
10572     \internal
10573 */
_q_updateBoundingRect(const QSizeF & size)10574 void QGraphicsTextItemPrivate::_q_updateBoundingRect(const QSizeF &size)
10575 {
10576     if (size != boundingRect.size()) {
10577         qq->prepareGeometryChange();
10578         boundingRect.setSize(size);
10579         qq->update();
10580     }
10581 }
10582 
10583 /*!
10584     \internal
10585 */
_q_ensureVisible(QRectF rect)10586 void QGraphicsTextItemPrivate::_q_ensureVisible(QRectF rect)
10587 {
10588     if (qq->hasFocus()) {
10589         rect.translate(-controlOffset());
10590         qq->ensureVisible(rect, /*xmargin=*/0, /*ymargin=*/0);
10591     }
10592 }
10593 
textControl() const10594 QWidgetTextControl *QGraphicsTextItemPrivate::textControl() const
10595 {
10596     if (!control) {
10597         QGraphicsTextItem *that = const_cast<QGraphicsTextItem *>(qq);
10598         control = new QWidgetTextControl(that);
10599         control->setTextInteractionFlags(Qt::NoTextInteraction);
10600 
10601         QObject::connect(control, SIGNAL(updateRequest(QRectF)),
10602                          qq, SLOT(_q_update(QRectF)));
10603         QObject::connect(control, SIGNAL(documentSizeChanged(QSizeF)),
10604                          qq, SLOT(_q_updateBoundingRect(QSizeF)));
10605         QObject::connect(control, SIGNAL(visibilityRequest(QRectF)),
10606                          qq, SLOT(_q_ensureVisible(QRectF)));
10607         QObject::connect(control, SIGNAL(linkActivated(QString)),
10608                          qq, SIGNAL(linkActivated(QString)));
10609         QObject::connect(control, SIGNAL(linkHovered(QString)),
10610                          qq, SIGNAL(linkHovered(QString)));
10611 
10612         const QSizeF pgSize = control->document()->pageSize();
10613         if (pgSize.height() != -1) {
10614             qq->prepareGeometryChange();
10615             that->dd->boundingRect.setSize(pgSize);
10616             qq->update();
10617         } else {
10618             that->dd->_q_updateBoundingRect(control->size());
10619         }
10620     }
10621     return control;
10622 }
10623 
10624 /*!
10625     \internal
10626 */
_q_mouseOnEdge(QGraphicsSceneMouseEvent * event)10627 bool QGraphicsTextItemPrivate::_q_mouseOnEdge(QGraphicsSceneMouseEvent *event)
10628 {
10629     QPainterPath path;
10630     path.addRect(qq->boundingRect());
10631 
10632     QPainterPath docPath;
10633     const QTextFrameFormat format = control->document()->rootFrame()->frameFormat();
10634     docPath.addRect(
10635         qq->boundingRect().adjusted(
10636             format.leftMargin(),
10637             format.topMargin(),
10638             -format.rightMargin(),
10639             -format.bottomMargin()));
10640 
10641     return path.subtracted(docPath).contains(event->pos());
10642 }
10643 
10644 /*!
10645     \fn void QGraphicsTextItem::linkActivated(const QString &link)
10646 
10647     This signal is emitted when the user clicks on a link on a text item
10648     that enables Qt::LinksAccessibleByMouse or Qt::LinksAccessibleByKeyboard.
10649     \a link is the link that was clicked.
10650 
10651     \sa setTextInteractionFlags()
10652 */
10653 
10654 /*!
10655     \fn void QGraphicsTextItem::linkHovered(const QString &link)
10656 
10657     This signal is emitted when the user hovers over a link on a text item
10658     that enables Qt::LinksAccessibleByMouse. \a link is
10659     the link that was hovered over.
10660 
10661     \sa setTextInteractionFlags()
10662 */
10663 
10664 /*!
10665     Sets the flags \a flags to specify how the text item should react to user
10666     input.
10667 
10668     The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function
10669     also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags
10670     is different from Qt::NoTextInteraction and clearing it otherwise.
10671 
10672     By default, the text is read-only. To transform the item into an editor,
10673     set the Qt::TextEditable flag.
10674 */
setTextInteractionFlags(Qt::TextInteractionFlags flags)10675 void QGraphicsTextItem::setTextInteractionFlags(Qt::TextInteractionFlags flags)
10676 {
10677     if (flags == Qt::NoTextInteraction)
10678         setFlags(this->flags() & ~(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod));
10679     else
10680         setFlags(this->flags() | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
10681 
10682     dd->textControl()->setTextInteractionFlags(flags);
10683 }
10684 
10685 /*!
10686     Returns the current text interaction flags.
10687 
10688     \sa setTextInteractionFlags()
10689 */
textInteractionFlags() const10690 Qt::TextInteractionFlags QGraphicsTextItem::textInteractionFlags() const
10691 {
10692     if (!dd->control)
10693         return Qt::NoTextInteraction;
10694     return dd->control->textInteractionFlags();
10695 }
10696 
10697 /*!
10698     \since 4.5
10699 
10700     If \a b is true, the \uicontrol Tab key will cause the widget to change focus;
10701     otherwise, the tab key will insert a tab into the document.
10702 
10703     In some occasions text edits should not allow the user to input tabulators
10704     or change indentation using the \uicontrol Tab key, as this breaks the focus
10705     chain. The default is false.
10706 
10707     \sa tabChangesFocus(), ItemIsFocusable, textInteractionFlags()
10708 */
setTabChangesFocus(bool b)10709 void QGraphicsTextItem::setTabChangesFocus(bool b)
10710 {
10711     dd->tabChangesFocus = b;
10712 }
10713 
10714 /*!
10715     \since 4.5
10716 
10717     Returns \c true if the \uicontrol Tab key will cause the widget to change focus;
10718     otherwise, false is returned.
10719 
10720     By default, this behavior is disabled, and this function will return false.
10721 
10722     \sa setTabChangesFocus()
10723 */
tabChangesFocus() const10724 bool QGraphicsTextItem::tabChangesFocus() const
10725 {
10726     return dd->tabChangesFocus;
10727 }
10728 
10729 /*!
10730     \property QGraphicsTextItem::openExternalLinks
10731 
10732     Specifies whether QGraphicsTextItem should automatically open links using
10733     QDesktopServices::openUrl() instead of emitting the
10734     linkActivated signal.
10735 
10736     The default value is false.
10737 */
setOpenExternalLinks(bool open)10738 void QGraphicsTextItem::setOpenExternalLinks(bool open)
10739 {
10740     dd->textControl()->setOpenExternalLinks(open);
10741 }
10742 
openExternalLinks() const10743 bool QGraphicsTextItem::openExternalLinks() const
10744 {
10745     if (!dd->control)
10746         return false;
10747     return dd->control->openExternalLinks();
10748 }
10749 
10750 /*!
10751     \property QGraphicsTextItem::textCursor
10752 
10753     This property represents the visible text cursor in an editable
10754     text item.
10755 
10756     By default, if the item's text has not been set, this property
10757     contains a null text cursor; otherwise it contains a text cursor
10758     placed at the start of the item's document.
10759 */
setTextCursor(const QTextCursor & cursor)10760 void QGraphicsTextItem::setTextCursor(const QTextCursor &cursor)
10761 {
10762     dd->textControl()->setTextCursor(cursor);
10763 }
10764 
textCursor() const10765 QTextCursor QGraphicsTextItem::textCursor() const
10766 {
10767     if (!dd->control)
10768         return QTextCursor();
10769     return dd->control->textCursor();
10770 }
10771 
10772 class QGraphicsSimpleTextItemPrivate : public QAbstractGraphicsShapeItemPrivate
10773 {
10774     Q_DECLARE_PUBLIC(QGraphicsSimpleTextItem)
10775 public:
QGraphicsSimpleTextItemPrivate()10776     inline QGraphicsSimpleTextItemPrivate() {
10777         pen.setStyle(Qt::NoPen);
10778         brush.setStyle(Qt::SolidPattern);
10779     }
10780     QString text;
10781     QFont font;
10782     QRectF boundingRect;
10783 
10784     void updateBoundingRect();
10785 };
10786 
setupTextLayout(QTextLayout * layout)10787 static QRectF setupTextLayout(QTextLayout *layout)
10788 {
10789     layout->setCacheEnabled(true);
10790     layout->beginLayout();
10791     while (layout->createLine().isValid())
10792         ;
10793     layout->endLayout();
10794     qreal maxWidth = 0;
10795     qreal y = 0;
10796     for (int i = 0; i < layout->lineCount(); ++i) {
10797         QTextLine line = layout->lineAt(i);
10798         maxWidth = qMax(maxWidth, line.naturalTextWidth());
10799         line.setPosition(QPointF(0, y));
10800         y += line.height();
10801     }
10802     return QRectF(0, 0, maxWidth, y);
10803 }
10804 
updateBoundingRect()10805 void QGraphicsSimpleTextItemPrivate::updateBoundingRect()
10806 {
10807     Q_Q(QGraphicsSimpleTextItem);
10808     QRectF br;
10809     if (text.isEmpty()) {
10810         br = QRectF();
10811     } else {
10812         QString tmp = text;
10813         tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
10814         QStackTextEngine engine(tmp, font);
10815         QTextLayout layout(&engine);
10816         br = setupTextLayout(&layout);
10817     }
10818     if (br != boundingRect) {
10819         q->prepareGeometryChange();
10820         boundingRect = br;
10821         q->update();
10822     }
10823 }
10824 
10825 /*!
10826     \class QGraphicsSimpleTextItem
10827     \brief The QGraphicsSimpleTextItem class provides a simple text path item
10828     that you can add to a QGraphicsScene.
10829     \since 4.2
10830     \ingroup graphicsview-api
10831     \inmodule QtWidgets
10832 
10833     To set the item's text, you can either pass a QString to
10834     QGraphicsSimpleTextItem's constructor, or call setText() to change the
10835     text later. To set the text fill color, call setBrush().
10836 
10837     The simple text item can have both a fill and an outline; setBrush() will
10838     set the text fill (i.e., text color), and setPen() sets the pen that will
10839     be used to draw the text outline. (The latter can be slow, especially for
10840     complex pens, and items with long text content.) If all you want is to
10841     draw a simple line of text, you should call setBrush() only, and leave the
10842     pen unset; QGraphicsSimpleTextItem's pen is by default Qt::NoPen.
10843 
10844     QGraphicsSimpleTextItem uses the text's formatted size and the associated
10845     font to provide a reasonable implementation of boundingRect(), shape(),
10846     and contains(). You can set the font by calling setFont().
10847 
10848     QGraphicsSimpleText does not display rich text; instead, you can use
10849     QGraphicsTextItem, which provides full text control capabilities.
10850 
10851     \image graphicsview-simpletextitem.png
10852 
10853     \sa QGraphicsTextItem, QGraphicsPathItem, QGraphicsRectItem,
10854     QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
10855     QGraphicsLineItem, {Graphics View Framework}
10856 */
10857 
10858 /*!
10859     Constructs a QGraphicsSimpleTextItem.
10860 
10861     \a parent is passed to QGraphicsItem's constructor.
10862 
10863     \sa QGraphicsScene::addItem()
10864 */
QGraphicsSimpleTextItem(QGraphicsItem * parent)10865 QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(QGraphicsItem *parent)
10866     : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent)
10867 {
10868 }
10869 
10870 /*!
10871     Constructs a QGraphicsSimpleTextItem, using \a text as the default plain text.
10872 
10873     \a parent is passed to QGraphicsItem's constructor.
10874 
10875     \sa QGraphicsScene::addItem()
10876 */
QGraphicsSimpleTextItem(const QString & text,QGraphicsItem * parent)10877 QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(const QString &text, QGraphicsItem *parent)
10878     : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent)
10879 {
10880     setText(text);
10881 }
10882 
10883 /*!
10884     Destroys the QGraphicsSimpleTextItem.
10885 */
~QGraphicsSimpleTextItem()10886 QGraphicsSimpleTextItem::~QGraphicsSimpleTextItem()
10887 {
10888 }
10889 
10890 /*!
10891     Sets the item's text to \a text. The text will be displayed as
10892     plain text. Newline characters ('\\n') as well as characters of
10893     type QChar::LineSeparator will cause item to break the text into
10894     multiple lines.
10895 */
setText(const QString & text)10896 void QGraphicsSimpleTextItem::setText(const QString &text)
10897 {
10898     Q_D(QGraphicsSimpleTextItem);
10899     if (d->text == text)
10900         return;
10901     d->text = text;
10902     d->updateBoundingRect();
10903     update();
10904 }
10905 
10906 /*!
10907     Returns the item's text.
10908 */
text() const10909 QString QGraphicsSimpleTextItem::text() const
10910 {
10911     Q_D(const QGraphicsSimpleTextItem);
10912     return d->text;
10913 }
10914 
10915 /*!
10916     Sets the font that is used to draw the item's text to \a font.
10917 */
setFont(const QFont & font)10918 void QGraphicsSimpleTextItem::setFont(const QFont &font)
10919 {
10920     Q_D(QGraphicsSimpleTextItem);
10921     d->font = font;
10922     d->updateBoundingRect();
10923 }
10924 
10925 /*!
10926     Returns the font that is used to draw the item's text.
10927 */
font() const10928 QFont QGraphicsSimpleTextItem::font() const
10929 {
10930     Q_D(const QGraphicsSimpleTextItem);
10931     return d->font;
10932 }
10933 
10934 /*!
10935     \reimp
10936 */
boundingRect() const10937 QRectF QGraphicsSimpleTextItem::boundingRect() const
10938 {
10939     Q_D(const QGraphicsSimpleTextItem);
10940     return d->boundingRect;
10941 }
10942 
10943 /*!
10944     \reimp
10945 */
shape() const10946 QPainterPath QGraphicsSimpleTextItem::shape() const
10947 {
10948     Q_D(const QGraphicsSimpleTextItem);
10949     QPainterPath path;
10950     path.addRect(d->boundingRect);
10951     return path;
10952 }
10953 
10954 /*!
10955     \reimp
10956 */
contains(const QPointF & point) const10957 bool QGraphicsSimpleTextItem::contains(const QPointF &point) const
10958 {
10959     Q_D(const QGraphicsSimpleTextItem);
10960     return d->boundingRect.contains(point);
10961 }
10962 
10963 /*!
10964     \reimp
10965 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)10966 void QGraphicsSimpleTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
10967 {
10968     Q_UNUSED(widget);
10969     Q_D(QGraphicsSimpleTextItem);
10970 
10971     painter->setFont(d->font);
10972 
10973     QString tmp = d->text;
10974     tmp.replace(QLatin1Char('\n'), QChar::LineSeparator);
10975     QStackTextEngine engine(tmp, d->font);
10976     QTextLayout layout(&engine);
10977 
10978     QPen p;
10979     p.setBrush(d->brush);
10980     painter->setPen(p);
10981     if (d->pen.style() == Qt::NoPen && d->brush.style() == Qt::SolidPattern) {
10982         painter->setBrush(Qt::NoBrush);
10983     } else {
10984         QTextLayout::FormatRange range;
10985         range.start = 0;
10986         range.length = layout.text().length();
10987         range.format.setTextOutline(d->pen);
10988         layout.setFormats(QVector<QTextLayout::FormatRange>(1, range));
10989     }
10990 
10991     setupTextLayout(&layout);
10992     layout.draw(painter, QPointF(0, 0));
10993 
10994     if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
10995         qt_graphicsItem_highlightSelected(this, painter, option);
10996 }
10997 
10998 /*!
10999     \reimp
11000 */
isObscuredBy(const QGraphicsItem * item) const11001 bool QGraphicsSimpleTextItem::isObscuredBy(const QGraphicsItem *item) const
11002 {
11003     return QAbstractGraphicsShapeItem::isObscuredBy(item);
11004 }
11005 
11006 /*!
11007     \reimp
11008 */
opaqueArea() const11009 QPainterPath QGraphicsSimpleTextItem::opaqueArea() const
11010 {
11011     return QAbstractGraphicsShapeItem::opaqueArea();
11012 }
11013 
11014 /*!
11015     \reimp
11016 */
type() const11017 int QGraphicsSimpleTextItem::type() const
11018 {
11019     return Type;
11020 }
11021 
11022 /*!
11023     \internal
11024 */
supportsExtension(Extension extension) const11025 bool QGraphicsSimpleTextItem::supportsExtension(Extension extension) const
11026 {
11027     Q_UNUSED(extension);
11028     return false;
11029 }
11030 
11031 /*!
11032     \internal
11033 */
setExtension(Extension extension,const QVariant & variant)11034 void QGraphicsSimpleTextItem::setExtension(Extension extension, const QVariant &variant)
11035 {
11036     Q_UNUSED(extension);
11037     Q_UNUSED(variant);
11038 }
11039 
11040 /*!
11041     \internal
11042 */
extension(const QVariant & variant) const11043 QVariant QGraphicsSimpleTextItem::extension(const QVariant &variant) const
11044 {
11045     Q_UNUSED(variant);
11046     return QVariant();
11047 }
11048 
11049 /*!
11050     \class QGraphicsItemGroup
11051     \brief The QGraphicsItemGroup class provides a container that treats
11052     a group of items as a single item.
11053     \since 4.2
11054     \ingroup graphicsview-api
11055     \inmodule QtWidgets
11056 
11057     A QGraphicsItemGroup is a special type of compound item that
11058     treats itself and all its children as one item (i.e., all events
11059     and geometries for all children are merged together). It's common
11060     to use item groups in presentation tools, when the user wants to
11061     group several smaller items into one big item in order to simplify
11062     moving and copying of items.
11063 
11064     If all you want is to store items inside other items, you can use
11065     any QGraphicsItem directly by passing a suitable parent to
11066     setParentItem().
11067 
11068     The boundingRect() function of QGraphicsItemGroup returns the
11069     bounding rectangle of all items in the item group.
11070     QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on
11071     its children (i.e., with respect to the geometry of the group
11072     item, the children are treated as if they were transformable).
11073 
11074     There are two ways to construct an item group. The easiest and
11075     most common approach is to pass a list of items (e.g., all
11076     selected items) to QGraphicsScene::createItemGroup(), which
11077     returns a new QGraphicsItemGroup item. The other approach is to
11078     manually construct a QGraphicsItemGroup item, add it to the scene
11079     calling QGraphicsScene::addItem(), and then add items to the group
11080     manually, one at a time by calling addToGroup(). To dismantle
11081     ("ungroup") an item group, you can either call
11082     QGraphicsScene::destroyItemGroup(), or you can manually remove all
11083     items from the group by calling removeFromGroup().
11084 
11085     \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 17
11086 
11087     The operation of adding and removing items preserves the items'
11088     scene-relative position and transformation, as opposed to calling
11089     setParentItem(), where only the child item's parent-relative
11090     position and transformation are kept.
11091 
11092     The addtoGroup() function reparents the target item to this item
11093     group, keeping the item's position and transformation intact
11094     relative to the scene. Visually, this means that items added via
11095     addToGroup() will remain completely unchanged as a result of this
11096     operation, regardless of the item or the group's current position
11097     or transformation; although the item's position and matrix are
11098     likely to change.
11099 
11100     The removeFromGroup() function has similar semantics to
11101     setParentItem(); it reparents the item to the parent item of the
11102     item group. As with addToGroup(), the item's scene-relative
11103     position and transformation remain intact.
11104 
11105     \sa QGraphicsItem, {Graphics View Framework}
11106 */
11107 
11108 class QGraphicsItemGroupPrivate : public QGraphicsItemPrivate
11109 {
11110 public:
11111     QRectF itemsBoundingRect;
11112 };
11113 
11114 /*!
11115     Constructs a QGraphicsItemGroup. \a parent is passed to QGraphicsItem's
11116     constructor.
11117 
11118     \sa QGraphicsScene::addItem()
11119 */
QGraphicsItemGroup(QGraphicsItem * parent)11120 QGraphicsItemGroup::QGraphicsItemGroup(QGraphicsItem *parent)
11121     : QGraphicsItem(*new QGraphicsItemGroupPrivate, parent)
11122 {
11123     setHandlesChildEvents(true);
11124 }
11125 
11126 /*!
11127     Destroys the QGraphicsItemGroup.
11128 */
~QGraphicsItemGroup()11129 QGraphicsItemGroup::~QGraphicsItemGroup()
11130 {
11131 }
11132 
11133 /*!
11134     Adds the given \a item and item's child items to this item group.
11135     The item and child items will be reparented to this group, but its
11136     position and transformation relative to the scene will stay intact.
11137 
11138     \sa removeFromGroup(), QGraphicsScene::createItemGroup()
11139 */
addToGroup(QGraphicsItem * item)11140 void QGraphicsItemGroup::addToGroup(QGraphicsItem *item)
11141 {
11142     Q_D(QGraphicsItemGroup);
11143     if (!item) {
11144         qWarning("QGraphicsItemGroup::addToGroup: cannot add null item");
11145         return;
11146     }
11147     if (item == this) {
11148         qWarning("QGraphicsItemGroup::addToGroup: cannot add a group to itself");
11149         return;
11150     }
11151 
11152     // COMBINE
11153     bool ok;
11154     QTransform itemTransform = item->itemTransform(this, &ok);
11155 
11156     if (!ok) {
11157         qWarning("QGraphicsItemGroup::addToGroup: could not find a valid transformation from item to group coordinates");
11158         return;
11159     }
11160 
11161     QTransform newItemTransform(itemTransform);
11162     item->setPos(mapFromItem(item, 0, 0));
11163     item->setParentItem(this);
11164 
11165     // removing position from translation component of the new transform
11166     if (!item->pos().isNull())
11167         newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
11168 
11169     // removing additional transformations properties applied with itemTransform()
11170     QPointF origin = item->transformOriginPoint();
11171     QMatrix4x4 m;
11172     QList<QGraphicsTransform*> transformList = item->transformations();
11173     for (int i = 0; i < transformList.size(); ++i)
11174         transformList.at(i)->applyTo(&m);
11175     newItemTransform *= m.toTransform().inverted();
11176     newItemTransform.translate(origin.x(), origin.y());
11177     newItemTransform.rotate(-item->rotation());
11178     newItemTransform.scale(1/item->scale(), 1/item->scale());
11179     newItemTransform.translate(-origin.x(), -origin.y());
11180 
11181     // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
11182 
11183     item->setTransform(newItemTransform);
11184     item->d_func()->setIsMemberOfGroup(true);
11185     prepareGeometryChange();
11186     d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect());
11187     update();
11188 }
11189 
11190 /*!
11191     Removes the specified \a item from this group. The item will be
11192     reparented to this group's parent item, or to 0 if this group has
11193     no parent.  Its position and transformation relative to the scene
11194     will stay intact.
11195 
11196     \sa addToGroup(), QGraphicsScene::destroyItemGroup()
11197 */
removeFromGroup(QGraphicsItem * item)11198 void QGraphicsItemGroup::removeFromGroup(QGraphicsItem *item)
11199 {
11200     Q_D(QGraphicsItemGroup);
11201     if (!item) {
11202         qWarning("QGraphicsItemGroup::removeFromGroup: cannot remove null item");
11203         return;
11204     }
11205 
11206     QGraphicsItem *newParent = d_ptr->parent;
11207 
11208     // COMBINE
11209     bool ok;
11210     QTransform itemTransform;
11211     if (newParent)
11212         itemTransform = item->itemTransform(newParent, &ok);
11213     else
11214         itemTransform = item->sceneTransform();
11215 
11216     QPointF oldPos = item->mapToItem(newParent, 0, 0);
11217     item->setParentItem(newParent);
11218     item->setPos(oldPos);
11219 
11220     // removing position from translation component of the new transform
11221     if (!item->pos().isNull())
11222         itemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
11223 
11224     // removing additional transformations properties applied
11225     // with itemTransform() or sceneTransform()
11226     QPointF origin = item->transformOriginPoint();
11227     QMatrix4x4 m;
11228     QList<QGraphicsTransform*> transformList = item->transformations();
11229     for (int i = 0; i < transformList.size(); ++i)
11230         transformList.at(i)->applyTo(&m);
11231     itemTransform *= m.toTransform().inverted();
11232     itemTransform.translate(origin.x(), origin.y());
11233     itemTransform.rotate(-item->rotation());
11234     itemTransform.scale(1 / item->scale(), 1 / item->scale());
11235     itemTransform.translate(-origin.x(), -origin.y());
11236 
11237     // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
11238 
11239     item->setTransform(itemTransform);
11240     item->d_func()->setIsMemberOfGroup(item->group() != nullptr);
11241 
11242     // ### Quite expensive. But removeFromGroup() isn't called very often.
11243     prepareGeometryChange();
11244     d->itemsBoundingRect = childrenBoundingRect();
11245 }
11246 
11247 /*!
11248     \reimp
11249 
11250     Returns the bounding rect of this group item, and all its children.
11251 */
boundingRect() const11252 QRectF QGraphicsItemGroup::boundingRect() const
11253 {
11254     Q_D(const QGraphicsItemGroup);
11255     return d->itemsBoundingRect;
11256 }
11257 
11258 /*!
11259     \reimp
11260 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)11261 void QGraphicsItemGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
11262                                QWidget *widget)
11263 {
11264     Q_UNUSED(widget);
11265     if (option->state & QStyle::State_Selected) {
11266         Q_D(QGraphicsItemGroup);
11267         painter->setBrush(Qt::NoBrush);
11268         painter->drawRect(d->itemsBoundingRect);
11269     }
11270 }
11271 
11272 /*!
11273     \reimp
11274 */
isObscuredBy(const QGraphicsItem * item) const11275 bool QGraphicsItemGroup::isObscuredBy(const QGraphicsItem *item) const
11276 {
11277     return QGraphicsItem::isObscuredBy(item);
11278 }
11279 
11280 /*!
11281     \reimp
11282 */
opaqueArea() const11283 QPainterPath QGraphicsItemGroup::opaqueArea() const
11284 {
11285     return QGraphicsItem::opaqueArea();
11286 }
11287 
11288 /*!
11289     \reimp
11290 */
type() const11291 int QGraphicsItemGroup::type() const
11292 {
11293     return Type;
11294 }
11295 
11296 #if QT_CONFIG(graphicseffect)
boundingRect(Qt::CoordinateSystem system) const11297 QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
11298 {
11299     const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
11300     if (!info && deviceCoordinates) {
11301         // Device coordinates without info not yet supported.
11302         qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
11303         return QRectF();
11304     }
11305 
11306     QRectF rect = item->boundingRect();
11307     if (!item->d_ptr->children.isEmpty())
11308         rect |= item->childrenBoundingRect();
11309 
11310     if (deviceCoordinates) {
11311         Q_ASSERT(info->painter);
11312         rect = info->painter->worldTransform().mapRect(rect);
11313     }
11314 
11315     return rect;
11316 }
11317 
draw(QPainter * painter)11318 void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
11319 {
11320     if (!info) {
11321         qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
11322         return;
11323     }
11324 
11325     Q_ASSERT(item->d_ptr->scene);
11326     QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
11327     if (painter == info->painter) {
11328         scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
11329                      info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform,
11330                      info->drawItem);
11331     } else {
11332         QTransform effectTransform = info->painter->worldTransform().inverted();
11333         effectTransform *= painter->worldTransform();
11334         scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
11335                      info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
11336                      info->drawItem);
11337     }
11338 }
11339 
11340 // sourceRect must be in the given coordinate system
paddedEffectRect(Qt::CoordinateSystem system,QGraphicsEffect::PixmapPadMode mode,const QRectF & sourceRect,bool * unpadded) const11341 QRectF QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
11342 {
11343     QRectF effectRectF;
11344 
11345     if (unpadded)
11346         *unpadded = false;
11347 
11348     if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
11349         if (info) {
11350             QRectF deviceRect = system == Qt::DeviceCoordinates ? sourceRect : info->painter->worldTransform().mapRect(sourceRect);
11351             effectRectF = item->graphicsEffect()->boundingRectFor(deviceRect);
11352             if (unpadded)
11353                 *unpadded = (effectRectF.size() == sourceRect.size());
11354             if (info && system == Qt::LogicalCoordinates)
11355                 effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
11356         } else {
11357             // no choice but to send a logical coordinate bounding rect to boundingRectFor
11358             effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
11359         }
11360     } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
11361         // adjust by 1.5 to account for cosmetic pens
11362         effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5);
11363     } else {
11364         effectRectF = sourceRect;
11365         if (unpadded)
11366             *unpadded = true;
11367     }
11368 
11369     return effectRectF;
11370 }
11371 
pixmap(Qt::CoordinateSystem system,QPoint * offset,QGraphicsEffect::PixmapPadMode mode) const11372 QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
11373                                                  QGraphicsEffect::PixmapPadMode mode) const
11374 {
11375     const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
11376     if (!info && deviceCoordinates) {
11377         // Device coordinates without info not yet supported.
11378         qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
11379         return QPixmap();
11380     }
11381     if (!item->d_ptr->scene)
11382         return QPixmap();
11383     QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
11384 
11385     bool unpadded;
11386     const QRectF sourceRect = boundingRect(system);
11387     QRectF effectRectF = paddedEffectRect(system, mode, sourceRect, &unpadded);
11388     QRect effectRect = effectRectF.toAlignedRect();
11389 
11390     if (offset)
11391         *offset = effectRect.topLeft();
11392 
11393     bool untransformed = !deviceCoordinates
11394             || info->painter->worldTransform().type() <= QTransform::TxTranslate;
11395     if (untransformed && unpadded && isPixmap()) {
11396         if (offset)
11397             *offset = boundingRect(system).topLeft().toPoint();
11398         return static_cast<QGraphicsPixmapItem *>(item)->pixmap();
11399     }
11400 
11401     if (effectRect.isEmpty())
11402         return QPixmap();
11403 
11404     const auto dpr = info ? info->painter->device()->devicePixelRatioF() : 1.0;
11405     QPixmap pixmap(QRectF(effectRectF.topLeft(), effectRectF.size() * dpr).toAlignedRect().size());
11406     pixmap.setDevicePixelRatio(dpr);
11407     pixmap.fill(Qt::transparent);
11408     QPainter pixmapPainter(&pixmap);
11409     pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);
11410 
11411     QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y());
11412     if (deviceCoordinates && info->effectTransform)
11413         effectTransform *= *info->effectTransform;
11414 
11415     if (!info) {
11416         // Logical coordinates without info.
11417         QTransform sceneTransform = item->sceneTransform();
11418         QTransform newEffectTransform = sceneTransform.inverted();
11419         newEffectTransform *= effectTransform;
11420         scened->draw(item, &pixmapPainter, nullptr, &sceneTransform, nullptr, nullptr, qreal(1.0),
11421                      &newEffectTransform, false, true);
11422     } else if (deviceCoordinates) {
11423         // Device coordinates with info.
11424         scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, nullptr,
11425                      info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
11426                      info->drawItem);
11427     } else {
11428         // Item coordinates with info.
11429         QTransform newEffectTransform = info->transformPtr->inverted();
11430         newEffectTransform *= effectTransform;
11431         scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, nullptr,
11432                      info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform,
11433                      info->drawItem);
11434     }
11435 
11436     pixmapPainter.end();
11437 
11438     return pixmap;
11439 }
11440 #endif // QT_CONFIG(graphicseffect)
11441 
11442 #ifndef QT_NO_DEBUG_STREAM
formatGraphicsItemHelper(QDebug debug,const QGraphicsItem * item)11443 static void formatGraphicsItemHelper(QDebug debug, const QGraphicsItem *item)
11444 {
11445     if (const QGraphicsItem *parent = item->parentItem())
11446           debug << ", parent=" << static_cast<const void *>(parent);
11447     debug << ", pos=";
11448     QtDebugUtils::formatQPoint(debug, item->pos());
11449     if (const qreal z = item->zValue())
11450         debug << ", z=" << z;
11451     if (item->flags())
11452         debug <<  ", flags=" << item->flags();
11453 }
11454 
11455 // FIXME: Qt 6: Make this QDebug operator<<(QDebug debug, const QGraphicsItem *item)
operator <<(QDebug debug,QGraphicsItem * item)11456 QDebug operator<<(QDebug debug, QGraphicsItem *item)
11457 {
11458     QDebugStateSaver saver(debug);
11459     debug.nospace();
11460 
11461     if (!item) {
11462         debug << "QGraphicsItem(0)";
11463         return debug;
11464     }
11465 
11466     if (QGraphicsObject *o = item->toGraphicsObject())
11467         debug << o->metaObject()->className();
11468     else
11469         debug << "QGraphicsItem";
11470     debug << '(' << static_cast<const void *>(item);
11471     if (const QGraphicsProxyWidget *pw = qgraphicsitem_cast<const QGraphicsProxyWidget *>(item)) {
11472         debug << ", widget=";
11473         if (const QWidget *w = pw->widget()) {
11474             debug << w->metaObject()->className() << '(' << static_cast<const void *>(w);
11475             if (!w->objectName().isEmpty())
11476                 debug << ", name=" << w->objectName();
11477             debug << ')';
11478         } else {
11479             debug << "QWidget(0)";
11480         }
11481     }
11482     formatGraphicsItemHelper(debug, item);
11483     debug << ')';
11484     return debug;
11485 }
11486 
11487 // FIXME: Qt 6: Make this QDebug operator<<(QDebug debug, const QGraphicsObject *item)
operator <<(QDebug debug,QGraphicsObject * item)11488 QDebug operator<<(QDebug debug, QGraphicsObject *item)
11489 {
11490     QDebugStateSaver saver(debug);
11491     debug.nospace();
11492 
11493     if (!item) {
11494         debug << "QGraphicsObject(0)";
11495         return debug;
11496     }
11497 
11498     debug << item->metaObject()->className() << '(' << static_cast<const void *>(item);
11499     if (!item->objectName().isEmpty())
11500         debug << ", name=" << item->objectName();
11501     formatGraphicsItemHelper(debug, item);
11502     debug << ')';
11503     return debug;
11504 }
11505 
operator <<(QDebug debug,QGraphicsItem::GraphicsItemChange change)11506 QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change)
11507 {
11508     const char *str = "UnknownChange";
11509     switch (change) {
11510     case QGraphicsItem::ItemChildAddedChange:
11511         str = "ItemChildAddedChange";
11512         break;
11513     case QGraphicsItem::ItemChildRemovedChange:
11514         str = "ItemChildRemovedChange";
11515         break;
11516     case QGraphicsItem::ItemCursorChange:
11517         str = "ItemCursorChange";
11518         break;
11519     case QGraphicsItem::ItemCursorHasChanged:
11520         str = "ItemCursorHasChanged";
11521         break;
11522     case QGraphicsItem::ItemEnabledChange:
11523         str = "ItemEnabledChange";
11524         break;
11525     case QGraphicsItem::ItemEnabledHasChanged:
11526         str = "ItemEnabledHasChanged";
11527         break;
11528     case QGraphicsItem::ItemFlagsChange:
11529         str = "ItemFlagsChange";
11530         break;
11531     case QGraphicsItem::ItemFlagsHaveChanged:
11532         str = "ItemFlagsHaveChanged";
11533         break;
11534 #if QT_DEPRECATED_SINCE(5, 14)
11535 QT_WARNING_PUSH
11536 QT_WARNING_DISABLE_DEPRECATED
11537     case QGraphicsItem::ItemMatrixChange:
11538         str = "ItemMatrixChange";
11539         break;
11540 QT_WARNING_POP
11541 #endif
11542     case QGraphicsItem::ItemParentChange:
11543         str = "ItemParentChange";
11544         break;
11545     case QGraphicsItem::ItemParentHasChanged:
11546         str = "ItemParentHasChanged";
11547         break;
11548     case QGraphicsItem::ItemPositionChange:
11549         str = "ItemPositionChange";
11550         break;
11551     case QGraphicsItem::ItemPositionHasChanged:
11552         str = "ItemPositionHasChanged";
11553         break;
11554     case QGraphicsItem::ItemSceneChange:
11555         str = "ItemSceneChange";
11556         break;
11557     case QGraphicsItem::ItemSceneHasChanged:
11558         str = "ItemSceneHasChanged";
11559         break;
11560     case QGraphicsItem::ItemSelectedChange:
11561         str = "ItemSelectedChange";
11562         break;
11563     case QGraphicsItem::ItemSelectedHasChanged:
11564         str = "ItemSelectedHasChanged";
11565         break;
11566     case QGraphicsItem::ItemToolTipChange:
11567         str = "ItemToolTipChange";
11568         break;
11569     case QGraphicsItem::ItemToolTipHasChanged:
11570         str = "ItemToolTipHasChanged";
11571         break;
11572     case QGraphicsItem::ItemTransformChange:
11573         str = "ItemTransformChange";
11574         break;
11575     case QGraphicsItem::ItemTransformHasChanged:
11576         str = "ItemTransformHasChanged";
11577         break;
11578     case QGraphicsItem::ItemVisibleChange:
11579         str = "ItemVisibleChange";
11580         break;
11581     case QGraphicsItem::ItemVisibleHasChanged:
11582         str = "ItemVisibleHasChanged";
11583         break;
11584     case QGraphicsItem::ItemZValueChange:
11585         str = "ItemZValueChange";
11586         break;
11587     case QGraphicsItem::ItemZValueHasChanged:
11588         str = "ItemZValueHasChanged";
11589         break;
11590     case QGraphicsItem::ItemOpacityChange:
11591         str = "ItemOpacityChange";
11592         break;
11593     case QGraphicsItem::ItemOpacityHasChanged:
11594         str = "ItemOpacityHasChanged";
11595         break;
11596     case QGraphicsItem::ItemScenePositionHasChanged:
11597         str = "ItemScenePositionHasChanged";
11598         break;
11599     case QGraphicsItem::ItemRotationChange:
11600         str = "ItemRotationChange";
11601         break;
11602     case QGraphicsItem::ItemRotationHasChanged:
11603         str = "ItemRotationHasChanged";
11604         break;
11605     case QGraphicsItem::ItemScaleChange:
11606         str = "ItemScaleChange";
11607         break;
11608     case QGraphicsItem::ItemScaleHasChanged:
11609         str = "ItemScaleHasChanged";
11610         break;
11611     case QGraphicsItem::ItemTransformOriginPointChange:
11612         str = "ItemTransformOriginPointChange";
11613         break;
11614     case QGraphicsItem::ItemTransformOriginPointHasChanged:
11615         str = "ItemTransformOriginPointHasChanged";
11616         break;
11617     }
11618     debug << str;
11619     return debug;
11620 }
11621 
operator <<(QDebug debug,QGraphicsItem::GraphicsItemFlag flag)11622 QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
11623 {
11624     const char *str = "UnknownFlag";
11625     switch (flag) {
11626     case QGraphicsItem::ItemIsMovable:
11627         str = "ItemIsMovable";
11628         break;
11629     case QGraphicsItem::ItemIsSelectable:
11630         str = "ItemIsSelectable";
11631         break;
11632     case QGraphicsItem::ItemIsFocusable:
11633         str = "ItemIsFocusable";
11634         break;
11635     case QGraphicsItem::ItemClipsToShape:
11636         str = "ItemClipsToShape";
11637         break;
11638     case QGraphicsItem::ItemClipsChildrenToShape:
11639         str = "ItemClipsChildrenToShape";
11640         break;
11641     case QGraphicsItem::ItemIgnoresTransformations:
11642         str = "ItemIgnoresTransformations";
11643         break;
11644     case QGraphicsItem::ItemIgnoresParentOpacity:
11645         str = "ItemIgnoresParentOpacity";
11646         break;
11647     case QGraphicsItem::ItemDoesntPropagateOpacityToChildren:
11648         str = "ItemDoesntPropagateOpacityToChildren";
11649         break;
11650     case QGraphicsItem::ItemStacksBehindParent:
11651         str = "ItemStacksBehindParent";
11652         break;
11653     case QGraphicsItem::ItemUsesExtendedStyleOption:
11654         str = "ItemUsesExtendedStyleOption";
11655         break;
11656     case QGraphicsItem::ItemHasNoContents:
11657         str = "ItemHasNoContents";
11658         break;
11659     case QGraphicsItem::ItemSendsGeometryChanges:
11660         str = "ItemSendsGeometryChanges";
11661         break;
11662     case QGraphicsItem::ItemAcceptsInputMethod:
11663         str = "ItemAcceptsInputMethod";
11664         break;
11665     case QGraphicsItem::ItemNegativeZStacksBehindParent:
11666         str = "ItemNegativeZStacksBehindParent";
11667         break;
11668     case QGraphicsItem::ItemIsPanel:
11669         str = "ItemIsPanel";
11670         break;
11671     case QGraphicsItem::ItemIsFocusScope:
11672         str = "ItemIsFocusScope";
11673         break;
11674     case QGraphicsItem::ItemSendsScenePositionChanges:
11675         str = "ItemSendsScenePositionChanges";
11676         break;
11677     case QGraphicsItem::ItemStopsClickFocusPropagation:
11678         str = "ItemStopsClickFocusPropagation";
11679         break;
11680     case QGraphicsItem::ItemStopsFocusHandling:
11681         str = "ItemStopsFocusHandling";
11682         break;
11683     case QGraphicsItem::ItemContainsChildrenInShape:
11684         str = "ItemContainsChildrenInShape";
11685         break;
11686     }
11687     debug << str;
11688     return debug;
11689 }
11690 
operator <<(QDebug debug,QGraphicsItem::GraphicsItemFlags flags)11691 QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
11692 {
11693     debug << '(';
11694     bool f = false;
11695     for (int i = 0; i < 17; ++i) {
11696         if (flags & (1 << i)) {
11697             if (f)
11698                 debug << '|';
11699             f = true;
11700             debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i)));
11701         }
11702     }
11703     debug << ')';
11704     return debug;
11705 }
11706 
11707 #endif
11708 
11709 QT_END_NAMESPACE
11710 
11711 #include "moc_qgraphicsitem.cpp"
11712