Fix scrolling of tab bar when the visible tab is wider than the visible space

When finding the index we need to scroll to, use the one where both start
and end of the tab rect are outside the currently visible section.
Otherwise we wouldn't scroll when the left-most index ends outside the
visible section.

Add test, which requires that the scroll buttons have object names.

Fixes: QTBUG-70498
Change-Id: Id153c77dd5fca146612375e0ff39bd1f3e0536b1
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
(cherry picked from commit 06b1e404c936847038cc7a371720b05f31532b6a)
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Volker Hilsheimer 2021-06-06 11:30:37 +02:00
parent 460ad31c7a
commit bed5306eaf
2 changed files with 79 additions and 4 deletions

View File

@ -408,10 +408,12 @@ void QTabBarPrivate::init()
{
Q_Q(QTabBar);
leftB = new QToolButton(q);
leftB->setObjectName(QStringLiteral("ScrollLeftButton"));
leftB->setAutoRepeat(true);
QObject::connect(leftB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
leftB->hide();
rightB = new QToolButton(q);
rightB->setObjectName(QStringLiteral("ScrollRightButton"));
rightB->setAutoRepeat(true);
QObject::connect(rightB, SIGNAL(clicked()), q, SLOT(_q_scrollTabs()));
rightB->hide();
@ -824,21 +826,24 @@ void QTabBarPrivate::_q_scrollTabs()
Q_Q(QTabBar);
const QObject *sender = q->sender();
const bool horizontal = !verticalTabs(shape);
const QRect scrollRect = normalizedScrollRect();
const QRect scrollRect = normalizedScrollRect().translated(scrollOffset, 0);
int i = -1;
if (sender == leftB) {
for (i = tabList.count() - 1; i >= 0; --i) {
int start = horizontal ? tabList.at(i)->rect.left() : tabList.at(i)->rect.top();
if (start < scrollRect.left() + scrollOffset) {
if (start < scrollRect.left()) {
makeVisible(i);
return;
}
}
} else if (sender == rightB) {
for (i = 0; i < tabList.count(); ++i) {
int end = horizontal ? tabList.at(i)->rect.right() : tabList.at(i)->rect.bottom();
if (end > scrollRect.right() + scrollOffset) {
const auto tabRect = tabList.at(i)->rect;
int start = horizontal ? tabRect.left() : tabRect.top();
int end = horizontal ? tabRect.right() : tabRect.bottom();
if (end > scrollRect.right() && start > scrollOffset) {
makeVisible(i);
return;
}

View File

@ -31,6 +31,7 @@
#include <QApplication>
#include <QTabBar>
#include <QPushButton>
#include <QLabel>
#include <QStyle>
#include <QStyleOptionTab>
#include <QProxyStyle>
@ -101,6 +102,9 @@ private slots:
void mouseWheel();
void scrollButtons_data();
void scrollButtons();
private:
void checkPositions(const TabBar &tabbar, const QList<int> &positions);
};
@ -927,6 +931,72 @@ void tst_QTabBar::mouseWheel()
QVERIFY(tabbar.currentIndex() != startIndex);
}
void tst_QTabBar::scrollButtons_data()
{
QTest::addColumn<QTabWidget::TabPosition>("tabPosition");
QTest::addColumn<Qt::LayoutDirection>("layoutDirection");
for (auto ld : {Qt::LeftToRight, Qt::RightToLeft}) {
const char *ldStr = ld == Qt::LeftToRight ? "LTR" : "RTL";
QTest::addRow("North, %s", ldStr) << QTabWidget::North << ld;
QTest::addRow("South, %s", ldStr) << QTabWidget::South << ld;
QTest::addRow("West, %s", ldStr) << QTabWidget::West << ld;
QTest::addRow("East, %s", ldStr) << QTabWidget::East << ld;
}
}
void tst_QTabBar::scrollButtons()
{
QFETCH(QTabWidget::TabPosition, tabPosition);
QFETCH(Qt::LayoutDirection, layoutDirection);
QWidget window;
QTabWidget tabWidget(&window);
tabWidget.setLayoutDirection(layoutDirection);
tabWidget.setTabPosition(tabPosition);
tabWidget.setElideMode(Qt::ElideNone);
tabWidget.setUsesScrollButtons(true);
const int tabCount = 5;
for (int i = 0; i < tabCount; ++i)
{
const QString num = QString::number(i);
tabWidget.addTab(new QLabel(num), num + " - Really long tab name to force arrows");
}
tabWidget.move(0, 0);
tabWidget.resize(tabWidget.minimumSizeHint());
window.show();
QVERIFY(QTest::qWaitForWindowActive(&window));
auto *leftB = tabWidget.tabBar()->findChild<QAbstractButton*>(QStringLiteral("ScrollLeftButton"));
auto *rightB = tabWidget.tabBar()->findChild<QAbstractButton*>(QStringLiteral("ScrollRightButton"));
QVERIFY(leftB->isVisible());
QVERIFY(!leftB->isEnabled());
QVERIFY(rightB->isVisible());
QVERIFY(rightB->isEnabled());
QVERIFY(!tabWidget.tabBar()->tabRect(1).intersects(tabWidget.tabBar()->rect()));
int index = 0;
for (; index < tabWidget.count(); ++index) {
QCOMPARE(leftB->isEnabled(), index > 0);
QCOMPARE(rightB->isEnabled(), index < tabWidget.count() - 1);
QVERIFY(tabWidget.tabBar()->tabRect(index).intersects(tabWidget.tabBar()->rect()));
QCOMPARE(tabWidget.tabBar()->tabAt(tabWidget.tabBar()->rect().center()), index);
if (rightB->isEnabled())
rightB->click();
}
for (--index; index >= 0; --index) {
QCOMPARE(leftB->isEnabled(), index >= 0);
QCOMPARE(rightB->isEnabled(), index < tabWidget.count() - 1);
QVERIFY(tabWidget.tabBar()->tabRect(index).intersects(tabWidget.tabBar()->rect()));
if (leftB->isEnabled())
leftB->click();
}
QVERIFY(!leftB->isEnabled());
}
#endif // QT_CONFIG(wheelevent)
QTEST_MAIN(tst_QTabBar)