Popup/Drawer: Reposition based on Overlay geometry instead of Window geometry
Calculations relating to the top and left edges are based on Overlay geometry, but calculations relating to the bottom and right edges are currently based on Window geometry instead. This patch makes all calculations based on Overlay geometry, for consistency. The single new auto-test covers both code paths modified by this patch, QQuickDrawerPositioner::reposition() and QQuickPopupPositioner::reposition() Change-Id: I6cf9bcc39985e7c9c325ba6c47198fb20215be4b Fixes: QTBUG-122963 Pick-to: 6.7 6.8 Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
This commit is contained in:
parent
fdac10eb0d
commit
931e67f543
|
@ -203,8 +203,11 @@ void QQuickDrawerPositioner::reposition()
|
|||
return;
|
||||
|
||||
QQuickDrawer *drawer = static_cast<QQuickDrawer*>(popup());
|
||||
QQuickWindow *window = drawer->window();
|
||||
if (!window)
|
||||
|
||||
// The overlay is assumed to fully cover the window's contents, although the overlay's geometry
|
||||
// might not always equal the window's geometry (for example, if the window's contents are rotated).
|
||||
QQuickOverlay *overlay = QQuickOverlay::overlay(drawer->window());
|
||||
if (!overlay)
|
||||
return;
|
||||
|
||||
const qreal position = drawer->position();
|
||||
|
@ -214,13 +217,13 @@ void QQuickDrawerPositioner::reposition()
|
|||
popupItem->setX((position - 1.0) * popupItem->width());
|
||||
break;
|
||||
case Qt::RightEdge:
|
||||
popupItem->setX(window->width() - position * popupItem->width());
|
||||
popupItem->setX(overlay->width() - position * popupItem->width());
|
||||
break;
|
||||
case Qt::TopEdge:
|
||||
popupItem->setY((position - 1.0) * popupItem->height());
|
||||
break;
|
||||
case Qt::BottomEdge:
|
||||
popupItem->setY(window->height() - position * popupItem->height());
|
||||
popupItem->setY(overlay->height() - position * popupItem->height());
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -153,12 +153,25 @@ void QQuickPopupPositioner::reposition()
|
|||
rect.moveTopLeft(m_parentItem->mapToItem(popupItem->parentItem(), rect.topLeft()));
|
||||
}
|
||||
|
||||
if (p->window) {
|
||||
// The overlay is assumed to fully cover the window's contents, although the overlay's geometry
|
||||
// might not always equal the window's geometry (for example, if the window's contents are rotated).
|
||||
QQuickOverlay *overlay = QQuickOverlay::overlay(p->window);
|
||||
if (overlay) {
|
||||
qreal boundsWidth = overlay->width();
|
||||
qreal boundsHeight = overlay->height();
|
||||
|
||||
// QTBUG-126843: On some platforms, the overlay's geometry is not yet available at the instant
|
||||
// when Component.completed() is emitted. Fall back to the window's geometry for this edge case.
|
||||
if (Q_UNLIKELY(boundsWidth <= 0)) {
|
||||
boundsWidth = p->window->width();
|
||||
boundsHeight = p->window->height();
|
||||
}
|
||||
|
||||
const QMarginsF margins = p->getMargins();
|
||||
QRectF bounds(qMax<qreal>(0.0, margins.left()),
|
||||
qMax<qreal>(0.0, margins.top()),
|
||||
p->window->width() - qMax<qreal>(0.0, margins.left()) - qMax<qreal>(0.0, margins.right()),
|
||||
p->window->height() - qMax<qreal>(0.0, margins.top()) - qMax<qreal>(0.0, margins.bottom()));
|
||||
boundsWidth - qMax<qreal>(0.0, margins.left()) - qMax<qreal>(0.0, margins.right()),
|
||||
boundsHeight - qMax<qreal>(0.0, margins.top()) - qMax<qreal>(0.0, margins.bottom()));
|
||||
|
||||
// if the popup doesn't fit horizontally inside the window, try flipping it around (left <-> right)
|
||||
if (p->allowHorizontalFlip && (rect.left() < bounds.left() || rect.right() > bounds.right())) {
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
ApplicationWindow {
|
||||
id: window
|
||||
width: 600
|
||||
height: 400 // We want width != height to test rotated geometry
|
||||
|
||||
// The derivation of this anchor setup is documented at QTBUG-123565
|
||||
background: Item {
|
||||
width: window.rotated ? window.height : window.width
|
||||
height: window.rotated ? window.width : window.height
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
Overlay.overlay.anchors.fill: background
|
||||
contentItem.anchors.fill: background
|
||||
contentItem.parent.rotation: rotated ? 90 : 0
|
||||
|
||||
property bool rotated: false
|
||||
property int drawerSize: 100
|
||||
property alias drawer_LR: drawer_LR
|
||||
property alias drawer_TB: drawer_TB
|
||||
|
||||
Drawer {
|
||||
id: drawer_LR
|
||||
edge: Qt.LeftEdge
|
||||
width: window.drawerSize
|
||||
height: parent.height
|
||||
}
|
||||
Drawer {
|
||||
id: drawer_TB
|
||||
edge: Qt.TopEdge
|
||||
width: parent.width
|
||||
height: window.drawerSize
|
||||
}
|
||||
}
|
||||
|
|
@ -56,6 +56,7 @@ private slots:
|
|||
void dragMargin();
|
||||
|
||||
void reposition();
|
||||
void rotate();
|
||||
void header();
|
||||
|
||||
void dragHandlerInteraction();
|
||||
|
@ -490,6 +491,53 @@ void tst_QQuickDrawer::reposition()
|
|||
QTRY_COMPARE(popupItem2->x(), 0.0);
|
||||
}
|
||||
|
||||
void tst_QQuickDrawer::rotate()
|
||||
{
|
||||
QQuickControlsApplicationHelper helper(this, u"rotate.qml"_s);
|
||||
QVERIFY2(helper.ready, helper.failureMessage());
|
||||
|
||||
QQuickApplicationWindow *window = helper.appWindow;
|
||||
window->show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(window));
|
||||
|
||||
QQuickDrawer *drawer_LR = window->property("drawer_LR").value<QQuickDrawer*>();
|
||||
QVERIFY(drawer_LR);
|
||||
QQuickItem *popupItem_LR = drawer_LR->popupItem();
|
||||
QVERIFY(popupItem_LR);
|
||||
|
||||
QQuickDrawer *drawer_TB = window->property("drawer_TB").value<QQuickDrawer*>();
|
||||
QVERIFY(drawer_TB);
|
||||
QQuickItem *popupItem_TB = drawer_TB->popupItem();
|
||||
QVERIFY(popupItem_TB);
|
||||
|
||||
drawer_LR->open();
|
||||
drawer_TB->open();
|
||||
|
||||
const int drawerSize = window->property("drawerSize").toInt();
|
||||
int virtualWidth = window->width();
|
||||
int virtualHeight = window->height();
|
||||
|
||||
// First iteration tests an unrotated window; 2nd iteration repeats the test with a rotated window
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
drawer_LR->setEdge(Qt::LeftEdge);
|
||||
QTRY_COMPARE(geometry(popupItem_LR), QRectF(0, 0, drawerSize, virtualHeight));
|
||||
|
||||
drawer_TB->setEdge(Qt::TopEdge);
|
||||
QTRY_COMPARE(geometry(popupItem_TB), QRectF(0, 0, virtualWidth, drawerSize));
|
||||
|
||||
drawer_LR->setEdge(Qt::RightEdge);
|
||||
QTRY_COMPARE(geometry(popupItem_LR), QRectF(virtualWidth - drawerSize, 0, drawerSize, virtualHeight));
|
||||
|
||||
drawer_TB->setEdge(Qt::BottomEdge);
|
||||
QTRY_COMPARE(geometry(popupItem_TB), QRectF(0, virtualHeight - drawerSize, virtualWidth, drawerSize));
|
||||
|
||||
if (i == 0) {
|
||||
window->setProperty("rotated", true);
|
||||
std::swap(virtualWidth, virtualHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QQuickDrawer::header()
|
||||
{
|
||||
QQuickControlsApplicationHelper helper(this, QStringLiteral("header.qml"));
|
||||
|
|
Loading…
Reference in New Issue