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
837QT_BEGIN_NAMESPACE
838
839static inline void _q_adjustRect(QRect *rect)
840{
841 Q_ASSERT(rect);
842 if (!rect->width())
843 rect->adjust(dx1: 0, dy1: 0, dx2: 1, dy2: 0);
844 if (!rect->height())
845 rect->adjust(dx1: 0, dy1: 0, dx2: 0, dy2: 1);
846}
847
848/*
849 ### Move this into QGraphicsItemPrivate
850 */
851class QGraphicsItemCustomDataStore
852{
853public:
854 QHash<const QGraphicsItem *, QMap<int, QVariant> > data;
855};
856Q_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*/
864static 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*/
888QGraphicsItemPrivate::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*/
960QGraphicsItemPrivate::~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*/
971void 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, root: false);
1039}
1040
1041void 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*/
1076void QGraphicsItemPrivate::setIsMemberOfGroup(bool enabled)
1077{
1078 Q_Q(QGraphicsItem);
1079 isMemberOfGroup = enabled;
1080 if (!qgraphicsitem_cast<QGraphicsItemGroup *>(item: 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*/
1091void 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(item: q, point: mouseEvent->pos()));
1101 mouseEvent->setLastPos(item->mapFromItem(item: q, point: 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, pos: item->mapFromItem(item: q, point: mouseEvent->buttonDownPos(button)));
1106 }
1107 }
1108 break;
1109 }
1110 case QEvent::GraphicsSceneWheel: {
1111 QGraphicsSceneWheelEvent *wheelEvent = static_cast<QGraphicsSceneWheelEvent *>(event);
1112 wheelEvent->setPos(item->mapFromItem(item: q, point: wheelEvent->pos()));
1113 break;
1114 }
1115 case QEvent::GraphicsSceneContextMenu: {
1116 QGraphicsSceneContextMenuEvent *contextEvent = static_cast<QGraphicsSceneContextMenuEvent *>(event);
1117 contextEvent->setPos(item->mapFromItem(item: q, point: contextEvent->pos()));
1118 break;
1119 }
1120 case QEvent::GraphicsSceneHoverMove: {
1121 QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
1122 hoverEvent->setPos(item->mapFromItem(item: q, point: 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
1138QTransform 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 *>(object: 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
1153QPointF QGraphicsItemPrivate::genericMapFromScene(const QPointF &pos,
1154 const QWidget *viewport) const
1155{
1156 return genericMapFromSceneTransform(viewport).map(p: 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*/
1167void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const
1168{
1169 // COMBINE
1170 if (viewTransform && itemIsUntransformable()) {
1171 *x = q_ptr->deviceTransform(viewportTransform: *viewTransform);
1172 } else {
1173 if (transformData)
1174 *x *= transformData->computedFullTransform();
1175 if (!pos.isNull())
1176 *x *= QTransform::fromTranslate(dx: pos.x(), dy: 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*/
1189void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const
1190{
1191 // COMBINE
1192 if (viewTransform && itemIsUntransformable()) {
1193 *x = q_ptr->deviceTransform(viewportTransform: *viewTransform);
1194 } else {
1195 x->translate(dx: pos.x(), dy: pos.y());
1196 if (transformData)
1197 *x = transformData->computedFullTransform(postmultiplyTransform: x);
1198 }
1199}
1200
1201void QGraphicsItemPrivate::updateSceneTransformFromParent()
1202{
1203 if (parent) {
1204 Q_ASSERT(!parent->d_ptr->dirtySceneTransform);
1205 if (parent->d_ptr->sceneTransformTranslateOnly) {
1206 sceneTransform = QTransform::fromTranslate(dx: parent->d_ptr->sceneTransform.dx() + pos.x(),
1207 dy: parent->d_ptr->sceneTransform.dy() + pos.y());
1208 } else {
1209 sceneTransform = parent->d_ptr->sceneTransform;
1210 sceneTransform.translate(dx: pos.x(), dy: pos.y());
1211 }
1212 if (transformData) {
1213 sceneTransform = transformData->computedFullTransform(postmultiplyTransform: &sceneTransform);
1214 sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
1215 } else {
1216 sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly;
1217 }
1218 } else if (!transformData) {
1219 sceneTransform = QTransform::fromTranslate(dx: pos.x(), dy: pos.y());
1220 sceneTransformTranslateOnly = 1;
1221 } else if (transformData->onlyTransform) {
1222 sceneTransform = transformData->transform;
1223 if (!pos.isNull())
1224 sceneTransform *= QTransform::fromTranslate(dx: pos.x(), dy: 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(dx: pos.x(), dy: pos.y());
1231 sceneTransform = transformData->computedFullTransform(postmultiplyTransform: &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*/
1244void 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: (newParent &&
1253 newParent->isWidget()) ? static_cast<QGraphicsWidget *>(newParent) : nullptr,
1254 oldScene: 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(item: q, QGraphicsItem::ItemParentChange, value: newParent);
1259
1260 // Disable scene pos notifications for old ancestors
1261 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
1262 scene->d_func()->setScenePosItemEnabled(item: q, enabled: false);
1263 }
1264
1265 if (subFocusItem && parent) {
1266 // Make sure none of the old parents point to this guy.
1267 subFocusItem->d_ptr->clearSubFocus(rootItem: 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(child: q);
1279 if (thisPointerVariant)
1280 parent->itemChange(change: QGraphicsItem::ItemChildRemovedChange, value: *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(item: q);
1288 } else if (!parent && newParent) {
1289 scene->d_func()->unregisterTopLevelItem(item: 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(child: fsi)) {
1303 parentFocusScopeItem = fsi;
1304 p->d_ptr->focusScopeItem = nullptr;
1305 fsi->d_ptr->focusScopeItemChange(isSubFocusItem: 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(isSubFocusItem: 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(item: q);
1359 } else if (!parent->d_func()->scene && scene) {
1360 // Remove this item from its former scene
1361 scene->removeItem(item: q);
1362 }
1363
1364 parent->d_ptr->addChild(child: q);
1365 if (thisPointerVariant)
1366 parent->itemChange(change: QGraphicsItem::ItemChildAddedChange, value: *thisPointerVariant);
1367 if (scene) {
1368 // Re-enable scene pos notifications for new ancestors
1369 if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
1370 scene->d_func()->setScenePosItemEnabled(item: q, enabled: 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(newVisible: parent->d_ptr->visible, /* explicit = */ explicitly: false, /* update = */ false);
1383 }
1384 if (parent->isEnabled() != enabled) {
1385 if (!parent->d_ptr->enabled || !explicitlyDisabled)
1386 setEnabledHelper(newEnabled: parent->d_ptr->enabled, /* explicit = */ explicitly: 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(newVisible: true, /* explicit = */ explicitly: false);
1400 if (!enabled && !explicitlyDisabled)
1401 setEnabledHelper(newEnabled: true, /* explicit = */ explicitly: 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(rootItem: newParent);
1412 if (parent && parent->isActive())
1413 subFocusItem->setFocus();
1414 }
1415
1416 // Deliver post-change notification
1417 if (newParentVariant)
1418 q->itemChange(change: QGraphicsItem::ItemParentHasChanged, value: *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*/
1429void 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(x: &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
1472void 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(t: 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(r: 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*/
1529void 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(key: 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*/
1550QGraphicsItem::QGraphicsItem(QGraphicsItem *parent)
1551 : d_ptr(new QGraphicsItemPrivate)
1552{
1553 d_ptr->q_ptr = this;
1554 setParentItem(parent);
1555}
1556
1557/*!
1558 \internal
1559*/
1560QGraphicsItem::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*/
1575QGraphicsItem::~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(ic: 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(target: 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(item: 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(key: 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*/
1658QGraphicsScene *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*/
1669QGraphicsItemGroup *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 *>(item: 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*/
1690void QGraphicsItem::setGroup(QGraphicsItemGroup *group)
1691{
1692 if (!group) {
1693 if (QGraphicsItemGroup *group = this->group())
1694 group->removeFromGroup(item: this);
1695 } else {
1696 group->addToGroup(item: 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*/
1706QGraphicsItem *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*/
1719QGraphicsItem *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*/
1735QGraphicsObject *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*/
1749QGraphicsWidget *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*/
1766QGraphicsWidget *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*/
1782QGraphicsWidget *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*/
1799QGraphicsItem *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*/
1812QGraphicsObject *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*/
1823const 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*/
1842void QGraphicsItem::setParentItem(QGraphicsItem *newParent)
1843{
1844 if (newParent == this) {
1845 qWarning(msg: "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(change: QGraphicsItem::ItemParentChange,
1852 value: QVariant::fromValue<QGraphicsItem *>(value: newParent)));
1853 newParent = qvariant_cast<QGraphicsItem *>(v: newParentVariant);
1854 if (newParent == d_ptr->parent)
1855 return;
1856
1857 const QVariant thisPointerVariant(QVariant::fromValue<QGraphicsItem *>(value: this));
1858 d_ptr->setParentItemHelper(newParent, newParentVariant: &newParentVariant, thisPointerVariant: &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*/
1880QList<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*/
1891bool 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*/
1903bool 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*/
1914bool 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*/
1928QGraphicsItem::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*/
1939void 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*/
1962void 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(change: ItemFlagsChange, value: 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(item: this, ItemFlagsChange, value: &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=*/updateChildren: 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(childFlag: 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(updateBoundingRect: 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(childFlag: 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(childFlag: 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(item: this);
2054 else
2055 d_ptr->scene->d_func()->leaveModal(item: 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(child: 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(child: 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(item: this);
2094 else
2095 d_ptr->scene->d_func()->unregisterScenePosItem(item: this);
2096 }
2097 d_ptr->scene->d_func()->markDirty(item: this, rect: QRectF(), /*invalidateChildren=*/true);
2098 }
2099
2100 // Notify change.
2101 itemChange(change: ItemFlagsHaveChanged, value: 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*/
2111QGraphicsItem::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*/
2153void 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*/
2184QGraphicsItem::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*/
2196void 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(item: this);
2205 d_ptr->panelModality = panelModality;
2206 if (enterLeaveModal && d_ptr->panelModality != NonModal)
2207 d_ptr->scene->d_func()->enterModal(item: this, panelModality: 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*/
2221bool 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(child: 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(child: this)
2251 && commonAncestorItem(other: 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*/
2267QString QGraphicsItem::toolTip() const
2268{
2269 return d_ptr->extra(type: 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*/
2278void QGraphicsItem::setToolTip(const QString &toolTip)
2279{
2280 const QVariant toolTipVariant(itemChange(change: ItemToolTipChange, value: toolTip));
2281 d_ptr->setExtra(type: QGraphicsItemPrivate::ExtraToolTip, value: toolTipVariant.toString());
2282 itemChange(change: ItemToolTipHasChanged, value: 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*/
2302QCursor QGraphicsItem::cursor() const
2303{
2304 return qvariant_cast<QCursor>(v: d_ptr->extra(type: 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*/
2322void QGraphicsItem::setCursor(const QCursor &cursor)
2323{
2324 const QVariant cursorVariant(itemChange(change: ItemCursorChange, value: QVariant::fromValue<QCursor>(value: cursor)));
2325 d_ptr->setExtra(type: QGraphicsItemPrivate::ExtraCursor, value: qvariant_cast<QCursor>(v: 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(point: view->mapToScene(point: viewPoint));
2336 // the cursor can only change if the current item is under the mouse
2337 if (boundingRect().contains(p: cursorPos)) {
2338 const auto itemsUnderCursor = view->items(pos: viewPoint);
2339 for (QGraphicsItem *itemUnderCursor : itemsUnderCursor) {
2340 if (itemUnderCursor->hasCursor()) {
2341 QMetaObject::invokeMethod(obj: view, member: "_q_setViewportCursor",
2342 Q_ARG(QCursor, itemUnderCursor->cursor()));
2343 break;
2344 }
2345 }
2346 }
2347 break;
2348 }
2349 }
2350 }
2351 itemChange(change: ItemCursorHasChanged, value: 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*/
2362bool 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*/
2372void QGraphicsItem::unsetCursor()
2373{
2374 if (!d_ptr->hasCursor)
2375 return;
2376 d_ptr->unsetExtra(type: 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(pos: view->mapFromGlobal(QCursor::pos())) == this) {
2382 QMetaObject::invokeMethod(obj: view, member: "_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*/
2399bool 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*/
2417bool 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*/
2437void 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(change: QGraphicsItem::ItemVisibleChange,
2456 value: 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 *>(v: extra(type: 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(item: q_ptr, rect: 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(t: q))
2480 q->ungrabMouse();
2481 if (scene->d_func()->keyboardGrabberItems.contains(t: q))
2482 q->ungrabKeyboard();
2483 if (q->isPanel() && panelModality != QGraphicsItem::NonModal)
2484 scene->d_func()->leaveModal(item: 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(next: true);
2494 break;
2495 }
2496 } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
2497 }
2498 if (clear)
2499 clearFocusHelper(/* giveFocusToParent = */ false, hiddenByParentPanel: 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(item: 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, explicitly: false, update: 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(child: 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(focusReason: 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(item: fi);
2562 } else if (flags & QGraphicsItem::ItemIsFocusScope &&
2563 !scene->focusItem() &&
2564 q->isAncestorOf(child: 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(focusReason: 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(change: QGraphicsItem::ItemVisibleHasChanged, value: 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*/
2625void QGraphicsItem::setVisible(bool visible)
2626{
2627 d_ptr->setVisibleHelper(newVisible: visible,
2628 /* explicit = */ explicitly: 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*/
2658bool 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*/
2669void 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(child: focusItem)) {
2689 do {
2690 if (focusItem == q_ptr) {
2691 clear = !static_cast<QGraphicsWidget *>(q_ptr)->focusNextPrevChild(next: 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(change: QGraphicsItem::ItemEnabledChange,
2705 value: 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(change: QGraphicsItem::ItemEnabledHasChanged, value: 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*/
2752void QGraphicsItem::setEnabled(bool enabled)
2753{
2754 d_ptr->setEnabledHelper(newEnabled: 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*/
2766bool 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*/
2797void 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(change: ItemSelectedChange, value: 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(change: QGraphicsItem::ItemSelectedHasChanged, value: 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*/
2850qreal 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*/
2866qreal 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*/
2897void QGraphicsItem::setOpacity(qreal opacity)
2898{
2899 // Notify change.
2900 const QVariant newOpacityVariant(itemChange(change: ItemOpacityChange, value: opacity));
2901
2902 // Normalized opacity
2903 qreal newOpacity = qBound(min: qreal(0), val: newOpacityVariant.toReal(), max: 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(change: ItemOpacityHasChanged, value: 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(reason: QGraphicsItemPrivate::OpacityChanged);
2921#endif // QT_CONFIG(graphicseffect)
2922 d_ptr->scene->d_func()->markDirty(item: this, rect: 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)
2940QGraphicsEffect *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*/
2960void 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
2983void 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*/
3006QRectF 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(sourceRect: 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(rect: sceneRect);
3019 QRect deviceEffectRect = effect->boundingRectFor(sourceRect: deviceRect).toAlignedRect();
3020 sceneEffectRect |= view->d_func()->mapRectToScene(rect: deviceEffectRect);
3021 }
3022 return q->mapRectFromScene(rect: 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*/
3038QRectF QGraphicsItemPrivate::effectiveBoundingRect(QGraphicsItem *topMostEffectItem) const
3039{
3040#if QT_CONFIG(graphicseffect)
3041 Q_Q(const QGraphicsItem);
3042 QRectF brect = effectiveBoundingRect(rect: 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(item: effectParent, rect: brect);
3053 const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(rect: brectInParentSpace);
3054 brect = effectParent->mapRectToItem(item: q, rect: 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*/
3083QRectF 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(p: 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*/
3109bool 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*/
3121void 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*/
3138Qt::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*/
3157void 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*/
3177bool 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*/
3220void 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*/
3245bool 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*/
3257void 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*/
3279bool 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*/
3295void QGraphicsItem::setFiltersChildEvents(bool enabled)
3296{
3297 if (d_ptr->filtersDescendantEvents == enabled)
3298 return;
3299
3300 d_ptr->filtersDescendantEvents = enabled;
3301 d_ptr->updateAncestorFlag(childFlag: 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*/
3321bool 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*/
3346void QGraphicsItem::setHandlesChildEvents(bool enabled)
3347{
3348 if (d_ptr->handlesChildEvents == enabled)
3349 return;
3350
3351 d_ptr->handlesChildEvents = enabled;
3352 d_ptr->updateAncestorFlag(childFlag: 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*/
3369bool 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*/
3390void 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(child: 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*/
3423bool 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*/
3457void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
3458{
3459 d_ptr->setFocusHelper(focusReason, /* climb = */ true, /* focusFromHide = */ false);
3460}
3461
3462/*!
3463 \internal
3464*/
3465void 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(isSubFocusItem: false);
3488 focusScopeItemChange(isSubFocusItem: 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(other: f);
3510 scene->focusItem()->d_ptr->clearSubFocus(rootItem: scene->focusItem(), stopItem: commonAncestor);
3511 }
3512
3513 f->d_ptr->setSubFocus(rootItem: f, stopItem: 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(item: 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*/
3536void QGraphicsItem::clearFocus()
3537{
3538 d_ptr->clearFocusHelper(/* giveFocusToParent = */ true,
3539 /* hiddenByParentPanel = */ false);
3540}
3541
3542/*!
3543 \internal
3544*/
3545void 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(isSubFocusItem: false);
3563 }
3564 if (subFocusItem->hasFocus())
3565 p->d_ptr->setFocusHelper(focusReason: 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(rootItem: q_ptr);
3578
3579 // If this item has the scene's input focus, clear it.
3580 scene->setFocusItem(item: 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*/
3592QGraphicsItem *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