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#include "qglobal.h"
5
6#include "qgraphicswidget.h"
7#include "qgraphicswidget_p.h"
8#include "qgraphicslayout.h"
9#include "qgraphicslayout_p.h"
10#include "qgraphicsscene.h"
11#include "qgraphicssceneevent.h"
12
13#ifndef QT_NO_ACTION
14#include <private/qaction_p.h>
15#endif
16#include <private/qapplication_p.h>
17#include <private/qgraphicsscene_p.h>
18#ifndef QT_NO_SHORTCUT
19#include <private/qshortcutmap_p.h>
20#endif
21#include <QtCore/qmutex.h>
22#include <QtCore/QScopeGuard>
23#include <QtWidgets/qapplication.h>
24#include <QtWidgets/qgraphicsview.h>
25#include <QtWidgets/qgraphicsproxywidget.h>
26#include <QtGui/qpalette.h>
27#include <QtGui/qpainterpath.h>
28#include <QtWidgets/qstyleoption.h>
29
30#include <qdebug.h>
31
32QT_BEGIN_NAMESPACE
33
34using namespace Qt::StringLiterals;
35
36/*!
37 \class QGraphicsWidget
38 \brief The QGraphicsWidget class is the base class for all widget
39 items in a QGraphicsScene.
40 \since 4.4
41 \ingroup graphicsview-api
42 \inmodule QtWidgets
43
44 QGraphicsWidget is an extended base item that provides extra functionality
45 over QGraphicsItem. It is similar to QWidget in many ways:
46
47 \list
48 \li Provides a \l palette, a \l font and a \l style().
49 \li Has a defined geometry().
50 \li Supports layouts with setLayout() and layout().
51 \li Supports shortcuts and actions with grabShortcut() and insertAction()
52 \endlist
53
54 Unlike QGraphicsItem, QGraphicsWidget is not an abstract class; you can
55 create instances of a QGraphicsWidget without having to subclass it.
56 This approach is useful for widgets that only serve the purpose of
57 organizing child widgets into a layout.
58
59 QGraphicsWidget can be used as a base item for your own custom item if
60 you require advanced input focus handling, e.g., tab focus and activation, or
61 layouts.
62
63 Since QGraphicsWidget resembles QWidget and has similar API, it is
64 easier to port a widget from QWidget to QGraphicsWidget, instead of
65 QGraphicsItem.
66
67 \note QWidget-based widgets can be directly embedded into a
68 QGraphicsScene using QGraphicsProxyWidget.
69
70 Noticeable differences between QGraphicsWidget and QWidget are:
71
72 \table
73 \header \li QGraphicsWidget
74 \li QWidget
75 \row \li Coordinates and geometry are defined with qreals (doubles or
76 floats, depending on the platform).
77 \li QWidget uses integer geometry (QPoint, QRect).
78 \row \li The widget is already visible by default; you do not have to
79 call show() to display the widget.
80 \li QWidget is hidden by default until you call show().
81 \row \li A subset of widget attributes are supported.
82 \li All widget attributes are supported.
83 \row \li A top-level item's style defaults to QGraphicsScene::style
84 \li A top-level widget's style defaults to QApplication::style
85 \row \li Graphics View provides a custom drag and drop framework, different
86 from QWidget.
87 \li Standard drag and drop framework.
88 \row \li Widget items do not support modality.
89 \li Full modality support.
90 \endtable
91
92 QGraphicsWidget supports a subset of Qt's widget attributes,
93 (Qt::WidgetAttribute), as shown in the table below. Any attributes not
94 listed in this table are unsupported, or otherwise unused.
95
96 \table
97 \header \li Widget Attribute \li Usage
98 \row \li Qt::WA_SetLayoutDirection
99 \li Set by setLayoutDirection(), cleared by
100 unsetLayoutDirection(). You can test this attribute to
101 check if the widget has been explicitly assigned a
102 \l{QGraphicsWidget::layoutDirection()}
103 {layoutDirection}. If the attribute is not set, the
104 \l{QGraphicsWidget::layoutDirection()}
105 {layoutDirection()} is inherited.
106 \row \li Qt::WA_RightToLeft
107 \li Toggled by setLayoutDirection(). Inherited from the
108 parent/scene. If set, the widget's layout will order
109 horizontally arranged widgets from right to left.
110 \row \li Qt::WA_SetStyle
111 \li Set and cleared by setStyle(). If this attribute is
112 set, the widget has been explicitly assigned a style.
113 If it is unset, the widget will use the scene's or the
114 application's style.
115 \row \li Qt::WA_Resized
116 \li Set by setGeometry() and resize().
117 \row \li Qt::WA_SetPalette
118 \li Set by setPalette().
119 \row \li Qt::WA_SetFont
120 \li Set by setFont().
121 \row \li Qt::WA_WindowPropagation
122 \li Enables propagation to window widgets.
123 \endtable
124
125 Although QGraphicsWidget inherits from both QObject and QGraphicsItem,
126 you should use the functions provided by QGraphicsItem, \e not QObject, to
127 manage the relationships between parent and child items. These functions
128 control the stacking order of items as well as their ownership.
129
130 \note The QObject::parent() should always return \nullptr for QGraphicsWidgets,
131 but this policy is not strictly defined.
132
133 \sa QGraphicsProxyWidget, QGraphicsItem, {Widgets and Layouts}
134*/
135
136/*!
137 Constructs a QGraphicsWidget instance. The optional \a parent argument is
138 passed to QGraphicsItem's constructor. The optional \a wFlags argument
139 specifies the widget's window flags (e.g., whether the widget should be a
140 window, a tool, a popup, etc).
141*/
142QGraphicsWidget::QGraphicsWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
143 : QGraphicsObject(*new QGraphicsWidgetPrivate, nullptr), QGraphicsLayoutItem(nullptr, false)
144{
145 Q_D(QGraphicsWidget);
146 d->init(parentItem: parent, wFlags);
147}
148
149/*!
150 \internal
151
152 Constructs a new QGraphicsWidget, using \a dd as parent.
153*/
154QGraphicsWidget::QGraphicsWidget(QGraphicsWidgetPrivate &dd, QGraphicsItem *parent, Qt::WindowFlags wFlags)
155 : QGraphicsObject(dd, nullptr), QGraphicsLayoutItem(nullptr, false)
156{
157 Q_D(QGraphicsWidget);
158 d->init(parentItem: parent, wFlags);
159}
160
161/*
162 \internal
163 \class QGraphicsWidgetStyles
164
165 We use this thread-safe class to maintain a hash of styles for widgets
166 styles. Note that QApplication::style() itself isn't thread-safe, QStyle
167 isn't thread-safe, and we don't have a thread-safe factory for creating
168 the default style, nor cloning a style.
169*/
170class QGraphicsWidgetStyles
171{
172public:
173 QStyle *styleForWidget(const QGraphicsWidget *widget) const
174 {
175 QMutexLocker locker(&mutex);
176 return styles.value(key: widget, defaultValue: 0);
177 }
178
179 void setStyleForWidget(QGraphicsWidget *widget, QStyle *style)
180 {
181 QMutexLocker locker(&mutex);
182 if (style)
183 styles[widget] = style;
184 else
185 styles.remove(key: widget);
186 }
187
188private:
189 QHash<const QGraphicsWidget *, QStyle *> styles;
190 mutable QMutex mutex;
191};
192Q_GLOBAL_STATIC(QGraphicsWidgetStyles, widgetStyles)
193
194/*!
195 Destroys the QGraphicsWidget instance.
196*/
197QGraphicsWidget::~QGraphicsWidget()
198{
199 Q_D(QGraphicsWidget);
200#ifndef QT_NO_ACTION
201 // Remove all actions from this widget
202 for (auto action : std::as_const(t&: d->actions)) {
203 QActionPrivate *apriv = action->d_func();
204 apriv->associatedObjects.removeAll(t: this);
205 }
206 d->actions.clear();
207#endif
208
209 if (QGraphicsScene *scn = scene()) {
210 QGraphicsScenePrivate *sceneD = scn->d_func();
211 if (sceneD->tabFocusFirst == this)
212 sceneD->tabFocusFirst = (d->focusNext == this ? nullptr : d->focusNext);
213 }
214 d->focusPrev->d_func()->focusNext = d->focusNext;
215 d->focusNext->d_func()->focusPrev = d->focusPrev;
216
217 // Play it really safe
218 d->focusNext = this;
219 d->focusPrev = this;
220
221 clearFocus();
222
223 //we check if we have a layout previously
224 if (d->layout) {
225 QGraphicsLayout *temp = d->layout;
226 const auto items = childItems();
227 for (QGraphicsItem *item : items) {
228 // In case of a custom layout which doesn't remove and delete items, we ensure that
229 // the parent layout item does not point to the deleted layout. This code is here to
230 // avoid regression from 4.4 to 4.5, because according to 4.5 docs it is not really needed.
231 if (item->isWidget()) {
232 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
233 if (widget->parentLayoutItem() == d->layout)
234 widget->setParentLayoutItem(nullptr);
235 }
236 }
237 d->layout = nullptr;
238 delete temp;
239 }
240
241 // Remove this graphics widget from widgetStyles
242 widgetStyles()->setStyleForWidget(widget: this, style: nullptr);
243
244 // Unset the parent here, when we're still a QGraphicsWidget.
245 // It is otherwise done in ~QGraphicsItem() where we'd be
246 // calling QGraphicsWidget members on an ex-QGraphicsWidget object
247 setParentItem(nullptr);
248}
249
250/*!
251 \property QGraphicsWidget::size
252 \brief the size of the widget
253
254 Calling resize() resizes the widget to a \a size bounded by minimumSize()
255 and maximumSize(). This property only affects the widget's width and
256 height (e.g., its right and bottom edges); the widget's position and
257 top-left corner remains unaffected.
258
259 Resizing a widget triggers the widget to immediately receive a
260 \l{QEvent::GraphicsSceneResize}{GraphicsSceneResize} event with the
261 widget's old and new size. If the widget has a layout assigned when this
262 event arrives, the layout will be activated and it will automatically
263 update any child widgets's geometry.
264
265 This property does not affect any layout of the parent widget. If the
266 widget itself is managed by a parent layout; e.g., it has a parent widget
267 with a layout assigned, that layout will not activate.
268
269 By default, this property contains a size with zero width and height.
270
271 \sa setGeometry(), QGraphicsSceneResizeEvent, QGraphicsLayout
272*/
273QSizeF QGraphicsWidget::size() const
274{
275 return QGraphicsLayoutItem::geometry().size();
276}
277
278void QGraphicsWidget::resize(const QSizeF &size)
279{
280 setGeometry(QRectF(pos(), size));
281}
282
283/*!
284 \fn void QGraphicsWidget::resize(qreal w, qreal h)
285 \overload
286
287 Constructs a resize with the given \c width (\a w) and \c height (\a h).
288 This convenience function is equivalent to calling resize(QSizeF(w, h)).
289
290 \sa setGeometry(), setTransform()
291*/
292
293/*!
294 \property QGraphicsWidget::sizePolicy
295 \brief the size policy for the widget
296 \sa sizePolicy(), setSizePolicy(), QWidget::sizePolicy()
297*/
298
299/*!
300 \fn QGraphicsWidget::geometryChanged()
301
302 This signal gets emitted whenever the geometry is changed in setGeometry().
303*/
304
305/*!
306 \property QGraphicsWidget::geometry
307 \brief the geometry of the widget
308
309 Sets the item's geometry to \a rect. The item's position and size are
310 modified as a result of calling this function. The item is first moved,
311 then resized.
312
313 A side effect of calling this function is that the widget will receive
314 a move event and a resize event. Also, if the widget has a layout
315 assigned, the layout will activate.
316
317 \sa geometry(), resize()
318*/
319void QGraphicsWidget::setGeometry(const QRectF &rect)
320{
321 QGraphicsWidgetPrivate *wd = QGraphicsWidget::d_func();
322 // Package relayout of children in a scope guard so we can just return early
323 // when this widget's geometry is sorted out.
324 const auto relayoutChildren = qScopeGuard(f: [this, wd]() {
325 if (QGraphicsLayout::instantInvalidatePropagation()) {
326 if (QGraphicsLayout *lay = wd->layout) {
327 if (!lay->isActivated()) {
328 QEvent layoutRequest(QEvent::LayoutRequest);
329 QCoreApplication::sendEvent(receiver: this, event: &layoutRequest);
330 }
331 }
332 }
333 });
334
335 QGraphicsLayoutItemPrivate *d = QGraphicsLayoutItem::d_ptr.data();
336 QRectF newGeom;
337 QPointF oldPos = d->geom.topLeft();
338 if (!wd->inSetPos) {
339 setAttribute(attribute: Qt::WA_Resized);
340 newGeom = rect;
341 newGeom.setSize(rect.size().expandedTo(otherSize: effectiveSizeHint(which: Qt::MinimumSize))
342 .boundedTo(otherSize: effectiveSizeHint(which: Qt::MaximumSize)));
343
344 if (newGeom == d->geom)
345 return;
346
347 // setPos triggers ItemPositionChange, which can adjust position
348 wd->inSetGeometry = 1;
349 setPos(newGeom.topLeft());
350 wd->inSetGeometry = 0;
351 newGeom.moveTopLeft(p: pos());
352
353 if (newGeom == d->geom)
354 return;
355
356 // Update and prepare to change the geometry (remove from index) if
357 // the size has changed.
358 if (wd->scene && rect.topLeft() == d->geom.topLeft())
359 prepareGeometryChange();
360 }
361
362 // Update the layout item geometry
363 if (oldPos != pos()) {
364 // Send move event.
365 QGraphicsSceneMoveEvent event;
366 event.setOldPos(oldPos);
367 event.setNewPos(pos());
368 QCoreApplication::sendEvent(receiver: this, event: &event);
369 if (wd->inSetPos) {
370 // Set the new position:
371 d->geom.moveTopLeft(p: pos());
372 emit geometryChanged();
373 return;
374 }
375 }
376
377 QSizeF oldSize = size();
378 QGraphicsLayoutItem::setGeometry(newGeom);
379 // Send resize event, if appropriate:
380 if (newGeom.size() != oldSize) {
381 if (oldSize.width() != newGeom.size().width())
382 emit widthChanged();
383 if (oldSize.height() != newGeom.size().height())
384 emit heightChanged();
385 QGraphicsLayout *lay = wd->layout;
386 if (!QGraphicsLayout::instantInvalidatePropagation() || !lay || lay->isActivated()) {
387 QGraphicsSceneResizeEvent re;
388 re.setOldSize(oldSize);
389 re.setNewSize(newGeom.size());
390 QCoreApplication::sendEvent(receiver: this, event: &re);
391 }
392 }
393
394 emit geometryChanged();
395}
396
397/*!
398 \fn QRectF QGraphicsWidget::rect() const
399
400 Returns the item's local rect as a QRectF. This function is equivalent
401 to QRectF(QPointF(), size()).
402
403 \sa setGeometry(), resize()
404*/
405
406/*!
407 \fn void QGraphicsWidget::setGeometry(qreal x, qreal y, qreal w, qreal h)
408
409 This convenience function is equivalent to calling setGeometry(QRectF(
410 \a x, \a y, \a w, \a h)).
411
412 \sa geometry(), resize()
413*/
414
415/*!
416 \property QGraphicsWidget::minimumSize
417 \brief the minimum size of the widget
418
419 \sa setMinimumSize(), minimumSize(), preferredSize, maximumSize
420*/
421
422/*!
423 \property QGraphicsWidget::preferredSize
424 \brief the preferred size of the widget
425
426 \sa setPreferredSize(), preferredSize(), minimumSize, maximumSize
427*/
428
429/*!
430 \property QGraphicsWidget::maximumSize
431 \brief the maximum size of the widget
432
433 \sa setMaximumSize(), maximumSize(), minimumSize, preferredSize
434*/
435
436/*!
437 \since 5.14
438
439 Sets the widget's contents margins to \a margins.
440
441 Contents margins are used by the assigned layout to define the placement
442 of subwidgets and layouts. Margins are particularly useful for widgets
443 that constrain subwidgets to only a section of its own geometry. For
444 example, a group box with a layout will place subwidgets inside its frame,
445 but below the title.
446
447 Changing a widget's contents margins will always trigger an update(), and
448 any assigned layout will be activated automatically. The widget will then
449 receive a \l{QEvent::ContentsRectChange}{ContentsRectChange} event.
450
451 \sa getContentsMargins(), setGeometry()
452*/
453void QGraphicsWidget::setContentsMargins(QMarginsF margins)
454{
455 Q_D(QGraphicsWidget);
456
457 if (!d->margins && margins.isNull())
458 return;
459 d->ensureMargins();
460 if (*d->margins == margins)
461 return;
462
463 *d->margins = margins;
464
465 if (QGraphicsLayout *l = d->layout)
466 l->invalidate();
467 else
468 updateGeometry();
469
470 QEvent e(QEvent::ContentsRectChange);
471 QCoreApplication::sendEvent(receiver: this, event: &e);
472}
473
474/*!
475 \overload
476
477 Sets the widget's contents margins to \a left, \a top, \a right and \a
478 bottom.
479*/
480void QGraphicsWidget::setContentsMargins(qreal left, qreal top, qreal right, qreal bottom)
481{
482 setContentsMargins({left, top, right, bottom});
483}
484
485/*!
486 Gets the widget's contents margins. The margins are stored in \a left, \a
487 top, \a right and \a bottom, as pointers to qreals. Each argument can
488 be \e {omitted} by passing \nullptr.
489
490 \sa setContentsMargins()
491*/
492void QGraphicsWidget::getContentsMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
493{
494 Q_D(const QGraphicsWidget);
495 if (left || top || right || bottom)
496 d->ensureMargins();
497 if (left)
498 *left = d->margins->left();
499 if (top)
500 *top = d->margins->top();
501 if (right)
502 *right = d->margins->right();
503 if (bottom)
504 *bottom = d->margins->bottom();
505}
506
507/*!
508 \since 5.14
509 Sets the widget's window frame margins to \a margins.
510 The default frame margins are provided by the style, and they
511 depend on the current window flags.
512
513 If you would like to draw your own window decoration, you can set your
514 own frame margins to override the default margins.
515
516 \sa unsetWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
517*/
518void QGraphicsWidget::setWindowFrameMargins(QMarginsF margins)
519{
520 Q_D(QGraphicsWidget);
521
522 if (!d->windowFrameMargins && margins.isNull())
523 return;
524 d->ensureWindowFrameMargins();
525 const bool unchanged = *d->windowFrameMargins == margins;
526 if (d->setWindowFrameMargins && unchanged)
527 return;
528 if (!unchanged)
529 prepareGeometryChange();
530 *d->windowFrameMargins = margins;
531 d->setWindowFrameMargins = true;
532}
533
534/*!
535 \overload
536 Sets the widget's window frame margins to \a left, \a top, \a right and
537 \a bottom.
538*/
539void QGraphicsWidget::setWindowFrameMargins(qreal left, qreal top, qreal right, qreal bottom)
540{
541 setWindowFrameMargins({left, top, right, bottom});
542}
543
544/*!
545 Gets the widget's window frame margins. The margins are stored in \a left,
546 \a top, \a right and \a bottom as pointers to qreals. Each argument can
547 be \e {omitted} by passing \nullptr.
548
549 \sa setWindowFrameMargins(), windowFrameRect()
550*/
551void QGraphicsWidget::getWindowFrameMargins(qreal *left, qreal *top, qreal *right, qreal *bottom) const
552{
553 Q_D(const QGraphicsWidget);
554 if (left || top || right || bottom)
555 d->ensureWindowFrameMargins();
556 if (left)
557 *left = d->windowFrameMargins->left();
558 if (top)
559 *top = d->windowFrameMargins->top();
560 if (right)
561 *right = d->windowFrameMargins->right();
562 if (bottom)
563 *bottom = d->windowFrameMargins->bottom();
564}
565
566/*!
567 Resets the window frame margins to the default value, provided by the style.
568
569 \sa setWindowFrameMargins(), getWindowFrameMargins(), windowFrameRect()
570*/
571void QGraphicsWidget::unsetWindowFrameMargins()
572{
573 Q_D(QGraphicsWidget);
574 if ((d->windowFlags & Qt::Window) && (d->windowFlags & Qt::WindowType_Mask) != Qt::Popup &&
575 (d->windowFlags & Qt::WindowType_Mask) != Qt::ToolTip && !(d->windowFlags & Qt::FramelessWindowHint)) {
576 QStyleOptionTitleBar bar;
577 d->initStyleOptionTitleBar(option: &bar);
578 QStyle *style = this->style();
579 const qreal margin = style->pixelMetric(metric: QStyle::PM_MdiSubWindowFrameWidth, option: &bar);
580 qreal titleBarHeight = d->titleBarHeight(options: bar);
581 setWindowFrameMargins(left: margin, top: titleBarHeight, right: margin, bottom: margin);
582 } else {
583 setWindowFrameMargins(left: 0, top: 0, right: 0, bottom: 0);
584 }
585 d->setWindowFrameMargins = false;
586}
587
588/*!
589 Returns the widget's geometry in parent coordinates including any window
590 frame.
591
592 \sa windowFrameRect(), getWindowFrameMargins(), setWindowFrameMargins()
593*/
594QRectF QGraphicsWidget::windowFrameGeometry() const
595{
596 Q_D(const QGraphicsWidget);
597 return d->windowFrameMargins
598 ? geometry().adjusted(xp1: -d->windowFrameMargins->left(), yp1: -d->windowFrameMargins->top(),
599 xp2: d->windowFrameMargins->right(), yp2: d->windowFrameMargins->bottom())
600 : geometry();
601}
602
603/*!
604 Returns the widget's local rect including any window frame.
605
606 \sa windowFrameGeometry(), getWindowFrameMargins(), setWindowFrameMargins()
607*/
608QRectF QGraphicsWidget::windowFrameRect() const
609{
610 Q_D(const QGraphicsWidget);
611 return d->windowFrameMargins
612 ? rect().adjusted(xp1: -d->windowFrameMargins->left(), yp1: -d->windowFrameMargins->top(),
613 xp2: d->windowFrameMargins->right(), yp2: d->windowFrameMargins->bottom())
614 : rect();
615}
616
617/*!
618 Populates a style option object for this widget based on its current
619 state, and stores the output in \a option. The default implementation
620 populates \a option with the following properties.
621
622 \table
623 \header
624 \li Style Option Property
625 \li Value
626 \row
627 \li state & QStyle::State_Enabled
628 \li Corresponds to QGraphicsItem::isEnabled().
629 \row
630 \li state & QStyle::State_HasFocus
631 \li Corresponds to QGraphicsItem::hasFocus().
632 \row
633 \li state & QStyle::State_MouseOver
634 \li Corresponds to QGraphicsItem::isUnderMouse().
635 \row
636 \li direction
637 \li Corresponds to QGraphicsWidget::layoutDirection().
638 \row
639 \li rect
640 \li Corresponds to QGraphicsWidget::rect().toRect().
641 \row
642 \li palette
643 \li Corresponds to QGraphicsWidget::palette().
644 \row
645 \li fontMetrics
646 \li Corresponds to QFontMetrics(QGraphicsWidget::font()).
647 \endtable
648
649 Subclasses of QGraphicsWidget should call the base implementation, and
650 then test the type of \a option using qstyleoption_cast<>() or test
651 QStyleOption::Type before storing widget-specific options.
652
653 For example:
654
655 \snippet code/src_gui_graphicsview_qgraphicswidget.cpp 0
656
657 \sa QStyleOption::initFrom()
658*/
659void QGraphicsWidget::initStyleOption(QStyleOption *option) const
660{
661 Q_ASSERT(option);
662
663 option->state = QStyle::State_None;
664 if (isEnabled())
665 option->state |= QStyle::State_Enabled;
666 if (hasFocus())
667 option->state |= QStyle::State_HasFocus;
668 // if (window->testAttribute(Qt::WA_KeyboardFocusChange)) // ### Window
669 // option->state |= QStyle::State_KeyboardFocusChange;
670 if (isUnderMouse())
671 option->state |= QStyle::State_MouseOver;
672 if (QGraphicsWidget *w = window()) {
673 if (w->isActiveWindow())
674 option->state |= QStyle::State_Active;
675 }
676 if (isWindow())
677 option->state |= QStyle::State_Window;
678 /*
679 ###
680#ifdef QT_KEYPAD_NAVIGATION
681 if (widget->hasEditFocus())
682 state |= QStyle::State_HasEditFocus;
683#endif
684 */
685 option->direction = layoutDirection();
686 option->rect = rect().toRect(); // ### truncation!
687 option->palette = palette();
688 if (!isEnabled()) {
689 option->palette.setCurrentColorGroup(QPalette::Disabled);
690 } else if (isActiveWindow()) {
691 option->palette.setCurrentColorGroup(QPalette::Active);
692 } else {
693 option->palette.setCurrentColorGroup(QPalette::Inactive);
694 }
695 option->fontMetrics = QFontMetrics(font());
696 option->styleObject = const_cast<QGraphicsWidget *>(this);
697}
698
699/*!
700 \reimp
701*/
702QSizeF QGraphicsWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
703{
704 Q_D(const QGraphicsWidget);
705 QSizeF sh;
706 if (d->layout) {
707 QSizeF marginSize(0,0);
708 if (d->margins) {
709 marginSize = QSizeF(d->margins->left() + d->margins->right(),
710 d->margins->top() + d->margins->bottom());
711 }
712 sh = d->layout->effectiveSizeHint(which, constraint: constraint - marginSize);
713 sh += marginSize;
714 } else {
715 switch (which) {
716 case Qt::MinimumSize:
717 sh = QSizeF(0, 0);
718 break;
719 case Qt::PreferredSize:
720 sh = QSizeF(50, 50); //rather arbitrary
721 break;
722 case Qt::MaximumSize:
723 sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
724 break;
725 default:
726 qWarning(msg: "QGraphicsWidget::sizeHint(): Don't know how to handle the value of 'which'");
727 break;
728 }
729 }
730 return sh;
731}
732
733/*!
734 \property QGraphicsWidget::layout
735 \brief The layout of the widget
736
737 Any existing layout manager is deleted before the new layout is assigned. If
738 \a layout is \nullptr, the widget is left without a layout. Existing subwidgets'
739 geometries will remain unaffected.
740
741 QGraphicsWidget takes ownership of \a layout.
742
743 All widgets that are currently managed by \a layout or all of its
744 sublayouts, are automatically reparented to this item. The layout is then
745 invalidated, and the child widget geometries are adjusted according to
746 this item's geometry() and contentsMargins(). Children who are not
747 explicitly managed by \a layout remain unaffected by the layout after
748 it has been assigned to this widget.
749
750 If no layout is currently managing this widget, layout() will return \nullptr.
751
752*/
753
754/*!
755 \fn void QGraphicsWidget::layoutChanged()
756 This signal gets emitted whenever the layout of the item changes
757 \internal
758*/
759
760/*!
761 Returns this widget's layout, or \nullptr if no layout is currently
762 managing this widget.
763
764 \sa setLayout()
765*/
766QGraphicsLayout *QGraphicsWidget::layout() const
767{
768 Q_D(const QGraphicsWidget);
769 return d->layout;
770}
771
772/*!
773 \fn void QGraphicsWidget::setLayout(QGraphicsLayout *layout)
774
775 Sets the layout for this widget to \a layout. Any existing layout manager
776 is deleted before the new layout is assigned. If \a layout is \nullptr, the
777 widget is left without a layout. Existing subwidgets' geometries will
778 remain unaffected.
779
780 All widgets that are currently managed by \a layout or all of its
781 sublayouts, are automatically reparented to this item. The layout is then
782 invalidated, and the child widget geometries are adjusted according to
783 this item's geometry() and contentsMargins(). Children who are not
784 explicitly managed by \a layout remain unaffected by the layout after
785 it has been assigned to this widget.
786
787 QGraphicsWidget takes ownership of \a layout.
788
789 \sa layout(), QGraphicsLinearLayout::addItem(), QGraphicsLayout::invalidate()
790*/
791void QGraphicsWidget::setLayout(QGraphicsLayout *l)
792{
793 Q_D(QGraphicsWidget);
794 if (d->layout == l)
795 return;
796 d->setLayout_helper(l);
797 if (!l)
798 return;
799
800 // Prevent assigning a layout that is already assigned to another widget.
801 QGraphicsLayoutItem *oldParent = l->parentLayoutItem();
802 if (oldParent && oldParent != this) {
803 qWarning(msg: "QGraphicsWidget::setLayout: Attempting to set a layout on %s"
804 " \"%s\", when the layout already has a parent",
805 metaObject()->className(), qPrintable(objectName()));
806 return;
807 }
808
809 // Install and activate the layout.
810 l->setParentLayoutItem(this);
811 l->d_func()->reparentChildItems(newParent: this);
812 l->invalidate();
813 emit layoutChanged();
814}
815
816/*!
817 Adjusts the size of the widget to its effective preferred size hint.
818
819 This function is called implicitly when the item is shown for the first
820 time.
821
822 \sa effectiveSizeHint(), Qt::MinimumSize
823*/
824void QGraphicsWidget::adjustSize()
825{
826 QSizeF sz = effectiveSizeHint(which: Qt::PreferredSize);
827 // What if sz is not valid?!
828 if (sz.isValid())
829 resize(size: sz);
830}
831
832/*!
833 \property QGraphicsWidget::layoutDirection
834 \brief the layout direction for this widget.
835
836 This property modifies this widget's and all of its descendants'
837 Qt::WA_RightToLeft attribute. It also sets this widget's
838 Qt::WA_SetLayoutDirection attribute.
839
840 The widget's layout direction determines the order in which the layout
841 manager horizontally arranges subwidgets of this widget. The default
842 value depends on the language and locale of the application, and is
843 typically in the same direction as words are read and written. With
844 Qt::LeftToRight, the layout starts placing subwidgets from the left
845 side of this widget towards the right. Qt::RightToLeft does the opposite -
846 the layout will place widgets starting from the right edge moving towards
847 the left.
848
849 Subwidgets inherit their layout direction from the parent. Top-level
850 widget items inherit their layout direction from
851 QGraphicsScene::layoutDirection. If you change a widget's layout direction
852 by calling setLayoutDirection(), the widget will send itself a
853 \l{QEvent::LayoutDirectionChange}{LayoutDirectionChange} event, and then
854 propagate the new layout direction to all its descendants.
855
856 \sa QWidget::layoutDirection, QApplication::layoutDirection
857*/
858Qt::LayoutDirection QGraphicsWidget::layoutDirection() const
859{
860 return testAttribute(attribute: Qt::WA_RightToLeft) ? Qt::RightToLeft : Qt::LeftToRight;
861}
862void QGraphicsWidget::setLayoutDirection(Qt::LayoutDirection direction)
863{
864 Q_D(QGraphicsWidget);
865 setAttribute(attribute: Qt::WA_SetLayoutDirection, on: true);
866 d->setLayoutDirection_helper(direction);
867}
868void QGraphicsWidget::unsetLayoutDirection()
869{
870 Q_D(QGraphicsWidget);
871 setAttribute(attribute: Qt::WA_SetLayoutDirection, on: false);
872 d->resolveLayoutDirection();
873}
874
875/*!
876 Returns a pointer to the widget's style. If this widget does not have any
877 explicitly assigned style, the scene's style is returned instead. In turn,
878 if the scene does not have any assigned style, this function returns
879 QApplication::style().
880
881 \sa setStyle()
882*/
883QStyle *QGraphicsWidget::style() const
884{
885 if (QStyle *style = widgetStyles()->styleForWidget(widget: this))
886 return style;
887 // ### This is not thread-safe. QApplication::style() is not thread-safe.
888 return scene() ? scene()->style() : QApplication::style();
889}
890
891/*!
892 Sets the widget's style to \a style. QGraphicsWidget does \e not take
893 ownership of \a style.
894
895 If no style is assigned, or \a style is \nullptr, the widget will use
896 QGraphicsScene::style() (if this has been set). Otherwise the widget will
897 use QApplication::style().
898
899 This function sets the Qt::WA_SetStyle attribute if \a style is not \nullptr;
900 otherwise it clears the attribute.
901
902 \sa style()
903*/
904void QGraphicsWidget::setStyle(QStyle *style)
905{
906 setAttribute(attribute: Qt::WA_SetStyle, on: style != nullptr);
907 widgetStyles()->setStyleForWidget(widget: this, style);
908
909 // Deliver StyleChange to the widget itself (doesn't propagate).
910 QEvent event(QEvent::StyleChange);
911 QCoreApplication::sendEvent(receiver: this, event: &event);
912}
913
914/*!
915 \property QGraphicsWidget::font
916 \brief the widgets' font
917
918 This property provides the widget's font.
919
920 QFont consists of font properties that have been explicitly defined and
921 properties implicitly inherited from the widget's parent. Hence, font()
922 can return a different font compared to the one set with setFont().
923 This scheme allows you to define single entries in a font without
924 affecting the font's inherited entries.
925
926 When a widget's font changes, it resolves its entries against its
927 parent widget. If the widget does not have a parent widget, it resolves
928 its entries against the scene. The widget then sends itself a
929 \l{QEvent::FontChange}{FontChange} event and notifies all its
930 descendants so that they can resolve their fonts as well.
931
932 By default, this property contains the application's default font.
933
934 \sa QApplication::font(), QGraphicsScene::font, QFont::resolve()
935*/
936QFont QGraphicsWidget::font() const
937{
938 Q_D(const QGraphicsWidget);
939 QFont fnt = d->font;
940 fnt.setResolveMask(fnt.resolveMask() | d->inheritedFontResolveMask);
941 return fnt;
942}
943void QGraphicsWidget::setFont(const QFont &font)
944{
945 Q_D(QGraphicsWidget);
946 setAttribute(attribute: Qt::WA_SetFont, on: font.resolveMask() != 0);
947
948 QFont naturalFont = d->naturalWidgetFont();
949 QFont resolvedFont = font.resolve(naturalFont);
950 d->setFont_helper(resolvedFont);
951}
952
953/*!
954 \property QGraphicsWidget::palette
955 \brief the widget's palette
956
957 This property provides the widget's palette. The palette provides colors
958 and brushes for color groups (e.g., QPalette::Button) and states (e.g.,
959 QPalette::Inactive), loosely defining the general look of the widget and
960 its children.
961
962 QPalette consists of color groups that have been explicitly defined, and
963 groups that are implicitly inherited from the widget's parent. Because of
964 this, palette() can return a different palette than what has been set with
965 setPalette(). This scheme allows you to define single entries in a palette
966 without affecting the palette's inherited entries.
967
968 When a widget's palette changes, it resolves its entries against its
969 parent widget, or if it doesn't have a parent widget, it resolves against
970 the scene. It then sends itself a \l{QEvent::PaletteChange}{PaletteChange}
971 event, and notifies all its descendants so they can resolve their palettes
972 as well.
973
974 By default, this property contains the application's default palette.
975
976 \sa QGuiApplication::palette(), QGraphicsScene::palette, QPalette::resolve()
977*/
978QPalette QGraphicsWidget::palette() const
979{
980 Q_D(const QGraphicsWidget);
981 return d->palette;
982}
983void QGraphicsWidget::setPalette(const QPalette &palette)
984{
985 Q_D(QGraphicsWidget);
986 setAttribute(attribute: Qt::WA_SetPalette, on: palette.resolveMask() != 0);
987
988 QPalette naturalPalette = d->naturalWidgetPalette();
989 QPalette resolvedPalette = palette.resolve(other: naturalPalette);
990 d->setPalette_helper(resolvedPalette);
991}
992
993/*!
994 \property QGraphicsWidget::autoFillBackground
995 \brief whether the widget background is filled automatically
996 \since 4.7
997
998 If enabled, this property will cause Qt to fill the background of the
999 widget before invoking the paint() method. The color used is defined by the
1000 QPalette::Window color role from the widget's \l{QPalette}{palette}.
1001
1002 In addition, Windows are always filled with QPalette::Window, unless the
1003 WA_OpaquePaintEvent or WA_NoSystemBackground attributes are set.
1004
1005 By default, this property is \c false.
1006
1007 \sa Qt::WA_OpaquePaintEvent, Qt::WA_NoSystemBackground,
1008*/
1009bool QGraphicsWidget::autoFillBackground() const
1010{
1011 Q_D(const QGraphicsWidget);
1012 return d->autoFillBackground;
1013}
1014void QGraphicsWidget::setAutoFillBackground(bool enabled)
1015{
1016 Q_D(QGraphicsWidget);
1017 if (d->autoFillBackground != enabled) {
1018 d->autoFillBackground = enabled;
1019 update();
1020 }
1021}
1022
1023/*!
1024 If this widget is currently managed by a layout, this function notifies
1025 the layout that the widget's size hints have changed and the layout
1026 may need to resize and reposition the widget accordingly.
1027
1028 Call this function if the widget's sizeHint() has changed.
1029
1030 \sa QGraphicsLayout::invalidate()
1031*/
1032void QGraphicsWidget::updateGeometry()
1033{
1034 QGraphicsLayoutItem::updateGeometry();
1035 QGraphicsLayoutItem *parentItem = parentLayoutItem();
1036
1037 if (parentItem && parentItem->isLayout()) {
1038 if (QGraphicsLayout::instantInvalidatePropagation()) {
1039 static_cast<QGraphicsLayout *>(parentItem)->invalidate();
1040 } else {
1041 parentItem->updateGeometry();
1042 }
1043 } else {
1044 if (parentItem) {
1045 // This is for custom layouting
1046 QGraphicsWidget *parentWid = parentWidget(); //###
1047 if (parentWid->isVisible())
1048 QCoreApplication::postEvent(receiver: parentWid, event: new QEvent(QEvent::LayoutRequest));
1049 } else {
1050 /**
1051 * If this is the topmost widget, post a LayoutRequest event to the widget.
1052 * When the event is received, it will start flowing all the way down to the leaf
1053 * widgets in one go. This will make a relayout flicker-free.
1054 */
1055 if (QGraphicsLayout::instantInvalidatePropagation())
1056 QCoreApplication::postEvent(receiver: static_cast<QGraphicsWidget *>(this), event: new QEvent(QEvent::LayoutRequest));
1057 }
1058 if (!QGraphicsLayout::instantInvalidatePropagation()) {
1059 bool wasResized = testAttribute(attribute: Qt::WA_Resized);
1060 resize(size: size()); // this will restrict the size
1061 setAttribute(attribute: Qt::WA_Resized, on: wasResized);
1062 }
1063 }
1064}
1065
1066/*!
1067 \reimp
1068
1069 QGraphicsWidget uses the base implementation of this function to catch and
1070 deliver events related to state changes in the item. Because of this, it is
1071 very important that subclasses call the base implementation.
1072
1073 \a change specifies the type of change, and \a value is the new value.
1074
1075 For example, QGraphicsWidget uses ItemVisibleChange to deliver
1076 \l{QEvent::Show} {Show} and \l{QEvent::Hide}{Hide} events,
1077 ItemPositionHasChanged to deliver \l{QEvent::Move}{Move} events,
1078 and ItemParentChange both to deliver \l{QEvent::ParentChange}
1079 {ParentChange} events, and for managing the focus chain.
1080
1081 QGraphicsWidget enables the ItemSendsGeometryChanges flag by default in
1082 order to track position changes.
1083
1084 \sa QGraphicsItem::itemChange()
1085*/
1086QVariant QGraphicsWidget::itemChange(GraphicsItemChange change, const QVariant &value)
1087{
1088 Q_D(QGraphicsWidget);
1089 switch (change) {
1090 case ItemEnabledHasChanged: {
1091 // Send EnabledChange after the enabled state has changed.
1092 QEvent event(QEvent::EnabledChange);
1093 QCoreApplication::sendEvent(receiver: this, event: &event);
1094 break;
1095 }
1096 case ItemVisibleChange:
1097 if (value.toBool()) {
1098 // Send Show event before the item has been shown.
1099 QShowEvent event;
1100 QCoreApplication::sendEvent(receiver: this, event: &event);
1101 bool resized = testAttribute(attribute: Qt::WA_Resized);
1102 if (!resized) {
1103 adjustSize();
1104 setAttribute(attribute: Qt::WA_Resized, on: false);
1105 }
1106 }
1107
1108 // layout size hint only changes if an item changes from/to explicitly hidden state
1109 if (value.toBool() || d->explicitlyHidden)
1110 updateGeometry();
1111 break;
1112 case ItemVisibleHasChanged:
1113 if (!value.toBool()) {
1114 // Send Hide event after the item has been hidden.
1115 QHideEvent event;
1116 QCoreApplication::sendEvent(receiver: this, event: &event);
1117 }
1118 break;
1119 case ItemPositionHasChanged:
1120 d->setGeometryFromSetPos();
1121 break;
1122 case ItemParentChange: {
1123 // Deliver ParentAboutToChange.
1124 QEvent event(QEvent::ParentAboutToChange);
1125 QCoreApplication::sendEvent(receiver: this, event: &event);
1126 break;
1127 }
1128 case ItemParentHasChanged: {
1129 // Deliver ParentChange.
1130 QEvent event(QEvent::ParentChange);
1131 QCoreApplication::sendEvent(receiver: this, event: &event);
1132 break;
1133 }
1134 case ItemCursorHasChanged: {
1135 // Deliver CursorChange.
1136 QEvent event(QEvent::CursorChange);
1137 QCoreApplication::sendEvent(receiver: this, event: &event);
1138 break;
1139 }
1140 case ItemToolTipHasChanged: {
1141 // Deliver ToolTipChange.
1142 QEvent event(QEvent::ToolTipChange);
1143 QCoreApplication::sendEvent(receiver: this, event: &event);
1144 break;
1145 }
1146 default:
1147 break;
1148 }
1149 return QGraphicsItem::itemChange(change, value);
1150}
1151
1152/*!
1153 \internal
1154
1155 This virtual function is used to notify changes to any property (both
1156 dynamic properties, and registered with Q_PROPERTY) in the
1157 widget. Depending on the property itself, the notification can be
1158 delivered before or after the value has changed.
1159
1160 \a propertyName is the name of the property (e.g., "size" or "font"), and
1161 \a value is the (proposed) new value of the property. The function returns
1162 the new value, which may be different from \a value if the notification
1163 supports adjusting the property value. The base implementation simply
1164 returns \a value for any \a propertyName.
1165
1166 QGraphicsWidget delivers notifications for the following properties:
1167
1168 \table
1169 \header \li propertyName \li Property
1170 \row \li layoutDirection \li QGraphicsWidget::layoutDirection
1171 \row \li size \li QGraphicsWidget::size
1172 \row \li font \li QGraphicsWidget::font
1173 \row \li palette \li QGraphicsWidget::palette
1174 \endtable
1175
1176 \sa itemChange()
1177*/
1178QVariant QGraphicsWidget::propertyChange(const QString &propertyName, const QVariant &value)
1179{
1180 Q_UNUSED(propertyName);
1181 return value;
1182}
1183
1184/*!
1185 QGraphicsWidget's implementation of sceneEvent() simply passes \a event to
1186 QGraphicsWidget::event(). You can handle all events for your widget in
1187 event() or in any of the convenience functions; you should not have to
1188 reimplement this function in a subclass of QGraphicsWidget.
1189
1190 Returns \c true if \a event has been recognized and processed; otherwise,
1191 returns \c false.
1192
1193 \sa QGraphicsItem::sceneEvent()
1194*/
1195bool QGraphicsWidget::sceneEvent(QEvent *event)
1196{
1197 return QGraphicsItem::sceneEvent(event);
1198}
1199
1200/*!
1201 This event handler, for \a event, receives events for the window frame if
1202 this widget is a window. Its base implementation provides support for
1203 default window frame interaction such as moving, resizing, etc.
1204
1205 You can reimplement this handler in a subclass of QGraphicsWidget to
1206 provide your own custom window frame interaction support.
1207
1208 Returns \c true if \a event has been recognized and processed; otherwise,
1209 returns \c false.
1210
1211 \sa event()
1212*/
1213bool QGraphicsWidget::windowFrameEvent(QEvent *event)
1214{
1215 Q_D(QGraphicsWidget);
1216 switch (event->type()) {
1217 case QEvent::GraphicsSceneMousePress:
1218 d->windowFrameMousePressEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
1219 break;
1220 case QEvent::GraphicsSceneMouseMove:
1221 d->ensureWindowData();
1222 if (d->windowData->grabbedSection != Qt::NoSection) {
1223 d->windowFrameMouseMoveEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
1224 event->accept();
1225 }
1226 break;
1227 case QEvent::GraphicsSceneMouseRelease:
1228 d->windowFrameMouseReleaseEvent(event: static_cast<QGraphicsSceneMouseEvent *>(event));
1229 break;
1230 case QEvent::GraphicsSceneHoverMove:
1231 d->windowFrameHoverMoveEvent(event: static_cast<QGraphicsSceneHoverEvent *>(event));
1232 break;
1233 case QEvent::GraphicsSceneHoverLeave:
1234 d->windowFrameHoverLeaveEvent(event: static_cast<QGraphicsSceneHoverEvent *>(event));
1235 break;
1236 default:
1237 break;
1238 }
1239 return event->isAccepted();
1240}
1241
1242/*!
1243 \since 4.4
1244
1245 Returns the window frame section at position \a pos, or
1246 Qt::NoSection if there is no window frame section at this
1247 position.
1248
1249 This function is used in QGraphicsWidget's base implementation for window
1250 frame interaction.
1251
1252 You can reimplement this function if you want to customize how a window
1253 can be interactively moved or resized. For instance, if you only want to
1254 allow a window to be resized by the bottom right corner, you can
1255 reimplement this function to return Qt::NoSection for all sections except
1256 Qt::BottomRightSection.
1257
1258 \sa windowFrameEvent(), paintWindowFrame(), windowFrameGeometry()
1259*/
1260Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const
1261{
1262 Q_D(const QGraphicsWidget);
1263
1264 const QRectF r = windowFrameRect();
1265 if (!r.contains(p: pos))
1266 return Qt::NoSection;
1267
1268 const qreal left = r.left();
1269 const qreal top = r.top();
1270 const qreal right = r.right();
1271 const qreal bottom = r.bottom();
1272 const qreal x = pos.x();
1273 const qreal y = pos.y();
1274
1275 const qreal cornerMargin = 20;
1276 //### Not sure of this one, it should be the same value for all edges.
1277 const qreal windowFrameWidth = d->windowFrameMargins
1278 ? d->windowFrameMargins->left() : 0;
1279
1280 Qt::WindowFrameSection s = Qt::NoSection;
1281 if (x <= left + cornerMargin) {
1282 if (y <= top + windowFrameWidth || (x <= left + windowFrameWidth && y <= top + cornerMargin)) {
1283 s = Qt::TopLeftSection;
1284 } else if (y >= bottom - windowFrameWidth || (x <= left + windowFrameWidth && y >= bottom - cornerMargin)) {
1285 s = Qt::BottomLeftSection;
1286 } else if (x <= left + windowFrameWidth) {
1287 s = Qt::LeftSection;
1288 }
1289 } else if (x >= right - cornerMargin) {
1290 if (y <= top + windowFrameWidth || (x >= right - windowFrameWidth && y <= top + cornerMargin)) {
1291 s = Qt::TopRightSection;
1292 } else if (y >= bottom - windowFrameWidth || (x >= right - windowFrameWidth && y >= bottom - cornerMargin)) {
1293 s = Qt::BottomRightSection;
1294 } else if (x >= right - windowFrameWidth) {
1295 s = Qt::RightSection;
1296 }
1297 } else if (y <= top + windowFrameWidth) {
1298 s = Qt::TopSection;
1299 } else if (y >= bottom - windowFrameWidth) {
1300 s = Qt::BottomSection;
1301 }
1302 if (s == Qt::NoSection) {
1303 QRectF r1 = r;
1304 r1.setHeight(d->windowFrameMargins
1305 ? d->windowFrameMargins->top() : 0);
1306 if (r1.contains(p: pos))
1307 s = Qt::TitleBarArea;
1308 }
1309 return s;
1310}
1311
1312/*!
1313 \reimp
1314
1315 Handles the \a event. QGraphicsWidget handles the following
1316 events:
1317
1318 \table
1319 \header \li Event \li Usage
1320 \row \li Polish
1321 \li Delivered to the widget some time after it has been
1322 shown.
1323 \row \li GraphicsSceneMove
1324 \li Delivered to the widget after its local position has
1325 changed.
1326 \row \li GraphicsSceneResize
1327 \li Delivered to the widget after its size has changed.
1328 \row \li Show
1329 \li Delivered to the widget before it has been shown.
1330 \row \li Hide
1331 \li Delivered to the widget after it has been hidden.
1332 \row \li PaletteChange
1333 \li Delivered to the widget after its palette has changed.
1334 \row \li FontChange
1335 \li Delivered to the widget after its font has changed.
1336 \row \li EnabledChange
1337 \li Delivered to the widget after its enabled state has
1338 changed.
1339 \row \li StyleChange
1340 \li Delivered to the widget after its style has changed.
1341 \row \li LayoutDirectionChange
1342 \li Delivered to the widget after its layout direction has
1343 changed.
1344 \row \li ContentsRectChange
1345 \li Delivered to the widget after its contents margins/
1346 contents rect has changed.
1347 \endtable
1348*/
1349bool QGraphicsWidget::event(QEvent *event)
1350{
1351 Q_D(QGraphicsWidget);
1352 // Forward the event to the layout first.
1353 if (d->layout)
1354 d->layout->widgetEvent(e: event);
1355
1356 // Handle the event itself.
1357 switch (event->type()) {
1358 case QEvent::GraphicsSceneMove:
1359 moveEvent(event: static_cast<QGraphicsSceneMoveEvent *>(event));
1360 break;
1361 case QEvent::GraphicsSceneResize:
1362 resizeEvent(event: static_cast<QGraphicsSceneResizeEvent *>(event));
1363 break;
1364 case QEvent::Show:
1365 showEvent(event: static_cast<QShowEvent *>(event));
1366 break;
1367 case QEvent::Hide:
1368 hideEvent(event: static_cast<QHideEvent *>(event));
1369 break;
1370 case QEvent::Polish:
1371 polishEvent();
1372 d->polished = true;
1373 if (!d->font.isCopyOf(QApplication::font()))
1374 d->updateFont(font: d->font);
1375 break;
1376 case QEvent::WindowActivate:
1377 case QEvent::WindowDeactivate:
1378 update();
1379 break;
1380 case QEvent::StyleAnimationUpdate:
1381 if (isVisible()) {
1382 event->accept();
1383 update();
1384 }
1385 break;
1386 // Taken from QWidget::event
1387 case QEvent::ActivationChange:
1388 case QEvent::EnabledChange:
1389 case QEvent::FontChange:
1390 case QEvent::StyleChange:
1391 case QEvent::PaletteChange:
1392 case QEvent::ParentChange:
1393 case QEvent::ContentsRectChange:
1394 case QEvent::LayoutDirectionChange:
1395 changeEvent(event);
1396 break;
1397 case QEvent::Close:
1398 closeEvent(event: (QCloseEvent *)event);
1399 break;
1400 case QEvent::GrabMouse:
1401 grabMouseEvent(event);
1402 break;
1403 case QEvent::UngrabMouse:
1404 ungrabMouseEvent(event);
1405 break;
1406 case QEvent::GrabKeyboard:
1407 grabKeyboardEvent(event);
1408 break;
1409 case QEvent::UngrabKeyboard:
1410 ungrabKeyboardEvent(event);
1411 break;
1412 case QEvent::GraphicsSceneMousePress:
1413 if (d->hasDecoration() && windowFrameEvent(event))
1414 return true;
1415 break;
1416 case QEvent::GraphicsSceneMouseMove:
1417 case QEvent::GraphicsSceneMouseRelease:
1418 case QEvent::GraphicsSceneMouseDoubleClick:
1419 d->ensureWindowData();
1420 if (d->hasDecoration() && d->windowData->grabbedSection != Qt::NoSection)
1421 return windowFrameEvent(event);
1422 break;
1423 case QEvent::GraphicsSceneHoverEnter:
1424 case QEvent::GraphicsSceneHoverMove:
1425 case QEvent::GraphicsSceneHoverLeave:
1426 if (d->hasDecoration()) {
1427 windowFrameEvent(event);
1428 // Filter out hover events if they were sent to us only because of the
1429 // decoration (special case in QGraphicsScenePrivate::dispatchHoverEvent).
1430 if (!acceptHoverEvents())
1431 return true;
1432 }
1433 break;
1434 default:
1435 break;
1436 }
1437 return QObject::event(event);
1438}
1439
1440/*!
1441 This event handler can be reimplemented to handle state changes.
1442
1443 The state being changed in this event can be retrieved through \a event.
1444
1445 Change events include: QEvent::ActivationChange, QEvent::EnabledChange,
1446 QEvent::FontChange, QEvent::StyleChange, QEvent::PaletteChange,
1447 QEvent::ParentChange, QEvent::LayoutDirectionChange, and
1448 QEvent::ContentsRectChange.
1449*/
1450void QGraphicsWidget::changeEvent(QEvent *event)
1451{
1452 Q_D(QGraphicsWidget);
1453 switch (event->type()) {
1454 case QEvent::StyleChange:
1455 // ### Don't unset if the margins are explicitly set.
1456 unsetWindowFrameMargins();
1457 if (d->layout)
1458 d->layout->invalidate();
1459 Q_FALLTHROUGH();
1460 case QEvent::FontChange:
1461 update();
1462 updateGeometry();
1463 break;
1464 case QEvent::PaletteChange:
1465 update();
1466 break;
1467 case QEvent::ParentChange:
1468 d->resolveFont(inheritedMask: d->inheritedFontResolveMask);
1469 d->resolvePalette(inheritedMask: d->inheritedPaletteResolveMask);
1470 break;
1471 default:
1472 break;
1473 }
1474}
1475
1476/*!
1477 This event handler, for \a event, can be reimplemented in a subclass to
1478 receive widget close events. The default implementation accepts the
1479 event.
1480
1481 \sa close(), QCloseEvent
1482*/
1483void QGraphicsWidget::closeEvent(QCloseEvent *event)
1484{
1485 event->accept();
1486}
1487
1488/*!
1489 \reimp
1490*/
1491void QGraphicsWidget::focusInEvent(QFocusEvent *event)
1492{
1493 Q_UNUSED(event);
1494 if (focusPolicy() != Qt::NoFocus)
1495 update();
1496}
1497
1498/*!
1499 Finds a new widget to give the keyboard focus to, as appropriate for Tab
1500 and Shift+Tab, and returns \c true if it can find a new widget; returns \c false
1501 otherwise. If \a next is true, this function searches forward; if \a next
1502 is false, it searches backward.
1503
1504 Sometimes, you will want to reimplement this function to provide special
1505 focus handling for your widget and its subwidgets. For example, a web
1506 browser might reimplement it to move its current active link forward or
1507 backward, and call the base implementation only when it reaches the last
1508 or first link on the page.
1509
1510 Child widgets call focusNextPrevChild() on their parent widgets, but only
1511 the window that contains the child widgets decides where to redirect
1512 focus. By reimplementing this function for an object, you gain control of
1513 focus traversal for all child widgets.
1514
1515 \sa focusPolicy()
1516*/
1517bool QGraphicsWidget::focusNextPrevChild(bool next)
1518{
1519 Q_D(QGraphicsWidget);
1520 // Let the parent's focusNextPrevChild implementation decide what to do.
1521 QGraphicsWidget *parent = nullptr;
1522 if (!isWindow() && (parent = parentWidget()))
1523 return parent->focusNextPrevChild(next);
1524 if (!d->scene)
1525 return false;
1526 if (d->scene->focusNextPrevChild(next))
1527 return true;
1528 if (isWindow()) {
1529 setFocus(next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
1530 if (hasFocus())
1531 return true;
1532 }
1533 return false;
1534}
1535
1536/*!
1537 \reimp
1538*/
1539void QGraphicsWidget::focusOutEvent(QFocusEvent *event)
1540{
1541 Q_UNUSED(event);
1542 if (focusPolicy() != Qt::NoFocus)
1543 update();
1544}
1545
1546/*!
1547 This event handler, for \l{QEvent::Hide}{Hide} events, is delivered after
1548 the widget has been hidden, for example, setVisible(false) has been called
1549 for the widget or one of its ancestors when the widget was previously
1550 shown.
1551
1552 You can reimplement this event handler to detect when your widget is
1553 hidden. Calling QEvent::accept() or QEvent::ignore() on \a event has no
1554 effect.
1555
1556 \sa showEvent(), QWidget::hideEvent(), ItemVisibleChange
1557*/
1558void QGraphicsWidget::hideEvent(QHideEvent *event)
1559{
1560 ///### focusNextPrevChild(true), don't lose focus when the focus widget
1561 // is hidden.
1562 Q_UNUSED(event);
1563}
1564
1565/*!
1566 This event handler, for \l{QEvent::GraphicsSceneMove}{GraphicsSceneMove}
1567 events, is delivered after the widget has moved (e.g., its local position
1568 has changed).
1569
1570 This event is only delivered when the item is moved locally. Calling
1571 setTransform() or moving any of the item's ancestors does not affect the
1572 item's local position.
1573
1574 You can reimplement this event handler to detect when your widget has
1575 moved. Calling QEvent::accept() or QEvent::ignore() on \a event has no
1576 effect.
1577
1578 \sa ItemPositionChange, ItemPositionHasChanged
1579*/
1580void QGraphicsWidget::moveEvent(QGraphicsSceneMoveEvent *event)
1581{
1582 // ### Last position is always == current position
1583 Q_UNUSED(event);
1584}
1585
1586/*!
1587 This event is delivered to the item by the scene at some point after it
1588 has been constructed, but before it is shown or otherwise accessed through
1589 the scene. You can use this event handler to do last-minute initializations
1590 of the widget which require the item to be fully constructed.
1591
1592 The base implementation does nothing.
1593*/
1594void QGraphicsWidget::polishEvent()
1595{
1596}
1597
1598/*!
1599 This event handler, for
1600 \l{QEvent::GraphicsSceneResize}{GraphicsSceneResize} events, is
1601 delivered after the widget has been resized (i.e., its local size has
1602 changed). \a event contains both the old and the new size.
1603
1604 This event is only delivered when the widget is resized locally; calling
1605 setTransform() on the widget or any of its ancestors or view, does not
1606 affect the widget's local size.
1607
1608 You can reimplement this event handler to detect when your widget has been
1609 resized. Calling QEvent::accept() or QEvent::ignore() on \a event has no
1610 effect.
1611
1612 \sa geometry(), setGeometry()
1613*/
1614void QGraphicsWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
1615{
1616 Q_UNUSED(event);
1617}
1618
1619/*!
1620 This event handler, for \l{QEvent::Show}{Show} events, is delivered before
1621 the widget has been shown, for example, setVisible(true) has been called
1622 for the widget or one of its ancestors when the widget was previously
1623 hidden.
1624
1625 You can reimplement this event handler to detect when your widget is
1626 shown. Calling QEvent::accept() or QEvent::ignore() on \a event has no
1627 effect.
1628
1629 \sa hideEvent(), QWidget::showEvent(), ItemVisibleChange
1630*/
1631void QGraphicsWidget::showEvent(QShowEvent *event)
1632{
1633 Q_UNUSED(event);
1634}
1635
1636/*!
1637 \reimp
1638*/
1639void QGraphicsWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
1640{
1641 Q_UNUSED(event);
1642}
1643
1644/*!
1645 \reimp
1646*/
1647void QGraphicsWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
1648{
1649 QGraphicsObject::hoverLeaveEvent(event);
1650}
1651
1652/*!
1653 This event handler, for \a event, can be reimplemented in a subclass to
1654 receive notifications for QEvent::GrabMouse events.
1655
1656 \sa grabMouse(), grabKeyboard()
1657*/
1658void QGraphicsWidget::grabMouseEvent(QEvent *event)
1659{
1660 Q_UNUSED(event);
1661}
1662
1663/*!
1664 This event handler, for \a event, can be reimplemented in a subclass to
1665 receive notifications for QEvent::UngrabMouse events.
1666
1667 \sa ungrabMouse(), ungrabKeyboard()
1668*/
1669void QGraphicsWidget::ungrabMouseEvent(QEvent *event)
1670{
1671 Q_UNUSED(event);
1672}
1673
1674/*!
1675 This event handler, for \a event, can be reimplemented in a subclass to
1676 receive notifications for QEvent::GrabKeyboard events.
1677
1678 \sa grabKeyboard(), grabMouse()
1679*/
1680void QGraphicsWidget::grabKeyboardEvent(QEvent *event)
1681{
1682 Q_UNUSED(event);
1683}
1684
1685/*!
1686 This event handler, for \a event, can be reimplemented in a subclass to
1687 receive notifications for QEvent::UngrabKeyboard events.
1688
1689 \sa ungrabKeyboard(), ungrabMouse()
1690*/
1691void QGraphicsWidget::ungrabKeyboardEvent(QEvent *event)
1692{
1693 Q_UNUSED(event);
1694}
1695
1696/*!
1697 Returns the widgets window type.
1698
1699 \sa windowFlags(), isWindow(), isPanel()
1700*/
1701Qt::WindowType QGraphicsWidget::windowType() const
1702{
1703 return Qt::WindowType(int(windowFlags()) & Qt::WindowType_Mask);
1704}
1705
1706/*!
1707 \property QGraphicsWidget::windowFlags
1708 \brief the widget's window flags
1709
1710 Window flags are a combination of a window type (e.g., Qt::Dialog) and
1711 several flags giving hints on the behavior of the window. The behavior
1712 is platform-dependent.
1713
1714 By default, this property contains no window flags.
1715
1716 Windows are panels. If you set the Qt::Window flag, the ItemIsPanel flag
1717 will be set automatically. If you clear the Qt::Window flag, the
1718 ItemIsPanel flag is also cleared. Note that the ItemIsPanel flag can be
1719 set independently of Qt::Window.
1720
1721 \sa isWindow(), isPanel()
1722*/
1723Qt::WindowFlags QGraphicsWidget::windowFlags() const
1724{
1725 Q_D(const QGraphicsWidget);
1726 return d->windowFlags;
1727}
1728void QGraphicsWidget::setWindowFlags(Qt::WindowFlags wFlags)
1729{
1730 Q_D(QGraphicsWidget);
1731 if (d->windowFlags == wFlags)
1732 return;
1733 bool wasPopup = (d->windowFlags & Qt::WindowType_Mask) == Qt::Popup;
1734
1735 d->adjustWindowFlags(wFlags: &wFlags);
1736 d->windowFlags = wFlags;
1737 if (!d->setWindowFrameMargins)
1738 unsetWindowFrameMargins();
1739
1740 setFlag(flag: ItemIsPanel, enabled: d->windowFlags & Qt::Window);
1741
1742 bool isPopup = (d->windowFlags & Qt::WindowType_Mask) == Qt::Popup;
1743 if (d->scene && isVisible() && wasPopup != isPopup) {
1744 // Popup state changed; update implicit mouse grab.
1745 if (!isPopup)
1746 d->scene->d_func()->removePopup(widget: this);
1747 else
1748 d->scene->d_func()->addPopup(widget: this);
1749 }
1750
1751 if (d->scene && d->scene->d_func()->allItemsIgnoreHoverEvents && d->hasDecoration()) {
1752 d->scene->d_func()->allItemsIgnoreHoverEvents = false;
1753 d->scene->d_func()->enableMouseTrackingOnViews();
1754 }
1755}
1756
1757/*!
1758 Returns \c true if this widget's window is in the active window, or if the
1759 widget does not have a window but is in an active scene (i.e., a scene
1760 that currently has focus).
1761
1762 The active window is the window that either contains a child widget that
1763 currently has input focus, or that itself has input focus.
1764
1765 \sa QGraphicsScene::activeWindow(), QGraphicsScene::setActiveWindow(), isActive()
1766*/
1767bool QGraphicsWidget::isActiveWindow() const
1768{
1769 return isActive();
1770}
1771
1772/*!
1773 \property QGraphicsWidget::windowTitle
1774 \brief This property holds the window title (caption).
1775
1776 This property is only used for windows.
1777
1778 By default, if no title has been set, this property contains an
1779 empty string.
1780*/
1781void QGraphicsWidget::setWindowTitle(const QString &title)
1782{
1783 Q_D(QGraphicsWidget);
1784 d->ensureWindowData();
1785 d->windowData->windowTitle = title;
1786}
1787QString QGraphicsWidget::windowTitle() const
1788{
1789 Q_D(const QGraphicsWidget);
1790 return d->windowData ? d->windowData->windowTitle : QString();
1791}
1792
1793/*!
1794 \property QGraphicsWidget::focusPolicy
1795 \brief the way the widget accepts keyboard focus
1796
1797 The focus policy is Qt::TabFocus if the widget accepts keyboard focus by
1798 tabbing, Qt::ClickFocus if the widget accepts focus by clicking,
1799 Qt::StrongFocus if it accepts both, and Qt::NoFocus (the default) if it
1800 does not accept focus at all.
1801
1802 You must enable keyboard focus for a widget if it processes keyboard
1803 events. This is normally done from the widget's constructor. For instance,
1804 the QLineEdit constructor calls setFocusPolicy(Qt::StrongFocus).
1805
1806 If you enable a focus policy (i.e., not Qt::NoFocus), QGraphicsWidget will
1807 automatically enable the ItemIsFocusable flag. Setting Qt::NoFocus on a
1808 widget will clear the ItemIsFocusable flag. If the widget currently has
1809 keyboard focus, the widget will automatically lose focus.
1810
1811 \sa focusInEvent(), focusOutEvent(), keyPressEvent(), keyReleaseEvent(), enabled
1812*/
1813Qt::FocusPolicy QGraphicsWidget::focusPolicy() const
1814{
1815 Q_D(const QGraphicsWidget);
1816 return d->focusPolicy;
1817}
1818void QGraphicsWidget::setFocusPolicy(Qt::FocusPolicy policy)
1819{
1820 Q_D(QGraphicsWidget);
1821 if (d->focusPolicy == policy)
1822 return;
1823 d->focusPolicy = policy;
1824 if (hasFocus() && policy == Qt::NoFocus)
1825 clearFocus();
1826 setFlag(flag: ItemIsFocusable, enabled: policy != Qt::NoFocus);
1827}
1828
1829/*!
1830 If this widget, a child or descendant of this widget currently has input
1831 focus, this function will return a pointer to that widget. If
1832 no descendant widget has input focus, \nullptr is returned.
1833
1834 \sa QGraphicsItem::focusItem(), QWidget::focusWidget()
1835*/
1836QGraphicsWidget *QGraphicsWidget::focusWidget() const
1837{
1838 Q_D(const QGraphicsWidget);
1839 if (d->subFocusItem && d->subFocusItem->d_ptr->isWidget)
1840 return static_cast<QGraphicsWidget *>(d->subFocusItem);
1841 return nullptr;
1842}
1843
1844#ifndef QT_NO_SHORTCUT
1845/*!
1846 \since 4.5
1847
1848 Adds a shortcut to Qt's shortcut system that watches for the given key \a
1849 sequence in the given \a context. If the \a context is
1850 Qt::ApplicationShortcut, the shortcut applies to the application as a
1851 whole. Otherwise, it is either local to this widget, Qt::WidgetShortcut,
1852 or to the window itself, Qt::WindowShortcut. For widgets that are not part
1853 of a window (i.e., top-level widgets and their children),
1854 Qt::WindowShortcut shortcuts apply to the scene.
1855
1856 If the same key \a sequence has been grabbed by several widgets,
1857 when the key \a sequence occurs a QEvent::Shortcut event is sent
1858 to all the widgets to which it applies in a non-deterministic
1859 order, but with the ``ambiguous'' flag set to true.
1860
1861 \warning You should not normally need to use this function;
1862 instead create \l{QAction}s with the shortcut key sequences you
1863 require (if you also want equivalent menu options and toolbar
1864 buttons), or create \l{QShortcut}s if you just need key sequences.
1865 Both QAction and QShortcut handle all the event filtering for you,
1866 and provide signals which are triggered when the user triggers the
1867 key sequence, so are much easier to use than this low-level
1868 function.
1869
1870 \sa releaseShortcut(), setShortcutEnabled(), QWidget::grabShortcut()
1871*/
1872int QGraphicsWidget::grabShortcut(const QKeySequence &sequence, Qt::ShortcutContext context)
1873{
1874 Q_ASSERT(qApp);
1875 if (sequence.isEmpty())
1876 return 0;
1877 // ### setAttribute(Qt::WA_GrabbedShortcut);
1878 return QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(owner: this, key: sequence, context, matcher: qWidgetShortcutContextMatcher);
1879}
1880
1881/*!
1882 \since 4.5
1883
1884 Removes the shortcut with the given \a id from Qt's shortcut
1885 system. The widget will no longer receive QEvent::Shortcut events
1886 for the shortcut's key sequence (unless it has other shortcuts
1887 with the same key sequence).
1888
1889 \warning You should not normally need to use this function since
1890 Qt's shortcut system removes shortcuts automatically when their
1891 parent widget is destroyed. It is best to use QAction or
1892 QShortcut to handle shortcuts, since they are easier to use than
1893 this low-level function. Note also that this is an expensive
1894 operation.
1895
1896 \sa grabShortcut(), setShortcutEnabled(), QWidget::releaseShortcut()
1897*/
1898void QGraphicsWidget::releaseShortcut(int id)
1899{
1900 Q_ASSERT(qApp);
1901 if (id)
1902 QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id, owner: this, key: 0);
1903}
1904
1905/*!
1906 \since 4.5
1907
1908 If \a enabled is true, the shortcut with the given \a id is
1909 enabled; otherwise the shortcut is disabled.
1910
1911 \warning You should not normally need to use this function since
1912 Qt's shortcut system enables/disables shortcuts automatically as
1913 widgets become hidden/visible and gain or lose focus. It is best
1914 to use QAction or QShortcut to handle shortcuts, since they are
1915 easier to use than this low-level function.
1916
1917 \sa grabShortcut(), releaseShortcut(), QWidget::setShortcutEnabled()
1918*/
1919void QGraphicsWidget::setShortcutEnabled(int id, bool enabled)
1920{
1921 Q_ASSERT(qApp);
1922 if (id)
1923 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enable: enabled, id, owner: this, key: 0);
1924}
1925
1926/*!
1927 \since 4.5
1928
1929 If \a enabled is true, auto repeat of the shortcut with the
1930 given \a id is enabled; otherwise it is disabled.
1931
1932 \sa grabShortcut(), releaseShortcut(), QWidget::setShortcutAutoRepeat()
1933*/
1934void QGraphicsWidget::setShortcutAutoRepeat(int id, bool enabled)
1935{
1936 Q_ASSERT(qApp);
1937 if (id)
1938 QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(on: enabled, id, owner: this, key: 0);
1939}
1940#endif
1941
1942#ifndef QT_NO_ACTION
1943/*!
1944 \since 4.5
1945
1946 Appends the action \a action to this widget's list of actions.
1947
1948 All QGraphicsWidgets have a list of \l{QAction}s, however they can be
1949 represented graphically in many different ways. The default use of the
1950 QAction list (as returned by actions()) is to create a context QMenu.
1951
1952 A QGraphicsWidget should only have one of each action and adding an action
1953 it already has will not cause the same action to be in the widget twice.
1954
1955 \sa removeAction(), insertAction(), actions(), QWidget::addAction()
1956*/
1957void QGraphicsWidget::addAction(QAction *action)
1958{
1959 insertAction(before: nullptr, action);
1960}
1961
1962/*!
1963 \since 4.5
1964
1965 Appends the actions \a actions to this widget's list of actions.
1966
1967 \sa removeAction(), QMenu, addAction(), QWidget::addActions()
1968*/
1969void QGraphicsWidget::addActions(const QList<QAction *> &actions)
1970{
1971 for (int i = 0; i < actions.size(); ++i)
1972 insertAction(before: nullptr, action: actions.at(i));
1973}
1974
1975/*!
1976 \since 4.5
1977
1978 Inserts the action \a action to this widget's list of actions,
1979 before the action \a before. It appends the action if \a before is \nullptr or
1980 \a before is not a valid action for this widget.
1981
1982 A QGraphicsWidget should only have one of each action.
1983
1984 \sa removeAction(), addAction(), QMenu, actions(),
1985 QWidget::insertActions()
1986*/
1987void QGraphicsWidget::insertAction(QAction *before, QAction *action)
1988{
1989 if (!action) {
1990 qWarning(msg: "QWidget::insertAction: Attempt to insert null action");
1991 return;
1992 }
1993
1994 Q_D(QGraphicsWidget);
1995 int index = d->actions.indexOf(t: action);
1996 if (index != -1)
1997 d->actions.removeAt(i: index);
1998
1999 int pos = d->actions.indexOf(t: before);
2000 if (pos < 0) {
2001 before = nullptr;
2002 pos = d->actions.size();
2003 }
2004 d->actions.insert(i: pos, t: action);
2005
2006 if (index == -1) {
2007 QActionPrivate *apriv = action->d_func();
2008 apriv->associatedObjects.append(t: this);
2009 }
2010
2011 QActionEvent e(QEvent::ActionAdded, action, before);
2012 QCoreApplication::sendEvent(receiver: this, event: &e);
2013}
2014
2015/*!
2016 \since 4.5
2017
2018 Inserts the actions \a actions to this widget's list of actions,
2019 before the action \a before. It appends the action if \a before is \nullptr or
2020 \a before is not a valid action for this widget.
2021
2022 A QGraphicsWidget can have at most one of each action.
2023
2024 \sa removeAction(), QMenu, insertAction(), QWidget::insertActions()
2025*/
2026void QGraphicsWidget::insertActions(QAction *before, const QList<QAction *> &actions)
2027{
2028 for (int i = 0; i < actions.size(); ++i)
2029 insertAction(before, action: actions.at(i));
2030}
2031
2032/*!
2033 \since 4.5
2034
2035 Removes the action \a action from this widget's list of actions.
2036
2037 \sa insertAction(), actions(), insertAction(), QWidget::removeAction()
2038*/
2039void QGraphicsWidget::removeAction(QAction *action)
2040{
2041 if (!action)
2042 return;
2043
2044 Q_D(QGraphicsWidget);
2045
2046 QActionPrivate *apriv = action->d_func();
2047 apriv->associatedObjects.removeAll(t: this);
2048
2049 if (d->actions.removeAll(t: action)) {
2050 QActionEvent e(QEvent::ActionRemoved, action);
2051 QCoreApplication::sendEvent(receiver: this, event: &e);
2052 }
2053}
2054
2055/*!
2056 \since 4.5
2057
2058 Returns the (possibly empty) list of this widget's actions.
2059
2060 \sa insertAction(), removeAction(), QWidget::actions(),
2061 QAction::associatedWidgets(), QAction::associatedGraphicsWidgets()
2062*/
2063QList<QAction *> QGraphicsWidget::actions() const
2064{
2065 Q_D(const QGraphicsWidget);
2066 return d->actions;
2067}
2068#endif
2069
2070/*!
2071 Moves the \a second widget around the ring of focus widgets so that
2072 keyboard focus moves from the \a first widget to the \a second widget when
2073 the Tab key is pressed.
2074
2075 Note that since the tab order of the \a second widget is changed, you
2076 should order a chain like this:
2077
2078 \snippet code/src_gui_graphicsview_qgraphicswidget.cpp 1
2079
2080 \e not like this:
2081
2082 \snippet code/src_gui_graphicsview_qgraphicswidget.cpp 2
2083
2084 If \a first is \nullptr, this indicates that \a second should be the first widget
2085 to receive input focus should the scene gain Tab focus (i.e., the user
2086 hits Tab so that focus passes into the scene). If \a second is \nullptr, this
2087 indicates that \a first should be the first widget to gain focus if the
2088 scene gained BackTab focus.
2089
2090 By default, tab order is defined implicitly using widget creation order.
2091
2092 \sa focusPolicy, {Keyboard Focus in Widgets}
2093*/
2094void QGraphicsWidget::setTabOrder(QGraphicsWidget *first, QGraphicsWidget *second)
2095{
2096 if (!first && !second) {
2097 qWarning(msg: "QGraphicsWidget::setTabOrder(0, 0) is undefined");
2098 return;
2099 }
2100 if ((first && second) && first->scene() != second->scene()) {
2101 qWarning(msg: "QGraphicsWidget::setTabOrder: scenes %p and %p are different",
2102 first->scene(), second->scene());
2103 return;
2104 }
2105 QGraphicsScene *scene = first ? first->scene() : second->scene();
2106 if (!scene) {
2107 qWarning(msg: "QGraphicsWidget::setTabOrder: assigning tab order from/to the"
2108 " scene requires the item to be in a scene.");
2109 return;
2110 }
2111
2112 // If either first or second are 0, the scene's tabFocusFirst is updated
2113 // to point to the first item in the scene's focus chain. Then first or
2114 // second are set to point to tabFocusFirst.
2115 QGraphicsScenePrivate *sceneD = scene->d_func();
2116 if (!first) {
2117 sceneD->tabFocusFirst = second;
2118 return;
2119 }
2120 if (!second) {
2121 sceneD->tabFocusFirst = first->d_func()->focusNext;
2122 return;
2123 }
2124
2125 // Both first and second are != 0.
2126 QGraphicsWidget *firstFocusNext = first->d_func()->focusNext;
2127 if (firstFocusNext == second) {
2128 // Nothing to do.
2129 return;
2130 }
2131
2132 // Update the focus chain.
2133 QGraphicsWidget *secondFocusPrev = second->d_func()->focusPrev;
2134 QGraphicsWidget *secondFocusNext = second->d_func()->focusNext;
2135 firstFocusNext->d_func()->focusPrev = second;
2136 first->d_func()->focusNext = second;
2137 second->d_func()->focusNext = firstFocusNext;
2138 second->d_func()->focusPrev = first;
2139 secondFocusPrev->d_func()->focusNext = secondFocusNext;
2140 secondFocusNext->d_func()->focusPrev = secondFocusPrev;
2141
2142 Q_ASSERT(first->d_func()->focusNext->d_func()->focusPrev == first);
2143 Q_ASSERT(first->d_func()->focusPrev->d_func()->focusNext == first);
2144
2145 Q_ASSERT(second->d_func()->focusNext->d_func()->focusPrev == second);
2146 Q_ASSERT(second->d_func()->focusPrev->d_func()->focusNext == second);
2147
2148}
2149
2150/*!
2151 If \a on is true, this function enables \a attribute; otherwise
2152 \a attribute is disabled.
2153
2154 See the class documentation for QGraphicsWidget for a complete list of
2155 which attributes are supported, and what they are for.
2156
2157 \sa testAttribute(), QWidget::setAttribute()
2158*/
2159void QGraphicsWidget::setAttribute(Qt::WidgetAttribute attribute, bool on)
2160{
2161 Q_D(QGraphicsWidget);
2162 // ### most flags require some immediate action
2163 // ### we might want to qWarn use of unsupported attributes
2164 // ### we might want to not use Qt::WidgetAttribute, but roll our own instead
2165 d->setAttribute(att: attribute, value: on);
2166}
2167
2168/*!
2169 Returns \c true if \a attribute is enabled for this widget; otherwise,
2170 returns \c false.
2171
2172 \sa setAttribute()
2173*/
2174bool QGraphicsWidget::testAttribute(Qt::WidgetAttribute attribute) const
2175{
2176 Q_D(const QGraphicsWidget);
2177 return d->testAttribute(att: attribute);
2178}
2179
2180/*!
2181 \enum QGraphicsWidget::anonymous
2182
2183 The value returned by the virtual type() function.
2184
2185 \value Type A graphics widget item
2186*/
2187
2188/*!
2189 \reimp
2190*/
2191int QGraphicsWidget::type() const
2192{
2193 return Type;
2194}
2195
2196/*!
2197 \reimp
2198*/
2199void QGraphicsWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
2200{
2201 Q_UNUSED(painter);
2202 Q_UNUSED(option);
2203 Q_UNUSED(widget);
2204}
2205
2206/*!
2207 This virtual function is called by QGraphicsScene to draw the window frame
2208 for windows using \a painter, \a option, and \a widget, in local
2209 coordinates. The base implementation uses the current style to render the
2210 frame and title bar.
2211
2212 You can reimplement this function in a subclass of QGraphicsWidget to
2213 provide custom rendering of the widget's window frame.
2214
2215 \sa QGraphicsItem::paint()
2216*/
2217void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
2218 QWidget *widget)
2219{
2220 const bool fillBackground = !testAttribute(attribute: Qt::WA_OpaquePaintEvent)
2221 && !testAttribute(attribute: Qt::WA_NoSystemBackground);
2222 QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(object: this);
2223 const bool embeddedWidgetFillsOwnBackground = proxy && proxy->widget();
2224
2225 if (rect().contains(r: option->exposedRect)) {
2226 if (fillBackground && !embeddedWidgetFillsOwnBackground)
2227 painter->fillRect(option->exposedRect, palette().window());
2228 return;
2229 }
2230
2231 Q_D(QGraphicsWidget);
2232
2233 QRect windowFrameRect = QRect(QPoint(), windowFrameGeometry().size().toSize());
2234 QStyleOptionTitleBar bar;
2235 bar.QStyleOption::operator=(other: *option);
2236 d->initStyleOptionTitleBar(option: &bar); // this clear flags in bar.state
2237 d->ensureWindowData();
2238 bar.state.setFlag(flag: QStyle::State_MouseOver, on: d->windowData->buttonMouseOver);
2239 bar.state.setFlag(flag: QStyle::State_Sunken, on: d->windowData->buttonSunken);
2240 bar.rect = windowFrameRect;
2241
2242 // translate painter to make the style happy
2243 const QPointF styleOrigin = this->windowFrameRect().topLeft();
2244 painter->translate(offset: styleOrigin);
2245
2246#ifdef Q_OS_MAC
2247 const QSize pixmapSize = windowFrameRect.size();
2248 if (pixmapSize.width() <= 0 || pixmapSize.height() <= 0)
2249 return;
2250 QPainter *realPainter = painter;
2251 QPixmap pm(pixmapSize);
2252 painter = new QPainter(&pm);
2253#endif
2254
2255 // Fill background
2256 QStyleHintReturnMask mask;
2257 bool setMask = style()->styleHint(stylehint: QStyle::SH_WindowFrame_Mask, opt: &bar, widget, returnData: &mask) && !mask.region.isEmpty();
2258 bool hasBorder = !style()->styleHint(stylehint: QStyle::SH_TitleBar_NoBorder, opt: &bar, widget);
2259 int frameWidth = style()->pixelMetric(metric: QStyle::PM_MdiSubWindowFrameWidth, option: &bar, widget);
2260 if (setMask) {
2261 painter->save();
2262 painter->setClipRegion(mask.region, op: Qt::IntersectClip);
2263 }
2264 if (fillBackground) {
2265 if (embeddedWidgetFillsOwnBackground) {
2266 // Don't fill the background twice.
2267 QPainterPath windowFrameBackground;
2268 windowFrameBackground.addRect(rect: windowFrameRect);
2269 // Adjust with 0.5 to avoid border artifacts between
2270 // widget background and frame background.
2271 windowFrameBackground.addRect(rect: rect().translated(p: -styleOrigin).adjusted(xp1: 0.5, yp1: 0.5, xp2: -0.5, yp2: -0.5));
2272 painter->fillPath(path: windowFrameBackground, brush: palette().window());
2273 } else {
2274 painter->fillRect(windowFrameRect, palette().window());
2275 }
2276 }
2277
2278 // Draw title
2279 int height = (int)d->titleBarHeight(options: bar);
2280 bar.rect.setHeight(height);
2281 if (hasBorder) // Frame is painted by PE_FrameWindow
2282 bar.rect.adjust(dx1: frameWidth, dy1: frameWidth, dx2: -frameWidth, dy2: 0);
2283
2284 painter->save();
2285 painter->setFont(QApplication::font(className: "QMdiSubWindowTitleBar"));
2286 style()->drawComplexControl(cc: QStyle::CC_TitleBar, opt: &bar, p: painter, widget);
2287 painter->restore();
2288 if (setMask)
2289 painter->restore();
2290 // Draw window frame
2291 QStyleOptionFrame frameOptions;
2292 frameOptions.QStyleOption::operator=(other: *option);
2293 initStyleOption(option: &frameOptions);
2294 if (!hasBorder)
2295 painter->setClipRect(windowFrameRect.adjusted(xp1: 0, yp1: +height, xp2: 0, yp2: 0), op: Qt::IntersectClip);
2296 frameOptions.state.setFlag(flag: QStyle::State_HasFocus, on: hasFocus());
2297 bool isActive = isActiveWindow();
2298 frameOptions.state.setFlag(flag: QStyle::State_Active, on: isActive);
2299
2300 frameOptions.palette.setCurrentColorGroup(isActive ? QPalette::Active : QPalette::Normal);
2301 frameOptions.rect = windowFrameRect;
2302 frameOptions.lineWidth = style()->pixelMetric(metric: QStyle::PM_MdiSubWindowFrameWidth, option: nullptr, widget);
2303 frameOptions.midLineWidth = 1;
2304 style()->drawPrimitive(pe: QStyle::PE_FrameWindow, opt: &frameOptions, p: painter, w: widget);
2305
2306#ifdef Q_OS_MAC
2307 realPainter->drawPixmap(QPoint(), pm);
2308 delete painter;
2309#endif
2310}
2311
2312/*!
2313 \reimp
2314*/
2315QRectF QGraphicsWidget::boundingRect() const
2316{
2317 return windowFrameRect();
2318}
2319
2320/*!
2321 \reimp
2322*/
2323QPainterPath QGraphicsWidget::shape() const
2324{
2325 QPainterPath path;
2326 path.addRect(rect: rect());
2327 return path;
2328}
2329
2330/*!
2331 Call this function to close the widget.
2332
2333 Returns \c true if the widget was closed; otherwise returns \c false.
2334 This slot will first send a QCloseEvent to the widget, which may or may
2335 not accept the event. If the event was ignored, nothing happens. If the
2336 event was accepted, it will hide() the widget.
2337
2338 If the widget has the Qt::WA_DeleteOnClose attribute set it will be
2339 deleted.
2340*/
2341bool QGraphicsWidget::close()
2342{
2343 QCloseEvent closeEvent;
2344 QCoreApplication::sendEvent(receiver: this, event: &closeEvent);
2345 if (!closeEvent.isAccepted()) {
2346 return false;
2347 }
2348 // hide
2349 if (isVisible()) {
2350 hide();
2351 }
2352 if (testAttribute(attribute: Qt::WA_DeleteOnClose)) {
2353 deleteLater();
2354 }
2355 return true;
2356}
2357
2358#if 0
2359void QGraphicsWidget::dumpFocusChain()
2360{
2361 qDebug("=========== Dumping focus chain ==============");
2362 int i = 0;
2363 QGraphicsWidget *next = this;
2364 QSet<QGraphicsWidget*> visited;
2365 do {
2366 if (!next) {
2367 qWarning("Found a focus chain that is not circular, (next == 0)");
2368 break;
2369 }
2370 qDebug() << i++ << QString::number(uint(next), 16) << next->className() << next->data(0) << QString::fromLatin1("focusItem:%1").arg(next->hasFocus() ? '1' : '0') << "next:"_L1 << next->d_func()->focusNext->data(0) << "prev:"_L1 << next->d_func()->focusPrev->data(0);
2371 if (visited.contains(next)) {
2372 qWarning("Already visited this node. However, I expected to dump until I found myself.");
2373 break;
2374 }
2375 visited << next;
2376 next = next->d_func()->focusNext;
2377 } while (next != this);
2378}
2379#endif
2380
2381QT_END_NAMESPACE
2382
2383#include "moc_qgraphicswidget.cpp"
2384

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