mirror of
https://bitbucket.org/smil3y/katie.git
synced 2025-02-27 12:22:57 +00:00
1510 lines
50 KiB
C++
1510 lines
50 KiB
C++
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the QtGui module of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** GNU General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
** General Public License version 3.0 as published by the Free Software
|
|
** Foundation and appearing in the file LICENSE.GPL included in the
|
|
** packaging of this file. Please review the following information to
|
|
** ensure the GNU General Public License version 3.0 requirements will be
|
|
** met: http://www.gnu.org/copyleft/gpl.html.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "qglobal.h"
|
|
|
|
#ifndef QT_NO_GRAPHICSVIEW
|
|
|
|
#include "qgraphicslayout.h"
|
|
#include "qgraphicsproxywidget.h"
|
|
#include "qgraphicsproxywidget_p.h"
|
|
#include "qwidget_p.h"
|
|
#include "qapplication_p.h"
|
|
|
|
#include <QtCore/qdebug.h>
|
|
#include <QtGui/qevent.h>
|
|
#include <QtGui/qgraphicsscene.h>
|
|
#include <QtGui/qgraphicssceneevent.h>
|
|
#include <QtGui/qlayout.h>
|
|
#include <QtGui/qpainter.h>
|
|
#include <QtGui/qstyleoption.h>
|
|
#include <QtGui/qgraphicsview.h>
|
|
#include <QtGui/qlistview.h>
|
|
#include <QtGui/qlineedit.h>
|
|
#include <QtGui/qtextedit.h>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
//#define GRAPHICSPROXYWIDGET_DEBUG
|
|
|
|
/*!
|
|
\class QGraphicsProxyWidget
|
|
\brief The QGraphicsProxyWidget class provides a proxy layer for embedding
|
|
a QWidget in a QGraphicsScene.
|
|
\since 4.4
|
|
\ingroup graphicsview-api
|
|
|
|
QGraphicsProxyWidget embeds QWidget-based widgets, for example, a
|
|
QPushButton, QFontComboBox, or even QFileDialog, into
|
|
QGraphicsScene. It forwards events between the two objects and
|
|
translates between QWidget's integer-based geometry and
|
|
QGraphicsWidget's qreal-based geometry. QGraphicsProxyWidget
|
|
supports all core features of QWidget, including tab focus,
|
|
keyboard input, Drag & Drop, and popups. You can also embed
|
|
complex widgets, e.g., widgets with subwidgets.
|
|
|
|
Example:
|
|
|
|
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 0
|
|
|
|
QGraphicsProxyWidget takes care of automatically embedding popup children
|
|
of embedded widgets through creating a child proxy for each popup. This
|
|
means that when an embedded QComboBox shows its popup list, a new
|
|
QGraphicsProxyWidget is created automatically, embedding the popup, and
|
|
positioning it correctly. This only works if the popup is child of the
|
|
embedded widget (for example QToolButton::setMenu() requires the QMenu instance
|
|
to be child of the QToolButton).
|
|
|
|
\section1 Embedding a Widget with QGraphicsProxyWidget
|
|
|
|
There are two ways to embed a widget using QGraphicsProxyWidget. The most
|
|
common way is to pass a widget pointer to QGraphicsScene::addWidget()
|
|
together with any relevant \l Qt::WindowFlags. This function returns a
|
|
pointer to a QGraphicsProxyWidget. You can then choose to reparent or
|
|
position either the proxy, or the embedded widget itself.
|
|
|
|
For example, in the code snippet below, we embed a group box into the proxy:
|
|
|
|
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 1
|
|
|
|
The image below is the output obtained with its contents margin and
|
|
contents rect labeled.
|
|
|
|
\image qgraphicsproxywidget-embed.png
|
|
|
|
Alternatively, you can start by creating a new QGraphicsProxyWidget item,
|
|
and then call setWidget() to embed a QWidget later. The widget() function
|
|
returns a pointer to the embedded widget. QGraphicsProxyWidget shares
|
|
ownership with QWidget, so if either of the two widgets are destroyed, the
|
|
other widget will be automatically destroyed as well.
|
|
|
|
\section1 Synchronizing Widget States
|
|
|
|
QGraphicsProxyWidget keeps its state in sync with the embedded widget. For
|
|
example, if the proxy is hidden or disabled, the embedded widget will be
|
|
hidden or disabled as well, and vice versa. When the widget is embedded by
|
|
calling addWidget(), QGraphicsProxyWidget copies the state from the widget
|
|
into the proxy, and after that, the two will stay synchronized where
|
|
possible. By default, when you embed a widget into a proxy, both the widget
|
|
and the proxy will be visible because a QGraphicsWidget is visible when
|
|
created (you do not have to call show()). If you explicitly hide the
|
|
embedded widget, the proxy will also become invisible.
|
|
|
|
Example:
|
|
|
|
\snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsproxywidget.cpp 2
|
|
|
|
QGraphicsProxyWidget maintains symmetry for the following states:
|
|
|
|
\table
|
|
\header \o QWidget state \o QGraphicsProxyWidget state \o Notes
|
|
\row \o QWidget::enabled
|
|
\o QGraphicsProxyWidget::enabled
|
|
\o
|
|
\row \o QWidget::visible
|
|
\o QGraphicsProxyWidget::visible
|
|
\o The explicit state is also symmetric.
|
|
\row \o QWidget::geometry
|
|
\o QGraphicsProxyWidget::geometry
|
|
\o Geometry is only guaranteed to be symmetric while
|
|
the embedded widget is visible.
|
|
\row \o QWidget::layoutDirection
|
|
\o QGraphicsProxyWidget::layoutDirection
|
|
\o
|
|
\row \o QWidget::style
|
|
\o QGraphicsProxyWidget::style
|
|
\o
|
|
\row \o QWidget::palette
|
|
\o QGraphicsProxyWidget::palette
|
|
\o
|
|
\row \o QWidget::font
|
|
\o QGraphicsProxyWidget::font
|
|
\o
|
|
\row \o QWidget::cursor
|
|
\o QGraphicsProxyWidget::cursor
|
|
\o The embedded widget overrides the proxy widget
|
|
cursor. The proxy cursor changes depending on
|
|
which embedded subwidget is currently under the
|
|
mouse.
|
|
\row \o QWidget::sizeHint()
|
|
\o QGraphicsProxyWidget::sizeHint()
|
|
\o All size hint functionality from the embedded
|
|
widget is forwarded by the proxy.
|
|
\row \o QWidget::getContentsMargins()
|
|
\o QGraphicsProxyWidget::getContentsMargins()
|
|
\o Updated once by setWidget().
|
|
\row \o QWidget::windowTitle
|
|
\o QGraphicsProxyWidget::windowTitle
|
|
\o Updated once by setWidget().
|
|
\endtable
|
|
|
|
\note QGraphicsScene keeps the embedded widget in a special state that
|
|
prevents it from disturbing other widgets (both embedded and not embedded)
|
|
while the widget is embedded. In this state, the widget may differ slightly
|
|
in behavior from when it is not embedded.
|
|
|
|
\warning This class is provided for convenience when bridging
|
|
QWidgets and QGraphicsItems, it should not be used for
|
|
high-performance scenarios.
|
|
|
|
\sa QGraphicsScene::addWidget(), QGraphicsWidget
|
|
*/
|
|
|
|
extern bool qt_sendSpontaneousEvent(QObject *, QEvent *);
|
|
Q_GUI_EXPORT extern bool qt_tab_all_widgets;
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::init()
|
|
{
|
|
Q_Q(QGraphicsProxyWidget);
|
|
q->setFocusPolicy(Qt::WheelFocus);
|
|
q->setAcceptDrops(true);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
QGraphicsSceneMouseEvent mouseEvent(QEvent::GraphicsSceneMouseMove);
|
|
mouseEvent.setPos(event->pos());
|
|
mouseEvent.setScreenPos(event->screenPos());
|
|
mouseEvent.setButton(Qt::NoButton);
|
|
mouseEvent.setButtons(0);
|
|
mouseEvent.setModifiers(event->modifiers());
|
|
sendWidgetMouseEvent(&mouseEvent);
|
|
event->setAccepted(mouseEvent.isAccepted());
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::sendWidgetMouseEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
if (!event || !widget || !widget->isVisible())
|
|
return;
|
|
Q_Q(QGraphicsProxyWidget);
|
|
|
|
// Find widget position and receiver.
|
|
QPointF pos = event->pos();
|
|
QPointer<QWidget> alienWidget = widget->childAt(pos.toPoint());
|
|
QPointer<QWidget> receiver = alienWidget ? alienWidget : widget;
|
|
|
|
if (QWidgetPrivate::nearestGraphicsProxyWidget(receiver) != q)
|
|
return; //another proxywidget will handle the events
|
|
|
|
// Translate QGraphicsSceneMouse events to QMouseEvents.
|
|
QEvent::Type type = QEvent::None;
|
|
switch (event->type()) {
|
|
case QEvent::GraphicsSceneMousePress:
|
|
type = QEvent::MouseButtonPress;
|
|
if (!embeddedMouseGrabber)
|
|
embeddedMouseGrabber = receiver;
|
|
else
|
|
receiver = embeddedMouseGrabber;
|
|
break;
|
|
case QEvent::GraphicsSceneMouseRelease:
|
|
type = QEvent::MouseButtonRelease;
|
|
if (embeddedMouseGrabber)
|
|
receiver = embeddedMouseGrabber;
|
|
break;
|
|
case QEvent::GraphicsSceneMouseDoubleClick:
|
|
type = QEvent::MouseButtonDblClick;
|
|
if (!embeddedMouseGrabber)
|
|
embeddedMouseGrabber = receiver;
|
|
else
|
|
receiver = embeddedMouseGrabber;
|
|
break;
|
|
case QEvent::GraphicsSceneMouseMove:
|
|
type = QEvent::MouseMove;
|
|
if (embeddedMouseGrabber)
|
|
receiver = embeddedMouseGrabber;
|
|
break;
|
|
default:
|
|
Q_ASSERT_X(false, "QGraphicsProxyWidget", "internal error");
|
|
break;
|
|
}
|
|
|
|
if (!lastWidgetUnderMouse) {
|
|
QApplicationPrivate::dispatchEnterLeave(embeddedMouseGrabber ? embeddedMouseGrabber : receiver, 0);
|
|
lastWidgetUnderMouse = receiver;
|
|
}
|
|
|
|
// Map event position from us to the receiver
|
|
pos = mapToReceiver(pos, receiver);
|
|
|
|
// Send mouse event.
|
|
QMouseEvent *mouseEvent = QMouseEvent::createExtendedMouseEvent(type, pos,
|
|
receiver->mapToGlobal(pos.toPoint()), event->button(),
|
|
event->buttons(), event->modifiers());
|
|
|
|
QWidget *embeddedMouseGrabberPtr = (QWidget *)embeddedMouseGrabber;
|
|
QApplicationPrivate::sendMouseEvent(receiver, mouseEvent, alienWidget, widget,
|
|
&embeddedMouseGrabberPtr, lastWidgetUnderMouse, event->spontaneous());
|
|
embeddedMouseGrabber = embeddedMouseGrabberPtr;
|
|
|
|
// Handle enter/leave events when last button is released from mouse
|
|
// grabber child widget.
|
|
if (embeddedMouseGrabber && type == QEvent::MouseButtonRelease && !event->buttons()) {
|
|
Q_Q(QGraphicsProxyWidget);
|
|
if (q->rect().contains(event->pos()) && q->acceptHoverEvents())
|
|
lastWidgetUnderMouse = alienWidget ? alienWidget : widget;
|
|
else // released on the frame our outside the item, or doesn't accept hover events.
|
|
lastWidgetUnderMouse = 0;
|
|
|
|
QApplicationPrivate::dispatchEnterLeave(lastWidgetUnderMouse, embeddedMouseGrabber);
|
|
embeddedMouseGrabber = 0;
|
|
|
|
#ifndef QT_NO_CURSOR
|
|
// ### Restore the cursor, don't override it.
|
|
if (!lastWidgetUnderMouse)
|
|
q->unsetCursor();
|
|
#endif
|
|
}
|
|
|
|
event->setAccepted(mouseEvent->isAccepted());
|
|
delete mouseEvent;
|
|
}
|
|
|
|
void QGraphicsProxyWidgetPrivate::sendWidgetKeyEvent(QKeyEvent *event)
|
|
{
|
|
Q_Q(QGraphicsProxyWidget);
|
|
if (!event || !widget || !widget->isVisible())
|
|
return;
|
|
|
|
QPointer<QWidget> receiver = widget->focusWidget();
|
|
if (!receiver)
|
|
receiver = widget;
|
|
Q_ASSERT(receiver);
|
|
|
|
do {
|
|
bool res = QApplication::sendEvent(receiver, event);
|
|
if ((res && event->isAccepted()) || (q->isWindow() && receiver == widget))
|
|
break;
|
|
receiver = receiver->parentWidget();
|
|
} while (receiver);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::removeSubFocusHelper(QWidget *widget, Qt::FocusReason reason)
|
|
{
|
|
QFocusEvent event(QEvent::FocusOut, reason);
|
|
QPointer<QWidget> widgetGuard = widget;
|
|
QApplication::sendEvent(widget, &event);
|
|
if (widgetGuard && event.isAccepted())
|
|
QApplication::sendEvent(widget->style(), &event);
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper
|
|
*/
|
|
QWidget *QGraphicsProxyWidgetPrivate::findFocusChild(QWidget *child, bool next) const
|
|
{
|
|
if (!widget)
|
|
return 0;
|
|
|
|
// Run around the focus chain until we find a widget that can take tab focus.
|
|
if (!child) {
|
|
child = next ? (QWidget *)widget : widget->d_func()->focus_prev;
|
|
} else {
|
|
child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
|
|
if ((next && child == widget) || (!next && child == widget->d_func()->focus_prev)) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
QWidget *oldChild = child;
|
|
uint focus_flag = qt_tab_all_widgets ? Qt::TabFocus : Qt::StrongFocus;
|
|
do {
|
|
if (child->isEnabled()
|
|
&& child->isVisibleTo(widget)
|
|
&& ((child->focusPolicy() & focus_flag) == focus_flag)
|
|
&& !(child->d_func()->extra && child->d_func()->extra->focus_proxy)) {
|
|
return child;
|
|
}
|
|
child = next ? child->d_func()->focus_next : child->d_func()->focus_prev;
|
|
} while (child != oldChild && !(next && child == widget) && !(!next && child == widget->d_func()->focus_prev));
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::_q_removeWidgetSlot()
|
|
{
|
|
Q_Q(QGraphicsProxyWidget);
|
|
if (!widget.isNull()) {
|
|
if (QWExtra *extra = widget->d_func()->extra)
|
|
extra->proxyWidget = 0;
|
|
}
|
|
widget = 0;
|
|
delete q;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::updateWidgetGeometryFromProxy()
|
|
{
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::updateProxyGeometryFromWidget()
|
|
{
|
|
Q_Q(QGraphicsProxyWidget);
|
|
if (!widget)
|
|
return;
|
|
|
|
QRectF widgetGeometry = widget->geometry();
|
|
QWidget *parentWidget = widget->parentWidget();
|
|
if (widget->isWindow()) {
|
|
QGraphicsProxyWidget *proxyParent = 0;
|
|
if (parentWidget && (proxyParent = qobject_cast<QGraphicsProxyWidget *>(q->parentWidget()))) {
|
|
// Nested window proxy (e.g., combobox popup), map widget to the
|
|
// parent widget's global coordinates, and map that to the parent
|
|
// proxy's child coordinates.
|
|
widgetGeometry.moveTo(proxyParent->subWidgetRect(parentWidget).topLeft()
|
|
+ parentWidget->mapFromGlobal(widget->pos()));
|
|
}
|
|
}
|
|
|
|
// Adjust to size hint if the widget has never been resized.
|
|
if (!widget->size().isValid())
|
|
widgetGeometry.setSize(widget->sizeHint());
|
|
|
|
// Assign new geometry.
|
|
posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
q->setGeometry(widgetGeometry);
|
|
posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
|
|
Embeds \a subWin as a subwindow of this proxy widget. \a subWin must be a top-level
|
|
widget and a descendant of the widget managed by this proxy. A separate subproxy
|
|
will be created as a child of this proxy widget to manage \a subWin.
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::embedSubWindow(QWidget *subWin)
|
|
{
|
|
QWExtra *extra;
|
|
if (!((extra = subWin->d_func()->extra) && extra->proxyWidget)) {
|
|
QGraphicsProxyWidget *subProxy = new QGraphicsProxyWidget(q_func(), subWin->windowFlags());
|
|
subProxy->d_func()->setWidget_helper(subWin, false);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
|
|
Removes ("unembeds") \a subWin and deletes the proxy holder item. This can
|
|
happen when QWidget::setParent() reparents the embedded window out of
|
|
"embedded space".
|
|
*/
|
|
void QGraphicsProxyWidgetPrivate::unembedSubWindow(QWidget *subWin)
|
|
{
|
|
foreach (QGraphicsItem *child, children) {
|
|
if (child->isWidget()) {
|
|
if (QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(child))) {
|
|
if (proxy->widget() == subWin) {
|
|
proxy->setWidget(0);
|
|
scene->removeItem(proxy);
|
|
delete proxy;
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool QGraphicsProxyWidgetPrivate::isProxyWidget() const
|
|
{
|
|
return true;
|
|
}
|
|
|
|
/*!
|
|
\internal
|
|
*/
|
|
QPointF QGraphicsProxyWidgetPrivate::mapToReceiver(const QPointF &pos, const QWidget *receiver) const
|
|
{
|
|
QPointF p = pos;
|
|
// Map event position from us to the receiver, preserving its
|
|
// precision (don't use QWidget::mapFrom here).
|
|
while (receiver && receiver != widget) {
|
|
p -= QPointF(receiver->pos());
|
|
receiver = receiver->parentWidget();
|
|
}
|
|
return p;
|
|
}
|
|
|
|
/*!
|
|
Constructs a new QGraphicsProxy widget. \a parent and \a wFlags are passed
|
|
to QGraphicsItem's constructor.
|
|
*/
|
|
QGraphicsProxyWidget::QGraphicsProxyWidget(QGraphicsItem *parent, Qt::WindowFlags wFlags)
|
|
: QGraphicsWidget(*new QGraphicsProxyWidgetPrivate, parent, 0, wFlags)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
d->init();
|
|
}
|
|
|
|
/*!
|
|
Destroys the proxy widget and any embedded widget.
|
|
*/
|
|
QGraphicsProxyWidget::~QGraphicsProxyWidget()
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (d->widget) {
|
|
QObject::disconnect(d->widget, SIGNAL(destroyed()), this, SLOT(_q_removeWidgetSlot()));
|
|
delete d->widget;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
Embeds \a widget into this proxy widget. The embedded widget must reside
|
|
exclusively either inside or outside of Graphics View. You cannot embed a
|
|
widget as long as it is is visible elsewhere in the UI, at the same time.
|
|
|
|
\a widget must be a top-level widget whose parent is 0.
|
|
|
|
When the widget is embedded, its state (e.g., visible, enabled, geometry,
|
|
size hints) is copied into the proxy widget. If the embedded widget is
|
|
explicitly hidden or disabled, the proxy widget will become explicitly
|
|
hidden or disabled after embedding is complete. The class documentation
|
|
has a full overview over the shared state.
|
|
|
|
QGraphicsProxyWidget's window flags determine whether the widget, after
|
|
embedding, will be given window decorations or not.
|
|
|
|
After this function returns, QGraphicsProxyWidget will keep its state
|
|
synchronized with that of \a widget whenever possible.
|
|
|
|
If a widget is already embedded by this proxy when this function is
|
|
called, that widget will first be automatically unembedded. Passing 0 for
|
|
the \a widget argument will only unembed the widget, and the ownership of
|
|
the currently embedded widget will be passed on to the caller.
|
|
Every child widget that are embedded will also be embedded and their proxy
|
|
widget destroyed.
|
|
|
|
Note that widgets with the Qt::WA_PaintOnScreen widget attribute
|
|
set and widgets that wrap an external application or controller
|
|
cannot be embedded.
|
|
|
|
\sa widget()
|
|
*/
|
|
void QGraphicsProxyWidget::setWidget(QWidget *widget)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
d->setWidget_helper(widget, true);
|
|
}
|
|
|
|
void QGraphicsProxyWidgetPrivate::setWidget_helper(QWidget *newWidget, bool autoShow)
|
|
{
|
|
Q_Q(QGraphicsProxyWidget);
|
|
if (newWidget == widget)
|
|
return;
|
|
if (widget) {
|
|
QObject::disconnect(widget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
|
|
widget->removeEventFilter(q);
|
|
widget->setAttribute(Qt::WA_DontShowOnScreen, false);
|
|
widget->d_func()->extra->proxyWidget = 0;
|
|
resolveFont(inheritedFontResolveMask);
|
|
resolvePalette(inheritedPaletteResolveMask);
|
|
widget->update();
|
|
|
|
foreach (QGraphicsItem *child, q->childItems()) {
|
|
if (child->d_ptr->isProxyWidget()) {
|
|
QGraphicsProxyWidget *childProxy = static_cast<QGraphicsProxyWidget *>(child);
|
|
QWidget * parent = childProxy->widget();
|
|
while (parent->parentWidget() != 0) {
|
|
if (parent == widget)
|
|
break;
|
|
parent = parent->parentWidget();
|
|
}
|
|
if (!childProxy->widget() || parent != widget)
|
|
continue;
|
|
childProxy->setWidget(0);
|
|
delete childProxy;
|
|
}
|
|
}
|
|
|
|
widget = 0;
|
|
#ifndef QT_NO_CURSOR
|
|
q->unsetCursor();
|
|
#endif
|
|
q->setAcceptHoverEvents(false);
|
|
if (!newWidget)
|
|
q->update();
|
|
}
|
|
if (!newWidget)
|
|
return;
|
|
if (!newWidget->isWindow()) {
|
|
QWExtra *extra = newWidget->parentWidget()->d_func()->extra;
|
|
if (!extra || !extra->proxyWidget) {
|
|
qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p "
|
|
"which is not a toplevel widget, and is not a child of an embedded widget", newWidget);
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Register this proxy within the widget's private.
|
|
// ### This is a bit backdoorish
|
|
QWExtra *extra = newWidget->d_func()->extra;
|
|
if (!extra) {
|
|
newWidget->d_func()->createExtra();
|
|
extra = newWidget->d_func()->extra;
|
|
}
|
|
QGraphicsProxyWidget **proxyWidget = &extra->proxyWidget;
|
|
if (*proxyWidget) {
|
|
if (*proxyWidget != q) {
|
|
qWarning("QGraphicsProxyWidget::setWidget: cannot embed widget %p"
|
|
"; already embedded", newWidget);
|
|
}
|
|
return;
|
|
}
|
|
*proxyWidget = q;
|
|
|
|
newWidget->setAttribute(Qt::WA_DontShowOnScreen);
|
|
newWidget->ensurePolished();
|
|
// Do not wait for this widget to close before the app closes ###
|
|
// shouldn't this widget inherit the attribute?
|
|
newWidget->setAttribute(Qt::WA_QuitOnClose, false);
|
|
q->setAcceptHoverEvents(true);
|
|
|
|
if (newWidget->testAttribute(Qt::WA_NoSystemBackground))
|
|
q->setAttribute(Qt::WA_NoSystemBackground);
|
|
if (newWidget->testAttribute(Qt::WA_OpaquePaintEvent))
|
|
q->setAttribute(Qt::WA_OpaquePaintEvent);
|
|
|
|
widget = newWidget;
|
|
|
|
// Changes only go from the widget to the proxy.
|
|
enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
posChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
sizeChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
|
|
if ((autoShow && !newWidget->testAttribute(Qt::WA_WState_ExplicitShowHide)) || !newWidget->testAttribute(Qt::WA_WState_Hidden)) {
|
|
newWidget->show();
|
|
}
|
|
|
|
// Copy the state from the widget onto the proxy.
|
|
#ifndef QT_NO_CURSOR
|
|
if (newWidget->testAttribute(Qt::WA_SetCursor))
|
|
q->setCursor(widget->cursor());
|
|
#endif
|
|
q->setEnabled(newWidget->isEnabled());
|
|
q->setVisible(newWidget->isVisible());
|
|
q->setLayoutDirection(newWidget->layoutDirection());
|
|
if (newWidget->testAttribute(Qt::WA_SetStyle))
|
|
q->setStyle(widget->style());
|
|
|
|
resolveFont(inheritedFontResolveMask);
|
|
resolvePalette(inheritedPaletteResolveMask);
|
|
|
|
if (!newWidget->testAttribute(Qt::WA_Resized))
|
|
newWidget->adjustSize();
|
|
|
|
int left, top, right, bottom;
|
|
newWidget->getContentsMargins(&left, &top, &right, &bottom);
|
|
q->setContentsMargins(left, top, right, bottom);
|
|
q->setWindowTitle(newWidget->windowTitle());
|
|
|
|
// size policies and constraints..
|
|
q->setSizePolicy(newWidget->sizePolicy());
|
|
QSize sz = newWidget->minimumSize();
|
|
q->setMinimumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
|
|
sz = newWidget->maximumSize();
|
|
q->setMaximumSize(sz.isNull() ? QSizeF() : QSizeF(sz));
|
|
|
|
updateProxyGeometryFromWidget();
|
|
|
|
// Hook up the event filter to keep the state up to date.
|
|
newWidget->installEventFilter(q);
|
|
QObject::connect(newWidget, SIGNAL(destroyed()), q, SLOT(_q_removeWidgetSlot()));
|
|
|
|
// Changes no longer go only from the widget to the proxy.
|
|
enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
|
|
/*!
|
|
Returns a pointer to the embedded widget.
|
|
|
|
\sa setWidget()
|
|
*/
|
|
QWidget *QGraphicsProxyWidget::widget() const
|
|
{
|
|
Q_D(const QGraphicsProxyWidget);
|
|
return d->widget;
|
|
}
|
|
|
|
/*!
|
|
Returns the rectangle for \a widget, which must be a descendant of
|
|
widget(), or widget() itself, in this proxy item's local coordinates.
|
|
|
|
If no widget is embedded, \a widget is 0, or \a widget is not a
|
|
descendant of the embedded widget, this function returns an empty QRectF.
|
|
|
|
\sa widget()
|
|
*/
|
|
QRectF QGraphicsProxyWidget::subWidgetRect(const QWidget *widget) const
|
|
{
|
|
Q_D(const QGraphicsProxyWidget);
|
|
if (!widget || !d->widget)
|
|
return QRectF();
|
|
if (d->widget == widget || d->widget->isAncestorOf(widget))
|
|
return QRectF(widget->mapTo(d->widget, QPoint(0, 0)), widget->size());
|
|
return QRectF();
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::setGeometry(const QRectF &rect)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
bool proxyResizesWidget = !d->posChangeMode && !d->sizeChangeMode;
|
|
if (proxyResizesWidget) {
|
|
d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
d->sizeChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
}
|
|
QGraphicsWidget::setGeometry(rect);
|
|
if (proxyResizesWidget) {
|
|
d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
d->sizeChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
QVariant QGraphicsProxyWidget::itemChange(GraphicsItemChange change,
|
|
const QVariant &value)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
|
|
switch (change) {
|
|
case ItemPositionChange:
|
|
// The item's position is either changed directly on the proxy, in
|
|
// which case the position change should propagate to the widget,
|
|
// otherwise it happens as a side effect when filtering QEvent::Move.
|
|
if (!d->posChangeMode)
|
|
d->posChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
break;
|
|
case ItemPositionHasChanged:
|
|
// Move the internal widget if we're in widget-to-proxy
|
|
// mode. Otherwise the widget has already moved.
|
|
if (d->widget && d->posChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
|
|
d->widget->move(value.toPoint());
|
|
if (d->posChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
|
|
d->posChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
break;
|
|
case ItemVisibleChange:
|
|
if (!d->visibleChangeMode)
|
|
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
break;
|
|
case ItemVisibleHasChanged:
|
|
if (d->widget && d->visibleChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
|
|
d->widget->setVisible(isVisible());
|
|
if (d->visibleChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
|
|
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
break;
|
|
case ItemEnabledChange:
|
|
if (!d->enabledChangeMode)
|
|
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
break;
|
|
case ItemEnabledHasChanged:
|
|
if (d->widget && d->enabledChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
|
|
d->widget->setEnabled(isEnabled());
|
|
if (d->enabledChangeMode == QGraphicsProxyWidgetPrivate::ProxyToWidgetMode)
|
|
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return QGraphicsWidget::itemChange(change, value);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
bool QGraphicsProxyWidget::event(QEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!d->widget)
|
|
return QGraphicsWidget::event(event);
|
|
|
|
switch (event->type()) {
|
|
case QEvent::StyleChange:
|
|
// Propagate style changes to the embedded widget.
|
|
if (!d->styleChangeMode) {
|
|
d->styleChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
d->widget->setStyle(style());
|
|
d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
case QEvent::FontChange: {
|
|
// Propagate to widget.
|
|
QWidgetPrivate *wd = d->widget->d_func();
|
|
int mask = d->font.resolve() | d->inheritedFontResolveMask;
|
|
wd->inheritedFontResolveMask = mask;
|
|
wd->resolveFont();
|
|
break;
|
|
}
|
|
case QEvent::PaletteChange: {
|
|
// Propagate to widget.
|
|
QWidgetPrivate *wd = d->widget->d_func();
|
|
int mask = d->palette.resolve() | d->inheritedPaletteResolveMask;
|
|
wd->inheritedPaletteResolveMask = mask;
|
|
wd->resolvePalette();
|
|
break;
|
|
}
|
|
case QEvent::ShortcutOverride: {
|
|
QWidget *focusWidget = d->widget->focusWidget();
|
|
while (focusWidget) {
|
|
QApplication::sendEvent(focusWidget, event);
|
|
if (event->isAccepted())
|
|
return true;
|
|
focusWidget = focusWidget->parentWidget();
|
|
}
|
|
return false;
|
|
}
|
|
case QEvent::KeyPress: {
|
|
QKeyEvent *k = static_cast<QKeyEvent *>(event);
|
|
if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
|
|
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
|
|
QWidget *focusWidget = d->widget->focusWidget();
|
|
while (focusWidget) {
|
|
bool res = QApplication::sendEvent(focusWidget, event);
|
|
if ((res && event->isAccepted()) || (isWindow() && focusWidget == d->widget)) {
|
|
event->accept();
|
|
break;
|
|
}
|
|
focusWidget = focusWidget->parentWidget();
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
#ifndef QT_NO_TOOLTIP
|
|
case QEvent::GraphicsSceneHelp: {
|
|
// Propagate the help event (for tooltip) to the widget under mouse
|
|
if (d->lastWidgetUnderMouse) {
|
|
QGraphicsSceneHelpEvent *he = static_cast<QGraphicsSceneHelpEvent *>(event);
|
|
QPoint pos = d->mapToReceiver(mapFromScene(he->scenePos()), d->lastWidgetUnderMouse).toPoint();
|
|
QHelpEvent e(QEvent::ToolTip, pos, he->screenPos());
|
|
QApplication::sendEvent(d->lastWidgetUnderMouse, &e);
|
|
event->setAccepted(e.isAccepted());
|
|
return e.isAccepted();
|
|
}
|
|
break;
|
|
}
|
|
case QEvent::ToolTipChange: {
|
|
// Propagate tooltip change to the widget
|
|
if (!d->tooltipChangeMode) {
|
|
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::ProxyToWidgetMode;
|
|
d->widget->setToolTip(toolTip());
|
|
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
return QGraphicsWidget::event(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
bool QGraphicsProxyWidget::eventFilter(QObject *object, QEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
|
|
if (object == d->widget) {
|
|
switch (event->type()) {
|
|
case QEvent::LayoutRequest:
|
|
updateGeometry();
|
|
break;
|
|
case QEvent::Resize:
|
|
// If the widget resizes itself, we resize the proxy too.
|
|
// Prevent feed-back by checking the geometry change mode.
|
|
if (!d->sizeChangeMode)
|
|
d->updateProxyGeometryFromWidget();
|
|
break;
|
|
case QEvent::Move:
|
|
// If the widget moves itself, we move the proxy too. Prevent
|
|
// feed-back by checking the geometry change mode.
|
|
if (!d->posChangeMode)
|
|
d->updateProxyGeometryFromWidget();
|
|
break;
|
|
case QEvent::Hide:
|
|
case QEvent::Show:
|
|
// If the widget toggles its visible state, the proxy will follow.
|
|
if (!d->visibleChangeMode) {
|
|
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
setVisible(event->type() == QEvent::Show);
|
|
d->visibleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
case QEvent::EnabledChange:
|
|
// If the widget toggles its enabled state, the proxy will follow.
|
|
if (!d->enabledChangeMode) {
|
|
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
setEnabled(d->widget->isEnabled());
|
|
d->enabledChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
case QEvent::StyleChange:
|
|
// Propagate style changes to the proxy.
|
|
if (!d->styleChangeMode) {
|
|
d->styleChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
setStyle(d->widget->style());
|
|
d->styleChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
#ifndef QT_NO_TOOLTIP
|
|
case QEvent::ToolTipChange:
|
|
// Propagate tooltip change to the proxy.
|
|
if (!d->tooltipChangeMode) {
|
|
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::WidgetToProxyMode;
|
|
setToolTip(d->widget->toolTip());
|
|
d->tooltipChangeMode = QGraphicsProxyWidgetPrivate::NoMode;
|
|
}
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return QGraphicsWidget::eventFilter(object, event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::showEvent(QShowEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::hideEvent(QHideEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
}
|
|
|
|
#ifndef QT_NO_CONTEXTMENU
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!event || !d->widget || !d->widget->isVisible() || !hasFocus())
|
|
return;
|
|
|
|
// Find widget position and receiver.
|
|
QPointF pos = event->pos();
|
|
QPointer<QWidget> alienWidget = d->widget->childAt(pos.toPoint());
|
|
QPointer<QWidget> receiver = alienWidget ? alienWidget : d->widget;
|
|
|
|
// Map event position from us to the receiver
|
|
pos = d->mapToReceiver(pos, receiver);
|
|
|
|
QPoint globalPos = receiver->mapToGlobal(pos.toPoint());
|
|
//If the receiver by-pass the proxy its popups
|
|
//will be top level QWidgets therefore they need
|
|
//the screen position. mapToGlobal expect the widget to
|
|
//have proper coordinates in regards of the windowing system
|
|
//but it's not true because the widget is embedded.
|
|
if (bypassGraphicsProxyWidget(receiver))
|
|
globalPos = event->screenPos();
|
|
|
|
// Send mouse event. ### Doesn't propagate the event.
|
|
QContextMenuEvent contextMenuEvent(QContextMenuEvent::Reason(event->reason()),
|
|
pos.toPoint(), globalPos, event->modifiers());
|
|
QApplication::sendEvent(receiver, &contextMenuEvent);
|
|
|
|
event->setAccepted(contextMenuEvent.isAccepted());
|
|
}
|
|
#endif // QT_NO_CONTEXTMENU
|
|
|
|
#ifndef QT_NO_DRAGANDDROP
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
#ifdef QT_NO_DRAGANDDROP
|
|
Q_UNUSED(event);
|
|
#else
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!d->widget)
|
|
return;
|
|
|
|
QDragEnterEvent proxyDragEnter(event->pos().toPoint(), event->dropAction(), event->mimeData(), event->buttons(), event->modifiers());
|
|
proxyDragEnter.setAccepted(event->isAccepted());
|
|
QApplication::sendEvent(d->widget, &proxyDragEnter);
|
|
event->setAccepted(proxyDragEnter.isAccepted());
|
|
if (proxyDragEnter.isAccepted()) // we discard answerRect
|
|
event->setDropAction(proxyDragEnter.dropAction());
|
|
#endif
|
|
}
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
#ifndef QT_NO_DRAGANDDROP
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!d->widget || !d->dragDropWidget)
|
|
return;
|
|
QDragLeaveEvent proxyDragLeave;
|
|
QApplication::sendEvent(d->dragDropWidget, &proxyDragLeave);
|
|
d->dragDropWidget = 0;
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
#ifdef QT_NO_DRAGANDDROP
|
|
Q_UNUSED(event);
|
|
#else
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!d->widget)
|
|
return;
|
|
QPointF p = event->pos();
|
|
event->ignore();
|
|
QPointer<QWidget> subWidget = d->widget->childAt(p.toPoint());
|
|
QPointer<QWidget> receiver = subWidget ? subWidget : d->widget;
|
|
bool eventDelivered = false;
|
|
for (; receiver; receiver = receiver->parentWidget()) {
|
|
if (!receiver->isEnabled() || !receiver->acceptDrops())
|
|
continue;
|
|
// Map event position from us to the receiver
|
|
QPoint receiverPos = d->mapToReceiver(p, receiver).toPoint();
|
|
if (receiver != d->dragDropWidget) {
|
|
// Try to enter before we leave
|
|
QDragEnterEvent dragEnter(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
|
|
dragEnter.setDropAction(event->proposedAction());
|
|
QApplication::sendEvent(receiver, &dragEnter);
|
|
event->setAccepted(dragEnter.isAccepted());
|
|
event->setDropAction(dragEnter.dropAction());
|
|
if (!event->isAccepted()) {
|
|
// propagate to the parent widget
|
|
continue;
|
|
}
|
|
|
|
d->lastDropAction = event->dropAction();
|
|
|
|
if (d->dragDropWidget) {
|
|
QDragLeaveEvent dragLeave;
|
|
QApplication::sendEvent(d->dragDropWidget, &dragLeave);
|
|
}
|
|
d->dragDropWidget = receiver;
|
|
}
|
|
|
|
QDragMoveEvent dragMove(receiverPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
|
|
event->setDropAction(d->lastDropAction);
|
|
QApplication::sendEvent(receiver, &dragMove);
|
|
event->setAccepted(dragMove.isAccepted());
|
|
event->setDropAction(dragMove.dropAction());
|
|
if (event->isAccepted())
|
|
d->lastDropAction = event->dropAction();
|
|
eventDelivered = true;
|
|
break;
|
|
}
|
|
|
|
if (!eventDelivered) {
|
|
if (d->dragDropWidget) {
|
|
// Leave the last drag drop item
|
|
QDragLeaveEvent dragLeave;
|
|
QApplication::sendEvent(d->dragDropWidget, &dragLeave);
|
|
d->dragDropWidget = 0;
|
|
}
|
|
// Propagate
|
|
event->setDropAction(Qt::IgnoreAction);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::dropEvent(QGraphicsSceneDragDropEvent *event)
|
|
{
|
|
#ifdef QT_NO_DRAGANDDROP
|
|
Q_UNUSED(event);
|
|
#else
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (d->widget && d->dragDropWidget) {
|
|
QPoint widgetPos = d->mapToReceiver(event->pos(), d->dragDropWidget).toPoint();
|
|
QDropEvent dropEvent(widgetPos, event->possibleActions(), event->mimeData(), event->buttons(), event->modifiers());
|
|
QApplication::sendEvent(d->dragDropWidget, &dropEvent);
|
|
event->setAccepted(dropEvent.isAccepted());
|
|
d->dragDropWidget = 0;
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
Q_D(QGraphicsProxyWidget);
|
|
// If hoverMove was compressed away, make sure we update properly here.
|
|
if (d->lastWidgetUnderMouse) {
|
|
QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
|
|
d->lastWidgetUnderMouse = 0;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::hoverMoveEvent";
|
|
#endif
|
|
// Ignore events on the window frame.
|
|
if (!d->widget || !rect().contains(event->pos())) {
|
|
if (d->lastWidgetUnderMouse) {
|
|
QApplicationPrivate::dispatchEnterLeave(0, d->lastWidgetUnderMouse);
|
|
d->lastWidgetUnderMouse = 0;
|
|
}
|
|
return;
|
|
}
|
|
|
|
d->embeddedMouseGrabber = 0;
|
|
d->sendWidgetMouseEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::grabMouseEvent(QEvent *event)
|
|
{
|
|
Q_UNUSED(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::ungrabMouseEvent(QEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
Q_UNUSED(event);
|
|
d->embeddedMouseGrabber = 0;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::mouseMoveEvent";
|
|
#endif
|
|
d->sendWidgetMouseEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::mousePressEvent";
|
|
#endif
|
|
d->sendWidgetMouseEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::mouseDoubleClickEvent";
|
|
#endif
|
|
d->sendWidgetMouseEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
#ifndef QT_NO_WHEELEVENT
|
|
void QGraphicsProxyWidget::wheelEvent(QGraphicsSceneWheelEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::wheelEvent";
|
|
#endif
|
|
if (!d->widget)
|
|
return;
|
|
|
|
QPointF pos = event->pos();
|
|
QPointer<QWidget> receiver = d->widget->childAt(pos.toPoint());
|
|
if (!receiver)
|
|
receiver = d->widget;
|
|
|
|
// Map event position from us to the receiver
|
|
pos = d->mapToReceiver(pos, receiver);
|
|
|
|
// Send mouse event.
|
|
QWheelEvent wheelEvent(pos.toPoint(), event->screenPos(), event->delta(),
|
|
event->buttons(), event->modifiers(), event->orientation());
|
|
QPointer<QWidget> focusWidget = d->widget->focusWidget();
|
|
qt_sendSpontaneousEvent(receiver, &wheelEvent);
|
|
event->setAccepted(wheelEvent.isAccepted());
|
|
|
|
// ### Remove, this should be done by proper focusIn/focusOut events.
|
|
if (focusWidget && !focusWidget->hasFocus()) {
|
|
focusWidget->update();
|
|
focusWidget = d->widget->focusWidget();
|
|
if (focusWidget && focusWidget->hasFocus())
|
|
focusWidget->update();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::mouseReleaseEvent";
|
|
#endif
|
|
d->sendWidgetMouseEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::keyPressEvent(QKeyEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::keyPressEvent";
|
|
#endif
|
|
d->sendWidgetKeyEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::keyReleaseEvent(QKeyEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::keyReleaseEvent";
|
|
#endif
|
|
d->sendWidgetKeyEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::focusInEvent(QFocusEvent *event)
|
|
{
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::focusInEvent";
|
|
#endif
|
|
Q_D(QGraphicsProxyWidget);
|
|
|
|
if (d->focusFromWidgetToProxy) {
|
|
// Prevent recursion when the proxy autogains focus through the
|
|
// embedded widget calling setFocus(). ### Could be done with event
|
|
// filter on FocusIn instead?
|
|
return;
|
|
}
|
|
|
|
d->proxyIsGivingFocus = true;
|
|
|
|
switch (event->reason()) {
|
|
case Qt::TabFocusReason: {
|
|
if (QWidget *focusChild = d->findFocusChild(0, true))
|
|
focusChild->setFocus(event->reason());
|
|
break;
|
|
}
|
|
case Qt::BacktabFocusReason:
|
|
if (QWidget *focusChild = d->findFocusChild(0, false))
|
|
focusChild->setFocus(event->reason());
|
|
break;
|
|
default:
|
|
if (d->widget && d->widget->focusWidget()) {
|
|
d->widget->focusWidget()->setFocus(event->reason());
|
|
}
|
|
break;
|
|
}
|
|
|
|
d->proxyIsGivingFocus = false;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::focusOutEvent(QFocusEvent *event)
|
|
{
|
|
#ifdef GRAPHICSPROXYWIDGET_DEBUG
|
|
qDebug() << "QGraphicsProxyWidget::focusOutEvent";
|
|
#endif
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (d->widget) {
|
|
// We need to explicitly remove subfocus from the embedded widget's
|
|
// focus widget.
|
|
if (QWidget *focusWidget = d->widget->focusWidget())
|
|
d->removeSubFocusHelper(focusWidget, event->reason());
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
bool QGraphicsProxyWidget::focusNextPrevChild(bool next)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (!d->widget || !d->scene)
|
|
return QGraphicsWidget::focusNextPrevChild(next);
|
|
|
|
Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
|
|
QWidget *lastFocusChild = d->widget->focusWidget();
|
|
if (QWidget *newFocusChild = d->findFocusChild(lastFocusChild, next)) {
|
|
newFocusChild->setFocus(reason);
|
|
return true;
|
|
}
|
|
|
|
return QGraphicsWidget::focusNextPrevChild(next);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
QSizeF QGraphicsProxyWidget::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
|
|
{
|
|
Q_D(const QGraphicsProxyWidget);
|
|
if (!d->widget)
|
|
return QGraphicsWidget::sizeHint(which, constraint);
|
|
|
|
QSizeF sh;
|
|
switch (which) {
|
|
case Qt::PreferredSize:
|
|
if (QLayout *l = d->widget->layout())
|
|
sh = l->sizeHint();
|
|
else
|
|
sh = d->widget->sizeHint();
|
|
break;
|
|
case Qt::MinimumSize:
|
|
if (QLayout *l = d->widget->layout())
|
|
sh = l->minimumSize();
|
|
else
|
|
sh = d->widget->minimumSizeHint();
|
|
break;
|
|
case Qt::MaximumSize:
|
|
if (QLayout *l = d->widget->layout())
|
|
sh = l->maximumSize();
|
|
else
|
|
sh = QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
break;
|
|
case Qt::MinimumDescent:
|
|
sh = constraint;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return sh;
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
if (d->widget) {
|
|
if (d->sizeChangeMode != QGraphicsProxyWidgetPrivate::WidgetToProxyMode)
|
|
d->widget->resize(event->newSize().toSize());
|
|
}
|
|
QGraphicsWidget::resizeEvent(event);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
void QGraphicsProxyWidget::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
|
|
{
|
|
Q_D(QGraphicsProxyWidget);
|
|
Q_UNUSED(widget);
|
|
if (!d->widget || !d->widget->isVisible())
|
|
return;
|
|
|
|
// Filter out repaints on the window frame.
|
|
const QRect exposedWidgetRect = (option->exposedRect & rect()).toAlignedRect();
|
|
if (exposedWidgetRect.isEmpty())
|
|
return;
|
|
|
|
// Disable QPainter's default pen being cosmetic. This allows widgets and
|
|
// styles to follow Qt's existing defaults without getting ugly cosmetic
|
|
// lines when scaled.
|
|
bool restore = !(painter->renderHints() & QPainter::NonCosmeticDefaultPen);
|
|
painter->setRenderHints(QPainter::NonCosmeticDefaultPen, true);
|
|
|
|
d->widget->render(painter, exposedWidgetRect.topLeft(), exposedWidgetRect);
|
|
|
|
// Restore the render hints if necessary.
|
|
if (restore)
|
|
painter->setRenderHints(QPainter::NonCosmeticDefaultPen, false);
|
|
}
|
|
|
|
/*!
|
|
\reimp
|
|
*/
|
|
int QGraphicsProxyWidget::type() const
|
|
{
|
|
return Type;
|
|
}
|
|
|
|
/*!
|
|
\since 4.5
|
|
|
|
Creates a proxy widget for the given \a child of the widget
|
|
contained in this proxy.
|
|
|
|
This function makes it possible to acquire proxies for
|
|
non top-level widgets. For instance, you can embed a dialog,
|
|
and then transform only one of its widgets.
|
|
|
|
If the widget is already embedded, return the existing proxy widget.
|
|
|
|
\sa newProxyWidget(), QGraphicsScene::addWidget()
|
|
*/
|
|
QGraphicsProxyWidget *QGraphicsProxyWidget::createProxyForChildWidget(QWidget *child)
|
|
{
|
|
QGraphicsProxyWidget *proxy = child->graphicsProxyWidget();
|
|
if (proxy)
|
|
return proxy;
|
|
if (!child->parentWidget()) {
|
|
qWarning("QGraphicsProxyWidget::createProxyForChildWidget: top-level widget not in a QGraphicsScene");
|
|
return 0;
|
|
}
|
|
|
|
QGraphicsProxyWidget *parentProxy = createProxyForChildWidget(child->parentWidget());
|
|
if (!parentProxy)
|
|
return 0;
|
|
|
|
if (!QMetaObject::invokeMethod(parentProxy, "newProxyWidget", Qt::DirectConnection,
|
|
Q_RETURN_ARG(QGraphicsProxyWidget*, proxy), Q_ARG(const QWidget*, child)))
|
|
return 0;
|
|
proxy->setParent(parentProxy);
|
|
proxy->setWidget(child);
|
|
return proxy;
|
|
}
|
|
|
|
/*!
|
|
\fn QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *child)
|
|
\since 4.5
|
|
|
|
Creates a proxy widget for the given \a child of the widget contained in this
|
|
proxy.
|
|
|
|
You should not call this function directly; use
|
|
QGraphicsProxyWidget::createProxyForChildWidget() instead.
|
|
|
|
This function is a fake virtual slot that you can reimplement in
|
|
your subclass in order to control how new proxy widgets are
|
|
created. The default implementation returns a proxy created with
|
|
the QGraphicsProxyWidget() constructor with this proxy widget as
|
|
the parent.
|
|
|
|
\sa createProxyForChildWidget()
|
|
*/
|
|
QGraphicsProxyWidget *QGraphicsProxyWidget::newProxyWidget(const QWidget *)
|
|
{
|
|
return new QGraphicsProxyWidget(this);
|
|
}
|
|
|
|
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
|
|
#include "moc_qgraphicsproxywidget.h"
|
|
|
|
#endif //QT_NO_GRAPHICSVIEW
|