Skip to content

Commit 34e72dc

Browse files
senthilauto2023GitHub Enterprise
authored and
GitHub Enterprise
committed
MAYA-131609: Tabs go missing when changing direction
With commit 1082038 from Qt R&D, we were still able to reproduce the missing tabs issue when a tab was removed with tab bar scrolled to the right. While I understand that the problem arose because the geometry was not ready when the API was called, I believe the scroll offset calculation could be rewritten to handle various scenarios, regardless of how and when this API is used. My change reorders the existing logic and achieves the following: Resets the scroll offset if there is enough space to fully display the tab bar before checking other conditions. If there is not enough space, it clamps the adjusted scrollOffset value within the limits. I have added a test case to demonstrate the issue we observed with the original commit.
2 parents 9d9e7c0 + a01806f commit 34e72dc

File tree

2 files changed

+63
-11
lines changed

2 files changed

+63
-11
lines changed

src/widgets/widgets/qtabbar.cpp

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -680,20 +680,26 @@ void QTabBarPrivate::makeVisible(int index)
680680
const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset);
681681
const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset);
682682

683-
if (tabStart < scrolledTabBarStart) {
684-
// Tab is outside on the left, so scroll left.
685-
scrollOffset = tabStart - scrollRect.left();
686-
} else if (tabEnd > scrolledTabBarEnd) {
687-
// Tab is outside on the right, so scroll right.
688-
scrollOffset = qMax(0, tabEnd - scrollRect.right());
689-
} else if (scrollOffset + entireScrollRect.width() > lastTabEnd + 1) {
690-
// fill any free space on the right without overshooting
691-
scrollOffset = qMax(0, lastTabEnd - entireScrollRect.width() + 1);
692-
} else if (available >= lastTabEnd) {
693-
// the entire tabbar fits, reset scroll
683+
if (available >= lastTabEnd) {
684+
// the entire tabbar fits, reset scroll offset.
694685
scrollOffset = 0;
686+
} else {
687+
if (tabStart < scrolledTabBarStart) {
688+
// Tab is partially occluded on the left, adjust offset to make tab fully visible.
689+
scrollOffset = tabStart - scrollRect.left();
690+
} else if (tabEnd > scrolledTabBarEnd) {
691+
// Tab is partially occluded on the right, adjust offset to make tab fully visible.
692+
scrollOffset = tabEnd - scrollRect.right();
693+
}
694+
695+
if (scrollOffset + entireScrollRect.width() > lastTabEnd + 1) {
696+
// fill any free space on the right without overshooting.
697+
scrollOffset = lastTabEnd - entireScrollRect.width() + 1;
698+
}
695699
}
696700

701+
scrollOffset = qMax(0, scrollOffset);
702+
697703
leftB->setEnabled(scrollOffset > -scrollRect.left());
698704
rightB->setEnabled(scrollOffset < lastTabEnd - scrollRect.right());
699705

tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ private slots:
100100
void resizeKeepsScroll();
101101
void changeTabTextKeepsScroll();
102102
void settingCurrentTabBeforeShowDoesntScroll();
103+
void checkScrollResetAfterTabRemoval();
103104

104105
private:
105106
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
@@ -1482,5 +1483,50 @@ void tst_QTabBar::settingCurrentTabBeforeShowDoesntScroll()
14821483
QCOMPARE_GT(getScrollOffset(), 0);
14831484
}
14841485

1486+
void tst_QTabBar::checkScrollResetAfterTabRemoval()
1487+
{
1488+
class TabWidget : public QTabWidget
1489+
{
1490+
public:
1491+
using QTabWidget::QTabWidget;
1492+
using QTabWidget::setTabBar;
1493+
};
1494+
1495+
TabWidget tabWidget;
1496+
QTabBar tabBar;
1497+
tabBar.setUsesScrollButtons(true);
1498+
1499+
tabWidget.setTabBar(&tabBar);
1500+
for (int i = 0; i < 6; ++i)
1501+
tabWidget.addTab(new QWidget, u"Tab %1"_s.arg(i));
1502+
tabWidget.setTabPosition(QTabWidget::North);
1503+
tabWidget.setCurrentIndex(0);
1504+
tabWidget.show();
1505+
QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));
1506+
1507+
QVERIFY(tabWidget.tabBar()->tabRect(0).intersects(tabWidget.tabBar()->rect()));
1508+
auto *rightButton = tabBar.findChild<QAbstractButton*>(u"ScrollRightButton"_s);
1509+
1510+
QVERIFY(rightButton);
1511+
QVERIFY(rightButton->isEnabled());
1512+
// simulate a right button click to increase the scroll offset.
1513+
for (int i = 0; i < 2; i++)
1514+
rightButton->click();
1515+
1516+
const auto getScrollOffset = [&]() -> int {
1517+
return static_cast<QTabBarPrivate *>(QObjectPrivate::get(&tabBar))->scrollOffset;
1518+
};
1519+
1520+
// scroll offset is expected to be greater than 0.
1521+
QCOMPARE_GT(getScrollOffset(), 0);
1522+
1523+
QVERIFY(!tabWidget.tabBar()->tabRect(0).intersects(tabWidget.tabBar()->rect()));
1524+
// try removing the last tab and check if the scroll offset is reset to 0, to show the first tab.
1525+
tabWidget.removeTab(5);
1526+
1527+
// scroll offset is expected to be reset to 0.
1528+
QCOMPARE(getScrollOffset(), 0);
1529+
}
1530+
14851531
QTEST_MAIN(tst_QTabBar)
14861532
#include "tst_qtabbar.moc"

0 commit comments

Comments
 (0)