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

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