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

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