Take overshoot into account when laying out QAbstractScrollArea
QAbstractScrollAreaPrivate::layoutChildren() positions the viewport, but did not take the overshoot from scrolling with a scroller into account. If the scroll area was resized during a scroll, then this resulted in the roll back overcompensating for the overshoot, placing the viewport outside the visible area. Fix this by taking the overshoot into account when positioning the viewport. Add a test case. We have to use QWindow-based mouse event simulation, as the QWidget based move events use QCursor::setPos, which doesn't reliably go through the gesture framework. Done-with: Volker Hilsheimer <volker.hilsheimer@qt.io> Done-with: Zhang Hao <zhanghao@uniontech.com> Fixes: QTBUG-94769 Pick-to: 5.15 6.2 Change-Id: Idf650c91e5a9cffa996e23e743939243b1d4fcc0 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>bb10
parent
a34a10c11f
commit
f7a4a79c62
|
|
@ -442,8 +442,10 @@ void QAbstractScrollAreaPrivate::layoutChildren_helper(bool *needHorizontalScrol
|
|||
viewportRect.adjust(right, top, -left, -bottom);
|
||||
else
|
||||
viewportRect.adjust(left, top, -right, -bottom);
|
||||
viewportRect = QStyle::visualRect(opt.direction, opt.rect, viewportRect);
|
||||
viewportRect.translate(-overshoot);
|
||||
viewport->setGeometry(viewportRect); // resize the viewport last
|
||||
|
||||
viewport->setGeometry(QStyle::visualRect(opt.direction, opt.rect, viewportRect)); // resize the viewport last
|
||||
*needHorizontalScrollbar = needh;
|
||||
*needVerticalScrollbar = needv;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#include <qlabel.h>
|
||||
#include <qwidget.h>
|
||||
#include <qdialog.h>
|
||||
#include <qscroller.h>
|
||||
|
||||
class tst_QAbstractScrollArea : public QObject
|
||||
{
|
||||
|
|
@ -57,6 +58,7 @@ private slots:
|
|||
void task214488_layoutDirection();
|
||||
|
||||
void margins();
|
||||
void resizeWithOvershoot();
|
||||
};
|
||||
|
||||
tst_QAbstractScrollArea::tst_QAbstractScrollArea()
|
||||
|
|
@ -394,5 +396,42 @@ void tst_QAbstractScrollArea::margins()
|
|||
QCOMPARE(area.viewportMargins(), margins);
|
||||
}
|
||||
|
||||
void tst_QAbstractScrollArea::resizeWithOvershoot()
|
||||
{
|
||||
QWidget window;
|
||||
|
||||
QScrollArea scrollArea(&window);
|
||||
scrollArea.setWidget([]{
|
||||
QWidget *widget = new QWidget;
|
||||
widget->setFixedSize(QSize(0, 200));
|
||||
return widget;
|
||||
}());
|
||||
scrollArea.setGeometry(0, 20, 100, 100);
|
||||
|
||||
QScroller::grabGesture(&scrollArea, QScroller::LeftMouseButtonGesture);
|
||||
|
||||
window.show();
|
||||
QVERIFY(QTest::qWaitForWindowExposed(&window));
|
||||
|
||||
const QPoint originAtRest = scrollArea.viewport()->pos();
|
||||
|
||||
QPoint center = scrollArea.viewport()->mapToGlobal(scrollArea.viewport()->rect().center());
|
||||
center = window.windowHandle()->mapFromGlobal(center);
|
||||
QTest::mousePress(window.windowHandle(), Qt::LeftButton, {}, center);
|
||||
QTest::mouseMove(window.windowHandle(), center + QPoint(0, 50));
|
||||
QTRY_COMPARE(scrollArea.viewport()->pos(), originAtRest + QPoint(0, 25));
|
||||
QPoint overshootPosition = scrollArea.viewport()->pos();
|
||||
|
||||
// trigger a layout of the scroll area while there's overshoot
|
||||
scrollArea.setGeometry(0, 0, 100, 120);
|
||||
QCOMPARE(scrollArea.viewport()->pos(), overshootPosition);
|
||||
QTest::mouseRelease(window.windowHandle(), Qt::LeftButton, {}, center + QPoint(0, 50));
|
||||
QTRY_COMPARE(scrollArea.viewport()->pos(), originAtRest);
|
||||
// Process a few more events and verify that the scroll area
|
||||
// doesn't overcompensate for the overshoot.
|
||||
QApplication::processEvents();
|
||||
QTRY_COMPARE(scrollArea.viewport()->pos(), originAtRest);
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QAbstractScrollArea)
|
||||
#include "tst_qabstractscrollarea.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue