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