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 
67 QT_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 */
QGraphicsWidget(QGraphicsItem * parent,Qt::WindowFlags wFlags)175 QGraphicsWidget::QGraphicsWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
176     : QGraphicsObject(*new QGraphicsWidgetPrivate, nullptr), QGraphicsLayoutItem(nullptr, false)
177 {
178     Q_D(QGraphicsWidget);
179     d->init(parent, wFlags);
180 }
181 
182 /*!
183     \internal
184 
185     Constructs a new QGraphicsWidget, using \a dd as parent.
186 */
QGraphicsWidget(QGraphicsWidgetPrivate & dd,QGraphicsItem * parent,Qt::WindowFlags wFlags)187 QGraphicsWidget::QGraphicsWidget(QGraphicsWidgetPrivate &dd, QGraphicsItem *parent, Qt::WindowFlags wFlags)
188     : QGraphicsObject(dd, nullptr), QGraphicsLayoutItem(nullptr, false)
189 {
190     Q_D(QGraphicsWidget);
191     d->init(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 */
203 class QGraphicsWidgetStyles
204 {
205 public:
styleForWidget(const QGraphicsWidget * widget) const206     QStyle *styleForWidget(const QGraphicsWidget *widget) const
207     {
208         QMutexLocker locker(&mutex);
209         return styles.value(widget, 0);
210     }
211 
setStyleForWidget(QGraphicsWidget * widget,QStyle * style)212     void setStyleForWidget(QGraphicsWidget *widget, QStyle *style)
213     {
214         QMutexLocker locker(&mutex);
215         if (style)
216             styles[widget] = style;
217         else
218             styles.remove(widget);
219     }
220 
221 private:
222     QHash<const QGraphicsWidget *, QStyle *> styles;
223     mutable QMutex mutex;
224 };
Q_GLOBAL_STATIC(QGraphicsWidgetStyles,widgetStyles)225 Q_GLOBAL_STATIC(QGraphicsWidgetStyles, widgetStyles)
226 
227 /*!
228     Destroys the QGraphicsWidget instance.
229 */
230 QGraphicsWidget::~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(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(this, 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 */
size() const306 QSizeF QGraphicsWidget::size() const
307 {
308     return QGraphicsLayoutItem::geometry().size();
309 }
310 
resize(const QSizeF & size)311 void 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 */
setGeometry(const QRectF & rect)352 void 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(Qt::WA_Resized);
360         newGeom = rect;
361         newGeom.setSize(rect.size().expandedTo(effectiveSizeHint(Qt::MinimumSize))
362                                    .boundedTo(effectiveSizeHint(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(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(this, &event);
395             if (wd->inSetPos) {
396                 //set the new pos
397                 d->geom.moveTopLeft(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(this, &re);
418                 }
419             } else {
420                 QCoreApplication::sendEvent(this, &re);
421             }
422         }
423     }
424 
425     emit geometryChanged();
426 relayoutChildrenAndReturn:
427     if (QGraphicsLayout::instantInvalidatePropagation()) {
428         if (QGraphicsLayout *lay = wd->layout) {
429             if (!lay->isActivated()) {
430                 QEvent layoutRequest(QEvent::LayoutRequest);
431                 QCoreApplication::sendEvent(this, &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 */
setContentsMargins(QMarginsF margins)493 void 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(this, &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 */
setContentsMargins(qreal left,qreal top,qreal right,qreal bottom)520 void 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 */
getContentsMargins(qreal * left,qreal * top,qreal * right,qreal * bottom) const532 void 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 */
setWindowFrameMargins(QMarginsF margins)558 void 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 */
setWindowFrameMargins(qreal left,qreal top,qreal right,qreal bottom)579 void 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 */
getWindowFrameMargins(qreal * left,qreal * top,qreal * right,qreal * bottom) const591 void 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 */
unsetWindowFrameMargins()611 void 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(&bar);
618         QStyle *style = this->style();
619         const qreal margin = style->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, &bar);
620         qreal titleBarHeight  = d->titleBarHeight(bar);
621         setWindowFrameMargins(margin, titleBarHeight, margin, margin);
622     } else {
623         setWindowFrameMargins(0, 0, 0, 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 */
windowFrameGeometry() const634 QRectF QGraphicsWidget::windowFrameGeometry() const
635 {
636     Q_D(const QGraphicsWidget);
637     return d->windowFrameMargins
638         ? geometry().adjusted(-d->windowFrameMargins->left(), -d->windowFrameMargins->top(),
639                               d->windowFrameMargins->right(), 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 */
windowFrameRect() const648 QRectF QGraphicsWidget::windowFrameRect() const
649 {
650     Q_D(const QGraphicsWidget);
651     return d->windowFrameMargins
652         ? rect().adjusted(-d->windowFrameMargins->left(), -d->windowFrameMargins->top(),
653                           d->windowFrameMargins->right(), 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 */
initStyleOption(QStyleOption * option) const699 void 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 */
sizeHint(Qt::SizeHint which,const QSizeF & constraint) const742 QSizeF 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 - 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("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 */
layout() const806 QGraphicsLayout *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 */
setLayout(QGraphicsLayout * l)831 void 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("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(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 */
adjustSize()864 void QGraphicsWidget::adjustSize()
865 {
866     QSizeF sz = effectiveSizeHint(Qt::PreferredSize);
867     // What if sz is not valid?!
868     if (sz.isValid())
869         resize(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 */
layoutDirection() const898 Qt::LayoutDirection QGraphicsWidget::layoutDirection() const
899 {
900     return testAttribute(Qt::WA_RightToLeft) ? Qt::RightToLeft : Qt::LeftToRight;
901 }
setLayoutDirection(Qt::LayoutDirection direction)902 void QGraphicsWidget::setLayoutDirection(Qt::LayoutDirection direction)
903 {
904     Q_D(QGraphicsWidget);
905     setAttribute(Qt::WA_SetLayoutDirection, true);
906     d->setLayoutDirection_helper(direction);
907 }
unsetLayoutDirection()908 void QGraphicsWidget::unsetLayoutDirection()
909 {
910     Q_D(QGraphicsWidget);
911     setAttribute(Qt::WA_SetLayoutDirection, 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 */
style() const923 QStyle *QGraphicsWidget::style() const
924 {
925     if (QStyle *style = widgetStyles()->styleForWidget(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 */
setStyle(QStyle * style)944 void QGraphicsWidget::setStyle(QStyle *style)
945 {
946     setAttribute(Qt::WA_SetStyle, style != nullptr);
947     widgetStyles()->setStyleForWidget(this, style);
948 
949     // Deliver StyleChange to the widget itself (doesn't propagate).
950     QEvent event(QEvent::StyleChange);
951     QCoreApplication::sendEvent(this, &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 */
font() const976 QFont QGraphicsWidget::font() const
977 {
978     Q_D(const QGraphicsWidget);
979     QFont fnt = d->font;
980     fnt.resolve(fnt.resolve() | d->inheritedFontResolveMask);
981     return fnt;
982 }
setFont(const QFont & font)983 void QGraphicsWidget::setFont(const QFont &font)
984 {
985     Q_D(QGraphicsWidget);
986     setAttribute(Qt::WA_SetFont, 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 */
palette() const1018 QPalette QGraphicsWidget::palette() const
1019 {
1020     Q_D(const QGraphicsWidget);
1021     return d->palette;
1022 }
setPalette(const QPalette & palette)1023 void QGraphicsWidget::setPalette(const QPalette &palette)
1024 {
1025     Q_D(QGraphicsWidget);
1026     setAttribute(Qt::WA_SetPalette, 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 */
autoFillBackground() const1049 bool QGraphicsWidget::autoFillBackground() const
1050 {
1051     Q_D(const QGraphicsWidget);
1052     return d->autoFillBackground;
1053 }
setAutoFillBackground(bool enabled)1054 void 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 */
updateGeometry()1072 void 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(parentWid, 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(static_cast<QGraphicsWidget *>(this), new QEvent(QEvent::LayoutRequest));
1097         }
1098         if (!QGraphicsLayout::instantInvalidatePropagation()) {
1099             bool wasResized = testAttribute(Qt::WA_Resized);
1100             resize(size()); // this will restrict the size
1101             setAttribute(Qt::WA_Resized, 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 */
itemChange(GraphicsItemChange change,const QVariant & value)1126 QVariant 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(this, &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(this, &event);
1141             bool resized = testAttribute(Qt::WA_Resized);
1142             if (!resized) {
1143                 adjustSize();
1144                 setAttribute(Qt::WA_Resized, 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(this, &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(this, &event);
1166         break;
1167     }
1168     case ItemParentHasChanged: {
1169         // Deliver ParentChange.
1170         QEvent event(QEvent::ParentChange);
1171         QCoreApplication::sendEvent(this, &event);
1172         break;
1173     }
1174     case ItemCursorHasChanged: {
1175         // Deliver CursorChange.
1176         QEvent event(QEvent::CursorChange);
1177         QCoreApplication::sendEvent(this, &event);
1178         break;
1179     }
1180     case ItemToolTipHasChanged: {
1181         // Deliver ToolTipChange.
1182         QEvent event(QEvent::ToolTipChange);
1183         QCoreApplication::sendEvent(this, &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 */
propertyChange(const QString & propertyName,const QVariant & value)1218 QVariant 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 */
sceneEvent(QEvent * event)1235 bool 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 */
windowFrameEvent(QEvent * event)1253 bool QGraphicsWidget::windowFrameEvent(QEvent *event)
1254 {
1255     Q_D(QGraphicsWidget);
1256     switch (event->type()) {
1257     case QEvent::GraphicsSceneMousePress:
1258         d->windowFrameMousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1259         break;
1260     case QEvent::GraphicsSceneMouseMove:
1261         d->ensureWindowData();
1262         if (d->windowData->grabbedSection != Qt::NoSection) {
1263             d->windowFrameMouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1264             event->accept();
1265         }
1266         break;
1267     case QEvent::GraphicsSceneMouseRelease:
1268         d->windowFrameMouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
1269         break;
1270     case QEvent::GraphicsSceneHoverMove:
1271         d->windowFrameHoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
1272         break;
1273     case QEvent::GraphicsSceneHoverLeave:
1274         d->windowFrameHoverLeaveEvent(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 */
windowFrameSectionAt(const QPointF & pos) const1300 Qt::WindowFrameSection QGraphicsWidget::windowFrameSectionAt(const QPointF &pos) const
1301 {
1302     Q_D(const QGraphicsWidget);
1303 
1304     const QRectF r = windowFrameRect();
1305     if (!r.contains(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(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 */
event(QEvent * event)1389 bool 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(event);
1395 
1396     // Handle the event itself.
1397     switch (event->type()) {
1398     case QEvent::GraphicsSceneMove:
1399         moveEvent(static_cast<QGraphicsSceneMoveEvent *>(event));
1400         break;
1401     case QEvent::GraphicsSceneResize:
1402         resizeEvent(static_cast<QGraphicsSceneResizeEvent *>(event));
1403         break;
1404     case QEvent::Show:
1405         showEvent(static_cast<QShowEvent *>(event));
1406         break;
1407     case QEvent::Hide:
1408         hideEvent(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(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((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 */
changeEvent(QEvent * event)1490 void 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(d->inheritedFontResolveMask);
1509         d->resolvePalette(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 */
closeEvent(QCloseEvent * event)1523 void QGraphicsWidget::closeEvent(QCloseEvent *event)
1524 {
1525     event->accept();
1526 }
1527 
1528 /*!
1529     \reimp
1530 */
focusInEvent(QFocusEvent * event)1531 void 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 */
focusNextPrevChild(bool next)1557 bool 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 */
focusOutEvent(QFocusEvent * event)1579 void 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 */
hideEvent(QHideEvent * event)1598 void 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 */
moveEvent(QGraphicsSceneMoveEvent * event)1620 void 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 */
polishEvent()1634 void 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 */
resizeEvent(QGraphicsSceneResizeEvent * event)1654 void 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 */
showEvent(QShowEvent * event)1671 void QGraphicsWidget::showEvent(QShowEvent *event)
1672 {
1673     Q_UNUSED(event);
1674 }
1675 
1676 /*!
1677     \reimp
1678 */
hoverMoveEvent(QGraphicsSceneHoverEvent * event)1679 void QGraphicsWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
1680 {
1681     Q_UNUSED(event);
1682 }
1683 
1684 /*!
1685     \reimp
1686 */
hoverLeaveEvent(QGraphicsSceneHoverEvent * event)1687 void 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 */
grabMouseEvent(QEvent * event)1698 void 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 */
ungrabMouseEvent(QEvent * event)1709 void 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 */
grabKeyboardEvent(QEvent * event)1720 void 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 */
ungrabKeyboardEvent(QEvent * event)1731 void 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 */
windowType() const1741 Qt::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 */
windowFlags() const1763 Qt::WindowFlags QGraphicsWidget::windowFlags() const
1764 {
1765     Q_D(const QGraphicsWidget);
1766     return d->windowFlags;
1767 }
setWindowFlags(Qt::WindowFlags wFlags)1768 void 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);
1776     d->windowFlags = wFlags;
1777     if (!d->setWindowFrameMargins)
1778         unsetWindowFrameMargins();
1779 
1780     setFlag(ItemIsPanel, 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(this);
1787         else
1788             d->scene->d_func()->addPopup(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 */
isActiveWindow() const1807 bool 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 */
setWindowTitle(const QString & title)1821 void QGraphicsWidget::setWindowTitle(const QString &title)
1822 {
1823     Q_D(QGraphicsWidget);
1824     d->ensureWindowData();
1825     d->windowData->windowTitle = title;
1826 }
windowTitle() const1827 QString 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 */
focusPolicy() const1853 Qt::FocusPolicy QGraphicsWidget::focusPolicy() const
1854 {
1855     Q_D(const QGraphicsWidget);
1856     return d->focusPolicy;
1857 }
setFocusPolicy(Qt::FocusPolicy policy)1858 void 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(ItemIsFocusable, 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 */
focusWidget() const1876 QGraphicsWidget *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 */
grabShortcut(const QKeySequence & sequence,Qt::ShortcutContext context)1912 int 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(this, sequence, context, 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 */
releaseShortcut(int id)1938 void QGraphicsWidget::releaseShortcut(int id)
1939 {
1940     Q_ASSERT(qApp);
1941     if (id)
1942         QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(id, this, 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 */
setShortcutEnabled(int id,bool enabled)1959 void QGraphicsWidget::setShortcutEnabled(int id, bool enabled)
1960 {
1961     Q_ASSERT(qApp);
1962     if (id)
1963         QGuiApplicationPrivate::instance()->shortcutMap.setShortcutEnabled(enabled, id, this, 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 */
setShortcutAutoRepeat(int id,bool enabled)1974 void QGraphicsWidget::setShortcutAutoRepeat(int id, bool enabled)
1975 {
1976     Q_ASSERT(qApp);
1977     if (id)
1978         QGuiApplicationPrivate::instance()->shortcutMap.setShortcutAutoRepeat(enabled, id, this, 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 */
addAction(QAction * action)1997 void QGraphicsWidget::addAction(QAction *action)
1998 {
1999     insertAction(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)
addActions(const QList<QAction * > & actions)2010 void QGraphicsWidget::addActions(const QList<QAction *> &actions)
2011 #else
2012 void QGraphicsWidget::addActions(QList<QAction *> actions)
2013 #endif
2014 {
2015     for (int i = 0; i < actions.count(); ++i)
2016         insertAction(nullptr, 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 */
insertAction(QAction * before,QAction * action)2031 void QGraphicsWidget::insertAction(QAction *before, QAction *action)
2032 {
2033     if (!action) {
2034         qWarning("QWidget::insertAction: Attempt to insert null action");
2035         return;
2036     }
2037 
2038     Q_D(QGraphicsWidget);
2039     int index = d->actions.indexOf(action);
2040     if (index != -1)
2041         d->actions.removeAt(index);
2042 
2043     int pos = d->actions.indexOf(before);
2044     if (pos < 0) {
2045         before = nullptr;
2046         pos = d->actions.size();
2047     }
2048     d->actions.insert(pos, action);
2049 
2050     if (index == -1) {
2051         QActionPrivate *apriv = action->d_func();
2052         apriv->graphicsWidgets.append(this);
2053     }
2054 
2055     QActionEvent e(QEvent::ActionAdded, action, before);
2056     QCoreApplication::sendEvent(this, &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)
insertActions(QAction * before,const QList<QAction * > & actions)2071 void QGraphicsWidget::insertActions(QAction *before, const QList<QAction *> &actions)
2072 #else
2073 void QGraphicsWidget::insertActions(QAction *before, QList<QAction *> actions)
2074 #endif
2075 {
2076     for (int i = 0; i < actions.count(); ++i)
2077         insertAction(before, 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 */
removeAction(QAction * action)2087 void 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(this);
2096 
2097     if (d->actions.removeAll(action)) {
2098         QActionEvent e(QEvent::ActionRemoved, action);
2099         QCoreApplication::sendEvent(this, &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 */
actions() const2111 QList<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 */
setTabOrder(QGraphicsWidget * first,QGraphicsWidget * second)2142 void QGraphicsWidget::setTabOrder(QGraphicsWidget *first, QGraphicsWidget *second)
2143 {
2144     if (!first && !second) {
2145         qWarning("QGraphicsWidget::setTabOrder(0, 0) is undefined");
2146         return;
2147     }
2148     if ((first && second) && first->scene() != second->scene()) {
2149         qWarning("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("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 */
setAttribute(Qt::WidgetAttribute attribute,bool on)2207 void 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(attribute, 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 */
testAttribute(Qt::WidgetAttribute attribute) const2222 bool QGraphicsWidget::testAttribute(Qt::WidgetAttribute attribute) const
2223 {
2224     Q_D(const QGraphicsWidget);
2225     return d->testAttribute(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 */
type() const2239 int QGraphicsWidget::type() const
2240 {
2241     return Type;
2242 }
2243 
2244 /*!
2245     \reimp
2246 */
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)2247 void 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 */
paintWindowFrame(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)2265 void QGraphicsWidget::paintWindowFrame(QPainter *painter, const QStyleOptionGraphicsItem *option,
2266                                        QWidget *widget)
2267 {
2268     const bool fillBackground = !testAttribute(Qt::WA_OpaquePaintEvent)
2269                                 && !testAttribute(Qt::WA_NoSystemBackground);
2270     QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(this);
2271     const bool embeddedWidgetFillsOwnBackground = proxy && proxy->widget();
2272 
2273     if (rect().contains(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=(*option);
2284     d->initStyleOptionTitleBar(&bar);   // this clear flags in bar.state
2285     d->ensureWindowData();
2286     bar.state.setFlag(QStyle::State_MouseOver, d->windowData->buttonMouseOver);
2287     bar.state.setFlag(QStyle::State_Sunken, 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(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(QStyle::SH_WindowFrame_Mask, &bar, widget, &mask) && !mask.region.isEmpty();
2306     bool hasBorder = !style()->styleHint(QStyle::SH_TitleBar_NoBorder, &bar, widget);
2307     int frameWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, &bar, widget);
2308     if (setMask) {
2309         painter->save();
2310         painter->setClipRegion(mask.region, Qt::IntersectClip);
2311     }
2312     if (fillBackground) {
2313         if (embeddedWidgetFillsOwnBackground) {
2314             // Don't fill the background twice.
2315             QPainterPath windowFrameBackground;
2316             windowFrameBackground.addRect(windowFrameRect);
2317             // Adjust with 0.5 to avoid border artifacts between
2318             // widget background and frame background.
2319             windowFrameBackground.addRect(rect().translated(-styleOrigin).adjusted(0.5, 0.5, -0.5, -0.5));
2320             painter->fillPath(windowFrameBackground, palette().window());
2321         } else {
2322             painter->fillRect(windowFrameRect, palette().window());
2323         }
2324     }
2325 
2326     // Draw title
2327     int height = (int)d->titleBarHeight(bar);
2328     bar.rect.setHeight(height);
2329     if (hasBorder) // Frame is painted by PE_FrameWindow
2330         bar.rect.adjust(frameWidth, frameWidth, -frameWidth, 0);
2331 
2332     painter->save();
2333     painter->setFont(QApplication::font("QMdiSubWindowTitleBar"));
2334     style()->drawComplexControl(QStyle::CC_TitleBar, &bar, painter, widget);
2335     painter->restore();
2336     if (setMask)
2337         painter->restore();
2338     // Draw window frame
2339     QStyleOptionFrame frameOptions;
2340     frameOptions.QStyleOption::operator=(*option);
2341     initStyleOption(&frameOptions);
2342     if (!hasBorder)
2343         painter->setClipRect(windowFrameRect.adjusted(0, +height, 0, 0), Qt::IntersectClip);
2344     frameOptions.state.setFlag(QStyle::State_HasFocus, hasFocus());
2345     bool isActive = isActiveWindow();
2346     frameOptions.state.setFlag(QStyle::State_Active, isActive);
2347 
2348     frameOptions.palette.setCurrentColorGroup(isActive ? QPalette::Active : QPalette::Normal);
2349     frameOptions.rect = windowFrameRect;
2350     frameOptions.lineWidth = style()->pixelMetric(QStyle::PM_MdiSubWindowFrameWidth, nullptr, widget);
2351     frameOptions.midLineWidth = 1;
2352     style()->drawPrimitive(QStyle::PE_FrameWindow, &frameOptions, painter, widget);
2353 
2354 #ifdef Q_OS_MAC
2355     realPainter->drawPixmap(QPoint(), pm);
2356     delete painter;
2357 #endif
2358 }
2359 
2360 /*!
2361     \reimp
2362 */
boundingRect() const2363 QRectF QGraphicsWidget::boundingRect() const
2364 {
2365     return windowFrameRect();
2366 }
2367 
2368 /*!
2369     \reimp
2370 */
shape() const2371 QPainterPath QGraphicsWidget::shape() const
2372 {
2373     QPainterPath path;
2374     path.addRect(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 */
close()2389 bool QGraphicsWidget::close()
2390 {
2391     QCloseEvent closeEvent;
2392     QCoreApplication::sendEvent(this, &closeEvent);
2393     if (!closeEvent.isAccepted()) {
2394         return false;
2395     }
2396     // hide
2397     if (isVisible()) {
2398         hide();
2399     }
2400     if (testAttribute(Qt::WA_DeleteOnClose)) {
2401         deleteLater();
2402     }
2403     return true;
2404 }
2405 
2406 #if 0
2407 void 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 
2429 QT_END_NAMESPACE
2430 
2431 #include "moc_qgraphicswidget.cpp"
2432