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