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 QGuiApplication::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 QGuiApplication::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 this item.
3613
3614 \sa focusProxy(), setFocus(), hasFocus()
3615*/
3616void QGraphicsItem::setFocusProxy(QGraphicsItem *item)
3617{
3618 if (item == d_ptr->focusProxy)
3619 return;
3620 if (item == this) {
3621 qWarning(msg: "QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
3622 return;
3623 }
3624 if (item) {
3625 if (item->d_ptr->scene != d_ptr->scene) {
3626 qWarning(msg: "QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
3627 return;
3628 }
3629 for (QGraphicsItem *f = item->focusProxy(); f != nullptr; f = f->focusProxy()) {
3630 if (f == this) {
3631 qWarning(msg: "QGraphicsItem::setFocusProxy: %p is already in the focus proxy chain", item);
3632 return;
3633 }
3634 }
3635 }
3636
3637 QGraphicsItem *lastFocusProxy = d_ptr->focusProxy;
3638 if (lastFocusProxy)
3639 lastFocusProxy->d_ptr->focusProxyRefs.removeOne(t: &d_ptr->focusProxy);
3640 d_ptr->focusProxy = item;
3641 if (item)
3642 item->d_ptr->focusProxyRefs << &d_ptr->focusProxy;
3643}
3644
3645/*!
3646 \since 4.6
3647
3648 If this item, a child or descendant of this item currently has input
3649 focus, this function will return a pointer to that item. If
3650 no descendant has input focus, \nullptr is returned.
3651
3652 \sa hasFocus(), setFocus(), QWidget::focusWidget()
3653*/
3654QGraphicsItem *QGraphicsItem::focusItem() const
3655{
3656 return d_ptr->subFocusItem;
3657}
3658
3659/*!
3660 \internal
3661
3662 Returns this item's focus scope item.
3663*/
3664QGraphicsItem *QGraphicsItem::focusScopeItem() const
3665{
3666 return d_ptr->focusScopeItem;
3667}
3668
3669/*!
3670 \since 4.4
3671 Grabs the mouse input.
3672
3673 This item will receive all mouse events for the scene until any of the
3674 following events occurs:
3675
3676 \list
3677 \li The item becomes invisible
3678 \li The item is removed from the scene
3679 \li The item is deleted
3680 \li The item call ungrabMouse()
3681 \li Another item calls grabMouse(); the item will regain the mouse grab
3682 when the other item calls ungrabMouse().
3683 \endlist
3684
3685 When an item gains the mouse grab, it receives a QEvent::GrabMouse
3686 event. When it loses the mouse grab, it receives a QEvent::UngrabMouse
3687 event. These events can be used to detect when your item gains or loses
3688 the mouse grab through other means than receiving mouse button events.
3689
3690 It is almost never necessary to explicitly grab the mouse in Qt, as Qt
3691 grabs and releases it sensibly. In particular, Qt grabs the mouse when you
3692 press a mouse button, and keeps the mouse grabbed until you release the
3693 last mouse button. Also, Qt::Popup widgets implicitly call grabMouse()
3694 when shown, and ungrabMouse() when hidden.
3695
3696 Note that only visible items can grab mouse input. Calling grabMouse() on
3697 an invisible item has no effect.
3698
3699 Keyboard events are not affected.
3700
3701 \sa QGraphicsScene::mouseGrabberItem(), ungrabMouse(), grabKeyboard()
3702*/
3703void QGraphicsItem::grabMouse()
3704{
3705 if (!d_ptr->scene) {
3706 qWarning(msg: "QGraphicsItem::grabMouse: cannot grab mouse without scene");
3707 return;
3708 }
3709 if (!d_ptr->visible) {
3710 qWarning(msg: "QGraphicsItem::grabMouse: cannot grab mouse while invisible");
3711 return;
3712 }
3713 d_ptr->scene->d_func()->grabMouse(item: this);
3714}
3715
3716/*!
3717 \since 4.4
3718 Releases the mouse grab.
3719
3720 \sa grabMouse(), ungrabKeyboard()
3721*/
3722void QGraphicsItem::ungrabMouse()
3723{
3724 if (!d_ptr->scene) {
3725 qWarning(msg: "QGraphicsItem::ungrabMouse: cannot ungrab mouse without scene");
3726 return;
3727 }
3728 d_ptr->scene->d_func()->ungrabMouse(item: this);
3729}
3730
3731/*!
3732 \since 4.4
3733 Grabs the keyboard input.
3734
3735 The item will receive all keyboard input to the scene until one of the
3736 following events occur:
3737
3738 \list
3739 \li The item becomes invisible
3740 \li The item is removed from the scene
3741 \li The item is deleted
3742 \li The item calls ungrabKeyboard()
3743 \li Another item calls grabKeyboard(); the item will regain the keyboard grab
3744 when the other item calls ungrabKeyboard().
3745 \endlist
3746
3747 When an item gains the keyboard grab, it receives a QEvent::GrabKeyboard
3748 event. When it loses the keyboard grab, it receives a
3749 QEvent::UngrabKeyboard event. These events can be used to detect when your
3750 item gains or loses the keyboard grab through other means than gaining
3751 input focus.
3752
3753 It is almost never necessary to explicitly grab the keyboard in Qt, as Qt
3754 grabs and releases it sensibly. In particular, Qt grabs the keyboard when
3755 your item gains input focus, and releases it when your item loses input
3756 focus, or when the item is hidden.
3757
3758 Note that only visible items can grab keyboard input. Calling
3759 grabKeyboard() on an invisible item has no effect.
3760
3761 Keyboard events are not affected.
3762
3763 \sa ungrabKeyboard(), grabMouse(), setFocus()
3764*/
3765void QGraphicsItem::grabKeyboard()
3766{
3767 if (!d_ptr->scene) {
3768 qWarning(msg: "QGraphicsItem::grabKeyboard: cannot grab keyboard without scene");
3769 return;
3770 }
3771 if (!d_ptr->visible) {
3772 qWarning(msg: "QGraphicsItem::grabKeyboard: cannot grab keyboard while invisible");
3773 return;
3774 }
3775 d_ptr->scene->d_func()->grabKeyboard(item: this);
3776}
3777
3778/*!
3779 \since 4.4
3780 Releases the keyboard grab.
3781
3782 \sa grabKeyboard(), ungrabMouse()
3783*/
3784void QGraphicsItem::ungrabKeyboard()
3785{
3786 if (!d_ptr->scene) {
3787 qWarning(msg: "QGraphicsItem::ungrabKeyboard: cannot ungrab keyboard without scene");
3788 return;
3789 }
3790 d_ptr->scene->d_func()->ungrabKeyboard(item: this);
3791}
3792
3793/*!
3794 Returns the position of the item in parent coordinates. If the item has no
3795 parent, its position is given in scene coordinates.
3796
3797 The position of the item describes its origin (local coordinate
3798 (0, 0)) in parent coordinates; this function returns the same as
3799 mapToParent(0, 0).
3800
3801 For convenience, you can also call scenePos() to determine the
3802 item's position in scene coordinates, regardless of its parent.
3803
3804 \sa x(), y(), setPos(), transform(), {The Graphics View Coordinate System}
3805*/
3806QPointF QGraphicsItem::pos() const
3807{
3808 return d_ptr->pos;
3809}
3810
3811/*!
3812 \fn QGraphicsItem::x() const
3813
3814 This convenience function is equivalent to calling pos().x().
3815
3816 \sa y()
3817*/
3818
3819/*!
3820 \since 4.6
3821
3822 Set's the \a x coordinate of the item's position. Equivalent to
3823 calling setPos(x, y()).
3824
3825 \sa x(), setPos()
3826*/
3827void QGraphicsItem::setX(qreal x)
3828{
3829 if (d_ptr->inDestructor)
3830 return;
3831
3832 if (qIsNaN(d: x))
3833 return;
3834
3835 setPos(QPointF(x, d_ptr->pos.y()));
3836}
3837
3838/*!
3839 \fn QGraphicsItem::y() const
3840
3841 This convenience function is equivalent to calling pos().y().
3842
3843 \sa x()
3844*/
3845
3846/*!
3847 \since 4.6
3848
3849 Set's the \a y coordinate of the item's position. Equivalent to
3850 calling setPos(x(), y).
3851
3852 \sa x(), setPos()
3853*/
3854void QGraphicsItem::setY(qreal y)
3855{
3856 if (d_ptr->inDestructor)
3857 return;
3858
3859 if (qIsNaN(d: y))
3860 return;
3861
3862 setPos(QPointF(d_ptr->pos.x(), y));
3863}
3864
3865/*!
3866 Returns the item's position in scene coordinates. This is
3867 equivalent to calling \c mapToScene(0, 0).
3868
3869 \sa pos(), sceneTransform(), {The Graphics View Coordinate System}
3870*/
3871QPointF QGraphicsItem::scenePos() const
3872{
3873 return mapToScene(ax: 0, ay: 0);
3874}
3875
3876/*!
3877 \internal
3878
3879 Sets the position \a pos.
3880*/
3881void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
3882{
3883 Q_Q(QGraphicsItem);
3884 inSetPosHelper = 1;
3885 if (scene)
3886 q->prepareGeometryChange();
3887 QPointF oldPos = this->pos;
3888 this->pos = pos;
3889 dirtySceneTransform = 1;
3890 inSetPosHelper = 0;
3891 if (isObject) {
3892 if (pos.x() != oldPos.x())
3893 emit static_cast<QGraphicsObject *>(q_ptr)->xChanged();
3894 if (pos.y() != oldPos.y())
3895 emit static_cast<QGraphicsObject *>(q_ptr)->yChanged();
3896 }
3897}
3898
3899/*!
3900 \internal
3901
3902 Sets the transform \a transform.
3903*/
3904void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform)
3905{
3906 q_ptr->prepareGeometryChange();
3907 transformData->transform = transform;
3908 dirtySceneTransform = 1;
3909 transformChanged();
3910}
3911
3912/*!
3913 Sets the position of the item to \a pos, which is in parent
3914 coordinates. For items with no parent, \a pos is in scene
3915 coordinates.
3916
3917 The position of the item describes its origin (local coordinate
3918 (0, 0)) in parent coordinates.
3919
3920 \sa pos(), scenePos(), {The Graphics View Coordinate System}
3921*/
3922void QGraphicsItem::setPos(const QPointF &pos)
3923{
3924 if (d_ptr->pos == pos)
3925 return;
3926
3927 if (d_ptr->inDestructor)
3928 return;
3929
3930 // Update and repositition.
3931 if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
3932 d_ptr->setPosHelper(pos);
3933 if (d_ptr->isWidget)
3934 static_cast<QGraphicsWidget *>(this)->d_func()->setGeometryFromSetPos();
3935 if (d_ptr->scenePosDescendants)
3936 d_ptr->sendScenePosChange();
3937 return;
3938 }
3939
3940 // Notify the item that the position is changing.
3941 const QVariant newPosVariant(itemChange(change: ItemPositionChange, value: QVariant::fromValue<QPointF>(value: pos)));
3942 QPointF newPos = newPosVariant.toPointF();
3943 if (newPos == d_ptr->pos)
3944 return;
3945
3946 // Update and repositition.
3947 d_ptr->setPosHelper(newPos);
3948
3949 // Send post-notification.
3950 itemChange(change: QGraphicsItem::ItemPositionHasChanged, value: newPosVariant);
3951 d_ptr->sendScenePosChange();
3952}
3953
3954/*!
3955 \fn void QGraphicsItem::setPos(qreal x, qreal y)
3956 \overload
3957
3958 This convenience function is equivalent to calling setPos(QPointF(\a x, \a
3959 y)).
3960*/
3961
3962/*!
3963 \fn void QGraphicsItem::moveBy(qreal dx, qreal dy)
3964
3965 Moves the item by \a dx points horizontally, and \a dy point
3966 vertically. This function is equivalent to calling setPos(pos() +
3967 QPointF(\a dx, \a dy)).
3968*/
3969
3970/*!
3971 If this item is part of a scene that is viewed by a QGraphicsView, this
3972 convenience function will attempt to scroll the view to ensure that \a
3973 rect is visible inside the view's viewport. If \a rect is a null rect (the
3974 default), QGraphicsItem will default to the item's bounding rect. \a xmargin
3975 and \a ymargin are the number of pixels the view should use for margins.
3976
3977 If the specified rect cannot be reached, the contents are scrolled to the
3978 nearest valid position.
3979
3980 If this item is not viewed by a QGraphicsView, this function does nothing.
3981
3982 \sa QGraphicsView::ensureVisible()
3983*/
3984void QGraphicsItem::ensureVisible(const QRectF &rect, int xmargin, int ymargin)
3985{
3986 if (d_ptr->scene) {
3987 QRectF sceneRect;
3988 if (!rect.isNull())
3989 sceneRect = sceneTransform().mapRect(rect);
3990 else
3991 sceneRect = sceneBoundingRect();
3992 foreach (QGraphicsView *view, d_ptr->scene->d_func()->views)
3993 view->ensureVisible(rect: sceneRect, xmargin, ymargin);
3994 }
3995}
3996
3997/*!
3998 \fn void QGraphicsItem::ensureVisible(qreal x, qreal y, qreal w, qreal h,
3999 int xmargin = 50, int ymargin = 50)
4000
4001 This convenience function is equivalent to calling
4002 ensureVisible(QRectF(\a x, \a y, \a w, \a h), \a xmargin, \a ymargin).
4003*/
4004
4005#if QT_DEPRECATED_SINCE(5, 13)
4006/*!
4007 \obsolete
4008
4009 Returns the item's affine transformation matrix. This is a subset or the
4010 item's full transformation matrix, and might not represent the item's full
4011 transformation.
4012
4013 Use transform() instead.
4014
4015 \sa setTransform(), sceneTransform()
4016*/
4017QMatrix QGraphicsItem::matrix() const
4018{
4019 return transform().toAffine();
4020}
4021#endif
4022
4023/*!
4024 \since 4.3
4025
4026 Returns this item's transformation matrix.
4027
4028 The transformation matrix is combined with the item's rotation(), scale()
4029 and transformations() into a combined transformations for the item.
4030
4031 The default transformation matrix is an identity matrix.
4032
4033 \sa setTransform(), sceneTransform()
4034*/
4035QTransform QGraphicsItem::transform() const
4036{
4037 if (!d_ptr->transformData)
4038 return QTransform();
4039 return d_ptr->transformData->transform;
4040}
4041
4042/*!
4043 \since 4.6
4044
4045 Returns the clockwise rotation, in degrees, around the Z axis. The default
4046 value is 0 (i.e., the item is not rotated).
4047
4048 The rotation is combined with the item's scale(), transform() and
4049 transformations() to map the item's coordinate system to the parent item.
4050
4051 \sa setRotation(), transformOriginPoint(), {Transformations}
4052*/
4053qreal QGraphicsItem::rotation() const
4054{
4055 if (!d_ptr->transformData)
4056 return 0;
4057 return d_ptr->transformData->rotation;
4058}
4059
4060/*!
4061 \since 4.6
4062
4063 Sets the clockwise rotation \a angle, in degrees, around the Z axis. The
4064 default value is 0 (i.e., the item is not rotated). Assigning a negative
4065 value will rotate the item counter-clockwise. Normally the rotation angle
4066 is in the range (-360, 360), but it's also possible to assign values
4067 outside of this range (e.g., a rotation of 370 degrees is the same as a
4068 rotation of 10 degrees).
4069
4070 The item is rotated around its transform origin point, which by default
4071 is (0, 0). You can select a different transformation origin by calling
4072 setTransformOriginPoint().
4073
4074 The rotation is combined with the item's scale(), transform() and
4075 transformations() to map the item's coordinate system to the parent item.
4076
4077 \sa rotation(), setTransformOriginPoint(), {Transformations}
4078*/
4079void QGraphicsItem::setRotation(qreal angle)
4080{
4081 prepareGeometryChange();
4082 qreal newRotation = angle;
4083
4084 if (d_ptr->flags & ItemSendsGeometryChanges) {
4085 // Notify the item that the rotation is changing.
4086 const QVariant newRotationVariant(itemChange(change: ItemRotationChange, value: angle));
4087 newRotation = newRotationVariant.toReal();
4088 }
4089
4090 if (!d_ptr->transformData)
4091 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4092
4093 if (d_ptr->transformData->rotation == newRotation)
4094 return;
4095
4096 d_ptr->transformData->rotation = newRotation;
4097 d_ptr->transformData->onlyTransform = false;
4098 d_ptr->dirtySceneTransform = 1;
4099
4100 // Send post-notification.
4101 if (d_ptr->flags & ItemSendsGeometryChanges)
4102 itemChange(change: ItemRotationHasChanged, value: newRotation);
4103
4104 if (d_ptr->isObject)
4105 emit static_cast<QGraphicsObject *>(this)->rotationChanged();
4106
4107 d_ptr->transformChanged();
4108}
4109
4110/*!
4111 \since 4.6
4112
4113 Returns the scale factor of the item. The default scale factor is 1.0
4114 (i.e., the item is not scaled).
4115
4116 The scale is combined with the item's rotation(), transform() and
4117 transformations() to map the item's coordinate system to the parent item.
4118
4119 \sa setScale(), rotation(), {Transformations}
4120*/
4121qreal QGraphicsItem::scale() const
4122{
4123 if (!d_ptr->transformData)
4124 return 1.;
4125 return d_ptr->transformData->scale;
4126}
4127
4128/*!
4129 \since 4.6
4130
4131 Sets the scale \a factor of the item. The default scale factor is 1.0
4132 (i.e., the item is not scaled). A scale factor of 0.0 will collapse the
4133 item to a single point. If you provide a negative scale factor, the
4134 item will be flipped and mirrored (i.e., rotated 180 degrees).
4135
4136 The item is scaled around its transform origin point, which by default
4137 is (0, 0). You can select a different transformation origin by calling
4138 setTransformOriginPoint().
4139
4140 The scale is combined with the item's rotation(), transform() and
4141 transformations() to map the item's coordinate system to the parent item.
4142
4143 \sa scale(), setTransformOriginPoint(), {Transformations Example}
4144*/
4145void QGraphicsItem::setScale(qreal factor)
4146{
4147 prepareGeometryChange();
4148 qreal newScale = factor;
4149
4150 if (d_ptr->flags & ItemSendsGeometryChanges) {
4151 // Notify the item that the scale is changing.
4152 const QVariant newScaleVariant(itemChange(change: ItemScaleChange, value: factor));
4153 newScale = newScaleVariant.toReal();
4154 }
4155
4156 if (!d_ptr->transformData)
4157 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4158
4159 if (d_ptr->transformData->scale == newScale)
4160 return;
4161
4162 d_ptr->transformData->scale = newScale;
4163 d_ptr->transformData->onlyTransform = false;
4164 d_ptr->dirtySceneTransform = 1;
4165
4166 // Send post-notification.
4167 if (d_ptr->flags & ItemSendsGeometryChanges)
4168 itemChange(change: ItemScaleHasChanged, value: newScale);
4169
4170 if (d_ptr->isObject)
4171 emit static_cast<QGraphicsObject *>(this)->scaleChanged();
4172
4173 d_ptr->transformChanged();
4174}
4175
4176
4177/*!
4178 \since 4.6
4179
4180 Returns a list of graphics transforms that currently apply to this item.
4181
4182 QGraphicsTransform is for applying and controlling a chain of individual
4183 transformation operations on an item. It's particularly useful in
4184 animations, where each transform operation needs to be interpolated
4185 independently, or differently.
4186
4187 The transformations are combined with the item's rotation(), scale() and
4188 transform() to map the item's coordinate system to the parent item.
4189
4190 \sa scale(), rotation(), transformOriginPoint(), {Transformations}
4191*/
4192QList<QGraphicsTransform *> QGraphicsItem::transformations() const
4193{
4194 if (!d_ptr->transformData)
4195 return QList<QGraphicsTransform *>();
4196 return d_ptr->transformData->graphicsTransforms;
4197}
4198
4199/*!
4200 \since 4.6
4201
4202 Sets a list of graphics \a transformations (QGraphicsTransform) that
4203 currently apply to this item.
4204
4205 If all you want is to rotate or scale an item, you should call setRotation()
4206 or setScale() instead. If you want to set an arbitrary transformation on
4207 an item, you can call setTransform().
4208
4209 QGraphicsTransform is for applying and controlling a chain of individual
4210 transformation operations on an item. It's particularly useful in
4211 animations, where each transform operation needs to be interpolated
4212 independently, or differently.
4213
4214 The transformations are combined with the item's rotation(), scale() and
4215 transform() to map the item's coordinate system to the parent item.
4216
4217 \sa scale(), setTransformOriginPoint(), {Transformations}
4218*/
4219void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transformations)
4220{
4221 prepareGeometryChange();
4222 if (!d_ptr->transformData)
4223 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4224 d_ptr->transformData->graphicsTransforms = transformations;
4225 for (int i = 0; i < transformations.size(); ++i)
4226 transformations.at(i)->d_func()->setItem(this);
4227 d_ptr->transformData->onlyTransform = false;
4228 d_ptr->dirtySceneTransform = 1;
4229 d_ptr->transformChanged();
4230}
4231
4232/*!
4233 \internal
4234*/
4235void QGraphicsItemPrivate::prependGraphicsTransform(QGraphicsTransform *t)
4236{
4237 if (!transformData)
4238 transformData = new QGraphicsItemPrivate::TransformData;
4239 if (!transformData->graphicsTransforms.contains(t))
4240 transformData->graphicsTransforms.prepend(t);
4241
4242 Q_Q(QGraphicsItem);
4243 t->d_func()->setItem(q);
4244 transformData->onlyTransform = false;
4245 dirtySceneTransform = 1;
4246 transformChanged();
4247}
4248
4249/*!
4250 \internal
4251*/
4252void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t)
4253{
4254 if (!transformData)
4255 transformData = new QGraphicsItemPrivate::TransformData;
4256 if (!transformData->graphicsTransforms.contains(t))
4257 transformData->graphicsTransforms.append(t);
4258
4259 Q_Q(QGraphicsItem);
4260 t->d_func()->setItem(q);
4261 transformData->onlyTransform = false;
4262 dirtySceneTransform = 1;
4263 transformChanged();
4264}
4265
4266/*!
4267 \since 4.6
4268
4269 Returns the origin point for the transformation in item coordinates.
4270
4271 The default is QPointF(0,0).
4272
4273 \sa setTransformOriginPoint(), {Transformations}
4274*/
4275QPointF QGraphicsItem::transformOriginPoint() const
4276{
4277 if (!d_ptr->transformData)
4278 return QPointF(0,0);
4279 return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin);
4280}
4281
4282/*!
4283 \since 4.6
4284
4285 Sets the \a origin point for the transformation in item coordinates.
4286
4287 \sa transformOriginPoint(), {Transformations}
4288*/
4289void QGraphicsItem::setTransformOriginPoint(const QPointF &origin)
4290{
4291 prepareGeometryChange();
4292 QPointF newOrigin = origin;
4293
4294 if (d_ptr->flags & ItemSendsGeometryChanges) {
4295 // Notify the item that the origin point is changing.
4296 const QVariant newOriginVariant(itemChange(change: ItemTransformOriginPointChange,
4297 value: QVariant::fromValue<QPointF>(value: origin)));
4298 newOrigin = newOriginVariant.toPointF();
4299 }
4300
4301 if (!d_ptr->transformData)
4302 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4303
4304 if (d_ptr->transformData->xOrigin == newOrigin.x()
4305 && d_ptr->transformData->yOrigin == newOrigin.y()) {
4306 return;
4307 }
4308
4309 d_ptr->transformData->xOrigin = newOrigin.x();
4310 d_ptr->transformData->yOrigin = newOrigin.y();
4311 d_ptr->transformData->onlyTransform = false;
4312 d_ptr->dirtySceneTransform = 1;
4313
4314 // Send post-notification.
4315 if (d_ptr->flags & ItemSendsGeometryChanges)
4316 itemChange(change: ItemTransformOriginPointHasChanged, value: QVariant::fromValue<QPointF>(value: newOrigin));
4317}
4318
4319/*!
4320 \fn void QGraphicsItem::setTransformOriginPoint(qreal x, qreal y)
4321
4322 \since 4.6
4323 \overload
4324
4325 Sets the origin point for the transformation in item coordinates.
4326 This is equivalent to calling setTransformOriginPoint(QPointF(\a x, \a y)).
4327
4328 \sa setTransformOriginPoint(), {Transformations}
4329*/
4330
4331
4332#if QT_DEPRECATED_SINCE(5, 13)
4333/*!
4334 \obsolete
4335
4336 Use sceneTransform() instead.
4337
4338 \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
4339*/
4340QMatrix QGraphicsItem::sceneMatrix() const
4341{
4342 d_ptr->ensureSceneTransform();
4343 return d_ptr->sceneTransform.toAffine();
4344}
4345#endif
4346
4347/*!
4348 \since 4.3
4349
4350 Returns this item's scene transformation matrix. This matrix can be used
4351 to map coordinates and geometrical shapes from this item's local
4352 coordinate system to the scene's coordinate system. To map coordinates
4353 from the scene, you must first invert the returned matrix.
4354
4355 Example:
4356
4357 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 4
4358
4359 Unlike transform(), which returns only an item's local transformation, this
4360 function includes the item's (and any parents') position, and all the transfomation properties.
4361
4362 \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations}
4363*/
4364QTransform QGraphicsItem::sceneTransform() const
4365{
4366 d_ptr->ensureSceneTransform();
4367 return d_ptr->sceneTransform;
4368}
4369
4370/*!
4371 \since 4.3
4372
4373 Returns this item's device transformation matrix, using \a
4374 viewportTransform to map from scene to device coordinates. This matrix can
4375 be used to map coordinates and geometrical shapes from this item's local
4376 coordinate system to the viewport's (or any device's) coordinate
4377 system. To map coordinates from the viewport, you must first invert the
4378 returned matrix.
4379
4380 Example:
4381
4382 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 5
4383
4384 This function is the same as combining this item's scene transform with
4385 the view's viewport transform, but it also understands the
4386 ItemIgnoresTransformations flag. The device transform can be used to do
4387 accurate coordinate mapping (and collision detection) for untransformable
4388 items.
4389
4390 \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate
4391 System}, itemTransform()
4392*/
4393QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const
4394{
4395 // Ensure we return the standard transform if we're not untransformable.
4396 if (!d_ptr->itemIsUntransformable()) {
4397 d_ptr->ensureSceneTransform();
4398 return d_ptr->sceneTransform * viewportTransform;
4399 }
4400
4401 // Find the topmost item that ignores view transformations.
4402 const QGraphicsItem *untransformedAncestor = this;
4403 QList<const QGraphicsItem *> parents;
4404 while (untransformedAncestor && ((untransformedAncestor->d_ptr->ancestorFlags
4405 & QGraphicsItemPrivate::AncestorIgnoresTransformations))) {
4406 parents.prepend(t: untransformedAncestor);
4407 untransformedAncestor = untransformedAncestor->parentItem();
4408 }
4409
4410 if (!untransformedAncestor) {
4411 // Assert in debug mode, continue in release.
4412 Q_ASSERT_X(untransformedAncestor, "QGraphicsItem::deviceTransform",
4413 "Invalid object structure!");
4414 return QTransform();
4415 }
4416
4417 // Determine the inherited origin. Find the parent of the topmost untransformable.
4418 // Use its scene transform to map the position of the untransformable. Then use
4419 // that viewport position as the anchoring point for the untransformable subtree.
4420 QGraphicsItem *parentOfUntransformedAncestor = untransformedAncestor->parentItem();
4421 QTransform inheritedMatrix;
4422 if (parentOfUntransformedAncestor)
4423 inheritedMatrix = parentOfUntransformedAncestor->sceneTransform();
4424 QPointF mappedPoint = (inheritedMatrix * viewportTransform).map(p: untransformedAncestor->pos());
4425
4426 // COMBINE
4427 QTransform matrix = QTransform::fromTranslate(dx: mappedPoint.x(), dy: mappedPoint.y());
4428 if (untransformedAncestor->d_ptr->transformData)
4429 matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(postmultiplyTransform: &matrix);
4430
4431 // Then transform and translate all children.
4432 for (int i = 0; i < parents.size(); ++i) {
4433 const QGraphicsItem *parent = parents.at(i);
4434 parent->d_ptr->combineTransformFromParent(x: &matrix);
4435 }
4436
4437 return matrix;
4438}
4439
4440/*!
4441 \since 4.5
4442
4443 Returns a QTransform that maps coordinates from this item to \a other. If
4444 \a ok is not null, and if there is no such transform, the boolean pointed
4445 to by \a ok will be set to false; otherwise it will be set to true.
4446
4447 This transform provides an alternative to the mapToItem() or mapFromItem()
4448 functions, by returning the appropriate transform so that you can map
4449 shapes and coordinates yourself. It also helps you write more efficient
4450 code when repeatedly mapping between the same two items.
4451
4452 \note In rare circumstances, there is no transform that maps between two
4453 items.
4454
4455 \sa mapToItem(), mapFromItem(), deviceTransform()
4456*/
4457QTransform QGraphicsItem::itemTransform(const QGraphicsItem *other, bool *ok) const
4458{
4459 // Catch simple cases first.
4460 if (other == nullptr) {
4461 qWarning(msg: "QGraphicsItem::itemTransform: null pointer passed");
4462 return QTransform();
4463 }
4464 if (other == this) {
4465 if (ok)
4466 *ok = true;
4467 return QTransform();
4468 }
4469
4470 QGraphicsItem *parent = d_ptr->parent;
4471 const QGraphicsItem *otherParent = other->d_ptr->parent;
4472
4473 // This is other's child
4474 if (parent == other) {
4475 if (ok)
4476 *ok = true;
4477 QTransform x;
4478 d_ptr->combineTransformFromParent(x: &x);
4479 return x;
4480 }
4481
4482 // This is other's parent
4483 if (otherParent == this) {
4484 const QPointF &otherPos = other->d_ptr->pos;
4485 if (other->d_ptr->transformData) {
4486 QTransform otherToParent;
4487 other->d_ptr->combineTransformFromParent(x: &otherToParent);
4488 return otherToParent.inverted(invertible: ok);
4489 }
4490 if (ok)
4491 *ok = true;
4492 return QTransform::fromTranslate(dx: -otherPos.x(), dy: -otherPos.y());
4493 }
4494
4495 // Siblings
4496 if (parent == otherParent) {
4497 // COMBINE
4498 const QPointF &itemPos = d_ptr->pos;
4499 const QPointF &otherPos = other->d_ptr->pos;
4500 if (!d_ptr->transformData && !other->d_ptr->transformData) {
4501 QPointF delta = itemPos - otherPos;
4502 if (ok)
4503 *ok = true;
4504 return QTransform::fromTranslate(dx: delta.x(), dy: delta.y());
4505 }
4506
4507 QTransform itemToParent;
4508 d_ptr->combineTransformFromParent(x: &itemToParent);
4509 QTransform otherToParent;
4510 other->d_ptr->combineTransformFromParent(x: &otherToParent);
4511 return itemToParent * otherToParent.inverted(invertible: ok);
4512 }
4513
4514 // Find the closest common ancestor. If the two items don't share an
4515 // ancestor, then the only way is to combine their scene transforms.
4516 const QGraphicsItem *commonAncestor = commonAncestorItem(other);
4517 if (!commonAncestor) {
4518 d_ptr->ensureSceneTransform();
4519 other->d_ptr->ensureSceneTransform();
4520 return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(invertible: ok);
4521 }
4522
4523 // If the two items are cousins (in sibling branches), map both to the
4524 // common ancestor, and combine the two transforms.
4525 bool cousins = other != commonAncestor && this != commonAncestor;
4526 if (cousins) {
4527 bool good = false;
4528 QTransform thisToScene = itemTransform(other: commonAncestor, ok: &good);
4529 QTransform otherToScene(Qt::Uninitialized);
4530 if (good)
4531 otherToScene = other->itemTransform(other: commonAncestor, ok: &good);
4532 if (!good) {
4533 if (ok)
4534 *ok = false;
4535 return QTransform();
4536 }
4537 return thisToScene * otherToScene.inverted(invertible: ok);
4538 }
4539
4540 // One is an ancestor of the other; walk the chain.
4541 bool parentOfOther = isAncestorOf(child: other);
4542 const QGraphicsItem *child = parentOfOther ? other : this;
4543 const QGraphicsItem *root = parentOfOther ? this : other;
4544
4545 QTransform x;
4546 const QGraphicsItem *p = child;
4547 do {
4548 p->d_ptr.data()->combineTransformToParent(x: &x);
4549 } while ((p = p->d_ptr->parent) && p != root);
4550 if (parentOfOther)
4551 return x.inverted(invertible: ok);
4552 if (ok)
4553 *ok = true;
4554 return x;
4555}
4556
4557#if QT_DEPRECATED_SINCE(5, 13)
4558QT_WARNING_PUSH
4559QT_WARNING_DISABLE_DEPRECATED
4560/*!
4561 \obsolete
4562
4563 Sets the item's affine transformation matrix. This is a subset or the
4564 item's full transformation matrix, and might not represent the item's full
4565 transformation.
4566
4567 Use setTransform() instead.
4568
4569 \sa transform(), {The Graphics View Coordinate System}
4570*/
4571void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
4572{
4573 if (!d_ptr->transformData)
4574 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4575
4576 QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix));
4577 if (d_ptr->transformData->transform == newTransform)
4578 return;
4579
4580 // Update and set the new transformation.
4581 if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
4582 d_ptr->setTransformHelper(newTransform);
4583 return;
4584 }
4585
4586 // Notify the item that the transformation matrix is changing.
4587 const QVariant newMatrixVariant = QVariant::fromValue<QMatrix>(value: newTransform.toAffine());
4588 newTransform = QTransform(qvariant_cast<QMatrix>(v: itemChange(change: ItemMatrixChange, value: newMatrixVariant)));
4589 if (d_ptr->transformData->transform == newTransform)
4590 return;
4591
4592 // Update and set the new transformation.
4593 d_ptr->setTransformHelper(newTransform);
4594
4595 // Send post-notification.
4596 itemChange(change: ItemTransformHasChanged, value: QVariant::fromValue<QTransform>(value: newTransform));
4597}
4598QT_WARNING_POP
4599#endif
4600
4601/*!
4602 \since 4.3
4603
4604 Sets the item's current transformation matrix to \a matrix.
4605
4606 If \a combine is true, then \a matrix is combined with the current matrix;
4607 otherwise, \a matrix \e replaces the current matrix. \a combine is false
4608 by default.
4609
4610 To simplify interaction with items using a transformed view, QGraphicsItem
4611 provides mapTo... and mapFrom... functions that can translate between
4612 items' and the scene's coordinates. For example, you can call mapToScene()
4613 to map an item coordiate to a scene coordinate, or mapFromScene() to map
4614 from scene coordinates to item coordinates.
4615
4616 The transformation matrix is combined with the item's rotation(), scale()
4617 and transformations() into a combined transformation that maps the item's
4618 coordinate system to its parent.
4619
4620 \sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations}
4621*/
4622void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
4623{
4624 if (!d_ptr->transformData)
4625 d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
4626
4627 QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix);
4628 if (d_ptr->transformData->transform == newTransform)
4629 return;
4630
4631 // Update and set the new transformation.
4632 if (!(d_ptr->flags & (ItemSendsGeometryChanges | ItemSendsScenePositionChanges))) {
4633 d_ptr->setTransformHelper(newTransform);
4634 if (d_ptr->scenePosDescendants)
4635 d_ptr->sendScenePosChange();
4636 return;
4637 }
4638
4639 // Notify the item that the transformation matrix is changing.
4640 const QVariant newTransformVariant(itemChange(change: ItemTransformChange,
4641 value: QVariant::fromValue<QTransform>(value: newTransform)));
4642 newTransform = qvariant_cast<QTransform>(v: newTransformVariant);
4643 if (d_ptr->transformData->transform == newTransform)
4644 return;
4645
4646 // Update and set the new transformation.
4647 d_ptr->setTransformHelper(newTransform);
4648
4649 // Send post-notification.
4650 itemChange(change: ItemTransformHasChanged, value: newTransformVariant);
4651 d_ptr->sendScenePosChange();
4652}
4653
4654#if QT_DEPRECATED_SINCE(5, 13)
4655/*!
4656 \obsolete
4657
4658 Use resetTransform() instead.
4659*/
4660void QGraphicsItem::resetMatrix()
4661{
4662 resetTransform();
4663}
4664#endif
4665
4666/*!
4667 \since 4.3
4668
4669 Resets this item's transformation matrix to the identity matrix or
4670 all the transformation properties to their default values.
4671 This is equivalent to calling \c setTransform(QTransform()).
4672
4673 \sa setTransform(), transform()
4674*/
4675void QGraphicsItem::resetTransform()
4676{
4677 setTransform(matrix: QTransform(), combine: false);
4678}
4679
4680/*!
4681 \fn void QGraphicsItem::rotate(qreal angle)
4682 \obsolete
4683
4684 Use
4685
4686 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 20
4687
4688 instead.
4689
4690 Rotates the current item transformation \a angle degrees clockwise around
4691 its origin. To translate around an arbitrary point (x, y), you need to
4692 combine translation and rotation with setTransform().
4693
4694 Example:
4695
4696 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 6
4697
4698 \sa setTransform(), transform(), scale(), shear(), translate()
4699*/
4700
4701/*!
4702 \fn void QGraphicsItem::scale(qreal sx, qreal sy)
4703 \obsolete
4704
4705 Use
4706
4707 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 21
4708
4709 instead.
4710
4711 Scales the current item transformation by (\a sx, \a sy) around its
4712 origin. To scale from an arbitrary point (x, y), you need to combine
4713 translation and scaling with setTransform().
4714
4715 Example:
4716
4717 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 7
4718
4719 \sa setTransform(), transform()
4720*/
4721
4722/*!
4723 \fn void QGraphicsItem::shear(qreal sh, qreal sv)
4724 \obsolete
4725
4726 Use
4727
4728 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 22
4729
4730 instead.
4731
4732 Shears the current item transformation by (\a sh, \a sv).
4733
4734 \sa setTransform(), transform()
4735*/
4736
4737/*!
4738 \fn void QGraphicsItem::translate(qreal dx, qreal dy)
4739 \obsolete
4740
4741 Use setPos() or setTransformOriginPoint() instead. For identical
4742 behavior, use
4743
4744 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 23
4745
4746 Translates the current item transformation by (\a dx, \a dy).
4747
4748 If all you want is to move an item, you should call moveBy() or
4749 setPos() instead; this function changes the item's translation,
4750 which is conceptually separate from its position.
4751
4752 \sa setTransform(), transform()
4753*/
4754
4755/*!
4756 This virtual function is called twice for all items by the
4757 QGraphicsScene::advance() slot. In the first phase, all items are called
4758 with \a phase == 0, indicating that items on the scene are about to
4759 advance, and then all items are called with \a phase == 1. Reimplement
4760 this function to update your item if you need simple scene-controlled
4761 animation.
4762
4763 The default implementation does nothing.
4764
4765 This function is intended for animations. An alternative is to
4766 multiple-inherit from QObject and QGraphicsItem and use the \l{The Animation
4767 Framework}{Animation Framework}.
4768
4769 \sa QGraphicsScene::advance(), QTimeLine
4770*/
4771void QGraphicsItem::advance(int phase)
4772{
4773 Q_UNUSED(phase);
4774}
4775
4776/*!
4777 Returns the Z-value of the item. The Z-value affects the stacking order of
4778 sibling (neighboring) items.
4779
4780 The default Z-value is 0.
4781
4782 \sa setZValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
4783*/
4784qreal QGraphicsItem::zValue() const
4785{
4786 return d_ptr->z;
4787}
4788
4789/*!
4790 Sets the Z-value of the item to \a z. The Z value decides the stacking
4791 order of sibling (neighboring) items. A sibling item of high Z value will
4792 always be drawn on top of another sibling item with a lower Z value.
4793
4794 If you restore the Z value, the item's insertion order will decide its
4795 stacking order.
4796
4797 The Z-value does not affect the item's size in any way.
4798
4799 The default Z-value is 0.
4800
4801 \sa zValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
4802*/
4803void QGraphicsItem::setZValue(qreal z)
4804{
4805 const QVariant newZVariant(itemChange(change: ItemZValueChange, value: z));
4806 qreal newZ = newZVariant.toReal();
4807 if (newZ == d_ptr->z)
4808 return;
4809
4810 if (d_ptr->scene && d_ptr->scene->d_func()->indexMethod != QGraphicsScene::NoIndex) {
4811 // Z Value has changed, we have to notify the index.
4812 d_ptr->scene->d_func()->index->itemChange(item: this, ItemZValueChange, value: &newZ);
4813 }
4814
4815 d_ptr->z = newZ;
4816 if (d_ptr->parent)
4817 d_ptr->parent->d_ptr->needSortChildren = 1;
4818 else if (d_ptr->scene)
4819 d_ptr->scene->d_func()->needSortTopLevelItems = 1;
4820
4821 if (d_ptr->scene)
4822 d_ptr->scene->d_func()->markDirty(item: this, rect: QRectF(), /*invalidateChildren=*/true);
4823
4824 itemChange(change: ItemZValueHasChanged, value: newZVariant);
4825
4826 if (d_ptr->flags & ItemNegativeZStacksBehindParent)
4827 setFlag(flag: QGraphicsItem::ItemStacksBehindParent, enabled: z < qreal(0.0));
4828
4829 if (d_ptr->isObject)
4830 emit static_cast<QGraphicsObject *>(this)->zChanged();
4831}
4832
4833/*!
4834 \internal
4835
4836 Ensures that the list of children is sorted by insertion order, and that
4837 the siblingIndexes are packed (no gaps), and start at 0.
4838
4839 ### This function is almost identical to
4840 QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes().
4841*/
4842void QGraphicsItemPrivate::ensureSequentialSiblingIndex()
4843{
4844 if (!sequentialOrdering) {
4845 std::sort(first: children.begin(), last: children.end(), comp: insertionOrder);
4846 sequentialOrdering = 1;
4847 needSortChildren = 1;
4848 }
4849 if (holesInSiblingIndex) {
4850 holesInSiblingIndex = 0;
4851 for (int i = 0; i < children.size(); ++i)
4852 children[i]->d_ptr->siblingIndex = i;
4853 }
4854}
4855
4856/*!
4857 \internal
4858*/
4859inline void QGraphicsItemPrivate::sendScenePosChange()
4860{
4861 Q_Q(QGraphicsItem);
4862 if (scene) {
4863 if (flags & QGraphicsItem::ItemSendsScenePositionChanges)
4864 q->itemChange(change: QGraphicsItem::ItemScenePositionHasChanged, value: q->scenePos());
4865 if (scenePosDescendants) {
4866 foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) {
4867 if (q->isAncestorOf(child: item))
4868 item->itemChange(change: QGraphicsItem::ItemScenePositionHasChanged, value: item->scenePos());
4869 }
4870 }
4871 }
4872}
4873
4874/*!
4875 \since 4.6
4876
4877 Stacks this item before \a sibling, which must be a sibling item (i.e., the
4878 two items must share the same parent item, or must both be toplevel items).
4879 The \a sibling must have the same Z value as this item, otherwise calling
4880 this function will have no effect.
4881
4882 By default, all sibling items are stacked by insertion order (i.e., the
4883 first item you add is drawn before the next item you add). If two items' Z
4884 values are different, then the item with the highest Z value is drawn on
4885 top. When the Z values are the same, the insertion order will decide the
4886 stacking order.
4887
4888 \sa setZValue(), ItemStacksBehindParent, {QGraphicsItem#Sorting}{Sorting}
4889*/
4890void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
4891{
4892 if (sibling == this)
4893 return;
4894 if (!sibling || d_ptr->parent != sibling->parentItem()) {
4895 qWarning(msg: "QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
4896 return;
4897 }
4898 QList<QGraphicsItem *> *siblings = d_ptr->parent
4899 ? &d_ptr->parent->d_ptr->children
4900 : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : nullptr);
4901 if (!siblings) {
4902 qWarning(msg: "QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
4903 return;
4904 }
4905
4906 // First, make sure that the sibling indexes have no holes. This also
4907 // marks the children list for sorting.
4908 if (d_ptr->parent)
4909 d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
4910 else
4911 d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
4912
4913 // Only move items with the same Z value, and that need moving.
4914 int siblingIndex = sibling->d_ptr->siblingIndex;
4915 int myIndex = d_ptr->siblingIndex;
4916 if (myIndex >= siblingIndex) {
4917 siblings->move(from: myIndex, to: siblingIndex);
4918 // Fixup the insertion ordering.
4919 for (int i = 0; i < siblings->size(); ++i) {
4920 int &index = siblings->at(i)->d_ptr->siblingIndex;
4921 if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
4922 ++index;
4923 }
4924 d_ptr->siblingIndex = siblingIndex;
4925 for (int i = 0; i < siblings->size(); ++i) {
4926 int &index = siblings->at(i)->d_ptr->siblingIndex;
4927 if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
4928 siblings->at(i)->d_ptr->siblingOrderChange();
4929 }
4930 d_ptr->siblingOrderChange();
4931 }
4932}
4933
4934/*!
4935 Returns the bounding rect of this item's descendants (i.e., its
4936 children, their children, etc.) in local coordinates. The
4937 rectangle will contain all descendants after they have been mapped
4938 to local coordinates. If the item has no children, this function
4939 returns an empty QRectF.
4940
4941 This does not include this item's own bounding rect; it only returns
4942 its descendants' accumulated bounding rect. If you need to include this
4943 item's bounding rect, you can add boundingRect() to childrenBoundingRect()
4944 using QRectF::operator|().
4945
4946 This function is linear in complexity; it determines the size of the
4947 returned bounding rect by iterating through all descendants.
4948
4949 \sa boundingRect(), sceneBoundingRect()
4950*/
4951QRectF QGraphicsItem::childrenBoundingRect() const
4952{
4953 if (!d_ptr->dirtyChildrenBoundingRect)
4954 return d_ptr->childrenBoundingRect;
4955
4956 d_ptr->childrenBoundingRect = QRectF();
4957 d_ptr->childrenBoundingRectHelper(x: nullptr, rect: &d_ptr->childrenBoundingRect, topMostEffectItem: nullptr);
4958 d_ptr->dirtyChildrenBoundingRect = 0;
4959 return d_ptr->childrenBoundingRect;
4960}
4961
4962/*!
4963 \fn virtual QRectF QGraphicsItem::boundingRect() const = 0
4964
4965 This pure virtual function defines the outer bounds of the item as
4966 a rectangle; all painting must be restricted to inside an item's
4967 bounding rect. QGraphicsView uses this to determine whether the
4968 item requires redrawing.
4969
4970 Although the item's shape can be arbitrary, the bounding rect is
4971 always rectangular, and it is unaffected by the items'
4972 transformation.
4973
4974 If you want to change the item's bounding rectangle, you must first call
4975 prepareGeometryChange(). This notifies the scene of the imminent change,
4976 so that it can update its item geometry index; otherwise, the scene will
4977 be unaware of the item's new geometry, and the results are undefined
4978 (typically, rendering artifacts are left within the view).
4979
4980 Reimplement this function to let QGraphicsView determine what
4981 parts of the widget, if any, need to be redrawn.
4982
4983 Note: For shapes that paint an outline / stroke, it is important
4984 to include half the pen width in the bounding rect. It is not
4985 necessary to compensate for antialiasing, though.
4986
4987 Example:
4988
4989 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 8
4990
4991 \sa boundingRegion(), shape(), contains(), {The Graphics View Coordinate
4992 System}, prepareGeometryChange()
4993*/
4994
4995/*!
4996 Returns the bounding rect of this item in scene coordinates, by combining
4997 sceneTransform() with boundingRect().
4998
4999 \sa boundingRect(), {The Graphics View Coordinate System}
5000*/
5001QRectF QGraphicsItem::sceneBoundingRect() const
5002{
5003 // Find translate-only offset
5004 // COMBINE
5005 QPointF offset;
5006 const QGraphicsItem *parentItem = this;
5007 const QGraphicsItemPrivate *itemd;
5008 do {
5009 itemd = parentItem->d_ptr.data();
5010 if (itemd->transformData)
5011 break;
5012 offset += itemd->pos;
5013 } while ((parentItem = itemd->parent));
5014
5015 QRectF br = boundingRect();
5016 br.translate(p: offset);
5017 if (!parentItem)
5018 return br;
5019 if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) {
5020 br.translate(dx: parentItem->d_ptr->sceneTransform.dx(), dy: parentItem->d_ptr->sceneTransform.dy());
5021 return br;
5022 }
5023 return parentItem->d_ptr->sceneTransform.mapRect(br);
5024}
5025
5026/*!
5027 Returns the shape of this item as a QPainterPath in local
5028 coordinates. The shape is used for many things, including collision
5029 detection, hit tests, and for the QGraphicsScene::items() functions.
5030
5031 The default implementation calls boundingRect() to return a simple
5032 rectangular shape, but subclasses can reimplement this function to return
5033 a more accurate shape for non-rectangular items. For example, a round item
5034 may choose to return an elliptic shape for better collision detection. For
5035 example:
5036
5037 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 9
5038
5039 The outline of a shape can vary depending on the width and style of the
5040 pen used when drawing. If you want to include this outline in the item's
5041 shape, you can create a shape from the stroke using QPainterPathStroker.
5042
5043 This function is called by the default implementations of contains() and
5044 collidesWithPath().
5045
5046 \sa boundingRect(), contains(), prepareGeometryChange(), QPainterPathStroker
5047*/
5048QPainterPath QGraphicsItem::shape() const
5049{
5050 QPainterPath path;
5051 path.addRect(rect: boundingRect());
5052 return path;
5053}
5054
5055/*!
5056 Returns \c true if this item is clipped. An item is clipped if it has either
5057 set the \l ItemClipsToShape flag, or if it or any of its ancestors has set
5058 the \l ItemClipsChildrenToShape flag.
5059
5060 Clipping affects the item's appearance (i.e., painting), as well as mouse
5061 and hover event delivery.
5062
5063 \sa clipPath(), shape(), setFlags()
5064*/
5065bool QGraphicsItem::isClipped() const
5066{
5067 Q_D(const QGraphicsItem);
5068 return (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
5069 || (d->flags & QGraphicsItem::ItemClipsToShape);
5070}
5071
5072/*!
5073 \since 4.5
5074
5075 Returns this item's clip path, or an empty QPainterPath if this item is
5076 not clipped. The clip path constrains the item's appearance and
5077 interaction (i.e., restricts the area the item can draw within and receive
5078 events for).
5079
5080 You can enable clipping by setting the ItemClipsToShape or
5081 ItemClipsChildrenToShape flags. The item's clip path is calculated by
5082 intersecting all clipping ancestors' shapes. If the item sets
5083 ItemClipsToShape, the final clip is intersected with the item's own shape.
5084
5085 \note Clipping introduces a performance penalty for all items involved;
5086 you should generally avoid using clipping if you can (e.g., if your items
5087 always draw inside boundingRect() or shape() boundaries, clipping is not
5088 necessary).
5089
5090 \sa isClipped(), shape(), setFlags()
5091*/
5092QPainterPath QGraphicsItem::clipPath() const
5093{
5094 Q_D(const QGraphicsItem);
5095 if (!isClipped())
5096 return QPainterPath();
5097
5098 const QRectF thisBoundingRect(boundingRect());
5099 if (thisBoundingRect.isEmpty())
5100 return QPainterPath();
5101
5102 QPainterPath clip;
5103 // Start with the item's bounding rect.
5104 clip.addRect(rect: thisBoundingRect);
5105
5106 if (d->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) {
5107 const QGraphicsItem *parent = this;
5108 const QGraphicsItem *lastParent = this;
5109
5110 // Intersect any in-between clips starting at the top and moving downwards.
5111 while ((parent = parent->d_ptr->parent)) {
5112 if (parent->d_ptr->flags & ItemClipsChildrenToShape) {
5113 // Map clip to the current parent and intersect with its shape/clipPath
5114 clip = lastParent->itemTransform(other: parent).map(p: clip);
5115 clip = clip.intersected(r: parent->shape());
5116 if (clip.isEmpty())
5117 return clip;
5118 lastParent = parent;
5119 }
5120
5121 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
5122 break;
5123 }
5124
5125 if (lastParent != this) {
5126 // Map clip back to the item's transform.
5127 // ### what if itemtransform fails
5128 clip = lastParent->itemTransform(other: this).map(p: clip);
5129 }
5130 }
5131
5132 if (d->flags & ItemClipsToShape)
5133 clip = clip.intersected(r: shape());
5134
5135 return clip;
5136}
5137
5138/*!
5139 Returns \c true if this item contains \a point, which is in local
5140 coordinates; otherwise, false is returned. It is most often called from
5141 QGraphicsView to determine what item is under the cursor, and for that
5142 reason, the implementation of this function should be as light-weight as
5143 possible.
5144
5145 By default, this function calls shape(), but you can reimplement it in a
5146 subclass to provide a (perhaps more efficient) implementation.
5147
5148 \sa shape(), boundingRect(), collidesWithPath()
5149*/
5150bool QGraphicsItem::contains(const QPointF &point) const
5151{
5152 return isClipped() ? clipPath().contains(pt: point) : shape().contains(pt: point);
5153}
5154
5155/*!
5156
5157 Returns \c true if this item collides with \a other; otherwise
5158 returns \c false.
5159
5160 The \a mode is applied to \a other, and the resulting shape or
5161 bounding rectangle is then compared to this item's shape. The
5162 default value for \a mode is Qt::IntersectsItemShape; \a other
5163 collides with this item if it either intersects, contains, or is
5164 contained by this item's shape (see Qt::ItemSelectionMode for
5165 details).
5166
5167 The default implementation is based on shape intersection, and it calls
5168 shape() on both items. Because the complexity of arbitrary shape-shape
5169 intersection grows with an order of magnitude when the shapes are complex,
5170 this operation can be noticably time consuming. You have the option of
5171 reimplementing this function in a subclass of QGraphicsItem to provide a
5172 custom algorithm. This allows you to make use of natural constraints in
5173 the shapes of your own items, in order to improve the performance of the
5174 collision detection. For instance, two untransformed perfectly circular
5175 items' collision can be determined very efficiently by comparing their
5176 positions and radii.
5177
5178 Keep in mind that when reimplementing this function and calling shape() or
5179 boundingRect() on \a other, the returned coordinates must be mapped to
5180 this item's coordinate system before any intersection can take place.
5181
5182 \sa contains(), shape()
5183*/
5184bool QGraphicsItem::collidesWithItem(const QGraphicsItem *other, Qt::ItemSelectionMode mode) const
5185{
5186 if (other == this)
5187 return true;
5188 if (!other)
5189 return false;
5190 // The items share the same clip if their closest clipper is the same, or
5191 // if one clips the other.
5192 bool clips = (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
5193 bool otherClips = (other->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren);
5194 if (clips || otherClips) {
5195 const QGraphicsItem *closestClipper = isAncestorOf(child: other) ? this : parentItem();
5196 while (closestClipper && !(closestClipper->flags() & ItemClipsChildrenToShape))
5197 closestClipper = closestClipper->parentItem();
5198 const QGraphicsItem *otherClosestClipper = other->isAncestorOf(child: this) ? other : other->parentItem();
5199 while (otherClosestClipper && !(otherClosestClipper->flags() & ItemClipsChildrenToShape))
5200 otherClosestClipper = otherClosestClipper->parentItem();
5201 if (closestClipper == otherClosestClipper) {
5202 d_ptr->localCollisionHack = 1;
5203 bool res = collidesWithPath(path: mapFromItem(item: other, path: other->shape()), mode);
5204 d_ptr->localCollisionHack = 0;
5205 return res;
5206 }
5207 }
5208
5209 QPainterPath otherShape = other->isClipped() ? other->clipPath() : other->shape();
5210 return collidesWithPath(path: mapFromItem(item: other, path: otherShape), mode);
5211}
5212
5213/*!
5214 Returns \c true if this item collides with \a path.
5215
5216 The collision is determined by \a mode. The default value for \a mode is
5217 Qt::IntersectsItemShape; \a path collides with this item if it either
5218 intersects, contains, or is contained by this item's shape.
5219
5220 Note that this function checks whether the item's shape or
5221 bounding rectangle (depending on \a mode) is contained within \a
5222 path, and not whether \a path is contained within the items shape
5223 or bounding rectangle.
5224
5225 \sa collidesWithItem(), contains(), shape()
5226*/
5227bool QGraphicsItem::collidesWithPath(const QPainterPath &path, Qt::ItemSelectionMode mode) const
5228{
5229 if (path.isEmpty()) {
5230 // No collision with empty paths.
5231 return false;
5232 }
5233
5234 QRectF rectA(boundingRect());
5235 _q_adjustRect(rect: &rectA);
5236 QRectF rectB(path.controlPointRect());
5237 _q_adjustRect(rect: &rectB);
5238 if (!rectA.intersects(r: rectB)) {
5239 // This we can determine efficiently. If the two rects neither
5240 // intersect nor contain eachother, then the two items do not collide.
5241 return false;
5242 }
5243
5244 // For further testing, we need this item's shape or bounding rect.
5245 QPainterPath thisShape;
5246 if (mode == Qt::IntersectsItemShape || mode == Qt::ContainsItemShape)
5247 thisShape = (isClipped() && !d_ptr->localCollisionHack) ? clipPath() : shape();
5248 else
5249 thisShape.addRect(rect: rectA);
5250
5251 if (thisShape == QPainterPath()) {
5252 // Empty shape? No collision.
5253 return false;
5254 }
5255
5256 // Use QPainterPath boolean operations to determine the collision, O(N*logN).
5257 if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
5258 return path.intersects(p: thisShape);
5259 return path.contains(p: thisShape);
5260}
5261
5262/*!
5263 Returns a list of all items that collide with this item.
5264
5265 The way collisions are detected is determined by applying \a mode
5266 to items that are compared to this item, i.e., each item's shape
5267 or bounding rectangle is checked against this item's shape. The
5268 default value for \a mode is Qt::IntersectsItemShape.
5269
5270 \sa collidesWithItem()
5271*/
5272QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const
5273{
5274 if (d_ptr->scene)
5275 return d_ptr->scene->collidingItems(item: this, mode);
5276 return QList<QGraphicsItem *>();
5277}
5278
5279/*!
5280 \internal
5281
5282 Item obscurity helper function.
5283
5284 Returns \c true if the subrect \a rect of \a item's bounding rect is obscured
5285 by \a other (i.e., \a other's opaque area covers \a item's \a rect
5286 completely. \a other is assumed to already be "on top of" \a item
5287 wrt. stacking order.
5288*/
5289static bool qt_QGraphicsItem_isObscured(const QGraphicsItem *item,
5290 const QGraphicsItem *other,
5291 const QRectF &rect)
5292{
5293 return other->mapToItem(item, path: other->opaqueArea()).contains(rect);
5294}
5295
5296/*!
5297 \overload
5298 \since 4.3
5299
5300 Returns \c true if \a rect is completely obscured by the opaque shape of any
5301 of colliding items above it (i.e., with a higher Z value than this item).
5302
5303 \sa opaqueArea()
5304*/
5305bool QGraphicsItem::isObscured(const QRectF &rect) const
5306{
5307 Q_D(const QGraphicsItem);
5308 if (!d->scene)
5309 return false;
5310
5311 QRectF br = boundingRect();
5312 QRectF testRect = rect.isNull() ? br : rect;
5313
5314 const auto items = d->scene->items(polygon: mapToScene(rect: br), mode: Qt::IntersectsItemBoundingRect);
5315 for (QGraphicsItem *item : items) {
5316 if (item == this)
5317 break;
5318 if (qt_QGraphicsItem_isObscured(item: this, other: item, rect: testRect))
5319 return true;
5320 }
5321 return false;
5322}
5323
5324/*!
5325 \fn bool QGraphicsItem::isObscured(qreal x, qreal y, qreal w, qreal h) const
5326 \overload
5327 \since 4.3
5328
5329 This convenience function is equivalent to calling isObscured(QRectF(\a x, \a y, \a w, \a h)).
5330*/
5331
5332/*!
5333 Returns \c true if this item's bounding rect is completely obscured by the
5334 opaque shape of \a item.
5335
5336 The base implementation maps \a item's opaqueArea() to this item's
5337 coordinate system, and then checks if this item's boundingRect() is fully
5338 contained within the mapped shape.
5339
5340 You can reimplement this function to provide a custom algorithm for
5341 determining whether this item is obscured by \a item.
5342
5343 \sa opaqueArea(), isObscured()
5344*/
5345bool QGraphicsItem::isObscuredBy(const QGraphicsItem *item) const
5346{
5347 if (!item)
5348 return false;
5349 return qt_closestItemFirst(item1: item, item2: this)
5350 && qt_QGraphicsItem_isObscured(item: this, other: item, rect: boundingRect());
5351}
5352
5353/*!
5354 This virtual function returns a shape representing the area where this
5355 item is opaque. An area is opaque if it is filled using an opaque brush or
5356 color (i.e., not transparent).
5357
5358 This function is used by isObscuredBy(), which is called by underlying
5359 items to determine if they are obscured by this item.
5360
5361 The default implementation returns an empty QPainterPath, indicating that
5362 this item is completely transparent and does not obscure any other items.
5363
5364 \sa isObscuredBy(), isObscured(), shape()
5365*/
5366QPainterPath QGraphicsItem::opaqueArea() const
5367{
5368 return QPainterPath();
5369}
5370
5371/*!
5372 \since 4.4
5373
5374 Returns the bounding region for this item. The coordinate space of the
5375 returned region depends on \a itemToDeviceTransform. If you pass an
5376 identity QTransform as a parameter, this function will return a local
5377 coordinate region.
5378
5379 The bounding region describes a coarse outline of the item's visual
5380 contents. Although it's expensive to calculate, it's also more precise
5381 than boundingRect(), and it can help to avoid unnecessary repainting when
5382 an item is updated. This is particularly efficient for thin items (e.g.,
5383 lines or simple polygons). You can tune the granularity for the bounding
5384 region by calling setBoundingRegionGranularity(). The default granularity
5385 is 0; in which the item's bounding region is the same as its bounding
5386 rect.
5387
5388 \a itemToDeviceTransform is the transformation from item coordinates to
5389 device coordinates. If you want this function to return a QRegion in scene
5390 coordinates, you can pass sceneTransform() as an argument.
5391
5392 \sa boundingRegionGranularity()
5393*/
5394QRegion QGraphicsItem::boundingRegion(const QTransform &itemToDeviceTransform) const
5395{
5396 // ### Ideally we would have a better way to generate this region,
5397 // preferably something in the lines of QPainterPath::toRegion(QTransform)
5398 // coupled with a way to generate a painter path from a set of painter
5399 // operations (e.g., QPicture::toPainterPath() or so). The current
5400 // approach generates a bitmap with the size of the item's bounding rect
5401 // in device coordinates, scaled by b.r.granularity, then paints the item
5402 // into the bitmap, converts the result to a QRegion and scales the region
5403 // back to device space with inverse granularity.
5404 qreal granularity = boundingRegionGranularity();
5405 QRect deviceRect = itemToDeviceTransform.mapRect(boundingRect()).toRect();
5406 _q_adjustRect(rect: &deviceRect);
5407 if (granularity == 0.0)
5408 return QRegion(deviceRect);
5409
5410 int pad = 1;
5411 QSize bitmapSize(qMax(a: 1, b: int(deviceRect.width() * granularity) + pad * 2),
5412 qMax(a: 1, b: int(deviceRect.height() * granularity) + pad * 2));
5413 QImage mask(bitmapSize, QImage::Format_ARGB32_Premultiplied);
5414 mask.fill(pixel: 0);
5415 QPainter p(&mask);
5416 p.setRenderHints(hints: QPainter::Antialiasing);
5417
5418 // Transform painter (### this code is from QGraphicsScene::drawItemHelper
5419 // and doesn't work properly with perspective transformations).
5420 QPointF viewOrigo = itemToDeviceTransform.map(p: QPointF(0, 0));
5421 QPointF offset = viewOrigo - deviceRect.topLeft();
5422 p.scale(sx: granularity, sy: granularity);
5423 p.translate(offset);
5424 p.translate(dx: pad, dy: pad);
5425 p.setWorldTransform(matrix: itemToDeviceTransform, combine: true);
5426 p.translate(offset: itemToDeviceTransform.inverted().map(p: QPointF(0, 0)));
5427
5428 // Render
5429 QStyleOptionGraphicsItem option;
5430 const_cast<QGraphicsItem *>(this)->paint(painter: &p, option: &option, widget: nullptr);
5431 p.end();
5432
5433 // Transform QRegion back to device space
5434 QTransform unscale = QTransform::fromScale(dx: 1 / granularity, dy: 1 / granularity);
5435 QRegion r;
5436 QBitmap colorMask = QBitmap::fromImage(image: mask.createMaskFromColor(color: 0));
5437 for (const QRect &rect : QRegion(colorMask)) {
5438 QRect xrect = unscale.mapRect(rect).translated(p: deviceRect.topLeft() - QPoint(pad, pad));
5439 r += xrect.adjusted(xp1: -1, yp1: -1, xp2: 1, yp2: 1) & deviceRect;
5440 }
5441 return r;
5442}
5443
5444/*!
5445 \since 4.4
5446
5447 Returns the item's bounding region granularity; a value between and
5448 including 0 and 1. The default value is 0 (i.e., the lowest granularity,
5449 where the bounding region corresponds to the item's bounding rectangle).
5450
5451\omit
5452### NOTE
5453\endomit
5454
5455 \sa setBoundingRegionGranularity()
5456*/
5457qreal QGraphicsItem::boundingRegionGranularity() const
5458{
5459 return d_ptr->hasBoundingRegionGranularity
5460 ? qvariant_cast<qreal>(v: d_ptr->extra(type: QGraphicsItemPrivate::ExtraBoundingRegionGranularity))
5461 : 0;
5462}
5463
5464/*!
5465 \since 4.4
5466 Sets the bounding region granularity to \a granularity; a value between
5467 and including 0 and 1. The default value is 0 (i.e., the lowest
5468 granularity, where the bounding region corresponds to the item's bounding
5469 rectangle).
5470
5471 The granularity is used by boundingRegion() to calculate how fine the
5472 bounding region of the item should be. The highest achievable granularity
5473 is 1, where boundingRegion() will return the finest outline possible for
5474 the respective device (e.g., for a QGraphicsView viewport, this gives you
5475 a pixel-perfect bounding region). The lowest possible granularity is
5476 0. The value of \a granularity describes the ratio between device
5477 resolution and the resolution of the bounding region (e.g., a value of
5478 0.25 will provide a region where each chunk corresponds to 4x4 device
5479 units / pixels).
5480
5481 \sa boundingRegionGranularity()
5482*/
5483void QGraphicsItem::setBoundingRegionGranularity(qreal granularity)
5484{
5485 if (granularity < 0.0 || granularity > 1.0) {
5486 qWarning(msg: "QGraphicsItem::setBoundingRegionGranularity: invalid granularity %g", granularity);
5487 return;
5488 }
5489 if (granularity == 0.0) {
5490 d_ptr->unsetExtra(type: QGraphicsItemPrivate::ExtraBoundingRegionGranularity);
5491 d_ptr->hasBoundingRegionGranularity = 0;
5492 return;
5493 }
5494 d_ptr->hasBoundingRegionGranularity = 1;
5495 d_ptr->setExtra(type: QGraphicsItemPrivate::ExtraBoundingRegionGranularity,
5496 value: QVariant::fromValue<qreal>(value: granularity));
5497}
5498
5499/*!
5500 \fn virtual void QGraphicsItem::paint(QPainter *painter, const
5501 QStyleOptionGraphicsItem *option, QWidget *widget = 0) = 0
5502
5503 This function, which is usually called by QGraphicsView, paints the
5504 contents of an item in local coordinates.
5505
5506 Reimplement this function in a QGraphicsItem subclass to provide the
5507 item's painting implementation, using \a painter. The \a option parameter
5508 provides style options for the item, such as its state, exposed area and
5509 its level-of-detail hints. The \a widget argument is optional. If
5510 provided, it points to the widget that is being painted on; otherwise, it
5511 is 0. For cached painting, \a widget is always 0.
5512
5513 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 10
5514
5515 The painter's pen is 0-width by default, and its pen is initialized to the
5516 QPalette::Text brush from the paint device's palette. The brush is
5517 initialized to QPalette::Window.
5518
5519 Make sure to constrain all painting inside the boundaries of
5520 boundingRect() to avoid rendering artifacts (as QGraphicsView does not
5521 clip the painter for you). In particular, when QPainter renders the
5522 outline of a shape using an assigned QPen, half of the outline will be
5523 drawn outside, and half inside, the shape you're rendering (e.g., with a
5524 pen width of 2 units, you must draw outlines 1 unit inside
5525 boundingRect()). QGraphicsItem does not support use of cosmetic pens with
5526 a non-zero width.
5527
5528 All painting is done in local coordinates.
5529
5530 \note It is mandatory that an item will always redraw itself in the exact
5531 same way, unless update() was called; otherwise visual artifacts may
5532 occur. In other words, two subsequent calls to paint() must always produce
5533 the same output, unless update() was called between them.
5534
5535 \note Enabling caching for an item does not guarantee that paint()
5536 will be invoked only once by the Graphics View framework,
5537 even without any explicit call to update(). See the documentation of
5538 setCacheMode() for more details.
5539
5540 \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
5541*/
5542
5543/*!
5544 \internal
5545 Returns \c true if we can discard an update request; otherwise false.
5546*/
5547bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit,
5548 bool ignoreOpacity) const
5549{
5550 // No scene, or if the scene is updating everything, means we have nothing
5551 // to do. The only exception is if the scene tracks the growing scene rect.
5552 return !scene
5553 || (!visible && !ignoreVisibleBit && !this->ignoreVisible)
5554 || (!ignoreDirtyBit && fullUpdatePending)
5555 || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
5556}
5557
5558/*!
5559 \internal
5560*/
5561int QGraphicsItemPrivate::depth() const
5562{
5563 if (itemDepth == -1)
5564 const_cast<QGraphicsItemPrivate *>(this)->resolveDepth();
5565
5566 return itemDepth;
5567}
5568
5569/*!
5570 \internal
5571*/
5572#if QT_CONFIG(graphicseffect)
5573void QGraphicsItemPrivate::invalidateParentGraphicsEffectsRecursively()
5574{
5575 QGraphicsItemPrivate *itemPrivate = this;
5576 do {
5577 if (itemPrivate->graphicsEffect) {
5578 itemPrivate->notifyInvalidated = 1;
5579
5580 if (!itemPrivate->updateDueToGraphicsEffect)
5581 static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
5582 }
5583 } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : nullptr));
5584}
5585
5586void QGraphicsItemPrivate::invalidateChildGraphicsEffectsRecursively(QGraphicsItemPrivate::InvalidateReason reason)
5587{
5588 if (!mayHaveChildWithGraphicsEffect)
5589 return;
5590
5591 for (int i = 0; i < children.size(); ++i) {
5592 QGraphicsItemPrivate *childPrivate = children.at(i)->d_ptr.data();
5593 if (reason == OpacityChanged && (childPrivate->flags & QGraphicsItem::ItemIgnoresParentOpacity))
5594 continue;
5595 if (childPrivate->graphicsEffect) {
5596 childPrivate->notifyInvalidated = 1;
5597 static_cast<QGraphicsItemEffectSourcePrivate *>(childPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
5598 }
5599
5600 childPrivate->invalidateChildGraphicsEffectsRecursively(reason);
5601 }
5602}
5603#endif // QT_CONFIG(graphicseffect)
5604
5605/*!
5606 \internal
5607*/
5608void QGraphicsItemPrivate::invalidateDepthRecursively()
5609{
5610 if (itemDepth == -1)
5611 return;
5612
5613 itemDepth = -1;
5614 for (int i = 0; i < children.size(); ++i)
5615 children.at(i)->d_ptr->invalidateDepthRecursively();
5616}
5617
5618/*!
5619 \internal
5620
5621 Resolves the stacking depth of this object and all its ancestors.
5622*/
5623void QGraphicsItemPrivate::resolveDepth()
5624{
5625 if (!parent)
5626 itemDepth = 0;
5627 else {
5628 if (parent->d_ptr->itemDepth == -1)
5629 parent->d_ptr->resolveDepth();
5630 itemDepth = parent->d_ptr->itemDepth + 1;
5631 }
5632}
5633
5634/*!
5635 \internal
5636
5637 ### This function is almost identical to
5638 QGraphicsScenePrivate::registerTopLevelItem().
5639*/
5640void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
5641{
5642 // Remove all holes from the sibling index list. Now the max index
5643 // number is equal to the size of the children list.
5644 ensureSequentialSiblingIndex();
5645 needSortChildren = 1; // ### maybe 0
5646 child->d_ptr->siblingIndex = children.size();
5647 children.append(t: child);
5648 if (isObject)
5649 emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
5650}
5651
5652/*!
5653 \internal
5654
5655 ### This function is almost identical to
5656 QGraphicsScenePrivate::unregisterTopLevelItem().
5657*/
5658void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
5659{
5660 // When removing elements in the middle of the children list,
5661 // there will be a "gap" in the list of sibling indexes (0,1,3,4).
5662 if (!holesInSiblingIndex)
5663 holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1;
5664 if (sequentialOrdering && !holesInSiblingIndex)
5665 children.removeAt(i: child->d_ptr->siblingIndex);
5666 else
5667 children.removeOne(t: child);
5668 // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because
5669 // the child is not guaranteed to be at the index after the list is sorted.
5670 // (see ensureSortedChildren()).
5671 child->d_ptr->siblingIndex = -1;
5672 if (isObject)
5673 emit static_cast<QGraphicsObject *>(q_ptr)->childrenChanged();
5674}
5675
5676/*!
5677 \internal
5678*/
5679QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
5680{
5681 return (QGraphicsItemCache *)qvariant_cast<void *>(v: extra(type: ExtraCacheData));
5682}
5683
5684/*!
5685 \internal
5686*/
5687QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
5688{
5689 QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(v: extra(type: ExtraCacheData));
5690 if (!c) {
5691 QGraphicsItemPrivate *that = const_cast<QGraphicsItemPrivate *>(this);
5692 c = new QGraphicsItemCache;
5693 that->setExtra(type: ExtraCacheData, value: QVariant::fromValue<void *>(value: c));
5694 }
5695 return c;
5696}
5697
5698/*!
5699 \internal
5700*/
5701void QGraphicsItemPrivate::removeExtraItemCache()
5702{
5703 QGraphicsItemCache *c = (QGraphicsItemCache *)qvariant_cast<void *>(v: extra(type: ExtraCacheData));
5704 if (c) {
5705 c->purge();
5706 delete c;
5707 }
5708 unsetExtra(type: ExtraCacheData);
5709}
5710
5711void QGraphicsItemPrivate::updatePaintedViewBoundingRects(bool updateChildren)
5712{
5713 if (!scene)
5714 return;
5715
5716 for (int i = 0; i < scene->d_func()->views.size(); ++i) {
5717 QGraphicsViewPrivate *viewPrivate = scene->d_func()->views.at(i)->d_func();
5718 QRect rect = paintedViewBoundingRects.value(key: viewPrivate->viewport);
5719 rect.translate(p: viewPrivate->dirtyScrollOffset);
5720 viewPrivate->updateRect(rect);
5721 }
5722
5723 if (updateChildren) {
5724 for (int i = 0; i < children.size(); ++i)
5725 children.at(i)->d_ptr->updatePaintedViewBoundingRects(updateChildren: true);
5726 }
5727}
5728
5729// Traverses all the ancestors up to the top-level and updates the pointer to
5730// always point to the top-most item that has a dirty scene transform.
5731// It then backtracks to the top-most dirty item and start calculating the
5732// scene transform by combining the item's transform (+pos) with the parent's
5733// cached scene transform (which we at this point know for sure is valid).
5734void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
5735{
5736 Q_ASSERT(topMostDirtyItem);
5737
5738 if (dirtySceneTransform)
5739 *topMostDirtyItem = q_ptr;
5740
5741 if (parent)
5742 parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
5743
5744 if (*topMostDirtyItem == q_ptr) {
5745 if (!dirtySceneTransform)
5746 return; // OK, neither my ancestors nor I have dirty scene transforms.
5747 *topMostDirtyItem = nullptr;
5748 } else if (*topMostDirtyItem) {
5749 return; // Continue backtrack.
5750 }
5751
5752 // This item and all its descendants have dirty scene transforms.
5753 // We're about to validate this item's scene transform, so we have to
5754 // invalidate all the children; otherwise there's no way for the descendants
5755 // to detect that the ancestor has changed.
5756 invalidateChildrenSceneTransform();
5757
5758 // COMBINE my transform with the parent's scene transform.
5759 updateSceneTransformFromParent();
5760 Q_ASSERT(!dirtySceneTransform);
5761}
5762
5763/*!
5764 \internal
5765*/
5766void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
5767{
5768 // Update focus child chain. Stop at panels, or if this item
5769 // is hidden, stop at the first item with a visible parent.
5770 QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
5771 if (parent->panel() != q_ptr->panel())
5772 return;
5773
5774 do {
5775 // Clear any existing ancestor's subFocusItem.
5776 if (parent != q_ptr && parent->d_ptr->subFocusItem) {
5777 if (parent->d_ptr->subFocusItem == q_ptr)
5778 break;
5779 parent->d_ptr->subFocusItem->d_ptr->clearSubFocus(rootItem: nullptr, stopItem);
5780 }
5781 parent->d_ptr->subFocusItem = q_ptr;
5782 parent->d_ptr->subFocusItemChange();
5783 } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible));
5784
5785 if (scene && !scene->isActive()) {
5786 scene->d_func()->passiveFocusItem = subFocusItem;
5787 scene->d_func()->lastFocusItem = subFocusItem;
5788 }
5789}
5790
5791/*!
5792 \internal
5793*/
5794void QGraphicsItemPrivate::clearSubFocus(QGraphicsItem *rootItem, QGraphicsItem *stopItem)
5795{
5796 // Reset sub focus chain.
5797 QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
5798 do {
5799 if (parent->d_ptr->subFocusItem != q_ptr)
5800 break;
5801 parent->d_ptr->subFocusItem = nullptr;
5802 if (parent != stopItem && !parent->isAncestorOf(child: stopItem))
5803 parent->d_ptr->subFocusItemChange();
5804 } while (!parent->isPanel() && (parent = parent->d_ptr->parent));
5805}
5806
5807/*!
5808 \internal
5809
5810 Sets the focusProxy pointer to \nullptr for all items that have this item as their
5811 focusProxy.
5812*/
5813void QGraphicsItemPrivate::resetFocusProxy()
5814{
5815 for (int i = 0; i < focusProxyRefs.size(); ++i)
5816 *focusProxyRefs.at(i) = nullptr;
5817 focusProxyRefs.clear();
5818}
5819
5820/*!
5821 \internal
5822
5823 Subclasses can reimplement this function to be notified when subFocusItem
5824 changes.
5825*/
5826void QGraphicsItemPrivate::subFocusItemChange()
5827{
5828}
5829
5830/*!
5831 \internal
5832
5833 Subclasses can reimplement this function to be notified when an item
5834 becomes a focusScopeItem (or is no longer a focusScopeItem).
5835*/
5836void QGraphicsItemPrivate::focusScopeItemChange(bool isSubFocusItem)
5837{
5838 Q_UNUSED(isSubFocusItem);
5839}
5840
5841/*!
5842 \internal
5843
5844 Subclasses can reimplement this function to be notified when its
5845 siblingIndex order is changed.
5846*/
5847void QGraphicsItemPrivate::siblingOrderChange()
5848{
5849}
5850
5851/*!
5852 \internal
5853
5854 Tells us if it is a proxy widget
5855*/
5856bool QGraphicsItemPrivate::isProxyWidget() const
5857{
5858 return false;
5859}
5860
5861/*!
5862 Schedules a redraw of the area covered by \a rect in this item. You can
5863 call this function whenever your item needs to be redrawn, such as if it
5864 changes appearance or size.
5865
5866 This function does not cause an immediate paint; instead it schedules a
5867 paint request that is processed by QGraphicsView after control reaches the
5868 event loop. The item will only be redrawn if it is visible in any
5869 associated view.
5870
5871 As a side effect of the item being repainted, other items that overlap the
5872 area \a rect may also be repainted.
5873
5874 If the item is invisible (i.e., isVisible() returns \c false), this function
5875 does nothing.
5876
5877 \sa paint(), boundingRect()
5878*/
5879void QGraphicsItem::update(const QRectF &rect)
5880{
5881 if (rect.isEmpty() && !rect.isNull())
5882 return;
5883
5884 // Make sure we notify effects about invalidated source.
5885#if QT_CONFIG(graphicseffect)
5886 d_ptr->invalidateParentGraphicsEffectsRecursively();
5887#endif // QT_CONFIG(graphicseffect)
5888
5889 if (CacheMode(d_ptr->cacheMode) != NoCache) {
5890 // Invalidate cache.
5891 QGraphicsItemCache *cache = d_ptr->extraItemCache();
5892 if (!cache->allExposed) {
5893 if (rect.isNull()) {
5894 cache->allExposed = true;
5895 cache->exposed.clear();
5896 } else {
5897 cache->exposed.append(t: rect);
5898 }
5899 }
5900 // Only invalidate cache; item is already dirty.
5901 if (d_ptr->fullUpdatePending)
5902 return;
5903 }
5904
5905 if (d_ptr->scene)
5906 d_ptr->scene->d_func()->markDirty(item: this, rect);
5907}
5908
5909/*!
5910 \since 4.4
5911 Scrolls the contents of \a rect by \a dx, \a dy. If \a rect is a null rect
5912 (the default), the item's bounding rect is scrolled.
5913
5914 Scrolling provides a fast alternative to simply redrawing when the
5915 contents of the item (or parts of the item) are shifted vertically or
5916 horizontally. Depending on the current transformation and the capabilities
5917 of the paint device (i.e., the viewport), this operation may consist of
5918 simply moving pixels from one location to another using memmove(). In most
5919 cases this is faster than rerendering the entire area.
5920
5921 After scrolling, the item will issue an update for the newly exposed
5922 areas. If scrolling is not supported (e.g., you are rendering to an OpenGL
5923 viewport, which does not benefit from scroll optimizations), this function
5924 is equivalent to calling update(\a rect).
5925
5926 \b{Note:} Scrolling is only supported when QGraphicsItem::ItemCoordinateCache
5927 is enabled; in all other cases calling this function is equivalent to calling
5928 update(\a rect). If you for sure know that the item is opaque and not overlapped
5929 by other items, you can map the \a rect to viewport coordinates and scroll the
5930 viewport.
5931
5932 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 19
5933
5934 \sa boundingRect()
5935*/
5936void QGraphicsItem::scroll(qreal dx, qreal dy, const QRectF &rect)
5937{
5938 Q_D(QGraphicsItem);
5939 if (dx == 0.0 && dy == 0.0)
5940 return;
5941 if (!d->scene)
5942 return;
5943
5944 // Accelerated scrolling means moving pixels from one location to another
5945 // and only redraw the newly exposed area. The following requirements must
5946 // be fulfilled in order to do that:
5947 //
5948 // 1) Item is opaque.
5949 // 2) Item is not overlapped by other items.
5950 //
5951 // There's (yet) no way to detect whether an item is opaque or not, which means
5952 // we cannot do accelerated scrolling unless the cache is enabled. In case of using
5953 // DeviceCoordinate cache we also have to take the device transform into account in
5954 // order to determine whether we can do accelerated scrolling or not. That's left out
5955 // for simplicity here, but it is definitely something we can consider in the future
5956 // as a performance improvement.
5957 if (d->cacheMode != QGraphicsItem::ItemCoordinateCache
5958 || !qFuzzyIsNull(d: dx - int(dx)) || !qFuzzyIsNull(d: dy - int(dy))) {
5959 update(rect);
5960 return;
5961 }
5962
5963 QGraphicsItemCache *cache = d->extraItemCache();
5964 if (cache->allExposed || cache->fixedSize.isValid()) {
5965 // Cache is either invalidated or item is scaled (see QGraphicsItem::setCacheMode).
5966 update(rect);
5967 return;
5968 }
5969
5970 // Find pixmap in cache.
5971 QPixmap cachedPixmap;
5972 if (!QPixmapCache::find(key: cache->key, pixmap: &cachedPixmap)) {
5973 update(rect);
5974 return;
5975 }
5976
5977 QRect scrollRect = (rect.isNull() ? boundingRect() : rect).toAlignedRect();
5978 if (!scrollRect.intersects(r: cache->boundingRect))
5979 return; // Nothing to scroll.
5980
5981 // Remove from cache to avoid deep copy when modifying.
5982 QPixmapCache::remove(key: cache->key);
5983
5984 QRegion exposed;
5985 cachedPixmap.scroll(dx, dy, rect: scrollRect.translated(p: -cache->boundingRect.topLeft()), exposed: &exposed);
5986
5987 // Reinsert into cache.
5988 cache->key = QPixmapCache::insert(pixmap: cachedPixmap);
5989
5990 // Translate the existing expose.
5991 for (int i = 0; i < cache->exposed.size(); ++i) {
5992 QRectF &e = cache->exposed[i];
5993 if (!rect.isNull() && !e.intersects(r: rect))
5994 continue;
5995 e.translate(dx, dy);
5996 }
5997
5998 // Append newly exposed areas. Note that the exposed region is currently
5999 // in pixmap coordinates, so we have to translate it to item coordinates.
6000 exposed.translate(p: cache->boundingRect.topLeft());
6001 for (const QRect &exposedRect : exposed)
6002 cache->exposed += exposedRect;
6003
6004 // Trigger update. This will redraw the newly exposed area and make sure
6005 // the pixmap is re-blitted in case there are overlapping items.
6006 d->scene->d_func()->markDirty(item: this, rect);
6007}
6008
6009/*!
6010 \fn void QGraphicsItem::update(qreal x, qreal y, qreal width, qreal height)
6011 \overload
6012
6013 This convenience function is equivalent to calling update(QRectF(\a x, \a
6014 y, \a width, \a height)).
6015*/
6016
6017/*!
6018 Maps the point \a point, which is in this item's coordinate system, to \a
6019 item's coordinate system, and returns the mapped coordinate.
6020
6021 If \a item is \nullptr, this function returns the same as mapToScene().
6022
6023 \sa itemTransform(), mapToParent(), mapToScene(), transform(), mapFromItem(), {The Graphics
6024 View Coordinate System}
6025*/
6026QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPointF &point) const
6027{
6028 if (item)
6029 return itemTransform(other: item).map(p: point);
6030 return mapToScene(point);
6031}
6032
6033/*!
6034 \fn QPointF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y) const
6035 \overload
6036
6037 This convenience function is equivalent to calling mapToItem(\a item,
6038 QPointF(\a x, \a y)).
6039*/
6040
6041/*!
6042 Maps the point \a point, which is in this item's coordinate system, to its
6043 parent's coordinate system, and returns the mapped coordinate. If the item
6044 has no parent, \a point will be mapped to the scene's coordinate system.
6045
6046 \sa mapToItem(), mapToScene(), transform(), mapFromParent(), {The Graphics
6047 View Coordinate System}
6048*/
6049QPointF QGraphicsItem::mapToParent(const QPointF &point) const
6050{
6051 // COMBINE
6052 if (!d_ptr->transformData)
6053 return point + d_ptr->pos;
6054 return d_ptr->transformToParent().map(p: point);
6055}
6056
6057/*!
6058 \fn QPointF QGraphicsItem::mapToParent(qreal x, qreal y) const
6059 \overload
6060
6061 This convenience function is equivalent to calling mapToParent(QPointF(\a
6062 x, \a y)).
6063*/
6064
6065/*!
6066 Maps the point \a point, which is in this item's coordinate system, to the
6067 scene's coordinate system, and returns the mapped coordinate.
6068
6069 \sa mapToItem(), mapToParent(), transform(), mapFromScene(), {The Graphics
6070 View Coordinate System}
6071*/
6072QPointF QGraphicsItem::mapToScene(const QPointF &point) const
6073{
6074 if (d_ptr->hasTranslateOnlySceneTransform())
6075 return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy());
6076 return d_ptr->sceneTransform.map(p: point);
6077}
6078
6079/*!
6080 \fn QPointF QGraphicsItem::mapToScene(qreal x, qreal y) const
6081 \overload
6082
6083 This convenience function is equivalent to calling mapToScene(QPointF(\a
6084 x, \a y)).
6085*/
6086
6087/*!
6088 Maps the rectangle \a rect, which is in this item's coordinate system, to
6089 \a item's coordinate system, and returns the mapped rectangle as a polygon.
6090
6091 If \a item is \nullptr, this function returns the same as mapToScene().
6092
6093 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6094 Graphics View Coordinate System}
6095*/
6096QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QRectF &rect) const
6097{
6098 if (item)
6099 return itemTransform(other: item).map(a: rect);
6100 return mapToScene(rect);
6101}
6102
6103/*!
6104 \fn QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6105 \since 4.3
6106
6107 This convenience function is equivalent to calling mapToItem(item, QRectF(\a x, \a y, \a w, \a h)).
6108*/
6109
6110/*!
6111 Maps the rectangle \a rect, which is in this item's coordinate system, to
6112 its parent's coordinate system, and returns the mapped rectangle as a
6113 polygon. If the item has no parent, \a rect will be mapped to the scene's
6114 coordinate system.
6115
6116 \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6117 Coordinate System}
6118*/
6119QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
6120{
6121 // COMBINE
6122 if (!d_ptr->transformData)
6123 return rect.translated(p: d_ptr->pos);
6124 return d_ptr->transformToParent().map(a: rect);
6125}
6126
6127/*!
6128 \fn QPolygonF QGraphicsItem::mapToParent(qreal x, qreal y, qreal w, qreal h) const
6129 \since 4.3
6130
6131 This convenience function is equivalent to calling mapToParent(QRectF(\a x, \a y, \a w, \a h)).
6132*/
6133
6134/*!
6135 Maps the rectangle \a rect, which is in this item's coordinate system, to
6136 the scene's coordinate system, and returns the mapped rectangle as a polygon.
6137
6138 \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6139 Coordinate System}
6140*/
6141QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const
6142{
6143 if (d_ptr->hasTranslateOnlySceneTransform())
6144 return rect.translated(dx: d_ptr->sceneTransform.dx(), dy: d_ptr->sceneTransform.dy());
6145 return d_ptr->sceneTransform.map(a: rect);
6146}
6147
6148/*!
6149 \fn QPolygonF QGraphicsItem::mapToScene(qreal x, qreal y, qreal w, qreal h) const
6150 \since 4.3
6151
6152 This convenience function is equivalent to calling mapToScene(QRectF(\a x, \a y, \a w, \a h)).
6153*/
6154
6155/*!
6156 \since 4.5
6157
6158 Maps the rectangle \a rect, which is in this item's coordinate system, to
6159 \a item's coordinate system, and returns the mapped rectangle as a new
6160 rectangle (i.e., the bounding rectangle of the resulting polygon).
6161
6162 If \a item is \nullptr, this function returns the same as mapRectToScene().
6163
6164 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6165 Graphics View Coordinate System}
6166*/
6167QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, const QRectF &rect) const
6168{
6169 if (item)
6170 return itemTransform(other: item).mapRect(rect);
6171 return mapRectToScene(rect);
6172}
6173
6174/*!
6175 \fn QRectF QGraphicsItem::mapRectToItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6176 \since 4.5
6177
6178 This convenience function is equivalent to calling mapRectToItem(item, QRectF(\a x, \a y, \a w, \a h)).
6179*/
6180
6181/*!
6182 \since 4.5
6183
6184 Maps the rectangle \a rect, which is in this item's coordinate system, to
6185 its parent's coordinate system, and returns the mapped rectangle as a new
6186 rectangle (i.e., the bounding rectangle of the resulting polygon).
6187
6188 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6189 Graphics View Coordinate System}
6190*/
6191QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
6192{
6193 // COMBINE
6194 if (!d_ptr->transformData)
6195 return rect.translated(p: d_ptr->pos);
6196 return d_ptr->transformToParent().mapRect(rect);
6197}
6198
6199/*!
6200 \fn QRectF QGraphicsItem::mapRectToParent(qreal x, qreal y, qreal w, qreal h) const
6201 \since 4.5
6202
6203 This convenience function is equivalent to calling mapRectToParent(QRectF(\a x, \a y, \a w, \a h)).
6204*/
6205
6206/*!
6207 \since 4.5
6208
6209 Maps the rectangle \a rect, which is in this item's coordinate system, to
6210 the scene coordinate system, and returns the mapped rectangle as a new
6211 rectangle (i.e., the bounding rectangle of the resulting polygon).
6212
6213 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6214 Graphics View Coordinate System}
6215*/
6216QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const
6217{
6218 if (d_ptr->hasTranslateOnlySceneTransform())
6219 return rect.translated(dx: d_ptr->sceneTransform.dx(), dy: d_ptr->sceneTransform.dy());
6220 return d_ptr->sceneTransform.mapRect(rect);
6221}
6222
6223/*!
6224 \fn QRectF QGraphicsItem::mapRectToScene(qreal x, qreal y, qreal w, qreal h) const
6225 \since 4.5
6226
6227 This convenience function is equivalent to calling mapRectToScene(QRectF(\a x, \a y, \a w, \a h)).
6228*/
6229
6230/*!
6231 \since 4.5
6232
6233 Maps the rectangle \a rect, which is in \a item's coordinate system, to
6234 this item's coordinate system, and returns the mapped rectangle as a new
6235 rectangle (i.e., the bounding rectangle of the resulting polygon).
6236
6237 If \a item is \nullptr, this function returns the same as mapRectFromScene().
6238
6239 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6240 Graphics View Coordinate System}
6241*/
6242QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, const QRectF &rect) const
6243{
6244 if (item)
6245 return item->itemTransform(other: this).mapRect(rect);
6246 return mapRectFromScene(rect);
6247}
6248
6249/*!
6250 \fn QRectF QGraphicsItem::mapRectFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6251 \since 4.5
6252
6253 This convenience function is equivalent to calling mapRectFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
6254*/
6255
6256/*!
6257 \since 4.5
6258
6259 Maps the rectangle \a rect, which is in this item's parent's coordinate
6260 system, to this item's coordinate system, and returns the mapped rectangle
6261 as a new rectangle (i.e., the bounding rectangle of the resulting
6262 polygon).
6263
6264 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6265 Graphics View Coordinate System}
6266*/
6267QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
6268{
6269 // COMBINE
6270 if (!d_ptr->transformData)
6271 return rect.translated(p: -d_ptr->pos);
6272 return d_ptr->transformToParent().inverted().mapRect(rect);
6273}
6274
6275/*!
6276 \fn QRectF QGraphicsItem::mapRectFromParent(qreal x, qreal y, qreal w, qreal h) const
6277 \since 4.5
6278
6279 This convenience function is equivalent to calling mapRectFromParent(QRectF(\a x, \a y, \a w, \a h)).
6280*/
6281
6282/*!
6283 \since 4.5
6284
6285 Maps the rectangle \a rect, which is in scene coordinates, to this item's
6286 coordinate system, and returns the mapped rectangle as a new rectangle
6287 (i.e., the bounding rectangle of the resulting polygon).
6288
6289 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6290 Graphics View Coordinate System}
6291*/
6292QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const
6293{
6294 if (d_ptr->hasTranslateOnlySceneTransform())
6295 return rect.translated(dx: -d_ptr->sceneTransform.dx(), dy: -d_ptr->sceneTransform.dy());
6296 return d_ptr->sceneTransform.inverted().mapRect(rect);
6297}
6298
6299/*!
6300 \fn QRectF QGraphicsItem::mapRectFromScene(qreal x, qreal y, qreal w, qreal h) const
6301 \since 4.5
6302
6303 This convenience function is equivalent to calling mapRectFromScene(QRectF(\a x, \a y, \a w, \a h)).
6304*/
6305
6306/*!
6307 Maps the polygon \a polygon, which is in this item's coordinate system, to
6308 \a item's coordinate system, and returns the mapped polygon.
6309
6310 If \a item is \nullptr, this function returns the same as mapToScene().
6311
6312 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6313 Graphics View Coordinate System}
6314*/
6315QPolygonF QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPolygonF &polygon) const
6316{
6317 if (item)
6318 return itemTransform(other: item).map(a: polygon);
6319 return mapToScene(polygon);
6320}
6321
6322/*!
6323 Maps the polygon \a polygon, which is in this item's coordinate system, to
6324 its parent's coordinate system, and returns the mapped polygon. If the
6325 item has no parent, \a polygon will be mapped to the scene's coordinate
6326 system.
6327
6328 \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6329 Coordinate System}
6330*/
6331QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
6332{
6333 // COMBINE
6334 if (!d_ptr->transformData)
6335 return polygon.translated(offset: d_ptr->pos);
6336 return d_ptr->transformToParent().map(a: polygon);
6337}
6338
6339/*!
6340 Maps the polygon \a polygon, which is in this item's coordinate system, to
6341 the scene's coordinate system, and returns the mapped polygon.
6342
6343 \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6344 Coordinate System}
6345*/
6346QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const
6347{
6348 if (d_ptr->hasTranslateOnlySceneTransform())
6349 return polygon.translated(dx: d_ptr->sceneTransform.dx(), dy: d_ptr->sceneTransform.dy());
6350 return d_ptr->sceneTransform.map(a: polygon);
6351}
6352
6353/*!
6354 Maps the path \a path, which is in this item's coordinate system, to
6355 \a item's coordinate system, and returns the mapped path.
6356
6357 If \a item is \nullptr, this function returns the same as mapToScene().
6358
6359 \sa itemTransform(), mapToParent(), mapToScene(), mapFromItem(), {The
6360 Graphics View Coordinate System}
6361*/
6362QPainterPath QGraphicsItem::mapToItem(const QGraphicsItem *item, const QPainterPath &path) const
6363{
6364 if (item)
6365 return itemTransform(other: item).map(p: path);
6366 return mapToScene(path);
6367}
6368
6369/*!
6370 Maps the path \a path, which is in this item's coordinate system, to
6371 its parent's coordinate system, and returns the mapped path. If the
6372 item has no parent, \a path will be mapped to the scene's coordinate
6373 system.
6374
6375 \sa mapToScene(), mapToItem(), mapFromParent(), {The Graphics View
6376 Coordinate System}
6377*/
6378QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
6379{
6380 // COMBINE
6381 if (!d_ptr->transformData)
6382 return path.translated(offset: d_ptr->pos);
6383 return d_ptr->transformToParent().map(p: path);
6384}
6385
6386/*!
6387 Maps the path \a path, which is in this item's coordinate system, to
6388 the scene's coordinate system, and returns the mapped path.
6389
6390 \sa mapToParent(), mapToItem(), mapFromScene(), {The Graphics View
6391 Coordinate System}
6392*/
6393QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const
6394{
6395 if (d_ptr->hasTranslateOnlySceneTransform())
6396 return path.translated(dx: d_ptr->sceneTransform.dx(), dy: d_ptr->sceneTransform.dy());
6397 return d_ptr->sceneTransform.map(p: path);
6398}
6399
6400/*!
6401 Maps the point \a point, which is in \a item's coordinate system, to this
6402 item's coordinate system, and returns the mapped coordinate.
6403
6404 If \a item is \nullptr, this function returns the same as mapFromScene().
6405
6406 \sa itemTransform(), mapFromParent(), mapFromScene(), transform(), mapToItem(), {The Graphics
6407 View Coordinate System}
6408*/
6409QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPointF &point) const
6410{
6411 if (item)
6412 return item->itemTransform(other: this).map(p: point);
6413 return mapFromScene(point);
6414}
6415
6416/*!
6417 \fn QPointF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y) const
6418 \overload
6419
6420 This convenience function is equivalent to calling mapFromItem(\a item,
6421 QPointF(\a x, \a y)).
6422*/
6423
6424/*!
6425 Maps the point \a point, which is in this item's parent's coordinate
6426 system, to this item's coordinate system, and returns the mapped
6427 coordinate.
6428
6429 \sa mapFromItem(), mapFromScene(), transform(), mapToParent(), {The Graphics
6430 View Coordinate System}
6431*/
6432QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
6433{
6434 // COMBINE
6435 if (d_ptr->transformData)
6436 return d_ptr->transformToParent().inverted().map(p: point);
6437 return point - d_ptr->pos;
6438}
6439
6440/*!
6441 \fn QPointF QGraphicsItem::mapFromParent(qreal x, qreal y) const
6442 \overload
6443
6444 This convenience function is equivalent to calling
6445 mapFromParent(QPointF(\a x, \a y)).
6446*/
6447
6448/*!
6449 Maps the point \a point, which is in this item's scene's coordinate
6450 system, to this item's coordinate system, and returns the mapped
6451 coordinate.
6452
6453 \sa mapFromItem(), mapFromParent(), transform(), mapToScene(), {The Graphics
6454 View Coordinate System}
6455*/
6456QPointF QGraphicsItem::mapFromScene(const QPointF &point) const
6457{
6458 if (d_ptr->hasTranslateOnlySceneTransform())
6459 return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy());
6460 return d_ptr->sceneTransform.inverted().map(p: point);
6461}
6462
6463/*!
6464 \fn QPointF QGraphicsItem::mapFromScene(qreal x, qreal y) const
6465 \overload
6466
6467 This convenience function is equivalent to calling mapFromScene(QPointF(\a
6468 x, \a y)).
6469*/
6470
6471/*!
6472 Maps the rectangle \a rect, which is in \a item's coordinate system, to
6473 this item's coordinate system, and returns the mapped rectangle as a
6474 polygon.
6475
6476 If \a item is \nullptr, this function returns the same as mapFromScene()
6477
6478 \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The Graphics View Coordinate
6479 System}
6480*/
6481QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QRectF &rect) const
6482{
6483 if (item)
6484 return item->itemTransform(other: this).map(a: rect);
6485 return mapFromScene(rect);
6486}
6487
6488/*!
6489 \fn QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, qreal x, qreal y, qreal w, qreal h) const
6490 \since 4.3
6491
6492 This convenience function is equivalent to calling mapFromItem(item, QRectF(\a x, \a y, \a w, \a h)).
6493*/
6494
6495/*!
6496 Maps the rectangle \a rect, which is in this item's parent's coordinate
6497 system, to this item's coordinate system, and returns the mapped rectangle
6498 as a polygon.
6499
6500 \sa mapToParent(), mapFromItem(), transform(), {The Graphics View Coordinate
6501 System}
6502*/
6503QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
6504{
6505 // COMBINE
6506 if (!d_ptr->transformData)
6507 return rect.translated(p: -d_ptr->pos);
6508 return d_ptr->transformToParent().inverted().map(a: rect);
6509}
6510
6511/*!
6512 \fn QPolygonF QGraphicsItem::mapFromParent(qreal x, qreal y, qreal w, qreal h) const
6513 \since 4.3
6514
6515 This convenience function is equivalent to calling mapFromItem(QRectF(\a x, \a y, \a w, \a h)).
6516*/
6517
6518/*!
6519 Maps the rectangle \a rect, which is in this item's scene's coordinate
6520 system, to this item's coordinate system, and returns the mapped rectangle
6521 as a polygon.
6522
6523 \sa mapToScene(), mapFromItem(), transform(), {The Graphics View Coordinate
6524 System}
6525*/
6526QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const
6527{
6528 if (d_ptr->hasTranslateOnlySceneTransform())
6529 return rect.translated(dx: -d_ptr->sceneTransform.dx(), dy: -d_ptr->sceneTransform.dy());
6530 return d_ptr->sceneTransform.inverted().map(a: rect);
6531}
6532
6533/*!
6534 \fn QPolygonF QGraphicsItem::mapFromScene(qreal x, qreal y, qreal w, qreal h) const
6535 \since 4.3
6536
6537 This convenience function is equivalent to calling mapFromScene(QRectF(\a x, \a y, \a w, \a h)).
6538*/
6539
6540/*!
6541 Maps the polygon \a polygon, which is in \a item's coordinate system, to
6542 this item's coordinate system, and returns the mapped polygon.
6543
6544 If \a item is \nullptr, this function returns the same as mapFromScene().
6545
6546 \sa itemTransform(), mapToItem(), mapFromParent(), transform(), {The
6547 Graphics View Coordinate System}
6548*/
6549QPolygonF QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPolygonF &polygon) const
6550{
6551 if (item)
6552 return item->itemTransform(other: this).map(a: polygon);
6553 return mapFromScene(polygon);
6554}
6555
6556/*!
6557 Maps the polygon \a polygon, which is in this item's parent's coordinate
6558 system, to this item's coordinate system, and returns the mapped polygon.
6559
6560 \sa mapToParent(), mapToItem(), transform(), {The Graphics View Coordinate
6561 System}
6562*/
6563QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
6564{
6565 // COMBINE
6566 if (!d_ptr->transformData)
6567 return polygon.translated(offset: -d_ptr->pos);
6568 return d_ptr->transformToParent().inverted().map(a: polygon);
6569}
6570
6571/*!
6572 Maps the polygon \a polygon, which is in this item's scene's coordinate
6573 system, to this item's coordinate system, and returns the mapped polygon.
6574
6575 \sa mapToScene(), mapFromParent(), transform(), {The Graphics View Coordinate
6576 System}
6577*/
6578QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const
6579{
6580 if (d_ptr->hasTranslateOnlySceneTransform())
6581 return polygon.translated(dx: -d_ptr->sceneTransform.dx(), dy: -d_ptr->sceneTransform.dy());
6582 return d_ptr->sceneTransform.inverted().map(a: polygon);
6583}
6584
6585/*!
6586 Maps the path \a path, which is in \a item's coordinate system, to
6587 this item's coordinate system, and returns the mapped path.
6588
6589 If \a item is \nullptr, this function returns the same as mapFromScene().
6590
6591 \sa itemTransform(), mapFromParent(), mapFromScene(), mapToItem(), {The
6592 Graphics View Coordinate System}
6593*/
6594QPainterPath QGraphicsItem::mapFromItem(const QGraphicsItem *item, const QPainterPath &path) const
6595{
6596 if (item)
6597 return item->itemTransform(other: this).map(p: path);
6598 return mapFromScene(path);
6599}
6600
6601/*!
6602 Maps the path \a path, which is in this item's parent's coordinate
6603 system, to this item's coordinate system, and returns the mapped path.
6604
6605 \sa mapFromScene(), mapFromItem(), mapToParent(), {The Graphics View
6606 Coordinate System}
6607*/
6608QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
6609{
6610 // COMBINE
6611 if (!d_ptr->transformData)
6612 return path.translated(offset: -d_ptr->pos);
6613 return d_ptr->transformToParent().inverted().map(p: path);
6614}
6615
6616/*!
6617 Maps the path \a path, which is in this item's scene's coordinate
6618 system, to this item's coordinate system, and returns the mapped path.
6619
6620 \sa mapFromParent(), mapFromItem(), mapToScene(), {The Graphics View
6621 Coordinate System}
6622*/
6623QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const
6624{
6625 if (d_ptr->hasTranslateOnlySceneTransform())
6626 return path.translated(dx: -d_ptr->sceneTransform.dx(), dy: -d_ptr->sceneTransform.dy());
6627 return d_ptr->sceneTransform.inverted().map(p: path);
6628}
6629
6630/*!
6631 Returns \c true if this item is an ancestor of \a child (i.e., if this item
6632 is \a child's parent, or one of \a child's parent's ancestors).
6633
6634 \sa parentItem()
6635*/
6636bool QGraphicsItem::isAncestorOf(const QGraphicsItem *child) const
6637{
6638 if (!child || child == this)
6639 return false;
6640 if (child->d_ptr->depth() < d_ptr->depth())
6641 return false;
6642 const QGraphicsItem *ancestor = child;
6643 while ((ancestor = ancestor->d_ptr->parent)) {
6644 if (ancestor == this)
6645 return true;
6646 }
6647 return false;
6648}
6649
6650/*!
6651 \since 4.4
6652
6653 Returns the closest common ancestor item of this item and \a other,
6654 or \nullptr if either \a other is \nullptr, or there is no common ancestor.
6655
6656 \sa isAncestorOf()
6657*/
6658QGraphicsItem *QGraphicsItem::commonAncestorItem(const QGraphicsItem *other) const
6659{
6660 if (!other)
6661 return nullptr;
6662 if (other == this)
6663 return const_cast<QGraphicsItem *>(this);
6664 const QGraphicsItem *thisw = this;
6665 const QGraphicsItem *otherw = other;
6666 int thisDepth = d_ptr->depth();
6667 int otherDepth = other->d_ptr->depth();
6668 while (thisDepth > otherDepth) {
6669 thisw = thisw->d_ptr->parent;
6670 --thisDepth;
6671 }
6672 while (otherDepth > thisDepth) {
6673 otherw = otherw->d_ptr->parent;
6674 --otherDepth;
6675 }
6676 while (thisw && thisw != otherw) {
6677 thisw = thisw->d_ptr->parent;
6678 otherw = otherw->d_ptr->parent;
6679 }
6680 return const_cast<QGraphicsItem *>(thisw);
6681}
6682
6683/*!
6684 \since 4.4
6685 Returns \c true if this item is currently under the mouse cursor in one of
6686 the views; otherwise, false is returned.
6687
6688 \sa QGraphicsScene::views(), QCursor::pos()
6689*/
6690bool QGraphicsItem::isUnderMouse() const
6691{
6692 Q_D(const QGraphicsItem);
6693 if (!d->scene)
6694 return false;
6695
6696 QPoint cursorPos = QCursor::pos();
6697 const auto views = d->scene->views();
6698 for (QGraphicsView *view : views) {
6699 if (contains(point: mapFromScene(point: view->mapToScene(point: view->mapFromGlobal(cursorPos)))))
6700 return true;
6701 }
6702 return false;
6703}
6704
6705/*!
6706 Returns this item's custom data for the key \a key as a QVariant.
6707
6708 Custom item data is useful for storing arbitrary properties in any
6709 item. Example:
6710
6711 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 11
6712
6713 Qt does not use this feature for storing data; it is provided solely
6714 for the convenience of the user.
6715
6716 \sa setData()
6717*/
6718QVariant QGraphicsItem::data(int key) const
6719{
6720 QGraphicsItemCustomDataStore *store = qt_dataStore();
6721 if (!store->data.contains(key: this))
6722 return QVariant();
6723 return store->data.value(key: this).value(akey: key);
6724}
6725
6726/*!
6727 Sets this item's custom data for the key \a key to \a value.
6728
6729 Custom item data is useful for storing arbitrary properties for any
6730 item. Qt does not use this feature for storing data; it is provided solely
6731 for the convenience of the user.
6732
6733 \sa data()
6734*/
6735void QGraphicsItem::setData(int key, const QVariant &value)
6736{
6737 qt_dataStore()->data[this][key] = value;
6738}
6739
6740/*!
6741 \fn T qgraphicsitem_cast(QGraphicsItem *item)
6742 \relates QGraphicsItem
6743 \since 4.2
6744
6745 Returns the given \a item cast to type T if \a item is of type T;
6746 otherwise, \nullptr is returned.
6747
6748 \note To make this function work correctly with custom items, reimplement
6749 the \l{QGraphicsItem::}{type()} function for each custom QGraphicsItem
6750 subclass.
6751
6752 \sa QGraphicsItem::type(), QGraphicsItem::UserType
6753*/
6754
6755/*!
6756 Returns the type of an item as an int. All standard graphicsitem classes
6757 are associated with a unique value; see QGraphicsItem::Type. This type
6758 information is used by qgraphicsitem_cast() to distinguish between types.
6759
6760 The default implementation (in QGraphicsItem) returns UserType.
6761
6762 To enable use of qgraphicsitem_cast() with a custom item, reimplement this
6763 function and declare a Type enum value equal to your custom item's type.
6764 Custom items must return a value larger than or equal to UserType (65536).
6765
6766 For example:
6767
6768 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 1
6769
6770 \sa UserType
6771*/
6772int QGraphicsItem::type() const
6773{
6774 return (int)UserType;
6775}
6776
6777/*!
6778 Installs an event filter for this item on \a filterItem, causing
6779 all events for this item to first pass through \a filterItem's
6780 sceneEventFilter() function.
6781
6782 To filter another item's events, install this item as an event filter
6783 for the other item. Example:
6784
6785 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 12
6786
6787 An item can only filter events for other items in the same
6788 scene. Also, an item cannot filter its own events; instead, you
6789 can reimplement sceneEvent() directly.
6790
6791 Items must belong to a scene for scene event filters to be installed and
6792 used.
6793
6794 \sa removeSceneEventFilter(), sceneEventFilter(), sceneEvent()
6795*/
6796void QGraphicsItem::installSceneEventFilter(QGraphicsItem *filterItem)
6797{
6798 if (!d_ptr->scene) {
6799 qWarning(msg: "QGraphicsItem::installSceneEventFilter: event filters can only be installed"
6800 " on items in a scene.");
6801 return;
6802 }
6803 if (d_ptr->scene != filterItem->scene()) {
6804 qWarning(msg: "QGraphicsItem::installSceneEventFilter: event filters can only be installed"
6805 " on items in the same scene.");
6806 return;
6807 }
6808 d_ptr->scene->d_func()->installSceneEventFilter(watched: this, filter: filterItem);
6809}
6810
6811/*!
6812 Removes an event filter on this item from \a filterItem.
6813
6814 \sa installSceneEventFilter()
6815*/
6816void QGraphicsItem::removeSceneEventFilter(QGraphicsItem *filterItem)
6817{
6818 if (!d_ptr->scene || d_ptr->scene != filterItem->scene())
6819 return;
6820 d_ptr->scene->d_func()->removeSceneEventFilter(watched: this, filter: filterItem);
6821}
6822
6823/*!
6824 Filters events for the item \a watched. \a event is the filtered
6825 event.
6826
6827 Reimplementing this function in a subclass makes it possible
6828 for the item to be used as an event filter for other items,
6829 intercepting all the events sent to those items before they are
6830 able to respond.
6831
6832 Reimplementations must return true to prevent further processing of
6833 a given event, ensuring that it will not be delivered to the watched
6834 item, or return false to indicate that the event should be propagated
6835 further by the event system.
6836
6837 \sa installSceneEventFilter()
6838*/
6839bool QGraphicsItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
6840{
6841 Q_UNUSED(watched);
6842 Q_UNUSED(event);
6843 return false;
6844}
6845
6846/*!
6847 This virtual function receives events to this item. Reimplement
6848 this function to intercept events before they are dispatched to
6849 the specialized event handlers contextMenuEvent(), focusInEvent(),
6850 focusOutEvent(), hoverEnterEvent(), hoverMoveEvent(),
6851 hoverLeaveEvent(), keyPressEvent(), keyReleaseEvent(),
6852 mousePressEvent(), mouseReleaseEvent(), mouseMoveEvent(), and
6853 mouseDoubleClickEvent().
6854
6855 Returns \c true if the event was recognized and handled; otherwise, (e.g., if
6856 the event type was not recognized,) false is returned.
6857
6858 \a event is the intercepted event.
6859*/
6860bool QGraphicsItem::sceneEvent(QEvent *event)
6861{
6862 if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents) {
6863 if (event->type() == QEvent::HoverEnter || event->type() == QEvent::HoverLeave
6864 || event->type() == QEvent::DragEnter || event->type() == QEvent::DragLeave) {
6865 // Hover enter and hover leave events for children are ignored;
6866 // hover move events are forwarded.
6867 return true;
6868 }
6869
6870 QGraphicsItem *handler = this;
6871 do {
6872 handler = handler->d_ptr->parent;
6873 Q_ASSERT(handler);
6874 } while (handler->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents);
6875 // Forward the event to the closest parent that handles child
6876 // events, mapping existing item-local coordinates to its
6877 // coordinate system.
6878 d_ptr->remapItemPos(event, item: handler);
6879 handler->sceneEvent(event);
6880 return true;
6881 }
6882
6883 if (event->type() == QEvent::FocusOut) {
6884 focusOutEvent(event: static_cast<QFocusEvent *>(event));
6885 return true;
6886 }
6887
6888 if (!d_ptr->visible) {
6889 // Eaten
6890 return true;
6891 }
6892
6893 switch (event->type()) {
6894 case QEvent::FocusIn:
6895 focusInEvent(event: static_cast<QFocusEvent *>(event));
6896 break;
6897 case QEvent::GraphicsSceneContextMenu:
6898 contextMenuEvent(event: static_cast<QGraphicsSceneContextMenuEvent *>(event));
6899 break;
6900 case QEvent::GraphicsSceneDragEnter:
6901 dragEnterEvent(event: static_cast<QGraphicsSceneDragDropEvent *>(event));
6902 break;
6903 case QEvent::GraphicsSceneDragMove:
6904 dragMoveEvent(event: static_cast<QGraphicsSceneDragDropEvent *>(event));
6905 break;
6906 case QEvent::GraphicsSceneDragLeave:
6907 dragLeaveEvent(event: static_cast<QGraphicsSceneDragDropEvent *>(event));
6908 break;
6909 case QEvent::GraphicsSceneDrop:
6910 dropEvent(event: static_cast<QGraphicsSceneDragDropEvent *>(event));
6911 break;
6912 case QEvent::GraphicsSceneHoverEnter:
6913 hoverEnterEvent(event: static_cast<QGraphicsSceneHoverEvent *>(event));
6914 break;
6915 case QEvent::GraphicsSceneHoverMove:
6916 hoverMoveEvent(event: static_cast<QGraphicsSceneHoverEvent *>(event));
6917 break;
6918 case QEvent::GraphicsSceneHoverLeave:
6919 hoverLeaveEvent(event: static_cast<QGraphicsSceneHoverEvent *>(event));
6920 break;
6921 case QEvent::GraphicsSceneMouseMove:
6922 mouseMoveEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
6923 break;
6924 case QEvent::GraphicsSceneMousePress:
6925 mousePressEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
6926 break;
6927 case QEvent::GraphicsSceneMouseRelease:
6928 mouseReleaseEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
6929 break;
6930 case QEvent::GraphicsSceneMouseDoubleClick:
6931 mouseDoubleClickEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
6932 break;
6933 case QEvent::GraphicsSceneWheel:
6934 wheelEvent(event: static_cast<QGraphicsSceneWheelEvent *>(event));
6935 break;
6936 case QEvent::KeyPress: {
6937 QKeyEvent *k = static_cast<QKeyEvent *>(event);
6938 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
6939 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
6940 bool res = false;
6941 if (k->key() == Qt::Key_Backtab
6942 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
6943 if (d_ptr->isWidget) {
6944 res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(next: false);
6945 } else if (d_ptr->scene) {
6946 res = d_ptr->scene->focusNextPrevChild(next: false);
6947 }
6948 } else if (k->key() == Qt::Key_Tab) {
6949 if (d_ptr->isWidget) {
6950 res = static_cast<QGraphicsWidget *>(this)->focusNextPrevChild(next: true);
6951 } else if (d_ptr->scene) {
6952 res = d_ptr->scene->focusNextPrevChild(next: true);
6953 }
6954 }
6955 if (!res)
6956 event->ignore();
6957 return true;
6958 }
6959 }
6960 keyPressEvent(event: static_cast<QKeyEvent *>(event));
6961 break;
6962 }
6963 case QEvent::KeyRelease:
6964 keyReleaseEvent(event: static_cast<QKeyEvent *>(event));
6965 break;
6966 case QEvent::InputMethod:
6967 inputMethodEvent(event: static_cast<QInputMethodEvent *>(event));
6968 break;
6969 case QEvent::WindowActivate:
6970 case QEvent::WindowDeactivate:
6971 // Propagate panel activation.
6972 if (d_ptr->scene) {
6973 for (int i = 0; i < d_ptr->children.size(); ++i) {
6974 QGraphicsItem *child = d_ptr->children.at(i);
6975 if (child->isVisible() && !child->isPanel()) {
6976 if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
6977 d_ptr->scene->sendEvent(item: child, event);
6978 }
6979 }
6980 }
6981 break;
6982 default:
6983 return false;
6984 }
6985
6986 return true;
6987}
6988
6989/*!
6990 This event handler can be reimplemented in a subclass to process context
6991 menu events. The \a event parameter contains details about the event to
6992 be handled.
6993
6994 If you ignore the event (i.e., by calling QEvent::ignore()), \a event
6995 will propagate to any item beneath this item. If no items accept the
6996 event, it will be ignored by the scene and propagate to the view.
6997
6998 It's common to open a QMenu in response to receiving a context menu
6999 event. Example:
7000
7001 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 13
7002
7003 The default implementation ignores the event.
7004
7005 \sa sceneEvent()
7006*/
7007void QGraphicsItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
7008{
7009 event->ignore();
7010}
7011
7012/*!
7013 This event handler, for event \a event, can be reimplemented to receive
7014 drag enter events for this item. Drag enter events are generated as the
7015 cursor enters the item's area.
7016
7017 By accepting the event (i.e., by calling QEvent::accept()), the item will
7018 accept drop events, in addition to receiving drag move and drag
7019 leave. Otherwise, the event will be ignored and propagate to the item
7020 beneath. If the event is accepted, the item will receive a drag move event
7021 before control goes back to the event loop.
7022
7023 A common implementation of dragEnterEvent accepts or ignores \a event
7024 depending on the associated mime data in \a event. Example:
7025
7026 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 14
7027
7028 Items do not receive drag and drop events by default; to enable this
7029 feature, call \c setAcceptDrops(true).
7030
7031 The default implementation does nothing.
7032
7033 \sa dropEvent(), dragMoveEvent(), dragLeaveEvent()
7034*/
7035void QGraphicsItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
7036{
7037 Q_D(QGraphicsItem);
7038 // binary compatibility workaround between 4.4 and 4.5
7039 if (d->isProxyWidget())
7040 static_cast<QGraphicsProxyWidget*>(this)->dragEnterEvent(event);
7041}
7042
7043/*!
7044 This event handler, for event \a event, can be reimplemented to receive
7045 drag leave events for this item. Drag leave events are generated as the
7046 cursor leaves the item's area. Most often you will not need to reimplement
7047 this function, but it can be useful for resetting state in your item
7048 (e.g., highlighting).
7049
7050 Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7051
7052 Items do not receive drag and drop events by default; to enable this
7053 feature, call \c setAcceptDrops(true).
7054
7055 The default implementation does nothing.
7056
7057 \sa dragEnterEvent(), dropEvent(), dragMoveEvent()
7058*/
7059void QGraphicsItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
7060{
7061 Q_D(QGraphicsItem);
7062 // binary compatibility workaround between 4.4 and 4.5
7063 if (d->isProxyWidget())
7064 static_cast<QGraphicsProxyWidget*>(this)->dragLeaveEvent(event);
7065}
7066
7067/*!
7068 This event handler, for event \a event, can be reimplemented to receive
7069 drag move events for this item. Drag move events are generated as the
7070 cursor moves around inside the item's area. Most often you will not need
7071 to reimplement this function; it is used to indicate that only parts of
7072 the item can accept drops.
7073
7074 Calling QEvent::ignore() or QEvent::accept() on \a event toggles whether
7075 or not the item will accept drops at the position from the event. By
7076 default, \a event is accepted, indicating that the item allows drops at
7077 the specified position.
7078
7079 Items do not receive drag and drop events by default; to enable this
7080 feature, call \c setAcceptDrops(true).
7081
7082 The default implementation does nothing.
7083
7084 \sa dropEvent(), dragEnterEvent(), dragLeaveEvent()
7085*/
7086void QGraphicsItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
7087{
7088 Q_D(QGraphicsItem);
7089 // binary compatibility workaround between 4.4 and 4.5
7090 if (d->isProxyWidget())
7091 static_cast<QGraphicsProxyWidget*>(this)->dragMoveEvent(event);
7092}
7093
7094/*!
7095 This event handler, for event \a event, can be reimplemented to receive
7096 drop events for this item. Items can only receive drop events if the last
7097 drag move event was accepted.
7098
7099 Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7100
7101 Items do not receive drag and drop events by default; to enable this
7102 feature, call \c setAcceptDrops(true).
7103
7104 The default implementation does nothing.
7105
7106 \sa dragEnterEvent(), dragMoveEvent(), dragLeaveEvent()
7107*/
7108void QGraphicsItem::dropEvent(QGraphicsSceneDragDropEvent *event)
7109{
7110 Q_D(QGraphicsItem);
7111 // binary compatibility workaround between 4.4 and 4.5
7112 if (d->isProxyWidget())
7113 static_cast<QGraphicsProxyWidget*>(this)->dropEvent(event);
7114}
7115
7116/*!
7117 This event handler, for event \a event, can be reimplemented to receive
7118 focus in events for this item. The default implementation calls
7119 ensureVisible().
7120
7121 \sa focusOutEvent(), sceneEvent(), setFocus()
7122*/
7123void QGraphicsItem::focusInEvent(QFocusEvent *event)
7124{
7125 Q_UNUSED(event);
7126 update();
7127}
7128
7129/*!
7130 This event handler, for event \a event, can be reimplemented to receive
7131 focus out events for this item. The default implementation does nothing.
7132
7133 \sa focusInEvent(), sceneEvent(), setFocus()
7134*/
7135void QGraphicsItem::focusOutEvent(QFocusEvent *event)
7136{
7137 Q_UNUSED(event);
7138 update();
7139}
7140
7141/*!
7142 This event handler, for event \a event, can be reimplemented to receive
7143 hover enter events for this item. The default implementation calls
7144 update(); otherwise it does nothing.
7145
7146 Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7147
7148 \sa hoverMoveEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
7149*/
7150void QGraphicsItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
7151{
7152 Q_UNUSED(event);
7153 update();
7154}
7155
7156/*!
7157 This event handler, for event \a event, can be reimplemented to receive
7158 hover move events for this item. The default implementation does nothing.
7159
7160 Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7161
7162 \sa hoverEnterEvent(), hoverLeaveEvent(), sceneEvent(), setAcceptHoverEvents()
7163*/
7164void QGraphicsItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
7165{
7166 Q_UNUSED(event);
7167}
7168
7169/*!
7170 This event handler, for event \a event, can be reimplemented to receive
7171 hover leave events for this item. The default implementation calls
7172 update(); otherwise it does nothing.
7173
7174 Calling QEvent::ignore() or QEvent::accept() on \a event has no effect.
7175
7176 \sa hoverEnterEvent(), hoverMoveEvent(), sceneEvent(), setAcceptHoverEvents()
7177*/
7178void QGraphicsItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
7179{
7180 Q_UNUSED(event);
7181 update();
7182}
7183
7184/*!
7185 This event handler, for event \a event, can be reimplemented to
7186 receive key press events for this item. The default implementation
7187 ignores the event. If you reimplement this handler, the event will by
7188 default be accepted.
7189
7190 Note that key events are only received for items that set the
7191 ItemIsFocusable flag, and that have keyboard input focus.
7192
7193 \sa keyReleaseEvent(), setFocus(), QGraphicsScene::setFocusItem(),
7194 sceneEvent()
7195*/
7196void QGraphicsItem::keyPressEvent(QKeyEvent *event)
7197{
7198 event->ignore();
7199}
7200
7201/*!
7202 This event handler, for event \a event, can be reimplemented to receive
7203 key release events for this item. The default implementation
7204 ignores the event. If you reimplement this handler, the event will by
7205 default be accepted.
7206
7207 Note that key events are only received for items that set the
7208 ItemIsFocusable flag, and that have keyboard input focus.
7209
7210 \sa keyPressEvent(), setFocus(), QGraphicsScene::setFocusItem(),
7211 sceneEvent()
7212*/
7213void QGraphicsItem::keyReleaseEvent(QKeyEvent *event)
7214{
7215 event->ignore();
7216}
7217
7218/*!
7219 This event handler, for event \a event, can be reimplemented to
7220 receive mouse press events for this item. Mouse press events are
7221 only delivered to items that accept the mouse button that is
7222 pressed. By default, an item accepts all mouse buttons, but you
7223 can change this by calling setAcceptedMouseButtons().
7224
7225 The mouse press event decides which item should become the mouse
7226 grabber (see QGraphicsScene::mouseGrabberItem()). If you do not
7227 reimplement this function, the press event will propagate to any
7228 topmost item beneath this item, and no other mouse events will be
7229 delivered to this item.
7230
7231 If you do reimplement this function, \a event will by default be
7232 accepted (see QEvent::accept()), and this item is then the mouse
7233 grabber. This allows the item to receive future move, release and
7234 doubleclick events. If you call QEvent::ignore() on \a event, this
7235 item will lose the mouse grab, and \a event will propagate to any
7236 topmost item beneath. No further mouse events will be delivered to
7237 this item unless a new mouse press event is received.
7238
7239 The default implementation handles basic item interaction, such as
7240 selection and moving. If you want to keep the base implementation
7241 when reimplementing this function, call
7242 QGraphicsItem::mousePressEvent() in your reimplementation.
7243
7244 The event is \l{QEvent::ignore()}d for items that are neither
7245 \l{QGraphicsItem::ItemIsMovable}{movable} nor
7246 \l{QGraphicsItem::ItemIsSelectable}{selectable}.
7247
7248 \sa mouseMoveEvent(), mouseReleaseEvent(),
7249 mouseDoubleClickEvent(), sceneEvent()
7250*/
7251void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
7252{
7253 if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
7254 bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
7255 if (!multiSelect) {
7256 if (!d_ptr->selected) {
7257 if (QGraphicsScene *scene = d_ptr->scene) {
7258 ++scene->d_func()->selectionChanging;
7259 scene->clearSelection();
7260 --scene->d_func()->selectionChanging;
7261 }
7262 setSelected(true);
7263 }
7264 }
7265 } else if (!(flags() & ItemIsMovable)) {
7266 event->ignore();
7267 }
7268 if (d_ptr->isWidget) {
7269 // Qt::Popup closes when you click outside.
7270 QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this);
7271 if ((w->windowFlags() & Qt::Popup) == Qt::Popup) {
7272 event->accept();
7273 if (!w->rect().contains(p: event->pos()))
7274 w->close();
7275 }
7276 }
7277}
7278
7279bool _qt_movableAncestorIsSelected(const QGraphicsItem *item)
7280{
7281 const QGraphicsItem *parent = item->parentItem();
7282 return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(item: parent));
7283}
7284
7285bool QGraphicsItemPrivate::movableAncestorIsSelected(const QGraphicsItem *item)
7286{
7287 const QGraphicsItem *parent = item->d_ptr->parent;
7288 return parent && (((parent->flags() & QGraphicsItem::ItemIsMovable) && parent->isSelected()) || _qt_movableAncestorIsSelected(item: parent));
7289}
7290
7291/*!
7292 This event handler, for event \a event, can be reimplemented to
7293 receive mouse move events for this item. If you do receive this
7294 event, you can be certain that this item also received a mouse
7295 press event, and that this item is the current mouse grabber.
7296
7297 Calling QEvent::ignore() or QEvent::accept() on \a event has no
7298 effect.
7299
7300 The default implementation handles basic item interaction, such as
7301 selection and moving. If you want to keep the base implementation
7302 when reimplementing this function, call
7303 QGraphicsItem::mouseMoveEvent() in your reimplementation.
7304
7305 Please note that mousePressEvent() decides which graphics item it
7306 is that receives mouse events. See the mousePressEvent()
7307 description for details.
7308
7309 \sa mousePressEvent(), mouseReleaseEvent(),
7310 mouseDoubleClickEvent(), sceneEvent()
7311*/
7312void QGraphicsItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
7313{
7314 if ((event->buttons() & Qt::LeftButton) && (flags() & ItemIsMovable)) {
7315 // Determine the list of items that need to be moved.
7316 QList<QGraphicsItem *> selectedItems;
7317 QHash<QGraphicsItem *, QPointF> initialPositions;
7318 if (d_ptr->scene) {
7319 selectedItems = d_ptr->scene->selectedItems();
7320 initialPositions = d_ptr->scene->d_func()->movingItemsInitialPositions;
7321 if (initialPositions.isEmpty()) {
7322 for (QGraphicsItem *item : qAsConst(t&: selectedItems))
7323 initialPositions[item] = item->pos();
7324 initialPositions[this] = pos();
7325 }
7326 d_ptr->scene->d_func()->movingItemsInitialPositions = initialPositions;
7327 }
7328
7329 // Find the active view.
7330 QGraphicsView *view = nullptr;
7331 if (event->widget())
7332 view = qobject_cast<QGraphicsView *>(object: event->widget()->parentWidget());
7333
7334 // Move all selected items
7335 int i = 0;
7336 bool movedMe = false;
7337 while (i <= selectedItems.size()) {
7338 QGraphicsItem *item = nullptr;
7339 if (i < selectedItems.size())
7340 item = selectedItems.at(i);
7341 else
7342 item = this;
7343 if (item == this) {
7344 // Slightly clumsy-looking way to ensure that "this" is part
7345 // of the list of items to move, this is to avoid allocations
7346 // (appending this item to the list of selected items causes a
7347 // detach).
7348 if (movedMe)
7349 break;
7350 movedMe = true;
7351 }
7352
7353 if ((item->flags() & ItemIsMovable) && !QGraphicsItemPrivate::movableAncestorIsSelected(item)) {
7354 QPointF currentParentPos;
7355 QPointF buttonDownParentPos;
7356 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations) {
7357 // Items whose ancestors ignore transformations need to
7358 // map screen coordinates to local coordinates, then map
7359 // those to the parent.
7360 QTransform viewToItemTransform = (item->deviceTransform(viewportTransform: view->viewportTransform())).inverted();
7361 currentParentPos = mapToParent(point: viewToItemTransform.map(p: QPointF(view->mapFromGlobal(event->screenPos()))));
7362 buttonDownParentPos = mapToParent(point: viewToItemTransform.map(p: QPointF(view->mapFromGlobal(event->buttonDownScreenPos(button: Qt::LeftButton)))));
7363 } else if (item->flags() & ItemIgnoresTransformations) {
7364 // Root items that ignore transformations need to
7365 // calculate their diff by mapping viewport coordinates
7366 // directly to parent coordinates.
7367 // COMBINE
7368 QTransform itemTransform;
7369 if (item->d_ptr->transformData)
7370 itemTransform = item->d_ptr->transformData->computedFullTransform();
7371 itemTransform.translate(dx: item->d_ptr->pos.x(), dy: item->d_ptr->pos.y());
7372 QTransform viewToParentTransform = itemTransform
7373 * (item->sceneTransform() * view->viewportTransform()).inverted();
7374 currentParentPos = viewToParentTransform.map(p: QPointF(view->mapFromGlobal(event->screenPos())));
7375 buttonDownParentPos = viewToParentTransform.map(p: QPointF(view->mapFromGlobal(event->buttonDownScreenPos(button: Qt::LeftButton))));
7376 } else {
7377 // All other items simply map from the scene.
7378 currentParentPos = item->mapToParent(point: item->mapFromScene(point: event->scenePos()));
7379 buttonDownParentPos = item->mapToParent(point: item->mapFromScene(point: event->buttonDownScenePos(button: Qt::LeftButton)));
7380 }
7381
7382 item->setPos(initialPositions.value(key: item) + currentParentPos - buttonDownParentPos);
7383
7384 if (item->flags() & ItemIsSelectable)
7385 item->setSelected(true);
7386 }
7387 ++i;
7388 }
7389
7390 } else {
7391 event->ignore();
7392 }
7393}
7394
7395/*!
7396 This event handler, for event \a event, can be reimplemented to
7397 receive mouse release events for this item.
7398
7399 Calling QEvent::ignore() or QEvent::accept() on \a event has no
7400 effect.
7401
7402 The default implementation handles basic item interaction, such as
7403 selection and moving. If you want to keep the base implementation
7404 when reimplementing this function, call
7405 QGraphicsItem::mouseReleaseEvent() in your reimplementation.
7406
7407 Please note that mousePressEvent() decides which graphics item it
7408 is that receives mouse events. See the mousePressEvent()
7409 description for details.
7410
7411 \sa mousePressEvent(), mouseMoveEvent(), mouseDoubleClickEvent(),
7412 sceneEvent()
7413*/
7414void QGraphicsItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
7415{
7416 if (event->button() == Qt::LeftButton && (flags() & ItemIsSelectable)) {
7417 bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
7418 if (event->scenePos() == event->buttonDownScenePos(button: Qt::LeftButton)) {
7419 // The item didn't move
7420 if (multiSelect) {
7421 setSelected(!isSelected());
7422 } else {
7423 bool selectionChanged = false;
7424 if (QGraphicsScene *scene = d_ptr->scene) {
7425 ++scene->d_func()->selectionChanging;
7426 // Clear everything but this item. Bypass
7427 // QGraphicsScene::clearSelection()'s default behavior by
7428 // temporarily removing this item from the selection list.
7429 if (d_ptr->selected) {
7430 scene->d_func()->selectedItems.remove(value: this);
7431 foreach (QGraphicsItem *item, scene->d_func()->selectedItems) {
7432 if (item->isSelected()) {
7433 selectionChanged = true;
7434 break;
7435 }
7436 }
7437 }
7438 scene->clearSelection();
7439 if (d_ptr->selected)
7440 scene->d_func()->selectedItems.insert(value: this);
7441 --scene->d_func()->selectionChanging;
7442 if (selectionChanged)
7443 emit d_ptr->scene->selectionChanged();
7444 }
7445 setSelected(true);
7446 }
7447 }
7448 }
7449 if (d_ptr->scene && !event->buttons())
7450 d_ptr->scene->d_func()->movingItemsInitialPositions.clear();
7451}
7452
7453/*!
7454 This event handler, for event \a event, can be reimplemented to
7455 receive mouse doubleclick events for this item.
7456
7457 When doubleclicking an item, the item will first receive a mouse
7458 press event, followed by a release event (i.e., a click), then a
7459 doubleclick event, and finally a release event.
7460
7461 Calling QEvent::ignore() or QEvent::accept() on \a event has no
7462 effect.
7463
7464 The default implementation calls mousePressEvent(). If you want to
7465 keep the base implementation when reimplementing this function,
7466 call QGraphicsItem::mouseDoubleClickEvent() in your
7467 reimplementation.
7468
7469 Note that an item will not receive double click events if it is
7470 neither \l {QGraphicsItem::ItemIsSelectable}{selectable} nor
7471 \l{QGraphicsItem::ItemIsMovable}{movable} (single mouse clicks are
7472 ignored in this case, and that stops the generation of double
7473 clicks).
7474
7475 \sa mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), sceneEvent()
7476*/
7477void QGraphicsItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
7478{
7479 mousePressEvent(event);
7480}
7481
7482/*!
7483 This event handler, for event \a event, can be reimplemented to receive
7484 wheel events for this item. If you reimplement this function, \a event
7485 will be accepted by default.
7486
7487 If you ignore the event, (i.e., by calling QEvent::ignore(),) it will
7488 propagate to any item beneath this item. If no items accept the event, it
7489 will be ignored by the scene, and propagate to the view (e.g., the view's
7490 vertical scroll bar).
7491
7492 The default implementation ignores the event.
7493
7494 \sa sceneEvent()
7495*/
7496void QGraphicsItem::wheelEvent(QGraphicsSceneWheelEvent *event)
7497{
7498 event->ignore();
7499}
7500
7501/*!
7502 This event handler, for event \a event, can be reimplemented to receive
7503 input method events for this item. The default implementation ignores the
7504 event.
7505
7506 \sa inputMethodQuery(), sceneEvent()
7507*/
7508void QGraphicsItem::inputMethodEvent(QInputMethodEvent *event)
7509{
7510 event->ignore();
7511}
7512
7513/*!
7514 This method is only relevant for input items. It is used by the
7515 input method to query a set of properties of the item to be able
7516 to support complex input method operations, such as support for
7517 surrounding text and reconversions. \a query specifies which
7518 property is queried.
7519
7520 \sa inputMethodEvent(), QInputMethodEvent
7521*/
7522QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
7523{
7524 Q_UNUSED(query);
7525 return QVariant();
7526}
7527
7528/*!
7529 Returns the current input method hints of this item.
7530
7531 Input method hints are only relevant for input items.
7532 The hints are used by the input method to indicate how it should operate.
7533 For example, if the Qt::ImhNumbersOnly flag is set, the input method may change
7534 its visual components to reflect that only numbers can be entered.
7535
7536 The effect may vary between input method implementations.
7537
7538 \since 4.6
7539
7540 \sa setInputMethodHints(), inputMethodQuery()
7541*/
7542Qt::InputMethodHints QGraphicsItem::inputMethodHints() const
7543{
7544 Q_D(const QGraphicsItem);
7545 return d->imHints;
7546}
7547
7548/*!
7549 Sets the current input method hints of this item to \a hints.
7550
7551 \since 4.6
7552
7553 \sa inputMethodHints(), inputMethodQuery()
7554*/
7555void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints)
7556{
7557 Q_D(QGraphicsItem);
7558 d->imHints = hints;
7559 if (!hasFocus())
7560 return;
7561 d->scene->d_func()->updateInputMethodSensitivityInViews();
7562 QWidget *fw = QApplication::focusWidget();
7563 if (!fw)
7564 return;
7565 QGuiApplication::inputMethod()->update(queries: Qt::ImHints);
7566}
7567
7568/*!
7569 Updates the item's micro focus.
7570
7571 \since 4.7
7572
7573 \sa QInputMethod
7574*/
7575void QGraphicsItem::updateMicroFocus()
7576{
7577}
7578
7579/*!
7580 This virtual function is called by QGraphicsItem to notify custom items
7581 that some part of the item's state changes. By reimplementing this
7582 function, you can react to a change, and in some cases (depending on \a
7583 change), adjustments can be made.
7584
7585 \a change is the parameter of the item that is changing. \a value is the
7586 new value; the type of the value depends on \a change.
7587
7588 Example:
7589
7590 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 15
7591
7592 The default implementation does nothing, and returns \a value.
7593
7594 Note: Certain QGraphicsItem functions cannot be called in a
7595 reimplementation of this function; see the GraphicsItemChange
7596 documentation for details.
7597
7598 \sa GraphicsItemChange
7599*/
7600QVariant QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)
7601{
7602 Q_UNUSED(change);
7603 return value;
7604}
7605
7606/*!
7607 \internal
7608
7609 Note: This is provided as a hook to avoid future problems related
7610 to adding virtual functions.
7611*/
7612bool QGraphicsItem::supportsExtension(Extension extension) const
7613{
7614 Q_UNUSED(extension);
7615 return false;
7616}
7617
7618/*!
7619 \internal
7620
7621 Note: This is provided as a hook to avoid future problems related
7622 to adding virtual functions.
7623*/
7624void QGraphicsItem::setExtension(Extension extension, const QVariant &variant)
7625{
7626 Q_UNUSED(extension);
7627 Q_UNUSED(variant);
7628}
7629
7630/*!
7631 \internal
7632
7633 Note: This is provided as a hook to avoid future problems related
7634 to adding virtual functions.
7635*/
7636QVariant QGraphicsItem::extension(const QVariant &variant) const
7637{
7638 Q_UNUSED(variant);
7639 return QVariant();
7640}
7641
7642/*!
7643 \internal
7644
7645 Adds this item to the scene's index. Called in conjunction with
7646 removeFromIndex() to ensure the index bookkeeping is correct when
7647 the item's position, transformation or shape changes.
7648*/
7649void QGraphicsItem::addToIndex()
7650{
7651 if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
7652 || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
7653 // ### add to child index only if applicable
7654 return;
7655 }
7656 if (d_ptr->scene)
7657 d_ptr->scene->d_func()->index->addItem(item: this);
7658}
7659
7660/*!
7661 \internal
7662
7663 Removes this item from the scene's index. Called in conjunction
7664 with addToIndex() to ensure the index bookkeeping is correct when
7665 the item's position, transformation or shape changes.
7666*/
7667void QGraphicsItem::removeFromIndex()
7668{
7669 if (d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
7670 || d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren) {
7671 // ### remove from child index only if applicable
7672 return;
7673 }
7674 if (d_ptr->scene)
7675 d_ptr->scene->d_func()->index->removeItem(item: this);
7676}
7677
7678/*!
7679 Prepares the item for a geometry change. Call this function before
7680 changing the bounding rect of an item to keep QGraphicsScene's index up to
7681 date.
7682
7683 prepareGeometryChange() will call update() if this is necessary.
7684
7685 Example:
7686
7687 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 16
7688
7689 \sa boundingRect()
7690*/
7691void QGraphicsItem::prepareGeometryChange()
7692{
7693 if (d_ptr->inDestructor)
7694 return;
7695 if (d_ptr->scene) {
7696 d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
7697 d_ptr->geometryChanged = 1;
7698 d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
7699 d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper;
7700
7701 QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
7702 scenePrivate->index->prepareBoundingRectChange(item: this);
7703 scenePrivate->markDirty(item: this, rect: QRectF(), /*invalidateChildren=*/true, /*force=*/false,
7704 /*ignoreOpacity=*/ false, /*removingItemFromScene=*/ false,
7705 /*updateBoundingRect=*/true);
7706
7707 // For compatibility reasons, we have to update the item's old geometry
7708 // if someone is connected to the changed signal or the scene has no views.
7709 // Note that this has to be done *after* markDirty to ensure that
7710 // _q_processDirtyItems is called before _q_emitUpdated.
7711 if (scenePrivate->isSignalConnected(signalIdx: scenePrivate->changedSignalIndex)
7712 || scenePrivate->views.isEmpty()) {
7713 if (d_ptr->hasTranslateOnlySceneTransform()) {
7714 d_ptr->scene->update(rect: boundingRect().translated(dx: d_ptr->sceneTransform.dx(),
7715 dy: d_ptr->sceneTransform.dy()));
7716 } else {
7717 d_ptr->scene->update(rect: d_ptr->sceneTransform.mapRect(boundingRect()));
7718 }
7719 }
7720 }
7721
7722 d_ptr->markParentDirty(/*updateBoundingRect=*/true);
7723}
7724
7725/*!
7726 \internal
7727
7728 Highlights \a item as selected.
7729
7730 NOTE: This function is a duplicate of qt_graphicsItem_highlightSelected() in
7731 qgraphicssvgitem.cpp!
7732*/
7733static void qt_graphicsItem_highlightSelected(
7734 QGraphicsItem *item, QPainter *painter, const QStyleOptionGraphicsItem *option)
7735{
7736 const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
7737 if (qFuzzyIsNull(d: qMax(a: murect.width(), b: murect.height())))
7738 return;
7739
7740 const QRectF mbrect = painter->transform().mapRect(item->boundingRect());
7741 if (qMin(a: mbrect.width(), b: mbrect.height()) < qreal(1.0))
7742 return;
7743
7744 qreal itemPenWidth;
7745 switch (item->type()) {
7746 case QGraphicsEllipseItem::Type:
7747 itemPenWidth = static_cast<QGraphicsEllipseItem *>(item)->pen().widthF();
7748 break;
7749 case QGraphicsPathItem::Type:
7750 itemPenWidth = static_cast<QGraphicsPathItem *>(item)->pen().widthF();
7751 break;
7752 case QGraphicsPolygonItem::Type:
7753 itemPenWidth = static_cast<QGraphicsPolygonItem *>(item)->pen().widthF();
7754 break;
7755 case QGraphicsRectItem::Type:
7756 itemPenWidth = static_cast<QGraphicsRectItem *>(item)->pen().widthF();
7757 break;
7758 case QGraphicsSimpleTextItem::Type:
7759 itemPenWidth = static_cast<QGraphicsSimpleTextItem *>(item)->pen().widthF();
7760 break;
7761 case QGraphicsLineItem::Type:
7762 itemPenWidth = static_cast<QGraphicsLineItem *>(item)->pen().widthF();
7763 break;
7764 default:
7765 itemPenWidth = 1.0;
7766 }
7767 const qreal pad = itemPenWidth / 2;
7768
7769 const qreal penWidth = 0; // cosmetic pen
7770
7771 const QColor fgcolor = option->palette.windowText().color();
7772 const QColor bgcolor( // ensure good contrast against fgcolor
7773 fgcolor.red() > 127 ? 0 : 255,
7774 fgcolor.green() > 127 ? 0 : 255,
7775 fgcolor.blue() > 127 ? 0 : 255);
7776
7777 painter->setPen(QPen(bgcolor, penWidth, Qt::SolidLine));
7778 painter->setBrush(Qt::NoBrush);
7779 painter->drawRect(rect: item->boundingRect().adjusted(xp1: pad, yp1: pad, xp2: -pad, yp2: -pad));
7780
7781 painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
7782 painter->setBrush(Qt::NoBrush);
7783 painter->drawRect(rect: item->boundingRect().adjusted(xp1: pad, yp1: pad, xp2: -pad, yp2: -pad));
7784}
7785
7786/*!
7787 \class QGraphicsObject
7788 \brief The QGraphicsObject class provides a base class for all graphics items that
7789 require signals, slots and properties.
7790 \since 4.6
7791 \ingroup graphicsview-api
7792 \inmodule QtWidgets
7793
7794 The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms.
7795 It maps many of QGraphicsItem's basic setters and getters to properties and adds notification
7796 signals for many of them.
7797
7798 \section1 Parents and Children
7799
7800 Each graphics object can be constructed with a parent item. This ensures that the
7801 item will be destroyed when its parent item is destroyed. Although QGraphicsObject
7802 inherits from both QObject and QGraphicsItem, you should use the functions provided
7803 by QGraphicsItem, \e not QObject, to manage the relationships between parent and
7804 child items.
7805
7806 The relationships between items can be explored using the parentItem() and childItems()
7807 functions. In the hierarchy of items in a scene, the parentObject() and parentWidget()
7808 functions are the equivalent of the QWidget::parent() and QWidget::parentWidget()
7809 functions for QWidget subclasses.
7810
7811 \sa QGraphicsWidget
7812*/
7813
7814/*!
7815 Constructs a QGraphicsObject with \a parent.
7816*/
7817QGraphicsObject::QGraphicsObject(QGraphicsItem *parent)
7818 : QGraphicsItem(parent)
7819{
7820 QGraphicsItem::d_ptr->isObject = true;
7821}
7822
7823/*!
7824 \internal
7825*/
7826QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent)
7827 : QGraphicsItem(dd, parent)
7828{
7829 QGraphicsItem::d_ptr->isObject = true;
7830}
7831
7832/*!
7833 Destructor.
7834*/
7835QGraphicsObject::~QGraphicsObject()
7836{
7837}
7838
7839/*!
7840 \reimp
7841*/
7842bool QGraphicsObject::event(QEvent *ev)
7843{
7844 if (ev->type() == QEvent::StyleAnimationUpdate) {
7845 if (isVisible()) {
7846 ev->accept();
7847 update();
7848 }
7849 return true;
7850 }
7851 return QObject::event(event: ev);
7852}
7853
7854#ifndef QT_NO_GESTURES
7855/*!
7856 Subscribes the graphics object to the given \a gesture with specific \a flags.
7857
7858 \sa ungrabGesture(), QGestureEvent
7859*/
7860void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
7861{
7862 bool contains = QGraphicsItem::d_ptr->gestureContext.contains(key: gesture);
7863 QGraphicsItem::d_ptr->gestureContext.insert(key: gesture, value: flags);
7864 if (!contains && QGraphicsItem::d_ptr->scene)
7865 QGraphicsItem::d_ptr->scene->d_func()->grabGesture(this, gesture);
7866}
7867
7868/*!
7869 Unsubscribes the graphics object from the given \a gesture.
7870
7871 \sa grabGesture(), QGestureEvent
7872*/
7873void QGraphicsObject::ungrabGesture(Qt::GestureType gesture)
7874{
7875 if (QGraphicsItem::d_ptr->gestureContext.remove(key: gesture) && QGraphicsItem::d_ptr->scene)
7876 QGraphicsItem::d_ptr->scene->d_func()->ungrabGesture(this, gesture);
7877}
7878#endif // QT_NO_GESTURES
7879
7880/*!
7881 Updates the item's micro focus. This is slot for convenience.
7882
7883 \since 4.7
7884
7885 \sa QInputMethod
7886*/
7887void QGraphicsObject::updateMicroFocus()
7888{
7889 QGraphicsItem::updateMicroFocus();
7890}
7891
7892void QGraphicsItemPrivate::children_append(QDeclarativeListProperty<QGraphicsObject> *list, QGraphicsObject *item)
7893{
7894 if (item) {
7895 QGraphicsObject *graphicsObject = static_cast<QGraphicsObject *>(list->object);
7896 if (QGraphicsItemPrivate::get(item: graphicsObject)->sendParentChangeNotification) {
7897 item->setParentItem(graphicsObject);
7898 } else {
7899 QGraphicsItemPrivate::get(item)->setParentItemHelper(newParent: graphicsObject, newParentVariant: nullptr, thisPointerVariant: nullptr);
7900 }
7901 }
7902}
7903
7904int QGraphicsItemPrivate::children_count(QDeclarativeListProperty<QGraphicsObject> *list)
7905{
7906 QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(item: static_cast<QGraphicsObject *>(list->object));
7907 return d->children.count();
7908}
7909
7910QGraphicsObject *QGraphicsItemPrivate::children_at(QDeclarativeListProperty<QGraphicsObject> *list, int index)
7911{
7912 QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(item: static_cast<QGraphicsObject *>(list->object));
7913 if (index >= 0 && index < d->children.count())
7914 return d->children.at(i: index)->toGraphicsObject();
7915 else
7916 return nullptr;
7917}
7918
7919void QGraphicsItemPrivate::children_clear(QDeclarativeListProperty<QGraphicsObject> *list)
7920{
7921 QGraphicsItemPrivate *d = QGraphicsItemPrivate::get(item: static_cast<QGraphicsObject *>(list->object));
7922 int childCount = d->children.count();
7923 if (d->sendParentChangeNotification) {
7924 for (int index = 0; index < childCount; index++)
7925 d->children.at(i: 0)->setParentItem(nullptr);
7926 } else {
7927 for (int index = 0; index < childCount; index++)
7928 QGraphicsItemPrivate::get(item: d->children.at(i: 0))->setParentItemHelper(newParent: nullptr, newParentVariant: nullptr, thisPointerVariant: nullptr);
7929 }
7930}
7931
7932/*!
7933 Returns a list of this item's children.
7934
7935 The items are sorted by stacking order. This takes into account both the
7936 items' insertion order and their Z-values.
7937
7938*/
7939QDeclarativeListProperty<QGraphicsObject> QGraphicsItemPrivate::childrenList()
7940{
7941 Q_Q(QGraphicsItem);
7942 if (isObject) {
7943 QGraphicsObject *that = static_cast<QGraphicsObject *>(q);
7944 return QDeclarativeListProperty<QGraphicsObject>(that, &children, children_append,
7945 children_count, children_at, children_clear);
7946 } else {
7947 //QGraphicsItem is not supported for this property
7948 return QDeclarativeListProperty<QGraphicsObject>();
7949 }
7950}
7951
7952/*!
7953 \internal
7954 Returns the width of the item
7955 Reimplemented by QGraphicsWidget
7956*/
7957qreal QGraphicsItemPrivate::width() const
7958{
7959 return 0;
7960}
7961
7962/*!
7963 \internal
7964 Set the width of the item
7965 Reimplemented by QGraphicsWidget
7966*/
7967void QGraphicsItemPrivate::setWidth(qreal w)
7968{
7969 Q_UNUSED(w);
7970}
7971
7972/*!
7973 \internal
7974 Reset the width of the item
7975 Reimplemented by QGraphicsWidget
7976*/
7977void QGraphicsItemPrivate::resetWidth()
7978{
7979}
7980
7981/*!
7982 \internal
7983 Returns the height of the item
7984 Reimplemented by QGraphicsWidget
7985*/
7986qreal QGraphicsItemPrivate::height() const
7987{
7988 return 0;
7989}
7990
7991/*!
7992 \internal
7993 Set the height of the item
7994 Reimplemented by QGraphicsWidget
7995*/
7996void QGraphicsItemPrivate::setHeight(qreal h)
7997{
7998 Q_UNUSED(h);
7999}
8000
8001/*!
8002 \internal
8003 Reset the height of the item
8004 Reimplemented by QGraphicsWidget
8005*/
8006void QGraphicsItemPrivate::resetHeight()
8007{
8008}
8009
8010/*!
8011 \property QGraphicsObject::children
8012 \since 4.7
8013 \internal
8014*/
8015
8016/*!
8017 \property QGraphicsObject::width
8018 \since 4.7
8019 \internal
8020*/
8021
8022/*!
8023 \property QGraphicsObject::height
8024 \since 4.7
8025 \internal
8026*/
8027
8028/*!
8029 \property QGraphicsObject::parent
8030 \brief the parent of the item
8031
8032 \note The item's parent is set independently of the parent object returned
8033 by QObject::parent().
8034
8035 \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject()
8036*/
8037
8038/*!
8039 \property QGraphicsObject::opacity
8040 \brief the opacity of the item
8041
8042 \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity()
8043*/
8044
8045/*!
8046 \fn QGraphicsObject::opacityChanged()
8047
8048 This signal gets emitted whenever the opacity of the item changes
8049
8050 \sa QGraphicsItem::opacity()
8051*/
8052
8053/*!
8054 \fn QGraphicsObject::parentChanged()
8055
8056 This signal gets emitted whenever the parent of the item changes
8057*/
8058
8059/*!
8060 \property QGraphicsObject::pos
8061 \brief the position of the item
8062
8063 Describes the items position.
8064
8065 \sa QGraphicsItem::setPos(), QGraphicsItem::pos()
8066*/
8067
8068/*!
8069 \property QGraphicsObject::x
8070 \brief the x position of the item
8071
8072 Describes the items x position.
8073
8074 \sa QGraphicsItem::setX(), setPos()
8075*/
8076
8077/*!
8078 \fn QGraphicsObject::xChanged()
8079
8080 This signal gets emitted whenever the x position of the item changes
8081
8082 \sa pos()
8083*/
8084
8085/*!
8086 \property QGraphicsObject::y
8087 \brief the y position of the item
8088
8089 Describes the items y position.
8090
8091 \sa QGraphicsItem::setY(), setPos()
8092*/
8093
8094/*!
8095 \fn QGraphicsObject::yChanged()
8096
8097 This signal gets emitted whenever the y position of the item changes.
8098
8099 \sa pos()
8100*/
8101
8102/*!
8103 \property QGraphicsObject::z
8104 \brief the z value of the item
8105
8106 Describes the items z value.
8107
8108 \sa QGraphicsItem::setZValue(), zValue()
8109*/
8110
8111/*!
8112 \fn QGraphicsObject::zChanged()
8113
8114 This signal gets emitted whenever the z value of the item changes.
8115
8116 \sa pos()
8117*/
8118
8119/*!
8120 \property QGraphicsObject::rotation
8121 This property holds the rotation of the item in degrees.
8122
8123 This specifies how many degrees to rotate the item around its transformOrigin.
8124 The default rotation is 0 degrees (i.e. not rotated at all).
8125*/
8126
8127/*!
8128 \fn QGraphicsObject::rotationChanged()
8129
8130 This signal gets emitted whenever the roation of the item changes.
8131*/
8132
8133/*!
8134 \property QGraphicsObject::scale
8135 This property holds the scale of the item.
8136
8137 A scale of less than 1 means the item will be displayed smaller than
8138 normal, and a scale of greater than 1 means the item will be
8139 displayed larger than normal. A negative scale means the item will
8140 be mirrored.
8141
8142 By default, items are displayed at a scale of 1 (i.e. at their
8143 normal size).
8144
8145 Scaling is from the item's transformOrigin.
8146*/
8147
8148/*!
8149 \fn void QGraphicsObject::scaleChanged()
8150
8151 This signal is emitted when the scale of the item changes.
8152*/
8153
8154
8155/*!
8156 \property QGraphicsObject::enabled
8157 \brief whether the item is enabled or not
8158
8159 This property is declared in QGraphicsItem.
8160
8161 By default, this property is \c true.
8162
8163 \sa QGraphicsItem::isEnabled(), QGraphicsItem::setEnabled()
8164*/
8165
8166/*!
8167 \fn void QGraphicsObject::enabledChanged()
8168
8169 This signal gets emitted whenever the item get's enabled or disabled.
8170
8171 \sa isEnabled()
8172*/
8173
8174/*!
8175 \property QGraphicsObject::visible
8176 \brief whether the item is visible or not
8177
8178 This property is declared in QGraphicsItem.
8179
8180 By default, this property is \c true.
8181
8182 \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible()
8183*/
8184
8185/*!
8186 \fn QGraphicsObject::visibleChanged()
8187
8188 This signal gets emitted whenever the visibility of the item changes
8189
8190 \sa visible
8191*/
8192
8193/*!
8194 \property QGraphicsObject::transformOriginPoint
8195 \brief the transformation origin
8196
8197 This property sets a specific point in the items coordiante system as the
8198 origin for scale and rotation.
8199
8200 \sa scale, rotation, QGraphicsItem::transformOriginPoint()
8201*/
8202
8203/*!
8204 \fn void QGraphicsObject::widthChanged()
8205 \internal
8206*/
8207
8208/*!
8209 \fn void QGraphicsObject::heightChanged()
8210 \internal
8211*/
8212
8213/*!
8214
8215 \fn QGraphicsObject::childrenChanged()
8216
8217 This signal gets emitted whenever the children list changes
8218 \internal
8219*/
8220
8221/*!
8222 \property QGraphicsObject::effect
8223 \since 4.7
8224 \brief the effect attached to this item
8225
8226 \sa QGraphicsItem::setGraphicsEffect(), QGraphicsItem::graphicsEffect()
8227*/
8228
8229/*!
8230 \class QAbstractGraphicsShapeItem
8231 \brief The QAbstractGraphicsShapeItem class provides a common base for
8232 all path items.
8233 \since 4.2
8234 \ingroup graphicsview-api
8235 \inmodule QtWidgets
8236
8237 This class does not fully implement an item by itself; in particular, it
8238 does not implement boundingRect() and paint(), which are inherited by
8239 QGraphicsItem.
8240
8241 You can subclass this item to provide a simple base implementation of
8242 accessors for the item's pen and brush.
8243
8244 \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPathItem,
8245 QGraphicsPolygonItem, QGraphicsTextItem, QGraphicsLineItem,
8246 QGraphicsPixmapItem, {Graphics View Framework}
8247*/
8248
8249class QAbstractGraphicsShapeItemPrivate : public QGraphicsItemPrivate
8250{
8251 Q_DECLARE_PUBLIC(QAbstractGraphicsShapeItem)
8252public:
8253
8254 QBrush brush;
8255 QPen pen;
8256
8257 // Cached bounding rectangle
8258 mutable QRectF boundingRect;
8259};
8260
8261/*!
8262 Constructs a QAbstractGraphicsShapeItem. \a parent is passed to
8263 QGraphicsItem's constructor.
8264*/
8265QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QGraphicsItem *parent)
8266 : QGraphicsItem(*new QAbstractGraphicsShapeItemPrivate, parent)
8267{
8268}
8269
8270/*!
8271 \internal
8272*/
8273QAbstractGraphicsShapeItem::QAbstractGraphicsShapeItem(QAbstractGraphicsShapeItemPrivate &dd, QGraphicsItem *parent)
8274 : QGraphicsItem(dd, parent)
8275{
8276}
8277
8278/*!
8279 Destroys a QAbstractGraphicsShapeItem.
8280*/
8281QAbstractGraphicsShapeItem::~QAbstractGraphicsShapeItem()
8282{
8283}
8284
8285/*!
8286 Returns the item's pen. If no pen has been set, this function returns
8287 QPen(), a default black solid line pen with 1 width.
8288*/
8289QPen QAbstractGraphicsShapeItem::pen() const
8290{
8291 Q_D(const QAbstractGraphicsShapeItem);
8292 return d->pen;
8293}
8294
8295/*!
8296 Sets the pen for this item to \a pen.
8297
8298 The pen is used to draw the item's outline.
8299
8300 \sa pen()
8301*/
8302void QAbstractGraphicsShapeItem::setPen(const QPen &pen)
8303{
8304 Q_D(QAbstractGraphicsShapeItem);
8305 if (d->pen == pen)
8306 return;
8307 prepareGeometryChange();
8308 d->pen = pen;
8309 d->boundingRect = QRectF();
8310 update();
8311}
8312
8313/*!
8314 Returns the item's brush, or an empty brush if no brush has been set.
8315
8316 \sa setBrush()
8317*/
8318QBrush QAbstractGraphicsShapeItem::brush() const
8319{
8320 Q_D(const QAbstractGraphicsShapeItem);
8321 return d->brush;
8322}
8323
8324/*!
8325 Sets the item's brush to \a brush.
8326
8327 The item's brush is used to fill the item.
8328
8329 If you use a brush with a QGradient, the gradient
8330 is relative to the item's coordinate system.
8331
8332 \sa brush()
8333*/
8334void QAbstractGraphicsShapeItem::setBrush(const QBrush &brush)
8335{
8336 Q_D(QAbstractGraphicsShapeItem);
8337 if (d->brush == brush)
8338 return;
8339 d->brush = brush;
8340 update();
8341}
8342
8343/*!
8344 \reimp
8345*/
8346bool QAbstractGraphicsShapeItem::isObscuredBy(const QGraphicsItem *item) const
8347{
8348 return QGraphicsItem::isObscuredBy(item);
8349}
8350
8351/*!
8352 \reimp
8353*/
8354QPainterPath QAbstractGraphicsShapeItem::opaqueArea() const
8355{
8356 Q_D(const QAbstractGraphicsShapeItem);
8357 if (d->brush.isOpaque())
8358 return isClipped() ? clipPath() : shape();
8359 return QGraphicsItem::opaqueArea();
8360}
8361
8362/*!
8363 \class QGraphicsPathItem
8364 \brief The QGraphicsPathItem class provides a path item that you
8365 can add to a QGraphicsScene.
8366 \since 4.2
8367 \ingroup graphicsview-api
8368 \inmodule QtWidgets
8369
8370 To set the item's path, pass a QPainterPath to QGraphicsPathItem's
8371 constructor, or call the setPath() function. The path() function
8372 returns the current path.
8373
8374 \image graphicsview-pathitem.png
8375
8376 QGraphicsPathItem uses the path to provide a reasonable
8377 implementation of boundingRect(), shape(), and contains(). The
8378 paint() function draws the path using the item's associated pen
8379 and brush, which you can set by calling the setPen() and
8380 setBrush() functions.
8381
8382 \sa QGraphicsRectItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
8383 QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8384 View Framework}
8385*/
8386
8387class QGraphicsPathItemPrivate : public QAbstractGraphicsShapeItemPrivate
8388{
8389 Q_DECLARE_PUBLIC(QGraphicsPathItem)
8390public:
8391 QPainterPath path;
8392};
8393
8394/*!
8395 Constructs a QGraphicsPath item using \a path as the default path. \a
8396 parent is passed to QAbstractGraphicsShapeItem's constructor.
8397
8398 \sa QGraphicsScene::addItem()
8399*/
8400QGraphicsPathItem::QGraphicsPathItem(const QPainterPath &path,
8401 QGraphicsItem *parent)
8402 : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent)
8403{
8404 if (!path.isEmpty())
8405 setPath(path);
8406}
8407
8408/*!
8409 Constructs a QGraphicsPath. \a parent is passed to
8410 QAbstractGraphicsShapeItem's constructor.
8411
8412 \sa QGraphicsScene::addItem()
8413*/
8414QGraphicsPathItem::QGraphicsPathItem(QGraphicsItem *parent)
8415 : QAbstractGraphicsShapeItem(*new QGraphicsPathItemPrivate, parent)
8416{
8417}
8418
8419/*!
8420 Destroys the QGraphicsPathItem.
8421*/
8422QGraphicsPathItem::~QGraphicsPathItem()
8423{
8424}
8425
8426/*!
8427 Returns the item's path as a QPainterPath. If no item has been set, an
8428 empty QPainterPath is returned.
8429
8430 \sa setPath()
8431*/
8432QPainterPath QGraphicsPathItem::path() const
8433{
8434 Q_D(const QGraphicsPathItem);
8435 return d->path;
8436}
8437
8438/*!
8439 Sets the item's path to be the given \a path.
8440
8441 \sa path()
8442*/
8443void QGraphicsPathItem::setPath(const QPainterPath &path)
8444{
8445 Q_D(QGraphicsPathItem);
8446 if (d->path == path)
8447 return;
8448 prepareGeometryChange();
8449 d->path = path;
8450 d->boundingRect = QRectF();
8451 update();
8452}
8453
8454/*!
8455 \reimp
8456*/
8457QRectF QGraphicsPathItem::boundingRect() const
8458{
8459 Q_D(const QGraphicsPathItem);
8460 if (d->boundingRect.isNull()) {
8461 qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
8462 if (pw == 0.0)
8463 d->boundingRect = d->path.controlPointRect();
8464 else {
8465 d->boundingRect = shape().controlPointRect();
8466 }
8467 }
8468 return d->boundingRect;
8469}
8470
8471/*!
8472 \reimp
8473*/
8474QPainterPath QGraphicsPathItem::shape() const
8475{
8476 Q_D(const QGraphicsPathItem);
8477 return qt_graphicsItem_shapeFromPath(path: d->path, pen: d->pen);
8478}
8479
8480/*!
8481 \reimp
8482*/
8483bool QGraphicsPathItem::contains(const QPointF &point) const
8484{
8485 return QAbstractGraphicsShapeItem::contains(point);
8486}
8487
8488/*!
8489 \reimp
8490*/
8491void QGraphicsPathItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
8492 QWidget *widget)
8493{
8494 Q_D(QGraphicsPathItem);
8495 Q_UNUSED(widget);
8496 painter->setPen(d->pen);
8497 painter->setBrush(d->brush);
8498 painter->drawPath(path: d->path);
8499
8500 if (option->state & QStyle::State_Selected)
8501 qt_graphicsItem_highlightSelected(item: this, painter, option);
8502}
8503
8504/*!
8505 \reimp
8506*/
8507bool QGraphicsPathItem::isObscuredBy(const QGraphicsItem *item) const
8508{
8509 return QAbstractGraphicsShapeItem::isObscuredBy(item);
8510}
8511
8512/*!
8513 \reimp
8514*/
8515QPainterPath QGraphicsPathItem::opaqueArea() const
8516{
8517 return QAbstractGraphicsShapeItem::opaqueArea();
8518}
8519
8520/*!
8521 \reimp
8522*/
8523int QGraphicsPathItem::type() const
8524{
8525 return Type;
8526}
8527
8528/*!
8529 \internal
8530*/
8531bool QGraphicsPathItem::supportsExtension(Extension extension) const
8532{
8533 Q_UNUSED(extension);
8534 return false;
8535}
8536
8537/*!
8538 \internal
8539*/
8540void QGraphicsPathItem::setExtension(Extension extension, const QVariant &variant)
8541{
8542 Q_UNUSED(extension);
8543 Q_UNUSED(variant);
8544}
8545
8546/*!
8547 \internal
8548*/
8549QVariant QGraphicsPathItem::extension(const QVariant &variant) const
8550{
8551 Q_UNUSED(variant);
8552 return QVariant();
8553}
8554
8555/*!
8556 \class QGraphicsRectItem
8557 \brief The QGraphicsRectItem class provides a rectangle item that you
8558 can add to a QGraphicsScene.
8559 \since 4.2
8560 \ingroup graphicsview-api
8561 \inmodule QtWidgets
8562
8563 To set the item's rectangle, pass a QRectF to QGraphicsRectItem's
8564 constructor, or call the setRect() function. The rect() function
8565 returns the current rectangle.
8566
8567 \image graphicsview-rectitem.png
8568
8569 QGraphicsRectItem uses the rectangle and the pen width to provide
8570 a reasonable implementation of boundingRect(), shape(), and
8571 contains(). The paint() function draws the rectangle using the
8572 item's associated pen and brush, which you can set by calling the
8573 setPen() and setBrush() functions.
8574
8575 \note The rendering of invalid rectangles, such as those with negative
8576 widths or heights, is undefined. If you cannot be sure that you are
8577 using valid rectangles (for example, if you are creating
8578 rectangles using data from an unreliable source) then you should
8579 use QRectF::normalized() to create normalized rectangles, and use
8580 those instead.
8581
8582 \sa QGraphicsPathItem, QGraphicsEllipseItem, QGraphicsPolygonItem,
8583 QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8584 View Framework}
8585*/
8586
8587class QGraphicsRectItemPrivate : public QAbstractGraphicsShapeItemPrivate
8588{
8589 Q_DECLARE_PUBLIC(QGraphicsRectItem)
8590public:
8591 QRectF rect;
8592};
8593
8594/*!
8595 Constructs a QGraphicsRectItem, using \a rect as the default rectangle.
8596 \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8597
8598 \sa QGraphicsScene::addItem()
8599*/
8600QGraphicsRectItem::QGraphicsRectItem(const QRectF &rect, QGraphicsItem *parent)
8601 : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8602{
8603 setRect(rect);
8604}
8605
8606/*!
8607 \fn QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal width, qreal height,
8608 QGraphicsItem *parent)
8609
8610 Constructs a QGraphicsRectItem with a default rectangle defined
8611 by (\a x, \a y) and the given \a width and \a height.
8612
8613 \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8614
8615 \sa QGraphicsScene::addItem()
8616*/
8617QGraphicsRectItem::QGraphicsRectItem(qreal x, qreal y, qreal w, qreal h,
8618 QGraphicsItem *parent)
8619 : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8620{
8621 setRect(QRectF(x, y, w, h));
8622}
8623
8624/*!
8625 Constructs a QGraphicsRectItem. \a parent is passed to
8626 QAbstractGraphicsShapeItem's constructor.
8627
8628 \sa QGraphicsScene::addItem()
8629*/
8630QGraphicsRectItem::QGraphicsRectItem(QGraphicsItem *parent)
8631 : QAbstractGraphicsShapeItem(*new QGraphicsRectItemPrivate, parent)
8632{
8633}
8634
8635/*!
8636 Destroys the QGraphicsRectItem.
8637*/
8638QGraphicsRectItem::~QGraphicsRectItem()
8639{
8640}
8641
8642/*!
8643 Returns the item's rectangle.
8644
8645 \sa setRect()
8646*/
8647QRectF QGraphicsRectItem::rect() const
8648{
8649 Q_D(const QGraphicsRectItem);
8650 return d->rect;
8651}
8652
8653/*!
8654 \fn void QGraphicsRectItem::setRect(const QRectF &rectangle)
8655
8656 Sets the item's rectangle to be the given \a rectangle.
8657
8658 \sa rect()
8659*/
8660void QGraphicsRectItem::setRect(const QRectF &rect)
8661{
8662 Q_D(QGraphicsRectItem);
8663 if (d->rect == rect)
8664 return;
8665 prepareGeometryChange();
8666 d->rect = rect;
8667 d->boundingRect = QRectF();
8668 update();
8669}
8670
8671/*!
8672 \fn void QGraphicsRectItem::setRect(qreal x, qreal y, qreal width, qreal height)
8673 \fn void QGraphicsEllipseItem::setRect(qreal x, qreal y, qreal width, qreal height)
8674
8675 Sets the item's rectangle to the rectangle defined by (\a x, \a y)
8676 and the given \a width and \a height.
8677
8678 This convenience function is equivalent to calling \c
8679 {setRect(QRectF(x, y, width, height))}
8680
8681 \sa rect()
8682*/
8683
8684/*!
8685 \reimp
8686*/
8687QRectF QGraphicsRectItem::boundingRect() const
8688{
8689 Q_D(const QGraphicsRectItem);
8690 if (d->boundingRect.isNull()) {
8691 qreal halfpw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF() / 2;
8692 d->boundingRect = d->rect;
8693 if (halfpw > 0.0)
8694 d->boundingRect.adjust(xp1: -halfpw, yp1: -halfpw, xp2: halfpw, yp2: halfpw);
8695 }
8696 return d->boundingRect;
8697}
8698
8699/*!
8700 \reimp
8701*/
8702QPainterPath QGraphicsRectItem::shape() const
8703{
8704 Q_D(const QGraphicsRectItem);
8705 QPainterPath path;
8706 path.addRect(rect: d->rect);
8707 return qt_graphicsItem_shapeFromPath(path, pen: d->pen);
8708}
8709
8710/*!
8711 \reimp
8712*/
8713bool QGraphicsRectItem::contains(const QPointF &point) const
8714{
8715 return QAbstractGraphicsShapeItem::contains(point);
8716}
8717
8718/*!
8719 \reimp
8720*/
8721void QGraphicsRectItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
8722 QWidget *widget)
8723{
8724 Q_D(QGraphicsRectItem);
8725 Q_UNUSED(widget);
8726 painter->setPen(d->pen);
8727 painter->setBrush(d->brush);
8728 painter->drawRect(rect: d->rect);
8729
8730 if (option->state & QStyle::State_Selected)
8731 qt_graphicsItem_highlightSelected(item: this, painter, option);
8732}
8733
8734/*!
8735 \reimp
8736*/
8737bool QGraphicsRectItem::isObscuredBy(const QGraphicsItem *item) const
8738{
8739 return QAbstractGraphicsShapeItem::isObscuredBy(item);
8740}
8741
8742/*!
8743 \reimp
8744*/
8745QPainterPath QGraphicsRectItem::opaqueArea() const
8746{
8747 return QAbstractGraphicsShapeItem::opaqueArea();
8748}
8749
8750/*!
8751 \reimp
8752*/
8753int QGraphicsRectItem::type() const
8754{
8755 return Type;
8756}
8757
8758/*!
8759 \internal
8760*/
8761bool QGraphicsRectItem::supportsExtension(Extension extension) const
8762{
8763 Q_UNUSED(extension);
8764 return false;
8765}
8766
8767/*!
8768 \internal
8769*/
8770void QGraphicsRectItem::setExtension(Extension extension, const QVariant &variant)
8771{
8772 Q_UNUSED(extension);
8773 Q_UNUSED(variant);
8774}
8775
8776/*!
8777 \internal
8778*/
8779QVariant QGraphicsRectItem::extension(const QVariant &variant) const
8780{
8781 Q_UNUSED(variant);
8782 return QVariant();
8783}
8784
8785/*!
8786 \class QGraphicsEllipseItem
8787 \brief The QGraphicsEllipseItem class provides an ellipse item that you
8788 can add to a QGraphicsScene.
8789 \since 4.2
8790 \ingroup graphicsview-api
8791 \inmodule QtWidgets
8792
8793 QGraphicsEllipseItem respresents an ellipse with a fill and an outline,
8794 and you can also use it for ellipse segments (see startAngle(),
8795 spanAngle()).
8796
8797 \table
8798 \row
8799 \li \inlineimage graphicsview-ellipseitem.png
8800 \li \inlineimage graphicsview-ellipseitem-pie.png
8801 \endtable
8802
8803 To set the item's ellipse, pass a QRectF to QGraphicsEllipseItem's
8804 constructor, or call setRect(). The rect() function returns the
8805 current ellipse geometry.
8806
8807 QGraphicsEllipseItem uses the rect and the pen width to provide a
8808 reasonable implementation of boundingRect(), shape(), and contains(). The
8809 paint() function draws the ellipse using the item's associated pen and
8810 brush, which you can set by calling setPen() and setBrush().
8811
8812 \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsPolygonItem,
8813 QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
8814 View Framework}
8815*/
8816
8817class QGraphicsEllipseItemPrivate : public QAbstractGraphicsShapeItemPrivate
8818{
8819 Q_DECLARE_PUBLIC(QGraphicsEllipseItem)
8820public:
8821 inline QGraphicsEllipseItemPrivate()
8822 : startAngle(0), spanAngle(360 * 16)
8823 { }
8824
8825 QRectF rect;
8826 int startAngle;
8827 int spanAngle;
8828};
8829
8830/*!
8831 Constructs a QGraphicsEllipseItem using \a rect as the default rectangle.
8832 \a parent is passed to QAbstractGraphicsShapeItem's constructor.
8833
8834 \sa QGraphicsScene::addItem()
8835*/
8836QGraphicsEllipseItem::QGraphicsEllipseItem(const QRectF &rect, QGraphicsItem *parent)
8837 : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8838{
8839 setRect(rect);
8840}
8841
8842/*!
8843 \fn QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal width, qreal height, QGraphicsItem *parent)
8844 \since 4.3
8845
8846 Constructs a QGraphicsEllipseItem using the rectangle defined by (\a x, \a
8847 y) and the given \a width and \a height, as the default rectangle. \a
8848 parent is passed to QAbstractGraphicsShapeItem's constructor.
8849
8850 \sa QGraphicsScene::addItem()
8851*/
8852QGraphicsEllipseItem::QGraphicsEllipseItem(qreal x, qreal y, qreal w, qreal h,
8853 QGraphicsItem *parent)
8854 : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8855{
8856 setRect(ax: x,ay: y,w,h);
8857}
8858
8859
8860
8861/*!
8862 Constructs a QGraphicsEllipseItem. \a parent is passed to
8863 QAbstractGraphicsShapeItem's constructor.
8864
8865 \sa QGraphicsScene::addItem()
8866*/
8867QGraphicsEllipseItem::QGraphicsEllipseItem(QGraphicsItem *parent)
8868 : QAbstractGraphicsShapeItem(*new QGraphicsEllipseItemPrivate, parent)
8869{
8870}
8871
8872/*!
8873 Destroys the QGraphicsEllipseItem.
8874*/
8875QGraphicsEllipseItem::~QGraphicsEllipseItem()
8876{
8877}
8878
8879/*!
8880 Returns the item's ellipse geometry as a QRectF.
8881
8882 \sa setRect(), QPainter::drawEllipse()
8883*/
8884QRectF QGraphicsEllipseItem::rect() const
8885{
8886 Q_D(const QGraphicsEllipseItem);
8887 return d->rect;
8888}
8889
8890/*!
8891 Sets the item's ellipse geometry to \a rect. The rectangle's left edge
8892 defines the left edge of the ellipse, and the rectangle's top edge
8893 describes the top of the ellipse. The height and width of the rectangle
8894 describe the height and width of the ellipse.
8895
8896 \sa rect(), QPainter::drawEllipse()
8897*/
8898void QGraphicsEllipseItem::setRect(const QRectF &rect)
8899{
8900 Q_D(QGraphicsEllipseItem);
8901 if (d->rect == rect)
8902 return;
8903 prepareGeometryChange();
8904 d->rect = rect;
8905 d->boundingRect = QRectF();
8906 update();
8907}
8908
8909/*!
8910 Returns the start angle for an ellipse segment in 16ths of a degree. This
8911 angle is used together with spanAngle() for representing an ellipse
8912 segment (a pie). By default, the start angle is 0.
8913
8914 \sa setStartAngle(), spanAngle()
8915*/
8916int QGraphicsEllipseItem::startAngle() const
8917{
8918 Q_D(const QGraphicsEllipseItem);
8919 return d->startAngle;
8920}
8921
8922/*!
8923 Sets the start angle for an ellipse segment to \a angle, which is in 16ths
8924 of a degree. This angle is used together with spanAngle() for representing
8925 an ellipse segment (a pie). By default, the start angle is 0.
8926
8927 \sa startAngle(), setSpanAngle(), QPainter::drawPie()
8928*/
8929void QGraphicsEllipseItem::setStartAngle(int angle)
8930{
8931 Q_D(QGraphicsEllipseItem);
8932 if (angle != d->startAngle) {
8933 prepareGeometryChange();
8934 d->boundingRect = QRectF();
8935 d->startAngle = angle;
8936 update();
8937 }
8938}
8939
8940/*!
8941 Returns the span angle of an ellipse segment in 16ths of a degree. This
8942 angle is used together with startAngle() for representing an ellipse
8943 segment (a pie). By default, this function returns 5760 (360 * 16, a full
8944 ellipse).
8945
8946 \sa setSpanAngle(), startAngle()
8947*/
8948int QGraphicsEllipseItem::spanAngle() const
8949{
8950 Q_D(const QGraphicsEllipseItem);
8951 return d->spanAngle;
8952}
8953
8954/*!
8955 Sets the span angle for an ellipse segment to \a angle, which is in 16ths
8956 of a degree. This angle is used together with startAngle() to represent an
8957 ellipse segment (a pie). By default, the span angle is 5760 (360 * 16, a
8958 full ellipse).
8959
8960 \sa spanAngle(), setStartAngle(), QPainter::drawPie()
8961*/
8962void QGraphicsEllipseItem::setSpanAngle(int angle)
8963{
8964 Q_D(QGraphicsEllipseItem);
8965 if (angle != d->spanAngle) {
8966 prepareGeometryChange();
8967 d->boundingRect = QRectF();
8968 d->spanAngle = angle;
8969 update();
8970 }
8971}
8972
8973/*!
8974 \reimp
8975*/
8976QRectF QGraphicsEllipseItem::boundingRect() const
8977{
8978 Q_D(const QGraphicsEllipseItem);
8979 if (d->boundingRect.isNull()) {
8980 qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
8981 if (pw == 0.0 && d->spanAngle == 360 * 16)
8982 d->boundingRect = d->rect;
8983 else
8984 d->boundingRect = shape().controlPointRect();
8985 }
8986 return d->boundingRect;
8987}
8988
8989/*!
8990 \reimp
8991*/
8992QPainterPath QGraphicsEllipseItem::shape() const
8993{
8994 Q_D(const QGraphicsEllipseItem);
8995 QPainterPath path;
8996 if (d->rect.isNull())
8997 return path;
8998 if (d->spanAngle != 360 * 16) {
8999 path.moveTo(p: d->rect.center());
9000 path.arcTo(rect: d->rect, startAngle: d->startAngle / 16.0, arcLength: d->spanAngle / 16.0);
9001 } else {
9002 path.addEllipse(rect: d->rect);
9003 }
9004
9005 return qt_graphicsItem_shapeFromPath(path, pen: d->pen);
9006}
9007
9008/*!
9009 \reimp
9010*/
9011bool QGraphicsEllipseItem::contains(const QPointF &point) const
9012{
9013 return QAbstractGraphicsShapeItem::contains(point);
9014}
9015
9016/*!
9017 \reimp
9018*/
9019void QGraphicsEllipseItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
9020 QWidget *widget)
9021{
9022 Q_D(QGraphicsEllipseItem);
9023 Q_UNUSED(widget);
9024 painter->setPen(d->pen);
9025 painter->setBrush(d->brush);
9026 if ((d->spanAngle != 0) && (qAbs(t: d->spanAngle) % (360 * 16) == 0))
9027 painter->drawEllipse(r: d->rect);
9028 else
9029 painter->drawPie(rect: d->rect, a: d->startAngle, alen: d->spanAngle);
9030
9031 if (option->state & QStyle::State_Selected)
9032 qt_graphicsItem_highlightSelected(item: this, painter, option);
9033}
9034
9035/*!
9036 \reimp
9037*/
9038bool QGraphicsEllipseItem::isObscuredBy(const QGraphicsItem *item) const
9039{
9040 return QAbstractGraphicsShapeItem::isObscuredBy(item);
9041}
9042
9043/*!
9044 \reimp
9045*/
9046QPainterPath QGraphicsEllipseItem::opaqueArea() const
9047{
9048 return QAbstractGraphicsShapeItem::opaqueArea();
9049}
9050
9051/*!
9052 \reimp
9053*/
9054int QGraphicsEllipseItem::type() const
9055{
9056 return Type;
9057}
9058
9059
9060/*!
9061 \internal
9062*/
9063bool QGraphicsEllipseItem::supportsExtension(Extension extension) const
9064{
9065 Q_UNUSED(extension);
9066 return false;
9067}
9068
9069/*!
9070 \internal
9071*/
9072void QGraphicsEllipseItem::setExtension(Extension extension, const QVariant &variant)
9073{
9074 Q_UNUSED(extension);
9075 Q_UNUSED(variant);
9076}
9077
9078/*!
9079 \internal
9080*/
9081QVariant QGraphicsEllipseItem::extension(const QVariant &variant) const
9082{
9083 Q_UNUSED(variant);
9084 return QVariant();
9085}
9086
9087/*!
9088 \class QGraphicsPolygonItem
9089 \brief The QGraphicsPolygonItem class provides a polygon item that you
9090 can add to a QGraphicsScene.
9091 \since 4.2
9092 \ingroup graphicsview-api
9093 \inmodule QtWidgets
9094
9095 To set the item's polygon, pass a QPolygonF to
9096 QGraphicsPolygonItem's constructor, or call the setPolygon()
9097 function. The polygon() function returns the current polygon.
9098
9099 \image graphicsview-polygonitem.png
9100
9101 QGraphicsPolygonItem uses the polygon and the pen width to provide
9102 a reasonable implementation of boundingRect(), shape(), and
9103 contains(). The paint() function draws the polygon using the
9104 item's associated pen and brush, which you can set by calling the
9105 setPen() and setBrush() functions.
9106
9107 \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9108 QGraphicsTextItem, QGraphicsLineItem, QGraphicsPixmapItem, {Graphics
9109 View Framework}
9110*/
9111
9112class QGraphicsPolygonItemPrivate : public QAbstractGraphicsShapeItemPrivate
9113{
9114 Q_DECLARE_PUBLIC(QGraphicsPolygonItem)
9115public:
9116 inline QGraphicsPolygonItemPrivate()
9117 : fillRule(Qt::OddEvenFill)
9118 { }
9119
9120 QPolygonF polygon;
9121 Qt::FillRule fillRule;
9122};
9123
9124/*!
9125 Constructs a QGraphicsPolygonItem with \a polygon as the default
9126 polygon. \a parent is passed to QAbstractGraphicsShapeItem's constructor.
9127
9128 \sa QGraphicsScene::addItem()
9129*/
9130QGraphicsPolygonItem::QGraphicsPolygonItem(const QPolygonF &polygon, QGraphicsItem *parent)
9131 : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent)
9132{
9133 setPolygon(polygon);
9134}
9135
9136/*!
9137 Constructs a QGraphicsPolygonItem. \a parent is passed to
9138 QAbstractGraphicsShapeItem's constructor.
9139
9140 \sa QGraphicsScene::addItem()
9141*/
9142QGraphicsPolygonItem::QGraphicsPolygonItem(QGraphicsItem *parent)
9143 : QAbstractGraphicsShapeItem(*new QGraphicsPolygonItemPrivate, parent)
9144{
9145}
9146
9147/*!
9148 Destroys the QGraphicsPolygonItem.
9149*/
9150QGraphicsPolygonItem::~QGraphicsPolygonItem()
9151{
9152}
9153
9154/*!
9155 Returns the item's polygon, or an empty polygon if no polygon
9156 has been set.
9157
9158 \sa setPolygon()
9159*/
9160QPolygonF QGraphicsPolygonItem::polygon() const
9161{
9162 Q_D(const QGraphicsPolygonItem);
9163 return d->polygon;
9164}
9165
9166/*!
9167 Sets the item's polygon to be the given \a polygon.
9168
9169 \sa polygon()
9170*/
9171void QGraphicsPolygonItem::setPolygon(const QPolygonF &polygon)
9172{
9173 Q_D(QGraphicsPolygonItem);
9174 if (d->polygon == polygon)
9175 return;
9176 prepareGeometryChange();
9177 d->polygon = polygon;
9178 d->boundingRect = QRectF();
9179 update();
9180}
9181
9182/*!
9183 Returns the fill rule of the polygon. The default fill rule is
9184 Qt::OddEvenFill.
9185
9186 \sa setFillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
9187*/
9188Qt::FillRule QGraphicsPolygonItem::fillRule() const
9189{
9190 Q_D(const QGraphicsPolygonItem);
9191 return d->fillRule;
9192}
9193
9194/*!
9195 Sets the fill rule of the polygon to \a rule. The default fill rule is
9196 Qt::OddEvenFill.
9197
9198 \sa fillRule(), QPainterPath::fillRule(), QPainter::drawPolygon()
9199*/
9200void QGraphicsPolygonItem::setFillRule(Qt::FillRule rule)
9201{
9202 Q_D(QGraphicsPolygonItem);
9203 if (rule != d->fillRule) {
9204 d->fillRule = rule;
9205 update();
9206 }
9207}
9208
9209/*!
9210 \reimp
9211*/
9212QRectF QGraphicsPolygonItem::boundingRect() const
9213{
9214 Q_D(const QGraphicsPolygonItem);
9215 if (d->boundingRect.isNull()) {
9216 qreal pw = pen().style() == Qt::NoPen ? qreal(0) : pen().widthF();
9217 if (pw == 0.0)
9218 d->boundingRect = d->polygon.boundingRect();
9219 else
9220 d->boundingRect = shape().controlPointRect();
9221 }
9222 return d->boundingRect;
9223}
9224
9225/*!
9226 \reimp
9227*/
9228QPainterPath QGraphicsPolygonItem::shape() const
9229{
9230 Q_D(const QGraphicsPolygonItem);
9231 QPainterPath path;
9232 path.addPolygon(polygon: d->polygon);
9233 return qt_graphicsItem_shapeFromPath(path, pen: d->pen);
9234}
9235
9236/*!
9237 \reimp
9238*/
9239bool QGraphicsPolygonItem::contains(const QPointF &point) const
9240{
9241 return QAbstractGraphicsShapeItem::contains(point);
9242}
9243
9244/*!
9245 \reimp
9246*/
9247void QGraphicsPolygonItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
9248{
9249 Q_D(QGraphicsPolygonItem);
9250 Q_UNUSED(widget);
9251 painter->setPen(d->pen);
9252 painter->setBrush(d->brush);
9253 painter->drawPolygon(polygon: d->polygon, fillRule: d->fillRule);
9254
9255 if (option->state & QStyle::State_Selected)
9256 qt_graphicsItem_highlightSelected(item: this, painter, option);
9257}
9258
9259/*!
9260 \reimp
9261*/
9262bool QGraphicsPolygonItem::isObscuredBy(const QGraphicsItem *item) const
9263{
9264 return QAbstractGraphicsShapeItem::isObscuredBy(item);
9265}
9266
9267/*!
9268 \reimp
9269*/
9270QPainterPath QGraphicsPolygonItem::opaqueArea() const
9271{
9272 return QAbstractGraphicsShapeItem::opaqueArea();
9273}
9274
9275/*!
9276 \reimp
9277*/
9278int QGraphicsPolygonItem::type() const
9279{
9280 return Type;
9281}
9282
9283/*!
9284 \internal
9285*/
9286bool QGraphicsPolygonItem::supportsExtension(Extension extension) const
9287{
9288 Q_UNUSED(extension);
9289 return false;
9290}
9291
9292/*!
9293 \internal
9294*/
9295void QGraphicsPolygonItem::setExtension(Extension extension, const QVariant &variant)
9296{
9297 Q_UNUSED(extension);
9298 Q_UNUSED(variant);
9299}
9300
9301/*!
9302 \internal
9303*/
9304QVariant QGraphicsPolygonItem::extension(const QVariant &variant) const
9305{
9306 Q_UNUSED(variant);
9307 return QVariant();
9308}
9309
9310/*!
9311 \class QGraphicsLineItem
9312 \brief The QGraphicsLineItem class provides a line item that you can add to a
9313 QGraphicsScene.
9314 \since 4.2
9315 \ingroup graphicsview-api
9316 \inmodule QtWidgets
9317
9318 To set the item's line, pass a QLineF to QGraphicsLineItem's
9319 constructor, or call the setLine() function. The line() function
9320 returns the current line. By default the line is black with a
9321 width of 0, but you can change this by calling setPen().
9322
9323 \image graphicsview-lineitem.png
9324
9325 QGraphicsLineItem uses the line and the pen width to provide a reasonable
9326 implementation of boundingRect(), shape(), and contains(). The paint()
9327 function draws the line using the item's associated pen.
9328
9329 \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9330 QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsPixmapItem,
9331 {Graphics View Framework}
9332*/
9333
9334class QGraphicsLineItemPrivate : public QGraphicsItemPrivate
9335{
9336 Q_DECLARE_PUBLIC(QGraphicsLineItem)
9337public:
9338 QLineF line;
9339 QPen pen;
9340};
9341
9342/*!
9343 Constructs a QGraphicsLineItem, using \a line as the default line. \a
9344 parent is passed to QGraphicsItem's constructor.
9345
9346 \sa QGraphicsScene::addItem()
9347*/
9348QGraphicsLineItem::QGraphicsLineItem(const QLineF &line, QGraphicsItem *parent)
9349 : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9350{
9351 setLine(line);
9352}
9353
9354/*!
9355 Constructs a QGraphicsLineItem, using the line between (\a x1, \a y1) and
9356 (\a x2, \a y2) as the default line. \a parent is passed to
9357 QGraphicsItem's constructor.
9358
9359 \sa QGraphicsScene::addItem()
9360*/
9361QGraphicsLineItem::QGraphicsLineItem(qreal x1, qreal y1, qreal x2, qreal y2, QGraphicsItem *parent)
9362 : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9363{
9364 setLine(x1, y1, x2, y2);
9365}
9366
9367
9368
9369/*!
9370 Constructs a QGraphicsLineItem. \a parent is passed to QGraphicsItem's
9371 constructor.
9372
9373 \sa QGraphicsScene::addItem()
9374*/
9375QGraphicsLineItem::QGraphicsLineItem(QGraphicsItem *parent)
9376 : QGraphicsItem(*new QGraphicsLineItemPrivate, parent)
9377{
9378}
9379
9380/*!
9381 Destroys the QGraphicsLineItem.
9382*/
9383QGraphicsLineItem::~QGraphicsLineItem()
9384{
9385}
9386
9387/*!
9388 Returns the item's pen, or a black solid 0-width pen if no pen has
9389 been set.
9390
9391 \sa setPen()
9392*/
9393QPen QGraphicsLineItem::pen() const
9394{
9395 Q_D(const QGraphicsLineItem);
9396 return d->pen;
9397}
9398
9399/*!
9400 Sets the item's pen to \a pen. If no pen is set, the line will be painted
9401 using a black solid 0-width pen.
9402
9403 \sa pen()
9404*/
9405void QGraphicsLineItem::setPen(const QPen &pen)
9406{
9407 Q_D(QGraphicsLineItem);
9408 if (d->pen == pen)
9409 return;
9410 prepareGeometryChange();
9411 d->pen = pen;
9412 update();
9413}
9414
9415/*!
9416 Returns the item's line, or a null line if no line has been set.
9417
9418 \sa setLine()
9419*/
9420QLineF QGraphicsLineItem::line() const
9421{
9422 Q_D(const QGraphicsLineItem);
9423 return d->line;
9424}
9425
9426/*!
9427 Sets the item's line to be the given \a line.
9428
9429 \sa line()
9430*/
9431void QGraphicsLineItem::setLine(const QLineF &line)
9432{
9433 Q_D(QGraphicsLineItem);
9434 if (d->line == line)
9435 return;
9436 prepareGeometryChange();
9437 d->line = line;
9438 update();
9439}
9440
9441/*!
9442 \fn void QGraphicsLineItem::setLine(qreal x1, qreal y1, qreal x2, qreal y2)
9443 \overload
9444
9445 Sets the item's line to be the line between (\a x1, \a y1) and (\a
9446 x2, \a y2).
9447
9448 This is the same as calling \c {setLine(QLineF(x1, y1, x2, y2))}.
9449*/
9450
9451/*!
9452 \reimp
9453*/
9454QRectF QGraphicsLineItem::boundingRect() const
9455{
9456 Q_D(const QGraphicsLineItem);
9457 if (d->pen.widthF() == 0.0) {
9458 const qreal x1 = d->line.p1().x();
9459 const qreal x2 = d->line.p2().x();
9460 const qreal y1 = d->line.p1().y();
9461 const qreal y2 = d->line.p2().y();
9462 qreal lx = qMin(a: x1, b: x2);
9463 qreal rx = qMax(a: x1, b: x2);
9464 qreal ty = qMin(a: y1, b: y2);
9465 qreal by = qMax(a: y1, b: y2);
9466 return QRectF(lx, ty, rx - lx, by - ty);
9467 }
9468 return shape().controlPointRect();
9469}
9470
9471/*!
9472 \reimp
9473*/
9474QPainterPath QGraphicsLineItem::shape() const
9475{
9476 Q_D(const QGraphicsLineItem);
9477 QPainterPath path;
9478 if (d->line == QLineF())
9479 return path;
9480
9481 path.moveTo(p: d->line.p1());
9482 path.lineTo(p: d->line.p2());
9483 return qt_graphicsItem_shapeFromPath(path, pen: d->pen);
9484}
9485
9486/*!
9487 \reimp
9488*/
9489bool QGraphicsLineItem::contains(const QPointF &point) const
9490{
9491 return QGraphicsItem::contains(point);
9492}
9493
9494/*!
9495 \reimp
9496*/
9497void QGraphicsLineItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
9498{
9499 Q_D(QGraphicsLineItem);
9500 Q_UNUSED(widget);
9501 painter->setPen(d->pen);
9502 painter->drawLine(l: d->line);
9503
9504 if (option->state & QStyle::State_Selected)
9505 qt_graphicsItem_highlightSelected(item: this, painter, option);
9506}
9507
9508/*!
9509 \reimp
9510*/
9511bool QGraphicsLineItem::isObscuredBy(const QGraphicsItem *item) const
9512{
9513 return QGraphicsItem::isObscuredBy(item);
9514}
9515
9516/*!
9517 \reimp
9518*/
9519QPainterPath QGraphicsLineItem::opaqueArea() const
9520{
9521 return QGraphicsItem::opaqueArea();
9522}
9523
9524/*!
9525 \reimp
9526*/
9527int QGraphicsLineItem::type() const
9528{
9529 return Type;
9530}
9531
9532/*!
9533 \internal
9534*/
9535bool QGraphicsLineItem::supportsExtension(Extension extension) const
9536{
9537 Q_UNUSED(extension);
9538 return false;
9539}
9540
9541/*!
9542 \internal
9543*/
9544void QGraphicsLineItem::setExtension(Extension extension, const QVariant &variant)
9545{
9546 Q_UNUSED(extension);
9547 Q_UNUSED(variant);
9548}
9549
9550/*!
9551 \internal
9552*/
9553QVariant QGraphicsLineItem::extension(const QVariant &variant) const
9554{
9555 Q_UNUSED(variant);
9556 return QVariant();
9557}
9558
9559/*!
9560 \class QGraphicsPixmapItem
9561 \brief The QGraphicsPixmapItem class provides a pixmap item that you can add to
9562 a QGraphicsScene.
9563 \since 4.2
9564 \ingroup graphicsview-api
9565 \inmodule QtWidgets
9566
9567 To set the item's pixmap, pass a QPixmap to QGraphicsPixmapItem's
9568 constructor, or call the setPixmap() function. The pixmap()
9569 function returns the current pixmap.
9570
9571 QGraphicsPixmapItem uses pixmap's optional alpha mask to provide a
9572 reasonable implementation of boundingRect(), shape(), and contains().
9573
9574 \image graphicsview-pixmapitem.png
9575
9576 The pixmap is drawn at the item's (0, 0) coordinate, as returned by
9577 offset(). You can change the drawing offset by calling setOffset().
9578
9579 You can set the pixmap's transformation mode by calling
9580 setTransformationMode(). By default, Qt::FastTransformation is used, which
9581 provides fast, non-smooth scaling. Qt::SmoothTransformation enables
9582 QPainter::SmoothPixmapTransform on the painter, and the quality depends on
9583 the platform and viewport. The result is usually not as good as calling
9584 QPixmap::scale() directly. Call transformationMode() to get the current
9585 transformation mode for the item.
9586
9587 \sa QGraphicsPathItem, QGraphicsRectItem, QGraphicsEllipseItem,
9588 QGraphicsTextItem, QGraphicsPolygonItem, QGraphicsLineItem,
9589 {Graphics View Framework}
9590*/
9591
9592/*!
9593 \enum QGraphicsPixmapItem::ShapeMode
9594
9595 This enum describes how QGraphicsPixmapItem calculates its shape and
9596 opaque area.
9597
9598 The default value is MaskShape.
9599
9600 \value MaskShape The shape is determined by calling QPixmap::mask().
9601 This shape includes only the opaque pixels of the pixmap.
9602 Because the shape is more complex, however, it can be slower than the other modes,
9603 and uses more memory.
9604
9605 \value BoundingRectShape The shape is determined by tracing the outline of
9606 the pixmap. This is the fastest shape mode, but it does not take into account
9607 any transparent areas on the pixmap.
9608
9609 \value HeuristicMaskShape The shape is determine by calling
9610 QPixmap::createHeuristicMask(). The performance and memory consumption
9611 is similar to MaskShape.
9612*/
9613extern QPainterPath qt_regionToPath(const QRegion &region);
9614
9615class QGraphicsPixmapItemPrivate : public QGraphicsItemPrivate
9616{
9617 Q_DECLARE_PUBLIC(QGraphicsPixmapItem)
9618public:
9619 QGraphicsPixmapItemPrivate()
9620 : transformationMode(Qt::FastTransformation),
9621 shapeMode(QGraphicsPixmapItem::MaskShape),
9622 hasShape(false)
9623 {}
9624
9625 QPixmap pixmap;
9626 Qt::TransformationMode transformationMode;
9627 QPointF offset;
9628 QGraphicsPixmapItem::ShapeMode shapeMode;
9629 QPainterPath shape;
9630 bool hasShape;
9631
9632 void updateShape()
9633 {
9634 shape = QPainterPath();
9635 switch (shapeMode) {
9636 case QGraphicsPixmapItem::MaskShape: {
9637 QBitmap mask = pixmap.mask();
9638 if (!mask.isNull()) {
9639 shape = qt_regionToPath(region: QRegion(mask).translated(p: offset.toPoint()));
9640 break;
9641 }
9642 Q_FALLTHROUGH();
9643 }
9644 case QGraphicsPixmapItem::BoundingRectShape:
9645 shape.addRect(rect: QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
9646 break;
9647 case QGraphicsPixmapItem::HeuristicMaskShape:
9648#ifndef QT_NO_IMAGE_HEURISTIC_MASK
9649 shape = qt_regionToPath(region: QRegion(pixmap.createHeuristicMask()).translated(p: offset.toPoint()));
9650#else
9651 shape.addRect(QRectF(offset.x(), offset.y(), pixmap.width(), pixmap.height()));
9652#endif
9653 break;
9654 }
9655 }
9656};
9657
9658/*!
9659 Constructs a QGraphicsPixmapItem, using \a pixmap as the default pixmap.
9660 \a parent is passed to QGraphicsItem's constructor.
9661
9662 \sa QGraphicsScene::addItem()
9663*/
9664QGraphicsPixmapItem::QGraphicsPixmapItem(const QPixmap &pixmap, QGraphicsItem *parent)
9665 : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent)
9666{
9667 setPixmap(pixmap);
9668}
9669
9670/*!
9671 Constructs a QGraphicsPixmapItem. \a parent is passed to QGraphicsItem's
9672 constructor.
9673
9674 \sa QGraphicsScene::addItem()
9675*/
9676QGraphicsPixmapItem::QGraphicsPixmapItem(QGraphicsItem *parent)
9677 : QGraphicsItem(*new QGraphicsPixmapItemPrivate, parent)
9678{
9679}
9680
9681/*!
9682 Destroys the QGraphicsPixmapItem.
9683*/
9684QGraphicsPixmapItem::~QGraphicsPixmapItem()
9685{
9686}
9687
9688/*!
9689 Sets the item's pixmap to \a pixmap.
9690
9691 \sa pixmap()
9692*/
9693void QGraphicsPixmapItem::setPixmap(const QPixmap &pixmap)
9694{
9695 Q_D(QGraphicsPixmapItem);
9696 prepareGeometryChange();
9697 d->pixmap = pixmap;
9698 d->hasShape = false;
9699 update();
9700}
9701
9702/*!
9703 Returns the item's pixmap, or an invalid QPixmap if no pixmap has been
9704 set.
9705
9706 \sa setPixmap()
9707*/
9708QPixmap QGraphicsPixmapItem::pixmap() const
9709{
9710 Q_D(const QGraphicsPixmapItem);
9711 return d->pixmap;
9712}
9713
9714/*!
9715 Returns the transformation mode of the pixmap. The default mode is
9716 Qt::FastTransformation, which provides quick transformation with no
9717 smoothing.
9718
9719 \sa setTransformationMode()
9720*/
9721Qt::TransformationMode QGraphicsPixmapItem::transformationMode() const
9722{
9723 Q_D(const QGraphicsPixmapItem);
9724 return d->transformationMode;
9725}
9726
9727/*!
9728 Sets the pixmap item's transformation mode to \a mode, and toggles an
9729 update of the item. The default mode is Qt::FastTransformation, which
9730 provides quick transformation with no smoothing.
9731
9732 Qt::SmoothTransformation enables QPainter::SmoothPixmapTransform on the
9733 painter, and the quality depends on the platform and viewport. The result
9734 is usually not as good as calling QPixmap::scale() directly.
9735
9736 \sa transformationMode()
9737*/
9738void QGraphicsPixmapItem::setTransformationMode(Qt::TransformationMode mode)
9739{
9740 Q_D(QGraphicsPixmapItem);
9741 if (mode != d->transformationMode) {
9742 d->transformationMode = mode;
9743 update();
9744 }
9745}
9746
9747/*!
9748 Returns the pixmap item's \e offset, which defines the point of the
9749 top-left corner of the pixmap, in local coordinates.
9750
9751 \sa setOffset()
9752*/
9753QPointF QGraphicsPixmapItem::offset() const
9754{
9755 Q_D(const QGraphicsPixmapItem);
9756 return d->offset;
9757}
9758
9759/*!
9760 Sets the pixmap item's offset to \a offset. QGraphicsPixmapItem will draw
9761 its pixmap using \a offset for its top-left corner.
9762
9763 \sa offset()
9764*/
9765void QGraphicsPixmapItem::setOffset(const QPointF &offset)
9766{
9767 Q_D(QGraphicsPixmapItem);
9768 if (d->offset == offset)
9769 return;
9770 prepareGeometryChange();
9771 d->offset = offset;
9772 d->hasShape = false;
9773 update();
9774}
9775
9776/*!
9777 \fn void QGraphicsPixmapItem::setOffset(qreal x, qreal y)
9778 \since 4.3
9779
9780 This convenience function is equivalent to calling setOffset(QPointF(\a x, \a y)).
9781*/
9782
9783/*!
9784 \reimp
9785*/
9786QRectF QGraphicsPixmapItem::boundingRect() const
9787{
9788 Q_D(const QGraphicsPixmapItem);
9789 if (d->pixmap.isNull())
9790 return QRectF();
9791 if (d->flags & ItemIsSelectable) {
9792 qreal pw = 1.0;
9793 return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio()).adjusted(xp1: -pw/2, yp1: -pw/2, xp2: pw/2, yp2: pw/2);
9794 } else {
9795 return QRectF(d->offset, QSizeF(d->pixmap.size()) / d->pixmap.devicePixelRatio());
9796 }
9797}
9798
9799/*!
9800 \reimp
9801*/
9802QPainterPath QGraphicsPixmapItem::shape() const
9803{
9804 Q_D(const QGraphicsPixmapItem);
9805 if (!d->hasShape) {
9806 QGraphicsPixmapItemPrivate *thatD = const_cast<QGraphicsPixmapItemPrivate *>(d);
9807 thatD->updateShape();
9808 thatD->hasShape = true;
9809 }
9810 return d_func()->shape;
9811}
9812
9813/*!
9814 \reimp
9815*/
9816bool QGraphicsPixmapItem::contains(const QPointF &point) const
9817{
9818 return QGraphicsItem::contains(point);
9819}
9820
9821/*!
9822 \reimp
9823*/
9824void QGraphicsPixmapItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
9825 QWidget *widget)
9826{
9827 Q_D(QGraphicsPixmapItem);
9828 Q_UNUSED(widget);
9829
9830 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform,
9831 on: (d->transformationMode == Qt::SmoothTransformation));
9832
9833 painter->drawPixmap(p: d->offset, pm: d->pixmap);
9834
9835 if (option->state & QStyle::State_Selected)
9836 qt_graphicsItem_highlightSelected(item: this, painter, option);
9837}
9838
9839/*!
9840 \reimp
9841*/
9842bool QGraphicsPixmapItem::isObscuredBy(const QGraphicsItem *item) const
9843{
9844 return QGraphicsItem::isObscuredBy(item);
9845}
9846
9847/*!
9848 \reimp
9849*/
9850QPainterPath QGraphicsPixmapItem::opaqueArea() const
9851{
9852 return shape();
9853}
9854
9855/*!
9856 \reimp
9857*/
9858int QGraphicsPixmapItem::type() const
9859{
9860 return Type;
9861}
9862
9863/*!
9864 Returns the item's shape mode. The shape mode describes how
9865 QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
9866
9867 \sa setShapeMode(), ShapeMode
9868*/
9869QGraphicsPixmapItem::ShapeMode QGraphicsPixmapItem::shapeMode() const
9870{
9871 return d_func()->shapeMode;
9872}
9873
9874/*!
9875 Sets the item's shape mode to \a mode. The shape mode describes how
9876 QGraphicsPixmapItem calculates its shape. The default mode is MaskShape.
9877
9878 \sa shapeMode(), ShapeMode
9879*/
9880void QGraphicsPixmapItem::setShapeMode(ShapeMode mode)
9881{
9882 Q_D(QGraphicsPixmapItem);
9883 if (d->shapeMode == mode)
9884 return;
9885 d->shapeMode = mode;
9886 d->hasShape = false;
9887}
9888
9889/*!
9890 \internal
9891*/
9892bool QGraphicsPixmapItem::supportsExtension(Extension extension) const
9893{
9894 Q_UNUSED(extension);
9895 return false;
9896}
9897
9898/*!
9899 \internal
9900*/
9901void QGraphicsPixmapItem::setExtension(Extension extension, const QVariant &variant)
9902{
9903 Q_UNUSED(extension);
9904 Q_UNUSED(variant);
9905}
9906
9907/*!
9908 \internal
9909*/
9910QVariant QGraphicsPixmapItem::extension(const QVariant &variant) const
9911{
9912 Q_UNUSED(variant);
9913 return QVariant();
9914}
9915
9916/*!
9917 \class QGraphicsTextItem
9918 \brief The QGraphicsTextItem class provides a text item that you can add to
9919 a QGraphicsScene to display formatted text.
9920 \since 4.2
9921 \ingroup graphicsview-api
9922 \inmodule QtWidgets
9923
9924 If you only need to show plain text in an item, consider using QGraphicsSimpleTextItem
9925 instead.
9926
9927 To set the item's text, pass a QString to QGraphicsTextItem's
9928 constructor, or call setHtml()/setPlainText().
9929
9930 QGraphicsTextItem uses the text's formatted size and the associated font
9931 to provide a reasonable implementation of boundingRect(), shape(),
9932 and contains(). You can set the font by calling setFont().
9933
9934 It is possible to make the item editable by setting the Qt::TextEditorInteraction flag
9935 using setTextInteractionFlags().
9936
9937 The item's preferred text width can be set using setTextWidth() and obtained
9938 using textWidth().
9939
9940 \note In order to align HTML text in the center, the item's text width must be set.
9941 Otherwise, you can call adjustSize() after setting the item's text.
9942
9943 \image graphicsview-textitem.png
9944
9945 \note QGraphicsTextItem accepts \l{QGraphicsItem::acceptHoverEvents()}{hover events}
9946 by default. You can change this with \l{QGraphicsItem::}{setAcceptHoverEvents()}.
9947
9948 \sa QGraphicsSimpleTextItem, QGraphicsPathItem, QGraphicsRectItem,
9949 QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
9950 QGraphicsLineItem, {Graphics View Framework}
9951*/
9952
9953class QGraphicsTextItemPrivate
9954{
9955public:
9956 QGraphicsTextItemPrivate()
9957 : control(nullptr), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0)
9958 { }
9959
9960 mutable QWidgetTextControl *control;
9961 QWidgetTextControl *textControl() const;
9962
9963 inline QPointF controlOffset() const
9964 { return QPointF(0., pageNumber * control->document()->pageSize().height()); }
9965 inline void sendControlEvent(QEvent *e)
9966 { if (control) control->processEvent(e, coordinateOffset: controlOffset()); }
9967
9968 void _q_updateBoundingRect(const QSizeF &);
9969 void _q_update(QRectF);
9970 void _q_ensureVisible(QRectF);
9971 bool _q_mouseOnEdge(QGraphicsSceneMouseEvent *);
9972
9973 QRectF boundingRect;
9974 int pageNumber;
9975 bool useDefaultImpl;
9976 bool tabChangesFocus;
9977
9978 uint clickCausedFocus : 1;
9979
9980 QGraphicsTextItem *qq;
9981};
9982
9983
9984/*!
9985 Constructs a QGraphicsTextItem, using \a text as the default plain
9986 text. \a parent is passed to QGraphicsItem's constructor.
9987
9988 \sa QGraphicsScene::addItem()
9989*/
9990QGraphicsTextItem::QGraphicsTextItem(const QString &text, QGraphicsItem *parent)
9991 : QGraphicsObject(*new QGraphicsItemPrivate, parent),
9992 dd(new QGraphicsTextItemPrivate)
9993{
9994 dd->qq = this;
9995 if (!text.isEmpty())
9996 setPlainText(text);
9997 setAcceptDrops(true);
9998 setAcceptHoverEvents(true);
9999 setFlags(ItemUsesExtendedStyleOption);
10000}
10001
10002/*!
10003 Constructs a QGraphicsTextItem. \a parent is passed to QGraphicsItem's
10004 constructor.
10005
10006 \sa QGraphicsScene::addItem()
10007*/
10008QGraphicsTextItem::QGraphicsTextItem(QGraphicsItem *parent)
10009 : QGraphicsObject(*new QGraphicsItemPrivate, parent),
10010 dd(new QGraphicsTextItemPrivate)
10011{
10012 dd->qq = this;
10013 setAcceptDrops(true);
10014 setAcceptHoverEvents(true);
10015 setFlag(flag: ItemUsesExtendedStyleOption);
10016}
10017
10018/*!
10019 Destroys the QGraphicsTextItem.
10020*/
10021QGraphicsTextItem::~QGraphicsTextItem()
10022{
10023 delete dd;
10024}
10025
10026/*!
10027 Returns the item's text converted to HTML, or an empty QString if no text has been set.
10028
10029 \sa setHtml()
10030*/
10031QString QGraphicsTextItem::toHtml() const
10032{
10033#ifndef QT_NO_TEXTHTMLPARSER
10034 if (dd->control)
10035 return dd->control->toHtml();
10036#endif
10037 return QString();
10038}
10039
10040/*!
10041 Sets the item's text to \a text, assuming that text is HTML formatted. If
10042 the item has keyboard input focus, this function will also call
10043 ensureVisible() to ensure that the text is visible in all viewports.
10044
10045 \sa toHtml(), hasFocus(), QGraphicsSimpleTextItem
10046*/
10047void QGraphicsTextItem::setHtml(const QString &text)
10048{
10049 dd->textControl()->setHtml(text);
10050}
10051
10052/*!
10053 Returns the item's text converted to plain text, or an empty QString if no text has been set.
10054
10055 \sa setPlainText()
10056*/
10057QString QGraphicsTextItem::toPlainText() const
10058{
10059 if (dd->control)
10060 return dd->control->toPlainText();
10061 return QString();
10062}
10063
10064/*!
10065 Sets the item's text to \a text. If the item has keyboard input focus,
10066 this function will also call ensureVisible() to ensure that the text is
10067 visible in all viewports.
10068
10069 \sa toHtml(), hasFocus()
10070*/
10071void QGraphicsTextItem::setPlainText(const QString &text)
10072{
10073 dd->textControl()->setPlainText(text);
10074}
10075
10076/*!
10077 Returns the item's font, which is used to render the text.
10078
10079 \sa setFont()
10080*/
10081QFont QGraphicsTextItem::font() const
10082{
10083 if (!dd->control)
10084 return QFont();
10085 return dd->control->document()->defaultFont();
10086}
10087
10088/*!
10089 Sets the font used to render the text item to \a font.
10090
10091 \sa font()
10092*/
10093void QGraphicsTextItem::setFont(const QFont &font)
10094{
10095 dd->textControl()->document()->setDefaultFont(font);
10096}
10097
10098/*!
10099 Sets the color for unformatted text to \a col.
10100*/
10101void QGraphicsTextItem::setDefaultTextColor(const QColor &col)
10102{
10103 QWidgetTextControl *c = dd->textControl();
10104 QPalette pal = c->palette();
10105 QColor old = pal.color(cr: QPalette::Text);
10106 pal.setColor(acr: QPalette::Text, acolor: col);
10107 c->setPalette(pal);
10108 if (old != col)
10109 update();
10110}
10111
10112/*!
10113 Returns the default text color that is used for unformatted text.
10114*/
10115QColor QGraphicsTextItem::defaultTextColor() const
10116{
10117 return dd->textControl()->palette().color(cr: QPalette::Text);
10118}
10119
10120/*!
10121 \reimp
10122*/
10123QRectF QGraphicsTextItem::boundingRect() const
10124{
10125 return dd->boundingRect;
10126}
10127
10128/*!
10129 \reimp
10130*/
10131QPainterPath QGraphicsTextItem::shape() const
10132{
10133 if (!dd->control)
10134 return QPainterPath();
10135 QPainterPath path;
10136 path.addRect(rect: dd->boundingRect);
10137 return path;
10138}
10139
10140/*!
10141 \reimp
10142*/
10143bool QGraphicsTextItem::contains(const QPointF &point) const
10144{
10145 return dd->boundingRect.contains(p: point);
10146}
10147
10148/*!
10149 \reimp
10150*/
10151void QGraphicsTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
10152 QWidget *widget)
10153{
10154 Q_UNUSED(widget);
10155 if (dd->control) {
10156 painter->save();
10157 QRectF r = option->exposedRect;
10158 painter->translate(offset: -dd->controlOffset());
10159 r.translate(p: dd->controlOffset());
10160
10161 QTextDocument *doc = dd->control->document();
10162 QTextDocumentLayout *layout = qobject_cast<QTextDocumentLayout *>(object: doc->documentLayout());
10163
10164 // the layout might need to expand the root frame to
10165 // the viewport if NoWrap is set
10166 if (layout)
10167 layout->setViewport(dd->boundingRect);
10168
10169 dd->control->drawContents(painter, rect: r);
10170
10171 if (layout)
10172 layout->setViewport(QRect());
10173
10174 painter->restore();
10175 }
10176
10177 if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
10178 qt_graphicsItem_highlightSelected(item: this, painter, option);
10179}
10180
10181/*!
10182 \reimp
10183*/
10184bool QGraphicsTextItem::isObscuredBy(const QGraphicsItem *item) const
10185{
10186 return QGraphicsItem::isObscuredBy(item);
10187}
10188
10189/*!
10190 \reimp
10191*/
10192QPainterPath QGraphicsTextItem::opaqueArea() const
10193{
10194 return QGraphicsItem::opaqueArea();
10195}
10196
10197/*!
10198 \reimp
10199*/
10200int QGraphicsTextItem::type() const
10201{
10202 return Type;
10203}
10204
10205/*!
10206 Sets the preferred width for the item's text. If the actual text
10207 is wider than the specified width then it will be broken into
10208 multiple lines.
10209
10210 If \a width is set to -1 then the text will not be broken into
10211 multiple lines unless it is enforced through an explicit line
10212 break or a new paragraph.
10213
10214 The default value is -1.
10215
10216 Note that QGraphicsTextItem keeps a QTextDocument internally,
10217 which is used to calculate the text width.
10218
10219 \sa textWidth(), QTextDocument::setTextWidth()
10220*/
10221void QGraphicsTextItem::setTextWidth(qreal width)
10222{
10223 dd->textControl()->setTextWidth(width);
10224}
10225
10226/*!
10227 Returns the text width.
10228
10229 The width is calculated with the QTextDocument that
10230 QGraphicsTextItem keeps internally.
10231
10232 \sa setTextWidth(), QTextDocument::textWidth()
10233*/
10234qreal QGraphicsTextItem::textWidth() const
10235{
10236 if (!dd->control)
10237 return -1;
10238 return dd->control->textWidth();
10239}
10240
10241/*!
10242 Adjusts the text item to a reasonable size.
10243*/
10244void QGraphicsTextItem::adjustSize()
10245{
10246 if (dd->control)
10247 dd->control->adjustSize();
10248}
10249
10250/*!
10251 Sets the text document \a document on the item.
10252*/
10253void QGraphicsTextItem::setDocument(QTextDocument *document)
10254{
10255 dd->textControl()->setDocument(document);
10256 dd->_q_updateBoundingRect(dd->control->size());
10257}
10258
10259/*!
10260 Returns the item's text document.
10261*/
10262QTextDocument *QGraphicsTextItem::document() const
10263{
10264 return dd->textControl()->document();
10265}
10266
10267/*!
10268 \reimp
10269*/
10270bool QGraphicsTextItem::sceneEvent(QEvent *event)
10271{
10272 QEvent::Type t = event->type();
10273 if (!dd->tabChangesFocus && (t == QEvent::KeyPress || t == QEvent::KeyRelease)) {
10274 int k = ((QKeyEvent *)event)->key();
10275 if (k == Qt::Key_Tab || k == Qt::Key_Backtab) {
10276 dd->sendControlEvent(e: event);
10277 return true;
10278 }
10279 }
10280 bool result = QGraphicsItem::sceneEvent(event);
10281
10282 // Ensure input context is updated.
10283 switch (event->type()) {
10284 case QEvent::ContextMenu:
10285 case QEvent::FocusIn:
10286 case QEvent::FocusOut:
10287 case QEvent::GraphicsSceneDragEnter:
10288 case QEvent::GraphicsSceneDragLeave:
10289 case QEvent::GraphicsSceneDragMove:
10290 case QEvent::GraphicsSceneDrop:
10291 case QEvent::GraphicsSceneHoverEnter:
10292 case QEvent::GraphicsSceneHoverLeave:
10293 case QEvent::GraphicsSceneHoverMove:
10294 case QEvent::GraphicsSceneMouseDoubleClick:
10295 case QEvent::GraphicsSceneMousePress:
10296 case QEvent::GraphicsSceneMouseMove:
10297 case QEvent::GraphicsSceneMouseRelease:
10298 case QEvent::KeyPress:
10299 case QEvent::KeyRelease:
10300 case QEvent::InputMethod:
10301 // Reset the focus widget's input context, regardless
10302 // of how this item gained or lost focus.
10303 if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut) {
10304 QGuiApplication::inputMethod()->reset();
10305 } else {
10306 QGuiApplication::inputMethod()->update(queries: Qt::ImQueryInput);
10307 }
10308 break;
10309 case QEvent::ShortcutOverride:
10310 dd->sendControlEvent(e: event);
10311 return true;
10312 default:
10313 break;
10314 }
10315
10316 return result;
10317}
10318
10319/*!
10320 \reimp
10321*/
10322void QGraphicsTextItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
10323{
10324 if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable))
10325 && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
10326 // User left-pressed on edge of selectable/movable item, use
10327 // base impl.
10328 dd->useDefaultImpl = true;
10329 } else if (event->buttons() == event->button()
10330 && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
10331 // User pressed first button on non-interactive item.
10332 dd->useDefaultImpl = true;
10333 }
10334 if (dd->useDefaultImpl) {
10335 QGraphicsItem::mousePressEvent(event);
10336 if (!event->isAccepted())
10337 dd->useDefaultImpl = false;
10338 return;
10339 }
10340
10341 dd->sendControlEvent(e: event);
10342}
10343
10344/*!
10345 \reimp
10346*/
10347void QGraphicsTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
10348{
10349 if (dd->useDefaultImpl) {
10350 QGraphicsItem::mouseMoveEvent(event);
10351 return;
10352 }
10353
10354 dd->sendControlEvent(e: event);
10355}
10356
10357/*!
10358 \reimp
10359*/
10360void QGraphicsTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
10361{
10362 if (dd->useDefaultImpl) {
10363 QGraphicsItem::mouseReleaseEvent(event);
10364 if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
10365 && !event->buttons()) {
10366 // User released last button on non-interactive item.
10367 dd->useDefaultImpl = false;
10368 } else if ((event->buttons() & Qt::LeftButton) == 0) {
10369 // User released the left button on an interactive item.
10370 dd->useDefaultImpl = false;
10371 }
10372 return;
10373 }
10374
10375 QWidget *widget = event->widget();
10376 if (widget && (dd->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(p: event->pos())) {
10377 qt_widget_private(widget)->handleSoftwareInputPanel(button: event->button(), clickCausedFocus: dd->clickCausedFocus);
10378 }
10379 dd->clickCausedFocus = 0;
10380 dd->sendControlEvent(e: event);
10381}
10382
10383/*!
10384 \reimp
10385*/
10386void QGraphicsTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
10387{
10388 if (dd->useDefaultImpl) {
10389 QGraphicsItem::mouseDoubleClickEvent(event);
10390 return;
10391 }
10392
10393 if (!hasFocus()) {
10394 QGraphicsItem::mouseDoubleClickEvent(event);
10395 return;
10396 }
10397
10398 dd->sendControlEvent(e: event);
10399}
10400
10401/*!
10402 \reimp
10403*/
10404void QGraphicsTextItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
10405{
10406 dd->sendControlEvent(e: event);
10407}
10408
10409/*!
10410 \reimp
10411*/
10412void QGraphicsTextItem::keyPressEvent(QKeyEvent *event)
10413{
10414 dd->sendControlEvent(e: event);
10415}
10416
10417/*!
10418 \reimp
10419*/
10420void QGraphicsTextItem::keyReleaseEvent(QKeyEvent *event)
10421{
10422 dd->sendControlEvent(e: event);
10423}
10424
10425/*!
10426 \reimp
10427*/
10428void QGraphicsTextItem::focusInEvent(QFocusEvent *event)
10429{
10430 dd->sendControlEvent(e: event);
10431 if (event->reason() == Qt::MouseFocusReason) {
10432 dd->clickCausedFocus = 1;
10433 }
10434 update();
10435}
10436
10437/*!
10438 \reimp
10439*/
10440void QGraphicsTextItem::focusOutEvent(QFocusEvent *event)
10441{
10442 dd->sendControlEvent(e: event);
10443 update();
10444}
10445
10446/*!
10447 \reimp
10448*/
10449void QGraphicsTextItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
10450{
10451 dd->sendControlEvent(e: event);
10452}
10453
10454/*!
10455 \reimp
10456*/
10457void QGraphicsTextItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
10458{
10459 dd->sendControlEvent(e: event);
10460}
10461
10462/*!
10463 \reimp
10464*/
10465void QGraphicsTextItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
10466{
10467 dd->sendControlEvent(e: event);
10468}
10469
10470/*!
10471 \reimp
10472*/
10473void QGraphicsTextItem::dropEvent(QGraphicsSceneDragDropEvent *event)
10474{
10475 dd->sendControlEvent(e: event);
10476}
10477
10478/*!
10479 \reimp
10480*/
10481void QGraphicsTextItem::inputMethodEvent(QInputMethodEvent *event)
10482{
10483 dd->sendControlEvent(e: event);
10484}
10485
10486/*!
10487 \reimp
10488*/
10489void QGraphicsTextItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
10490{
10491 dd->sendControlEvent(e: event);
10492}
10493
10494/*!
10495 \reimp
10496*/
10497void QGraphicsTextItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
10498{
10499 dd->sendControlEvent(e: event);
10500}
10501
10502/*!
10503 \reimp
10504*/
10505void QGraphicsTextItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
10506{
10507 dd->sendControlEvent(e: event);
10508}
10509
10510/*!
10511 \reimp
10512*/
10513QVariant QGraphicsTextItem::inputMethodQuery(Qt::InputMethodQuery query) const
10514{
10515 QVariant v;
10516 if (query == Qt::ImHints)
10517 v = int(inputMethodHints());
10518 else if (dd->control)
10519 v = dd->control->inputMethodQuery(property: query, argument: QVariant());
10520 if (dd->control) {
10521 if (v.userType() == QMetaType::QRectF)
10522 v = v.toRectF().translated(p: -dd->controlOffset());
10523 else if (v.userType() == QMetaType::QPointF)
10524 v = v.toPointF() - dd->controlOffset();
10525 else if (v.userType() == QMetaType::QRect)
10526 v = v.toRect().translated(p: -dd->controlOffset().toPoint());
10527 else if (v.userType() == QMetaType::QPoint)
10528 v = v.toPoint() - dd->controlOffset().toPoint();
10529 }
10530 return v;
10531}
10532
10533/*!
10534 \internal
10535*/
10536bool QGraphicsTextItem::supportsExtension(Extension extension) const
10537{
10538 Q_UNUSED(extension);
10539 return false;
10540}
10541
10542/*!
10543 \internal
10544*/
10545void QGraphicsTextItem::setExtension(Extension extension, const QVariant &variant)
10546{
10547 Q_UNUSED(extension);
10548 Q_UNUSED(variant);
10549}
10550
10551/*!
10552 \internal
10553*/
10554QVariant QGraphicsTextItem::extension(const QVariant &variant) const
10555{
10556 Q_UNUSED(variant);
10557 return QVariant();
10558}
10559
10560/*!
10561 \internal
10562*/
10563void QGraphicsTextItemPrivate::_q_update(QRectF rect)
10564{
10565 if (rect.isValid()) {
10566 rect.translate(p: -controlOffset());
10567 } else {
10568 rect = boundingRect;
10569 }
10570 if (rect.intersects(r: boundingRect))
10571 qq->update(rect);
10572}
10573
10574/*!
10575 \internal
10576*/
10577void QGraphicsTextItemPrivate::_q_updateBoundingRect(const QSizeF &size)
10578{
10579 if (size != boundingRect.size()) {
10580 qq->prepareGeometryChange();
10581 boundingRect.setSize(size);
10582 qq->update();
10583 }
10584}
10585
10586/*!
10587 \internal
10588*/
10589void QGraphicsTextItemPrivate::_q_ensureVisible(QRectF rect)
10590{
10591 if (qq->hasFocus()) {
10592 rect.translate(p: -controlOffset());
10593 qq->ensureVisible(rect, /*xmargin=*/0, /*ymargin=*/0);
10594 }
10595}
10596
10597QWidgetTextControl *QGraphicsTextItemPrivate::textControl() const
10598{
10599 if (!control) {
10600 QGraphicsTextItem *that = const_cast<QGraphicsTextItem *>(qq);
10601 control = new QWidgetTextControl(that);
10602 control->setTextInteractionFlags(Qt::NoTextInteraction);
10603
10604 QObject::connect(sender: control, SIGNAL(updateRequest(QRectF)),
10605 receiver: qq, SLOT(_q_update(QRectF)));
10606 QObject::connect(sender: control, SIGNAL(documentSizeChanged(QSizeF)),
10607 receiver: qq, SLOT(_q_updateBoundingRect(QSizeF)));
10608 QObject::connect(sender: control, SIGNAL(visibilityRequest(QRectF)),
10609 receiver: qq, SLOT(_q_ensureVisible(QRectF)));
10610 QObject::connect(sender: control, SIGNAL(linkActivated(QString)),
10611 receiver: qq, SIGNAL(linkActivated(QString)));
10612 QObject::connect(sender: control, SIGNAL(linkHovered(QString)),
10613 receiver: qq, SIGNAL(linkHovered(QString)));
10614
10615 const QSizeF pgSize = control->document()->pageSize();
10616 if (pgSize.height() != -1) {
10617 qq->prepareGeometryChange();
10618 that->dd->boundingRect.setSize(pgSize);
10619 qq->update();
10620 } else {
10621 that->dd->_q_updateBoundingRect(size: control->size());
10622 }
10623 }
10624 return control;
10625}
10626
10627/*!
10628 \internal
10629*/
10630bool QGraphicsTextItemPrivate::_q_mouseOnEdge(QGraphicsSceneMouseEvent *event)
10631{
10632 QPainterPath path;
10633 path.addRect(rect: qq->boundingRect());
10634
10635 QPainterPath docPath;
10636 const QTextFrameFormat format = control->document()->rootFrame()->frameFormat();
10637 docPath.addRect(
10638 rect: qq->boundingRect().adjusted(
10639 xp1: format.leftMargin(),
10640 yp1: format.topMargin(),
10641 xp2: -format.rightMargin(),
10642 yp2: -format.bottomMargin()));
10643
10644 return path.subtracted(r: docPath).contains(pt: event->pos());
10645}
10646
10647/*!
10648 \fn void QGraphicsTextItem::linkActivated(const QString &link)
10649
10650 This signal is emitted when the user clicks on a link on a text item
10651 that enables Qt::LinksAccessibleByMouse or Qt::LinksAccessibleByKeyboard.
10652 \a link is the link that was clicked.
10653
10654 \sa setTextInteractionFlags()
10655*/
10656
10657/*!
10658 \fn void QGraphicsTextItem::linkHovered(const QString &link)
10659
10660 This signal is emitted when the user hovers over a link on a text item
10661 that enables Qt::LinksAccessibleByMouse. \a link is
10662 the link that was hovered over.
10663
10664 \sa setTextInteractionFlags()
10665*/
10666
10667/*!
10668 Sets the flags \a flags to specify how the text item should react to user
10669 input.
10670
10671 The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function
10672 also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags
10673 is different from Qt::NoTextInteraction and clearing it otherwise.
10674
10675 By default, the text is read-only. To transform the item into an editor,
10676 set the Qt::TextEditable flag.
10677*/
10678void QGraphicsTextItem::setTextInteractionFlags(Qt::TextInteractionFlags flags)
10679{
10680 if (flags == Qt::NoTextInteraction)
10681 setFlags(this->flags() & ~(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod));
10682 else
10683 setFlags(this->flags() | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
10684
10685 dd->textControl()->setTextInteractionFlags(flags);
10686}
10687
10688/*!
10689 Returns the current text interaction flags.
10690
10691 \sa setTextInteractionFlags()
10692*/
10693Qt::TextInteractionFlags QGraphicsTextItem::textInteractionFlags() const
10694{
10695 if (!dd->control)
10696 return Qt::NoTextInteraction;
10697 return dd->control->textInteractionFlags();
10698}
10699
10700/*!
10701 \since 4.5
10702
10703 If \a b is true, the \uicontrol Tab key will cause the widget to change focus;
10704 otherwise, the tab key will insert a tab into the document.
10705
10706 In some occasions text edits should not allow the user to input tabulators
10707 or change indentation using the \uicontrol Tab key, as this breaks the focus
10708 chain. The default is false.
10709
10710 \sa tabChangesFocus(), ItemIsFocusable, textInteractionFlags()
10711*/
10712void QGraphicsTextItem::setTabChangesFocus(bool b)
10713{
10714 dd->tabChangesFocus = b;
10715}
10716
10717/*!
10718 \since 4.5
10719
10720 Returns \c true if the \uicontrol Tab key will cause the widget to change focus;
10721 otherwise, false is returned.
10722
10723 By default, this behavior is disabled, and this function will return false.
10724
10725 \sa setTabChangesFocus()
10726*/
10727bool QGraphicsTextItem::tabChangesFocus() const
10728{
10729 return dd->tabChangesFocus;
10730}
10731
10732/*!
10733 \property QGraphicsTextItem::openExternalLinks
10734
10735 Specifies whether QGraphicsTextItem should automatically open links using
10736 QDesktopServices::openUrl() instead of emitting the
10737 linkActivated signal.
10738
10739 The default value is false.
10740*/
10741void QGraphicsTextItem::setOpenExternalLinks(bool open)
10742{
10743 dd->textControl()->setOpenExternalLinks(open);
10744}
10745
10746bool QGraphicsTextItem::openExternalLinks() const
10747{
10748 if (!dd->control)
10749 return false;
10750 return dd->control->openExternalLinks();
10751}
10752
10753/*!
10754 \property QGraphicsTextItem::textCursor
10755
10756 This property represents the visible text cursor in an editable
10757 text item.
10758
10759 By default, if the item's text has not been set, this property
10760 contains a null text cursor; otherwise it contains a text cursor
10761 placed at the start of the item's document.
10762*/
10763void QGraphicsTextItem::setTextCursor(const QTextCursor &cursor)
10764{
10765 dd->textControl()->setTextCursor(cursor);
10766}
10767
10768QTextCursor QGraphicsTextItem::textCursor() const
10769{
10770 if (!dd->control)
10771 return QTextCursor();
10772 return dd->control->textCursor();
10773}
10774
10775class QGraphicsSimpleTextItemPrivate : public QAbstractGraphicsShapeItemPrivate
10776{
10777 Q_DECLARE_PUBLIC(QGraphicsSimpleTextItem)
10778public:
10779 inline QGraphicsSimpleTextItemPrivate() {
10780 pen.setStyle(Qt::NoPen);
10781 brush.setStyle(Qt::SolidPattern);
10782 }
10783 QString text;
10784 QFont font;
10785 QRectF boundingRect;
10786
10787 void updateBoundingRect();
10788};
10789
10790static QRectF setupTextLayout(QTextLayout *layout)
10791{
10792 layout->setCacheEnabled(true);
10793 layout->beginLayout();
10794 while (layout->createLine().isValid())
10795 ;
10796 layout->endLayout();
10797 qreal maxWidth = 0;
10798 qreal y = 0;
10799 for (int i = 0; i < layout->lineCount(); ++i) {
10800 QTextLine line = layout->lineAt(i);
10801 maxWidth = qMax(a: maxWidth, b: line.naturalTextWidth());
10802 line.setPosition(QPointF(0, y));
10803 y += line.height();
10804 }
10805 return QRectF(0, 0, maxWidth, y);
10806}
10807
10808void QGraphicsSimpleTextItemPrivate::updateBoundingRect()
10809{
10810 Q_Q(QGraphicsSimpleTextItem);
10811 QRectF br;
10812 if (text.isEmpty()) {
10813 br = QRectF();
10814 } else {
10815 QString tmp = text;
10816 tmp.replace(before: QLatin1Char('\n'), after: QChar::LineSeparator);
10817 QStackTextEngine engine(tmp, font);
10818 QTextLayout layout(&engine);
10819 br = setupTextLayout(&layout);
10820 }
10821 if (br != boundingRect) {
10822 q->prepareGeometryChange();
10823 boundingRect = br;
10824 q->update();
10825 }
10826}
10827
10828/*!
10829 \class QGraphicsSimpleTextItem
10830 \brief The QGraphicsSimpleTextItem class provides a simple text path item
10831 that you can add to a QGraphicsScene.
10832 \since 4.2
10833 \ingroup graphicsview-api
10834 \inmodule QtWidgets
10835
10836 To set the item's text, you can either pass a QString to
10837 QGraphicsSimpleTextItem's constructor, or call setText() to change the
10838 text later. To set the text fill color, call setBrush().
10839
10840 The simple text item can have both a fill and an outline; setBrush() will
10841 set the text fill (i.e., text color), and setPen() sets the pen that will
10842 be used to draw the text outline. (The latter can be slow, especially for
10843 complex pens, and items with long text content.) If all you want is to
10844 draw a simple line of text, you should call setBrush() only, and leave the
10845 pen unset; QGraphicsSimpleTextItem's pen is by default Qt::NoPen.
10846
10847 QGraphicsSimpleTextItem uses the text's formatted size and the associated
10848 font to provide a reasonable implementation of boundingRect(), shape(),
10849 and contains(). You can set the font by calling setFont().
10850
10851 QGraphicsSimpleText does not display rich text; instead, you can use
10852 QGraphicsTextItem, which provides full text control capabilities.
10853
10854 \image graphicsview-simpletextitem.png
10855
10856 \sa QGraphicsTextItem, QGraphicsPathItem, QGraphicsRectItem,
10857 QGraphicsEllipseItem, QGraphicsPixmapItem, QGraphicsPolygonItem,
10858 QGraphicsLineItem, {Graphics View Framework}
10859*/
10860
10861/*!
10862 Constructs a QGraphicsSimpleTextItem.
10863
10864 \a parent is passed to QGraphicsItem's constructor.
10865
10866 \sa QGraphicsScene::addItem()
10867*/
10868QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(QGraphicsItem *parent)
10869 : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent)
10870{
10871}
10872
10873/*!
10874 Constructs a QGraphicsSimpleTextItem, using \a text as the default plain text.
10875
10876 \a parent is passed to QGraphicsItem's constructor.
10877
10878 \sa QGraphicsScene::addItem()
10879*/
10880QGraphicsSimpleTextItem::QGraphicsSimpleTextItem(const QString &text, QGraphicsItem *parent)
10881 : QAbstractGraphicsShapeItem(*new QGraphicsSimpleTextItemPrivate, parent)
10882{
10883 setText(text);
10884}
10885
10886/*!
10887 Destroys the QGraphicsSimpleTextItem.
10888*/
10889QGraphicsSimpleTextItem::~QGraphicsSimpleTextItem()
10890{
10891}
10892
10893/*!
10894 Sets the item's text to \a text. The text will be displayed as
10895 plain text. Newline characters ('\\n') as well as characters of
10896 type QChar::LineSeparator will cause item to break the text into
10897 multiple lines.
10898*/
10899void QGraphicsSimpleTextItem::setText(const QString &text)
10900{
10901 Q_D(QGraphicsSimpleTextItem);
10902 if (d->text == text)
10903 return;
10904 d->text = text;
10905 d->updateBoundingRect();
10906 update();
10907}
10908
10909/*!
10910 Returns the item's text.
10911*/
10912QString QGraphicsSimpleTextItem::text() const
10913{
10914 Q_D(const QGraphicsSimpleTextItem);
10915 return d->text;
10916}
10917
10918/*!
10919 Sets the font that is used to draw the item's text to \a font.
10920*/
10921void QGraphicsSimpleTextItem::setFont(const QFont &font)
10922{
10923 Q_D(QGraphicsSimpleTextItem);
10924 d->font = font;
10925 d->updateBoundingRect();
10926}
10927
10928/*!
10929 Returns the font that is used to draw the item's text.
10930*/
10931QFont QGraphicsSimpleTextItem::font() const
10932{
10933 Q_D(const QGraphicsSimpleTextItem);
10934 return d->font;
10935}
10936
10937/*!
10938 \reimp
10939*/
10940QRectF QGraphicsSimpleTextItem::boundingRect() const
10941{
10942 Q_D(const QGraphicsSimpleTextItem);
10943 return d->boundingRect;
10944}
10945
10946/*!
10947 \reimp
10948*/
10949QPainterPath QGraphicsSimpleTextItem::shape() const
10950{
10951 Q_D(const QGraphicsSimpleTextItem);
10952 QPainterPath path;
10953 path.addRect(rect: d->boundingRect);
10954 return path;
10955}
10956
10957/*!
10958 \reimp
10959*/
10960bool QGraphicsSimpleTextItem::contains(const QPointF &point) const
10961{
10962 Q_D(const QGraphicsSimpleTextItem);
10963 return d->boundingRect.contains(p: point);
10964}
10965
10966/*!
10967 \reimp
10968*/
10969void QGraphicsSimpleTextItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
10970{
10971 Q_UNUSED(widget);
10972 Q_D(QGraphicsSimpleTextItem);
10973
10974 painter->setFont(d->font);
10975
10976 QString tmp = d->text;
10977 tmp.replace(before: QLatin1Char('\n'), after: QChar::LineSeparator);
10978 QStackTextEngine engine(tmp, d->font);
10979 QTextLayout layout(&engine);
10980
10981 QPen p;
10982 p.setBrush(d->brush);
10983 painter->setPen(p);
10984 if (d->pen.style() == Qt::NoPen && d->brush.style() == Qt::SolidPattern) {
10985 painter->setBrush(Qt::NoBrush);
10986 } else {
10987 QTextLayout::FormatRange range;
10988 range.start = 0;
10989 range.length = layout.text().length();
10990 range.format.setTextOutline(d->pen);
10991 layout.setFormats(QVector<QTextLayout::FormatRange>(1, range));
10992 }
10993
10994 setupTextLayout(&layout);
10995 layout.draw(p: painter, pos: QPointF(0, 0));
10996
10997 if (option->state & (QStyle::State_Selected | QStyle::State_HasFocus))
10998 qt_graphicsItem_highlightSelected(item: this, painter, option);
10999}
11000
11001/*!
11002 \reimp
11003*/
11004bool QGraphicsSimpleTextItem::isObscuredBy(const QGraphicsItem *item) const
11005{
11006 return QAbstractGraphicsShapeItem::isObscuredBy(item);
11007}
11008
11009/*!
11010 \reimp
11011*/
11012QPainterPath QGraphicsSimpleTextItem::opaqueArea() const
11013{
11014 return QAbstractGraphicsShapeItem::opaqueArea();
11015}
11016
11017/*!
11018 \reimp
11019*/
11020int QGraphicsSimpleTextItem::type() const
11021{
11022 return Type;
11023}
11024
11025/*!
11026 \internal
11027*/
11028bool QGraphicsSimpleTextItem::supportsExtension(Extension extension) const
11029{
11030 Q_UNUSED(extension);
11031 return false;
11032}
11033
11034/*!
11035 \internal
11036*/
11037void QGraphicsSimpleTextItem::setExtension(Extension extension, const QVariant &variant)
11038{
11039 Q_UNUSED(extension);
11040 Q_UNUSED(variant);
11041}
11042
11043/*!
11044 \internal
11045*/
11046QVariant QGraphicsSimpleTextItem::extension(const QVariant &variant) const
11047{
11048 Q_UNUSED(variant);
11049 return QVariant();
11050}
11051
11052/*!
11053 \class QGraphicsItemGroup
11054 \brief The QGraphicsItemGroup class provides a container that treats
11055 a group of items as a single item.
11056 \since 4.2
11057 \ingroup graphicsview-api
11058 \inmodule QtWidgets
11059
11060 A QGraphicsItemGroup is a special type of compound item that
11061 treats itself and all its children as one item (i.e., all events
11062 and geometries for all children are merged together). It's common
11063 to use item groups in presentation tools, when the user wants to
11064 group several smaller items into one big item in order to simplify
11065 moving and copying of items.
11066
11067 If all you want is to store items inside other items, you can use
11068 any QGraphicsItem directly by passing a suitable parent to
11069 setParentItem().
11070
11071 The boundingRect() function of QGraphicsItemGroup returns the
11072 bounding rectangle of all items in the item group.
11073 QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on
11074 its children (i.e., with respect to the geometry of the group
11075 item, the children are treated as if they were transformable).
11076
11077 There are two ways to construct an item group. The easiest and
11078 most common approach is to pass a list of items (e.g., all
11079 selected items) to QGraphicsScene::createItemGroup(), which
11080 returns a new QGraphicsItemGroup item. The other approach is to
11081 manually construct a QGraphicsItemGroup item, add it to the scene
11082 calling QGraphicsScene::addItem(), and then add items to the group
11083 manually, one at a time by calling addToGroup(). To dismantle
11084 ("ungroup") an item group, you can either call
11085 QGraphicsScene::destroyItemGroup(), or you can manually remove all
11086 items from the group by calling removeFromGroup().
11087
11088 \snippet code/src_gui_graphicsview_qgraphicsitem.cpp 17
11089
11090 The operation of adding and removing items preserves the items'
11091 scene-relative position and transformation, as opposed to calling
11092 setParentItem(), where only the child item's parent-relative
11093 position and transformation are kept.
11094
11095 The addtoGroup() function reparents the target item to this item
11096 group, keeping the item's position and transformation intact
11097 relative to the scene. Visually, this means that items added via
11098 addToGroup() will remain completely unchanged as a result of this
11099 operation, regardless of the item or the group's current position
11100 or transformation; although the item's position and matrix are
11101 likely to change.
11102
11103 The removeFromGroup() function has similar semantics to
11104 setParentItem(); it reparents the item to the parent item of the
11105 item group. As with addToGroup(), the item's scene-relative
11106 position and transformation remain intact.
11107
11108 \sa QGraphicsItem, {Graphics View Framework}
11109*/
11110
11111class QGraphicsItemGroupPrivate : public QGraphicsItemPrivate
11112{
11113public:
11114 QRectF itemsBoundingRect;
11115};
11116
11117/*!
11118 Constructs a QGraphicsItemGroup. \a parent is passed to QGraphicsItem's
11119 constructor.
11120
11121 \sa QGraphicsScene::addItem()
11122*/
11123QGraphicsItemGroup::QGraphicsItemGroup(QGraphicsItem *parent)
11124 : QGraphicsItem(*new QGraphicsItemGroupPrivate, parent)
11125{
11126 setHandlesChildEvents(true);
11127}
11128
11129/*!
11130 Destroys the QGraphicsItemGroup.
11131*/
11132QGraphicsItemGroup::~QGraphicsItemGroup()
11133{
11134}
11135
11136/*!
11137 Adds the given \a item and item's child items to this item group.
11138 The item and child items will be reparented to this group, but its
11139 position and transformation relative to the scene will stay intact.
11140
11141 \sa removeFromGroup(), QGraphicsScene::createItemGroup()
11142*/
11143void QGraphicsItemGroup::addToGroup(QGraphicsItem *item)
11144{
11145 Q_D(QGraphicsItemGroup);
11146 if (!item) {
11147 qWarning(msg: "QGraphicsItemGroup::addToGroup: cannot add null item");
11148 return;
11149 }
11150 if (item == this) {
11151 qWarning(msg: "QGraphicsItemGroup::addToGroup: cannot add a group to itself");
11152 return;
11153 }
11154
11155 // COMBINE
11156 bool ok;
11157 QTransform itemTransform = item->itemTransform(other: this, ok: &ok);
11158
11159 if (!ok) {
11160 qWarning(msg: "QGraphicsItemGroup::addToGroup: could not find a valid transformation from item to group coordinates");
11161 return;
11162 }
11163
11164 QTransform newItemTransform(itemTransform);
11165 item->setPos(mapFromItem(item, ax: 0, ay: 0));
11166 item->setParentItem(this);
11167
11168 // removing position from translation component of the new transform
11169 if (!item->pos().isNull())
11170 newItemTransform *= QTransform::fromTranslate(dx: -item->x(), dy: -item->y());
11171
11172 // removing additional transformations properties applied with itemTransform()
11173 QPointF origin = item->transformOriginPoint();
11174 QMatrix4x4 m;
11175 QList<QGraphicsTransform*> transformList = item->transformations();
11176 for (int i = 0; i < transformList.size(); ++i)
11177 transformList.at(i)->applyTo(matrix: &m);
11178 newItemTransform *= m.toTransform().inverted();
11179 newItemTransform.translate(dx: origin.x(), dy: origin.y());
11180 newItemTransform.rotate(a: -item->rotation());
11181 newItemTransform.scale(sx: 1/item->scale(), sy: 1/item->scale());
11182 newItemTransform.translate(dx: -origin.x(), dy: -origin.y());
11183
11184 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
11185
11186 item->setTransform(matrix: newItemTransform);
11187 item->d_func()->setIsMemberOfGroup(true);
11188 prepareGeometryChange();
11189 d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect());
11190 update();
11191}
11192
11193/*!
11194 Removes the specified \a item from this group. The item will be
11195 reparented to this group's parent item, or to 0 if this group has
11196 no parent. Its position and transformation relative to the scene
11197 will stay intact.
11198
11199 \sa addToGroup(), QGraphicsScene::destroyItemGroup()
11200*/
11201void QGraphicsItemGroup::removeFromGroup(QGraphicsItem *item)
11202{
11203 Q_D(QGraphicsItemGroup);
11204 if (!item) {
11205 qWarning(msg: "QGraphicsItemGroup::removeFromGroup: cannot remove null item");
11206 return;
11207 }
11208
11209 QGraphicsItem *newParent = d_ptr->parent;
11210
11211 // COMBINE
11212 bool ok;
11213 QTransform itemTransform;
11214 if (newParent)
11215 itemTransform = item->itemTransform(other: newParent, ok: &ok);
11216 else
11217 itemTransform = item->sceneTransform();
11218
11219 QPointF oldPos = item->mapToItem(item: newParent, ax: 0, ay: 0);
11220 item->setParentItem(newParent);
11221 item->setPos(oldPos);
11222
11223 // removing position from translation component of the new transform
11224 if (!item->pos().isNull())
11225 itemTransform *= QTransform::fromTranslate(dx: -item->x(), dy: -item->y());
11226
11227 // removing additional transformations properties applied
11228 // with itemTransform() or sceneTransform()
11229 QPointF origin = item->transformOriginPoint();
11230 QMatrix4x4 m;
11231 QList<QGraphicsTransform*> transformList = item->transformations();
11232 for (int i = 0; i < transformList.size(); ++i)
11233 transformList.at(i)->applyTo(matrix: &m);
11234 itemTransform *= m.toTransform().inverted();
11235 itemTransform.translate(dx: origin.x(), dy: origin.y());
11236 itemTransform.rotate(a: -item->rotation());
11237 itemTransform.scale(sx: 1 / item->scale(), sy: 1 / item->scale());
11238 itemTransform.translate(dx: -origin.x(), dy: -origin.y());
11239
11240 // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
11241
11242 item->setTransform(matrix: itemTransform);
11243 item->d_func()->setIsMemberOfGroup(item->group() != nullptr);
11244
11245 // ### Quite expensive. But removeFromGroup() isn't called very often.
11246 prepareGeometryChange();
11247 d->itemsBoundingRect = childrenBoundingRect();
11248}
11249
11250/*!
11251 \reimp
11252
11253 Returns the bounding rect of this group item, and all its children.
11254*/
11255QRectF QGraphicsItemGroup::boundingRect() const
11256{
11257 Q_D(const QGraphicsItemGroup);
11258 return d->itemsBoundingRect;
11259}
11260
11261/*!
11262 \reimp
11263*/
11264void QGraphicsItemGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
11265 QWidget *widget)
11266{
11267 Q_UNUSED(widget);
11268 if (option->state & QStyle::State_Selected) {
11269 Q_D(QGraphicsItemGroup);
11270 painter->setBrush(Qt::NoBrush);
11271 painter->drawRect(rect: d->itemsBoundingRect);
11272 }
11273}
11274
11275/*!
11276 \reimp
11277*/
11278bool QGraphicsItemGroup::isObscuredBy(const QGraphicsItem *item) const
11279{
11280 return QGraphicsItem::isObscuredBy(item);
11281}
11282
11283/*!
11284 \reimp
11285*/
11286QPainterPath QGraphicsItemGroup::opaqueArea() const
11287{
11288 return QGraphicsItem::opaqueArea();
11289}
11290
11291/*!
11292 \reimp
11293*/
11294int QGraphicsItemGroup::type() const
11295{
11296 return Type;
11297}
11298
11299#if QT_CONFIG(graphicseffect)
11300QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
11301{
11302 const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
11303 if (!info && deviceCoordinates) {
11304 // Device coordinates without info not yet supported.
11305 qWarning(msg: "QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
11306 return QRectF();
11307 }
11308
11309 QRectF rect = item->boundingRect();
11310 if (!item->d_ptr->children.isEmpty())
11311 rect |= item->childrenBoundingRect();
11312
11313 if (deviceCoordinates) {
11314 Q_ASSERT(info->painter);
11315 rect = info->painter->worldTransform().mapRect(rect);
11316 }
11317
11318 return rect;
11319}
11320
11321void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
11322{
11323 if (!info) {
11324 qWarning(msg: "QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
11325 return;
11326 }
11327
11328 Q_ASSERT(item->d_ptr->scene);
11329 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
11330 if (painter == info->painter) {
11331 scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
11332 info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform,
11333 info->drawItem);
11334 } else {
11335 QTransform effectTransform = info->painter->worldTransform().inverted();
11336 effectTransform *= painter->worldTransform();
11337 scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
11338 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
11339 info->drawItem);
11340 }
11341}
11342
11343// sourceRect must be in the given coordinate system
11344QRectF QGraphicsItemEffectSourcePrivate::paddedEffectRect(Qt::CoordinateSystem system, QGraphicsEffect::PixmapPadMode mode, const QRectF &sourceRect, bool *unpadded) const
11345{
11346 QRectF effectRectF;
11347
11348 if (unpadded)
11349 *unpadded = false;
11350
11351 if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
11352 if (info) {
11353 QRectF deviceRect = system == Qt::DeviceCoordinates ? sourceRect : info->painter->worldTransform().mapRect(sourceRect);
11354 effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect: deviceRect);
11355 if (unpadded)
11356 *unpadded = (effectRectF.size() == sourceRect.size());
11357 if (info && system == Qt::LogicalCoordinates)
11358 effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
11359 } else {
11360 // no choice but to send a logical coordinate bounding rect to boundingRectFor
11361 effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
11362 }
11363 } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
11364 // adjust by 1.5 to account for cosmetic pens
11365 effectRectF = sourceRect.adjusted(xp1: -1.5, yp1: -1.5, xp2: 1.5, yp2: 1.5);
11366 } else {
11367 effectRectF = sourceRect;
11368 if (unpadded)
11369 *unpadded = true;
11370 }
11371
11372 return effectRectF;
11373}
11374
11375QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
11376 QGraphicsEffect::PixmapPadMode mode) const
11377{
11378 const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
11379 if (!info && deviceCoordinates) {
11380 // Device coordinates without info not yet supported.
11381 qWarning(msg: "QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
11382 return QPixmap();
11383 }
11384 if (!item->d_ptr->scene)
11385 return QPixmap();
11386 QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
11387
11388 bool unpadded;
11389 const QRectF sourceRect = boundingRect(system);
11390 QRectF effectRectF = paddedEffectRect(system, mode, sourceRect, unpadded: &unpadded);
11391 QRect effectRect = effectRectF.toAlignedRect();
11392
11393 if (offset)
11394 *offset = effectRect.topLeft();
11395
11396 bool untransformed = !deviceCoordinates
11397 || info->painter->worldTransform().type() <= QTransform::TxTranslate;
11398 if (untransformed && unpadded && isPixmap()) {
11399 if (offset)
11400 *offset = boundingRect(system).topLeft().toPoint();
11401 return static_cast<QGraphicsPixmapItem *>(item)->pixmap();
11402 }
11403
11404 if (effectRect.isEmpty())
11405 return QPixmap();
11406
11407 const auto dpr = info ? info->painter->device()->devicePixelRatioF() : 1.0;
11408 QPixmap pixmap(QRectF(effectRectF.topLeft(), effectRectF.size() * dpr).toAlignedRect().size());
11409 pixmap.setDevicePixelRatio(dpr);
11410 pixmap.fill(fillColor: Qt::transparent);
11411 QPainter pixmapPainter(&pixmap);
11412 pixmapPainter.setRenderHints(hints: info ? info->painter->renderHints() : QPainter::TextAntialiasing);
11413
11414 QTransform effectTransform = QTransform::fromTranslate(dx: -effectRect.x(), dy: -effectRect.y());
11415 if (deviceCoordinates && info->effectTransform)
11416 effectTransform *= *info->effectTransform;
11417
11418 if (!info) {
11419 // Logical coordinates without info.
11420 QTransform sceneTransform = item->sceneTransform();
11421 QTransform newEffectTransform = sceneTransform.inverted();
11422 newEffectTransform *= effectTransform;
11423 scened->draw(item, &pixmapPainter, nullptr, &sceneTransform, nullptr, nullptr, qreal(1.0),
11424 &newEffectTransform, false, true);
11425 } else if (deviceCoordinates) {
11426 // Device coordinates with info.
11427 scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, nullptr,
11428 info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
11429 info->drawItem);
11430 } else {
11431 // Item coordinates with info.
11432 QTransform newEffectTransform = info->transformPtr->inverted();
11433 newEffectTransform *= effectTransform;
11434 scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, nullptr,
11435 info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform,
11436 info->drawItem);
11437 }
11438
11439 pixmapPainter.end();
11440
11441 return pixmap;
11442}
11443#endif // QT_CONFIG(graphicseffect)
11444
11445#ifndef QT_NO_DEBUG_STREAM
11446static void formatGraphicsItemHelper(QDebug debug, const QGraphicsItem *item)
11447{
11448 if (const QGraphicsItem *parent = item->parentItem())
11449 debug << ", parent=" << static_cast<const void *>(parent);
11450 debug << ", pos=";
11451 QtDebugUtils::formatQPoint(debug, point: item->pos());
11452 if (const qreal z = item->zValue())
11453 debug << ", z=" << z;
11454 if (item->flags())
11455 debug << ", flags=" << item->flags();
11456}
11457
11458// FIXME: Qt 6: Make this QDebug operator<<(QDebug debug, const QGraphicsItem *item)
11459QDebug operator<<(QDebug debug, QGraphicsItem *item)
11460{
11461 QDebugStateSaver saver(debug);
11462 debug.nospace();
11463
11464 if (!item) {
11465 debug << "QGraphicsItem(0)";
11466 return debug;
11467 }
11468
11469 if (QGraphicsObject *o = item->toGraphicsObject())
11470 debug << o->metaObject()->className();
11471 else
11472 debug << "QGraphicsItem";
11473 debug << '(' << static_cast<const void *>(item);
11474 if (const QGraphicsProxyWidget *pw = qgraphicsitem_cast<const QGraphicsProxyWidget *>(item)) {
11475 debug << ", widget=";
11476 if (const QWidget *w = pw->widget()) {
11477 debug << w->metaObject()->className() << '(' << static_cast<const void *>(w);
11478 if (!w->objectName().isEmpty())
11479 debug << ", name=" << w->objectName();
11480 debug << ')';
11481 } else {
11482 debug << "QWidget(0)";
11483 }
11484 }
11485 formatGraphicsItemHelper(debug, item);
11486 debug << ')';
11487 return debug;
11488}
11489
11490// FIXME: Qt 6: Make this QDebug operator<<(QDebug debug, const QGraphicsObject *item)
11491QDebug operator<<(QDebug debug, QGraphicsObject *item)
11492{
11493 QDebugStateSaver saver(debug);
11494 debug.nospace();
11495
11496 if (!item) {
11497 debug << "QGraphicsObject(0)";
11498 return debug;
11499 }
11500
11501 debug << item->metaObject()->className() << '(' << static_cast<const void *>(item);
11502 if (!item->objectName().isEmpty())
11503 debug << ", name=" << item->objectName();
11504 formatGraphicsItemHelper(debug, item);
11505 debug << ')';
11506 return debug;
11507}
11508
11509QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemChange change)
11510{
11511 const char *str = "UnknownChange";
11512 switch (change) {
11513 case QGraphicsItem::ItemChildAddedChange:
11514 str = "ItemChildAddedChange";
11515 break;
11516 case QGraphicsItem::ItemChildRemovedChange:
11517 str = "ItemChildRemovedChange";
11518 break;
11519 case QGraphicsItem::ItemCursorChange:
11520 str = "ItemCursorChange";
11521 break;
11522 case QGraphicsItem::ItemCursorHasChanged:
11523 str = "ItemCursorHasChanged";
11524 break;
11525 case QGraphicsItem::ItemEnabledChange:
11526 str = "ItemEnabledChange";
11527 break;
11528 case QGraphicsItem::ItemEnabledHasChanged:
11529 str = "ItemEnabledHasChanged";
11530 break;
11531 case QGraphicsItem::ItemFlagsChange:
11532 str = "ItemFlagsChange";
11533 break;
11534 case QGraphicsItem::ItemFlagsHaveChanged:
11535 str = "ItemFlagsHaveChanged";
11536 break;
11537#if QT_DEPRECATED_SINCE(5, 14)
11538QT_WARNING_PUSH
11539QT_WARNING_DISABLE_DEPRECATED
11540 case QGraphicsItem::ItemMatrixChange:
11541 str = "ItemMatrixChange";
11542 break;
11543QT_WARNING_POP
11544#endif
11545 case QGraphicsItem::ItemParentChange:
11546 str = "ItemParentChange";
11547 break;
11548 case QGraphicsItem::ItemParentHasChanged:
11549 str = "ItemParentHasChanged";
11550 break;
11551 case QGraphicsItem::ItemPositionChange:
11552 str = "ItemPositionChange";
11553 break;
11554 case QGraphicsItem::ItemPositionHasChanged:
11555 str = "ItemPositionHasChanged";
11556 break;
11557 case QGraphicsItem::ItemSceneChange:
11558 str = "ItemSceneChange";
11559 break;
11560 case QGraphicsItem::ItemSceneHasChanged:
11561 str = "ItemSceneHasChanged";
11562 break;
11563 case QGraphicsItem::ItemSelectedChange:
11564 str = "ItemSelectedChange";
11565 break;
11566 case QGraphicsItem::ItemSelectedHasChanged:
11567 str = "ItemSelectedHasChanged";
11568 break;
11569 case QGraphicsItem::ItemToolTipChange:
11570 str = "ItemToolTipChange";
11571 break;
11572 case QGraphicsItem::ItemToolTipHasChanged:
11573 str = "ItemToolTipHasChanged";
11574 break;
11575 case QGraphicsItem::ItemTransformChange:
11576 str = "ItemTransformChange";
11577 break;
11578 case QGraphicsItem::ItemTransformHasChanged:
11579 str = "ItemTransformHasChanged";
11580 break;
11581 case QGraphicsItem::ItemVisibleChange:
11582 str = "ItemVisibleChange";
11583 break;
11584 case QGraphicsItem::ItemVisibleHasChanged:
11585 str = "ItemVisibleHasChanged";
11586 break;
11587 case QGraphicsItem::ItemZValueChange:
11588 str = "ItemZValueChange";
11589 break;
11590 case QGraphicsItem::ItemZValueHasChanged:
11591 str = "ItemZValueHasChanged";
11592 break;
11593 case QGraphicsItem::ItemOpacityChange:
11594 str = "ItemOpacityChange";
11595 break;
11596 case QGraphicsItem::ItemOpacityHasChanged:
11597 str = "ItemOpacityHasChanged";
11598 break;
11599 case QGraphicsItem::ItemScenePositionHasChanged:
11600 str = "ItemScenePositionHasChanged";
11601 break;
11602 case QGraphicsItem::ItemRotationChange:
11603 str = "ItemRotationChange";
11604 break;
11605 case QGraphicsItem::ItemRotationHasChanged:
11606 str = "ItemRotationHasChanged";
11607 break;
11608 case QGraphicsItem::ItemScaleChange:
11609 str = "ItemScaleChange";
11610 break;
11611 case QGraphicsItem::ItemScaleHasChanged:
11612 str = "ItemScaleHasChanged";
11613 break;
11614 case QGraphicsItem::ItemTransformOriginPointChange:
11615 str = "ItemTransformOriginPointChange";
11616 break;
11617 case QGraphicsItem::ItemTransformOriginPointHasChanged:
11618 str = "ItemTransformOriginPointHasChanged";
11619 break;
11620 }
11621 debug << str;
11622 return debug;
11623}
11624
11625QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlag flag)
11626{
11627 const char *str = "UnknownFlag";
11628 switch (flag) {
11629 case QGraphicsItem::ItemIsMovable:
11630 str = "ItemIsMovable";
11631 break;
11632 case QGraphicsItem::ItemIsSelectable:
11633 str = "ItemIsSelectable";
11634 break;
11635 case QGraphicsItem::ItemIsFocusable:
11636 str = "ItemIsFocusable";
11637 break;
11638 case QGraphicsItem::ItemClipsToShape:
11639 str = "ItemClipsToShape";
11640 break;
11641 case QGraphicsItem::ItemClipsChildrenToShape:
11642 str = "ItemClipsChildrenToShape";
11643 break;
11644 case QGraphicsItem::ItemIgnoresTransformations:
11645 str = "ItemIgnoresTransformations";
11646 break;
11647 case QGraphicsItem::ItemIgnoresParentOpacity:
11648 str = "ItemIgnoresParentOpacity";
11649 break;
11650 case QGraphicsItem::ItemDoesntPropagateOpacityToChildren:
11651 str = "ItemDoesntPropagateOpacityToChildren";
11652 break;
11653 case QGraphicsItem::ItemStacksBehindParent:
11654 str = "ItemStacksBehindParent";
11655 break;
11656 case QGraphicsItem::ItemUsesExtendedStyleOption:
11657 str = "ItemUsesExtendedStyleOption";
11658 break;
11659 case QGraphicsItem::ItemHasNoContents:
11660 str = "ItemHasNoContents";
11661 break;
11662 case QGraphicsItem::ItemSendsGeometryChanges:
11663 str = "ItemSendsGeometryChanges";
11664 break;
11665 case QGraphicsItem::ItemAcceptsInputMethod:
11666 str = "ItemAcceptsInputMethod";
11667 break;
11668 case QGraphicsItem::ItemNegativeZStacksBehindParent:
11669 str = "ItemNegativeZStacksBehindParent";
11670 break;
11671 case QGraphicsItem::ItemIsPanel:
11672 str = "ItemIsPanel";
11673 break;
11674 case QGraphicsItem::ItemIsFocusScope:
11675 str = "ItemIsFocusScope";
11676 break;
11677 case QGraphicsItem::ItemSendsScenePositionChanges:
11678 str = "ItemSendsScenePositionChanges";
11679 break;
11680 case QGraphicsItem::ItemStopsClickFocusPropagation:
11681 str = "ItemStopsClickFocusPropagation";
11682 break;
11683 case QGraphicsItem::ItemStopsFocusHandling:
11684 str = "ItemStopsFocusHandling";
11685 break;
11686 case QGraphicsItem::ItemContainsChildrenInShape:
11687 str = "ItemContainsChildrenInShape";
11688 break;
11689 }
11690 debug << str;
11691 return debug;
11692}
11693
11694QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
11695{
11696 debug << '(';
11697 bool f = false;
11698 for (int i = 0; i < 17; ++i) {
11699 if (flags & (1 << i)) {
11700 if (f)
11701 debug << '|';
11702 f = true;
11703 debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i)));
11704 }
11705 }
11706 debug << ')';
11707 return debug;
11708}
11709
11710#endif
11711
11712QT_END_NAMESPACE
11713
11714#include "moc_qgraphicsitem.cpp"
11715

source code of qtbase/src/widgets/graphicsview/qgraphicsitem.cpp