QTabBar: properly calc tab positions when changing tab position

The previous attempt to fix this bug did not work out well since it
tried too hard to avoid double calculations. Therefore restore the old
behavior and fix makeVisible() instead.
This amends 1082038bd89d0bbba4df0d9b3f8af3cd0a2f96f2

Pick-to: 6.5
Fixes: QTBUG-119366
Change-Id: I738a3cd3537ecf0983480d2f961f45f81d101bd9
Reviewed-by: Axel Spoerl <axel.spoerl@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
(cherry picked from commit 4e6f7ad26c31fe484421e873cf0de0fad0c878ee)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Christian Ehrlicher 2023-12-06 19:57:30 +01:00 committed by Qt Cherry-pick Bot
parent 4e9051417f
commit 8fc4a796ba
2 changed files with 64 additions and 6 deletions

View File

@ -680,7 +680,10 @@ void QTabBarPrivate::makeVisible(int index)
const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset);
const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset);
if (tabStart < scrolledTabBarStart) {
if (available >= lastTabEnd) {
// the entire tabbar fits, reset scroll
scrollOffset = 0;
} else if (tabStart < scrolledTabBarStart) {
// Tab is outside on the left, so scroll left.
scrollOffset = tabStart - scrollRect.left();
} else if (tabEnd > scrolledTabBarEnd) {
@ -689,9 +692,6 @@ void QTabBarPrivate::makeVisible(int index)
} else if (scrollOffset + entireScrollRect.width() > lastTabEnd + 1) {
// fill any free space on the right without overshooting
scrollOffset = qMax(0, lastTabEnd - entireScrollRect.width() + 1);
} else if (available >= lastTabEnd) {
// the entire tabbar fits, reset scroll
scrollOffset = 0;
}
leftB->setEnabled(scrollOffset > -scrollRect.left());
@ -831,9 +831,14 @@ void QTabBarPrivate::refresh()
pressedIndex = -1;
}
layoutDirty = true;
if (q->isVisible())
if (!q->isVisible()) {
layoutDirty = true;
} else {
layoutTabs();
makeVisible(currentIndex);
q->update();
q->updateGeometry();
}
}
/*!

View File

@ -102,6 +102,7 @@ private slots:
void changeTabTextKeepsScroll();
void settingCurrentTabBeforeShowDoesntScroll();
void checkPositionsAfterShapeChange();
void checkScrollOffsetAfterTabRemoval();
private:
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
@ -1543,5 +1544,57 @@ void tst_QTabBar::checkPositionsAfterShapeChange()
QVERIFY(opt.rect.top() > 0);
}
void tst_QTabBar::checkScrollOffsetAfterTabRemoval()
{
QTabWidget tabWidget;
QTabBar *tabBar = tabWidget.tabBar();
for (int i = 0; i < 10; ++i)
tabWidget.addTab(new QWidget, u"Tab %1"_s.arg(i));
tabWidget.setTabPosition(QTabWidget::North);
tabWidget.resize(300, 300);
tabWidget.setCurrentIndex(0);
tabWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));
auto *rightButton = tabBar->findChild<QAbstractButton *>(u"ScrollRightButton"_s);
auto *leftButton = tabBar->findChild<QAbstractButton *>(u"ScrollLeftButton"_s);
QVERIFY(leftButton);
QVERIFY(rightButton);
QVERIFY(rightButton->isEnabled());
QVERIFY(!leftButton->isEnabled());
// scroll to the right
tabBar->setCurrentIndex(9);
QVERIFY(!rightButton->isEnabled());
QVERIFY(leftButton->isEnabled());
// scroll to the center
tabBar->setCurrentIndex(2);
QVERIFY(rightButton->isEnabled());
QVERIFY(leftButton->isEnabled());
const auto getScrollOffset = [&]() -> int {
return static_cast<QTabBarPrivate *>(QObjectPrivate::get(tabBar))->scrollOffset;
};
// the scroll offset should not change when a tab right outside
// the scroll rect is removed
auto oldOffset = getScrollOffset();
tabWidget.removeTab(9);
QCOMPARE(getScrollOffset(), oldOffset);
// the scroll offset must change when a tab left outside
// the scroll rect is removed
oldOffset = getScrollOffset();
tabWidget.removeTab(0);
QVERIFY(getScrollOffset() < oldOffset);
// the scroll offset must change when there is empty
// place in the right after tab removal
oldOffset = getScrollOffset();
QVERIFY(oldOffset > 0);
for (int i : { 7, 6, 5, 4, 3 })
tabWidget.removeTab(i);
QCOMPARE(getScrollOffset(), 0);
QVERIFY(!rightButton->isVisible());
QVERIFY(!leftButton->isVisible());
}
QTEST_MAIN(tst_QTabBar)
#include "tst_qtabbar.moc"