Fix global coordinate mapping for child widgets in QGraphicsView.

Move the code path handling widgets embedded in QGraphicsProxyWidget
into the loop moving up the parent hierarchy.

Add child widget to test.

Task-number: QTBUG-41135
Change-Id: Ibd86413faaa927145a85a2f5864f162979135053
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
Friedemann Kleint 2015-06-18 10:08:01 +02:00 committed by Marc Mutz
parent 54675bdf7d
commit 56aad2ad60
2 changed files with 45 additions and 26 deletions

View File

@ -12264,20 +12264,21 @@ QPaintEngine *QWidget::paintEngine() const
*/
QPoint QWidget::mapToGlobal(const QPoint &pos) const
{
#ifndef QT_NO_GRAPHICSVIEW
Q_D(const QWidget);
if (d->extra && d->extra->proxyWidget && d->extra->proxyWidget->scene()) {
const QList <QGraphicsView *> views = d->extra->proxyWidget->scene()->views();
if (!views.isEmpty()) {
const QPointF scenePos = d->extra->proxyWidget->mapToScene(pos);
const QPoint viewPortPos = views.first()->mapFromScene(scenePos);
return views.first()->viewport()->mapToGlobal(viewPortPos);
}
}
#endif // !QT_NO_GRAPHICSVIEW
int x = pos.x(), y = pos.y();
const QWidget *w = this;
while (w) {
#ifndef QT_NO_GRAPHICSVIEW
const QWidgetPrivate *d = w->d_func();
if (d->extra && d->extra->proxyWidget && d->extra->proxyWidget->scene()) {
const QList <QGraphicsView *> views = d->extra->proxyWidget->scene()->views();
if (!views.isEmpty()) {
const QPointF scenePos = d->extra->proxyWidget->mapToScene(QPoint(x, y));
const QPoint viewPortPos = views.first()->mapFromScene(scenePos);
return views.first()->viewport()->mapToGlobal(viewPortPos);
}
}
#endif // !QT_NO_GRAPHICSVIEW
QWindow *window = w->windowHandle();
if (window && window->handle())
return window->mapToGlobal(QPoint(x, y));
@ -12299,20 +12300,21 @@ QPoint QWidget::mapToGlobal(const QPoint &pos) const
*/
QPoint QWidget::mapFromGlobal(const QPoint &pos) const
{
#ifndef QT_NO_GRAPHICSVIEW
Q_D(const QWidget);
if (d->extra && d->extra->proxyWidget && d->extra->proxyWidget->scene()) {
const QList <QGraphicsView *> views = d->extra->proxyWidget->scene()->views();
if (!views.isEmpty()) {
const QPoint viewPortPos = views.first()->viewport()->mapFromGlobal(pos);
const QPointF scenePos = views.first()->mapToScene(viewPortPos);
return d->extra->proxyWidget->mapFromScene(scenePos).toPoint();
}
}
#endif // !QT_NO_GRAPHICSVIEW
int x = pos.x(), y = pos.y();
const QWidget *w = this;
while (w) {
#ifndef QT_NO_GRAPHICSVIEW
const QWidgetPrivate *d = w->d_func();
if (d->extra && d->extra->proxyWidget && d->extra->proxyWidget->scene()) {
const QList <QGraphicsView *> views = d->extra->proxyWidget->scene()->views();
if (!views.isEmpty()) {
const QPoint viewPortPos = views.first()->viewport()->mapFromGlobal(QPoint(x, y));
const QPointF scenePos = views.first()->mapToScene(viewPortPos);
return d->extra->proxyWidget->mapFromScene(scenePos).toPoint();
}
}
#endif // !QT_NO_GRAPHICSVIEW
QWindow *window = w->windowHandle();
if (window && window->handle())
return window->mapFromGlobal(QPoint(x, y));

View File

@ -3670,6 +3670,14 @@ void tst_QGraphicsProxyWidget::QTBUG_6986_sendMouseEventToAlienWidget()
QTRY_COMPARE(scene.hoverButton->hoverLeaveReceived, true);
}
static QByteArray msgPointMismatch(const QPoint &actual, const QPoint &expected)
{
QString result;
QDebug(&result) << actual << " != " << expected << " manhattanLength="
<< (expected - actual).manhattanLength();
return result.toLocal8Bit();
}
void tst_QGraphicsProxyWidget::mapToGlobal() // QTBUG-41135
{
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
@ -3681,20 +3689,29 @@ void tst_QGraphicsProxyWidget::mapToGlobal() // QTBUG-41135
view.move(availableGeometry.bottomRight() - QPoint(size.width(), size.height()) - QPoint(100, 100));
QWidget *embeddedWidget = new QWidget;
embeddedWidget->setFixedSize(size / 2);
QWidget *childWidget = new QWidget(embeddedWidget);
childWidget->setStyleSheet(QLatin1String("background-color: \"red\"; "));
childWidget->resize(embeddedWidget->size() / 2);
childWidget->move(embeddedWidget->width() / 4, embeddedWidget->height() / 4); // center in embeddedWidget
scene.addWidget(embeddedWidget);
QApplication::setActiveWindow(&view);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
const QPoint embeddedCenter = embeddedWidget->geometry().center();
const QPoint embeddedCenter = embeddedWidget->rect().center();
const QPoint embeddedCenterGlobal = embeddedWidget->mapToGlobal(embeddedCenter);
QCOMPARE(embeddedWidget->mapFromGlobal(embeddedCenterGlobal), embeddedCenter);
// This should be equivalent to the view center give or take rounding
// errors due to odd window margins
const QPoint viewCenter = view.geometry().center();
QVERIFY2((viewCenter - embeddedCenterGlobal).manhattanLength() <= 2,
qPrintable(QStringLiteral("%1, %2 != %3, %4")
.arg(viewCenter.x()).arg(viewCenter.y())
.arg(embeddedCenterGlobal.x()).arg(embeddedCenterGlobal.y())));
msgPointMismatch(embeddedCenterGlobal, viewCenter).constData());
// Same test with child centered on embeddedWidget
const QPoint childCenter = childWidget->rect().center();
const QPoint childCenterGlobal = childWidget->mapToGlobal(childCenter);
QCOMPARE(childWidget->mapFromGlobal(childCenterGlobal), childCenter);
QVERIFY2((viewCenter - childCenterGlobal).manhattanLength() <= 4,
msgPointMismatch(childCenterGlobal, viewCenter).constData());
}
void tst_QGraphicsProxyWidget::mapToGlobalWithoutScene() // QTBUG-44509