QWidget::mapTo/FromGlobal(): Fix transformation in case of QGraphicsItem::ItemIgnoresTransformations

Extract a helper returning the transform from
QGraphicsViewPrivate::mapToViewRect() and use that.

Fixes: QTBUG-128913
Change-Id: Idc31f653c23cd7d0e5bbb8af560f010f01ac4d4b
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
(cherry picked from commit deb4e08c1212aa3d43f62f9e7211bf69d3be0ada)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Friedemann Kleint 2024-10-29 10:21:04 +01:00 committed by Qt Cherry-pick Bot
parent 5f3e64235e
commit 5d612a72ad
4 changed files with 66 additions and 17 deletions

View File

@ -885,16 +885,14 @@ void QGraphicsViewPrivate::populateSceneDragDropEvent(QGraphicsSceneDragDropEven
/*!
\internal
*/
QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const
QTransform QGraphicsViewPrivate::mapToViewTransform(const QGraphicsItem *item) const
{
Q_Q(const QGraphicsView);
if (dirtyScroll)
const_cast<QGraphicsViewPrivate *>(this)->updateScroll();
if (item->d_ptr->itemIsUntransformable()) {
QTransform itv = item->deviceTransform(q->viewportTransform());
return itv.mapRect(rect).toAlignedRect();
}
if (item->d_ptr->itemIsUntransformable())
return item->deviceTransform(q->viewportTransform());
// Translate-only
// COMBINE
@ -908,21 +906,20 @@ QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRect
offset += itemd->pos;
} while ((parentItem = itemd->parent));
QRectF baseRect = rect.translated(offset.x(), offset.y());
QTransform move = QTransform::fromTranslate(offset.x(), offset.y());
if (!parentItem) {
if (identityMatrix) {
baseRect.translate(-scrollX, -scrollY);
return baseRect.toAlignedRect();
}
return matrix.mapRect(baseRect).translated(-scrollX, -scrollY).toAlignedRect();
move.translate(-scrollX, -scrollY);
return identityMatrix ? move : matrix * move;
}
QTransform tr = parentItem->sceneTransform();
if (!identityMatrix)
tr *= matrix;
QRectF r = tr.mapRect(baseRect);
r.translate(-scrollX, -scrollY);
return r.toAlignedRect();
return move * tr * QTransform::fromTranslate(-scrollX, -scrollY);
}
QRect QGraphicsViewPrivate::mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const
{
return mapToViewTransform(item).mapRect(rect).toAlignedRect();
}
/*!

View File

@ -139,6 +139,7 @@ public:
void populateSceneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
QDropEvent *source);
QTransform mapToViewTransform(const QGraphicsItem *item) const;
QRect mapToViewRect(const QGraphicsItem *item, const QRectF &rect) const;
QRegion mapToViewRegion(const QGraphicsItem *item, const QRectF &rect) const;
QRegion dirtyRegion;

View File

@ -60,6 +60,7 @@
#include "QtWidgets/qgraphicsproxywidget.h"
#include "QtWidgets/qgraphicsscene.h"
#include "private/qgraphicsproxywidget_p.h"
#include "private/qgraphicsview_p.h"
#endif
#include "QtWidgets/qabstractscrollarea.h"
#include "private/qabstractscrollarea_p.h"
@ -12644,8 +12645,8 @@ static MapToGlobalTransformResult mapToGlobalTransform(const QWidget *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();
auto *viewP = static_cast<QGraphicsViewPrivate *>(qt_widget_private(views.constFirst()));
result.transform *= viewP->mapToViewTransform(qgpw);
w = views.first()->viewport();
}
}

View File

@ -135,6 +135,7 @@ private slots:
void QTBUG_6986_sendMouseEventToAlienWidget();
void mapToGlobal();
void mapToGlobalWithoutScene();
void mapToGlobalIgnoreTranformation();
void QTBUG_43780_visibility();
#if QT_CONFIG(wheelevent)
void wheelEventPropagation();
@ -3552,6 +3553,55 @@ void tst_QGraphicsProxyWidget::mapToGlobalWithoutScene() // QTBUG-44509
QCOMPARE(embeddedWidget->mapFromGlobal(globalPos), localPos);
}
// QTBUG-128913, QGraphicsProxyWidget with ItemIgnoresTransformations
void tst_QGraphicsProxyWidget::mapToGlobalIgnoreTranformation()
{
const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
const QSize size = availableGeometry.size() / 2;
QGraphicsScene scene;
QGraphicsView view(&scene);
view.setWindowTitle(QLatin1StringView(QTest::currentTestFunction()));
view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setTransform(QTransform::fromScale(2, 2));
view.resize(size);
view.move(availableGeometry.bottomRight() - QPoint(size.width(), size.height())
- QPoint(100, 100));
static constexpr int labelWidth = 200;
static constexpr int labelHeight = 50;
auto *transforming = new QGraphicsProxyWidget();
auto *transformingLabel = new QLabel("Transforming"_L1);
transformingLabel->resize(labelWidth, labelHeight);
transforming->setWidget(transformingLabel);
transforming->setPos(0, 0);
scene.addItem(transforming);
auto *nonTransforming = new QGraphicsProxyWidget();
nonTransforming->setFlag(QGraphicsItem::ItemIgnoresTransformations);
auto *nonTransformingLabel = new QLabel("NonTransforming"_L1);
nonTransformingLabel->resize(labelWidth, labelHeight);
nonTransforming->setWidget(nonTransformingLabel);
nonTransforming->setPos(labelWidth, 0);
scene.addItem(nonTransforming);
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
const QPoint labelCenter{ labelWidth / 2, labelHeight / 2 };
const QPoint topPos = view.geometry().topLeft() + view.viewport()->geometry().topLeft();
const QPoint transformingGlobal = transformingLabel->mapToGlobal(labelCenter);
const QPoint nonTransformingGlobal = nonTransformingLabel->mapToGlobal(labelCenter);
// Center of label at 0,0 scaled by 2 should match size
QCOMPARE(transformingGlobal - topPos, QPoint(labelWidth, labelHeight));
// Center of non-transforming label at 200 (scaled by 2), 0
QCOMPARE(nonTransformingGlobal - topPos,
QPoint(labelWidth * 2 + labelWidth / 2, labelHeight / 2));
}
// QTBUG_43780: Embedded widgets have isWindow()==true but showing them should not
// trigger the top-level widget code path of show() that closes all popups
// (for example combo popups).