Skip to content

Commit

Permalink
MAYA-131609: Tabs go missing when changing direction
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
senthilauto2023 authored and GitHub Enterprise committed Nov 28, 2023
2 parents 9d9e7c0 + a01806f commit 34e72dc
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 11 deletions.
28 changes: 17 additions & 11 deletions src/widgets/widgets/qtabbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -680,20 +680,26 @@ 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) {
// Tab is outside on the left, so scroll left.
scrollOffset = tabStart - scrollRect.left();
} else if (tabEnd > scrolledTabBarEnd) {
// Tab is outside on the right, so scroll right.
scrollOffset = qMax(0, tabEnd - scrollRect.right());
} 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
if (available >= lastTabEnd) {
// the entire tabbar fits, reset scroll offset.
scrollOffset = 0;
} else {
if (tabStart < scrolledTabBarStart) {
// Tab is partially occluded on the left, adjust offset to make tab fully visible.
scrollOffset = tabStart - scrollRect.left();
} else if (tabEnd > scrolledTabBarEnd) {
// Tab is partially occluded on the right, adjust offset to make tab fully visible.
scrollOffset = tabEnd - scrollRect.right();
}

if (scrollOffset + entireScrollRect.width() > lastTabEnd + 1) {
// fill any free space on the right without overshooting.
scrollOffset = lastTabEnd - entireScrollRect.width() + 1;
}
}

scrollOffset = qMax(0, scrollOffset);

leftB->setEnabled(scrollOffset > -scrollRect.left());
rightB->setEnabled(scrollOffset < lastTabEnd - scrollRect.right());

Expand Down
46 changes: 46 additions & 0 deletions tests/auto/widgets/widgets/qtabbar/tst_qtabbar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ private slots:
void resizeKeepsScroll();
void changeTabTextKeepsScroll();
void settingCurrentTabBeforeShowDoesntScroll();
void checkScrollResetAfterTabRemoval();

private:
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
Expand Down Expand Up @@ -1482,5 +1483,50 @@ void tst_QTabBar::settingCurrentTabBeforeShowDoesntScroll()
QCOMPARE_GT(getScrollOffset(), 0);
}

void tst_QTabBar::checkScrollResetAfterTabRemoval()
{
class TabWidget : public QTabWidget
{
public:
using QTabWidget::QTabWidget;
using QTabWidget::setTabBar;
};

TabWidget tabWidget;
QTabBar tabBar;
tabBar.setUsesScrollButtons(true);

tabWidget.setTabBar(&tabBar);
for (int i = 0; i < 6; ++i)
tabWidget.addTab(new QWidget, u"Tab %1"_s.arg(i));
tabWidget.setTabPosition(QTabWidget::North);
tabWidget.setCurrentIndex(0);
tabWidget.show();
QVERIFY(QTest::qWaitForWindowExposed(&tabWidget));

QVERIFY(tabWidget.tabBar()->tabRect(0).intersects(tabWidget.tabBar()->rect()));
auto *rightButton = tabBar.findChild<QAbstractButton*>(u"ScrollRightButton"_s);

QVERIFY(rightButton);
QVERIFY(rightButton->isEnabled());
// simulate a right button click to increase the scroll offset.
for (int i = 0; i < 2; i++)
rightButton->click();

const auto getScrollOffset = [&]() -> int {
return static_cast<QTabBarPrivate *>(QObjectPrivate::get(&tabBar))->scrollOffset;
};

// scroll offset is expected to be greater than 0.
QCOMPARE_GT(getScrollOffset(), 0);

QVERIFY(!tabWidget.tabBar()->tabRect(0).intersects(tabWidget.tabBar()->rect()));
// try removing the last tab and check if the scroll offset is reset to 0, to show the first tab.
tabWidget.removeTab(5);

// scroll offset is expected to be reset to 0.
QCOMPARE(getScrollOffset(), 0);
}

QTEST_MAIN(tst_QTabBar)
#include "tst_qtabbar.moc"

0 comments on commit 34e72dc

Please sign in to comment.