QWidget::mapTo/FromGlobal(): Rewrite using a QTransform.
Introduce a function going up the widget hierarchy determining a QTransform for mapping the coordinates applying the transformations of any QGraphicsView instances found. In mapFromGlobal(), use the inverse of it. This fixes the case of widget hierarchies embedded into QGraphicsView with transformations. Increase fuzz in the tests due to float rounding errors. Task-number: QTBUG-41135 Task-number: QTBUG-50030 Task-number: QTBUG-50136 Task-number: QTBUG-52507 Change-Id: I507e0bccd546250fe9c2d1b74ef38657d61490b4 Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
parent
a26435d65c
commit
474af0a61d
@ -12346,6 +12346,53 @@ static inline bool canMapPosition(QWindow *window)
|
||||
return window->handle() && !qt_window_private(window)->resizeEventPending;
|
||||
}
|
||||
|
||||
#ifndef QT_NO_GRAPHICSVIEW
|
||||
static inline QGraphicsProxyWidget *graphicsProxyWidget(const QWidget *w)
|
||||
{
|
||||
QGraphicsProxyWidget *result = Q_NULLPTR;
|
||||
const QWidgetPrivate *d = qt_widget_private(const_cast<QWidget *>(w));
|
||||
if (d->extra)
|
||||
result = d->extra->proxyWidget;
|
||||
return result;
|
||||
}
|
||||
#endif // !QT_NO_GRAPHICSVIEW
|
||||
|
||||
struct MapToGlobalTransformResult {
|
||||
QTransform transform;
|
||||
QWindow *window;
|
||||
};
|
||||
|
||||
static MapToGlobalTransformResult mapToGlobalTransform(const QWidget *w)
|
||||
{
|
||||
MapToGlobalTransformResult result;
|
||||
result.window = Q_NULLPTR;
|
||||
for ( ; w ; w = w->parentWidget()) {
|
||||
#ifndef QT_NO_GRAPHICSVIEW
|
||||
if (QGraphicsProxyWidget *qgpw = graphicsProxyWidget(w)) {
|
||||
if (const QGraphicsScene *scene = qgpw->scene()) {
|
||||
const QList <QGraphicsView *> views = scene->views();
|
||||
if (!views.isEmpty()) {
|
||||
result.transform *= qgpw->sceneTransform();
|
||||
result.transform *= views.first()->viewportTransform();
|
||||
w = views.first()->viewport();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif // !QT_NO_GRAPHICSVIEW
|
||||
QWindow *window = w->windowHandle();
|
||||
if (window && canMapPosition(window)) {
|
||||
result.window = window;
|
||||
break;
|
||||
}
|
||||
|
||||
const QPoint topLeft = w->geometry().topLeft();
|
||||
result.transform.translate(topLeft.x(), topLeft.y());
|
||||
if (w->isWindow())
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn QPoint QWidget::mapToGlobal(const QPoint &pos) const
|
||||
|
||||
@ -12357,29 +12404,9 @@ static inline bool canMapPosition(QWindow *window)
|
||||
*/
|
||||
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) {
|
||||
QWindow *window = w->windowHandle();
|
||||
if (window && canMapPosition(window))
|
||||
return window->mapToGlobal(QPoint(x, y));
|
||||
|
||||
x += w->data->crect.x();
|
||||
y += w->data->crect.y();
|
||||
w = w->isWindow() ? 0 : w->parentWidget();
|
||||
}
|
||||
return QPoint(x, y);
|
||||
const MapToGlobalTransformResult t = mapToGlobalTransform(this);
|
||||
const QPoint g = t.transform.map(pos);
|
||||
return t.window ? t.window->mapToGlobal(g) : g;
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -12392,29 +12419,9 @@ 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) {
|
||||
QWindow *window = w->windowHandle();
|
||||
if (window && canMapPosition(window))
|
||||
return window->mapFromGlobal(QPoint(x, y));
|
||||
|
||||
x -= w->data->crect.x();
|
||||
y -= w->data->crect.y();
|
||||
w = w->isWindow() ? 0 : w->parentWidget();
|
||||
}
|
||||
return QPoint(x, y);
|
||||
const MapToGlobalTransformResult t = mapToGlobalTransform(this);
|
||||
const QPoint windowLocal = t.window ? t.window->mapFromGlobal(pos) : pos;
|
||||
return t.transform.inverted().map(windowLocal);
|
||||
}
|
||||
|
||||
QWidget *qt_pressGrab = 0;
|
||||
|
@ -3682,16 +3682,19 @@ static QByteArray msgPointMismatch(const QPoint &actual, const QPoint &expected)
|
||||
void tst_QGraphicsProxyWidget::mapToGlobal() // QTBUG-41135
|
||||
{
|
||||
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
|
||||
const QSize size = availableGeometry.size() / 5;
|
||||
const QSize size = availableGeometry.size() / 4;
|
||||
QGraphicsScene scene;
|
||||
QGraphicsView view(&scene);
|
||||
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
view.setTransform(QTransform::fromScale(2, 2)); // QTBUG-50136, use transform.
|
||||
view.setWindowTitle(QTest::currentTestFunction());
|
||||
view.resize(size);
|
||||
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);
|
||||
QWidget *embeddedWidget = new QGroupBox(QLatin1String("Embedded"));
|
||||
embeddedWidget->setStyleSheet(QLatin1String("background-color: \"yellow\"; "));
|
||||
embeddedWidget->setFixedSize((size - QSize(10, 10)) / 2);
|
||||
QWidget *childWidget = new QGroupBox(QLatin1String("Child"), embeddedWidget);
|
||||
childWidget->setStyleSheet(QLatin1String("background-color: \"red\"; "));
|
||||
childWidget->resize(embeddedWidget->size() / 2);
|
||||
childWidget->move(embeddedWidget->width() / 4, embeddedWidget->height() / 4); // center in embeddedWidget
|
||||
@ -3705,18 +3708,16 @@ void tst_QGraphicsProxyWidget::mapToGlobal() // QTBUG-41135
|
||||
// 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,
|
||||
QVERIFY2((viewCenter - embeddedCenterGlobal).manhattanLength() <= 3,
|
||||
msgPointMismatch(embeddedCenterGlobal, viewCenter).constData());
|
||||
|
||||
// Same test with child centered on embeddedWidget. The correct
|
||||
// mapping is not implemented yet, but at least make sure
|
||||
// Same test with child centered on embeddedWidget. Also make sure
|
||||
// the roundtrip maptoGlobal()/mapFromGlobal() returns the same
|
||||
// point since that is important for mouse event handling (QTBUG-50030,
|
||||
// QTBUG-50136).
|
||||
const QPoint childCenter = childWidget->rect().center();
|
||||
const QPoint childCenterGlobal = childWidget->mapToGlobal(childCenter);
|
||||
QCOMPARE(childWidget->mapFromGlobal(childCenterGlobal), childCenter);
|
||||
QEXPECT_FAIL("", "Not implemented for child widgets of embedded widgets", Continue);
|
||||
QVERIFY2((viewCenter - childCenterGlobal).manhattanLength() <= 4,
|
||||
msgPointMismatch(childCenterGlobal, viewCenter).constData());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user