Widgets: enable scroll buttons to be placed anywhere on a QTabBar

If a tab bar contain more tabs than it can fit inside its geometry, it
will show two scroll buttons that lets the user scroll left or right.
From before, those buttons where hard coded to always be placed
together on the right side of the tab bar.

This patch will make it possible for the style to specify the exact
geometry of both scroll buttons. The reason for this is that 3rd party
styles has a specific need to place the "scroll left" button on the left
side, and the "scroll right" on the right side. Additionally, there is a
need to draw fade-out effects on tabs that end up half-way obscured by the
buttons. This can already be achieved by extending the tab tear concept to
include two tears/fade effects, one for each side of the tab bar.

Previous code in QTabBar that hard-coded scroll buttons and related
functionality will now be factored out to the style, and the base
style (QCommonStyle) will implement the old default logic of placing the
buttons together on the right side. Six new style enums will be added:

SE_TabBarScrollLeftButton: the rect of the left scroll button
SE_TabBarScrollRightButton: the rect of the right scroll button
SE_TabBarTearIndicatorLeft: the rect of the left tab tear
SE_TabBarTearIndicatorRight: the rect of the right tab tear
PE_IndicatorTabTearLeft: draw the left tab tear
PE_IndicatorTabTearRight: draw the right tab tear

Change-Id: I4cda05c2f7323de5cbd3ca071eb796085257c19b
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
This commit is contained in:
Richard Moe Gustavsen 2015-09-29 13:15:29 +02:00
parent 52e335e191
commit a955d9d142
5 changed files with 226 additions and 98 deletions

View File

@ -552,18 +552,31 @@ void QCommonStyle::drawPrimitive(PrimitiveElement pe, const QStyleOption *opt, Q
case PE_IndicatorTabTear: case PE_IndicatorTabTear:
if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) { if (const QStyleOptionTab *tab = qstyleoption_cast<const QStyleOptionTab *>(opt)) {
bool rtl = tab->direction == Qt::RightToLeft; bool rtl = tab->direction == Qt::RightToLeft;
QRect rect = tab->rect; const bool horizontal = tab->rect.height() > tab->rect.width();
const int margin = 4;
QPainterPath path; QPainterPath path;
rect.setTop(rect.top() + ((tab->state & State_Selected) ? 1 : 3)); if (horizontal) {
rect.setBottom(rect.bottom() - ((tab->state & State_Selected) ? 0 : 2)); QRect rect = tab->rect.adjusted(rtl ? margin : 0, 0, rtl ? 1 : -margin, 0);
rect.setTop(rect.top() + ((tab->state & State_Selected) ? 1 : 3));
rect.setBottom(rect.bottom() - ((tab->state & State_Selected) ? 0 : 2));
path.moveTo(QPoint(rtl ? rect.right() : rect.left(), rect.top())); path.moveTo(QPoint(rtl ? rect.right() : rect.left(), rect.top()));
int count = 4; int count = 4;
for(int jags = 1; jags <= count; ++jags, rtl = !rtl) for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
path.lineTo(QPoint(rtl ? rect.left() : rect.right(), rect.top() + jags * rect.height()/count)); path.lineTo(QPoint(rtl ? rect.left() : rect.right(), rect.top() + jags * rect.height()/count));
} else {
QRect rect = tab->rect.adjusted(0, 0, 0, -margin);
rect.setLeft(rect.left() + ((tab->state & State_Selected) ? 1 : 3));
rect.setRight(rect.right() - ((tab->state & State_Selected) ? 0 : 2));
p->setPen(QPen(tab->palette.light(), qreal(.8))); path.moveTo(QPoint(rect.left(), rect.top()));
int count = 4;
for (int jags = 1; jags <= count; ++jags, rtl = !rtl)
path.lineTo(QPoint(rect.left() + jags * rect.width()/count, rtl ? rect.top() : rect.bottom()));
}
p->setPen(QPen(tab->palette.dark(), qreal(.8)));
p->setBrush(tab->palette.background()); p->setBrush(tab->palette.background());
p->setRenderHint(QPainter::Antialiasing); p->setRenderHint(QPainter::Antialiasing);
p->drawPath(path); p->drawPath(path);
@ -2796,13 +2809,13 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt,
case QTabBar::TriangularNorth: case QTabBar::TriangularNorth:
case QTabBar::RoundedSouth: case QTabBar::RoundedSouth:
case QTabBar::TriangularSouth: case QTabBar::TriangularSouth:
r.setRect(tab->rect.left(), tab->rect.top(), 4, opt->rect.height()); r.setRect(tab->rect.left(), tab->rect.top(), 8, opt->rect.height());
break; break;
case QTabBar::RoundedWest: case QTabBar::RoundedWest:
case QTabBar::TriangularWest: case QTabBar::TriangularWest:
case QTabBar::RoundedEast: case QTabBar::RoundedEast:
case QTabBar::TriangularEast: case QTabBar::TriangularEast:
r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), 4); r.setRect(tab->rect.left(), tab->rect.top(), opt->rect.width(), 8);
break; break;
default: default:
break; break;
@ -2810,6 +2823,23 @@ QRect QCommonStyle::subElementRect(SubElement sr, const QStyleOption *opt,
r = visualRect(opt->direction, opt->rect, r); r = visualRect(opt->direction, opt->rect, r);
} }
break; break;
case SE_TabBarScrollLeftButton: {
const bool vertical = opt->rect.width() < opt->rect.height();
const Qt::LayoutDirection ld = widget->layoutDirection();
const int buttonWidth = qMax(pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width());
const int buttonOverlap = pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, widget);
r = vertical ? QRect(0, opt->rect.height() - (buttonWidth * 2) + buttonOverlap, opt->rect.width(), buttonWidth)
: QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - (buttonWidth * 2) + buttonOverlap, 0, buttonWidth, opt->rect.height()));
break; }
case SE_TabBarScrollRightButton: {
const bool vertical = opt->rect.width() < opt->rect.height();
const Qt::LayoutDirection ld = widget->layoutDirection();
const int buttonWidth = qMax(pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, widget), QApplication::globalStrut().width());
r = vertical ? QRect(0, opt->rect.height() - buttonWidth, opt->rect.width(), buttonWidth)
: QStyle::visualRect(ld, opt->rect, QRect(opt->rect.width() - buttonWidth, 0, buttonWidth, opt->rect.height()));
break; }
#endif #endif
case SE_TreeViewDisclosureItem: case SE_TreeViewDisclosureItem:
r = opt->rect; r = opt->rect;

View File

@ -691,7 +691,9 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
\value PE_PanelToolBar The panel for a toolbar. \value PE_PanelToolBar The panel for a toolbar.
\value PE_PanelTipLabel The panel for a tip label. \value PE_PanelTipLabel The panel for a tip label.
\value PE_FrameTabBarBase The frame that is drawn for a tab bar, ususally drawn for a tab bar that isn't part of a tab widget. \value PE_FrameTabBarBase The frame that is drawn for a tab bar, ususally drawn for a tab bar that isn't part of a tab widget.
\value PE_IndicatorTabTear An indicator that a tab is partially scrolled out of the visible tab bar when there are many tabs. \value PE_IndicatorTabTear Deprecated. Use \l{PE_IndicatorTabTearLeft} instead.
\value PE_IndicatorTabTearLeft An indicator that a tab is partially scrolled out on the left side of the visible tab bar when there are many tabs.
\value PE_IndicatorTabTearRight An indicator that a tab is partially scrolled out on the right side of the visible tab bar when there are many tabs.
\value PE_IndicatorColumnViewArrow An arrow in a QColumnView. \value PE_IndicatorColumnViewArrow An arrow in a QColumnView.
\value PE_Widget A plain QWidget. \value PE_Widget A plain QWidget.
@ -1057,7 +1059,12 @@ void QStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment,
\value SE_ItemViewItemCheckIndicator Area for a view item's check mark. \value SE_ItemViewItemCheckIndicator Area for a view item's check mark.
\value SE_TabBarTearIndicator Area for the tear indicator on a tab bar with scroll arrows. \value SE_TabBarTearIndicator Deprecated. Use SE_TabBarTearIndicatorLeft instead.
\value SE_TabBarTearIndicatorLeft Area for the tear indicator on the left side of a tab bar with scroll arrows.
\value SE_TabBarTearIndicatorRight Area for the tear indicator on the right side of a tab bar with scroll arrows.
\value SE_TabBarScrollLeftButton Area for the scroll left button on a tab bar with scroll buttons.
\value SE_TabBarScrollRightButton Area for the scroll right button on a tab bar with scroll buttons.
\value SE_TreeViewDisclosureItem Area for the actual disclosure item in a tree branch. \value SE_TreeViewDisclosureItem Area for the actual disclosure item in a tree branch.

View File

@ -171,6 +171,7 @@ public:
PE_IndicatorToolBarSeparator, PE_IndicatorToolBarSeparator,
PE_PanelTipLabel, PE_PanelTipLabel,
PE_IndicatorTabTear, PE_IndicatorTabTear,
PE_IndicatorTabTearLeft = PE_IndicatorTabTear,
PE_PanelScrollAreaCorner, PE_PanelScrollAreaCorner,
PE_Widget, PE_Widget,
@ -186,6 +187,8 @@ public:
PE_IndicatorTabClose, PE_IndicatorTabClose,
PE_PanelMenu, PE_PanelMenu,
PE_IndicatorTabTearRight,
// do not add any values below/greater this // do not add any values below/greater this
PE_CustomBase = 0xf000000 PE_CustomBase = 0xf000000
}; };
@ -302,6 +305,7 @@ public:
SE_ItemViewItemCheckIndicator = SE_ViewItemCheckIndicator, SE_ItemViewItemCheckIndicator = SE_ViewItemCheckIndicator,
SE_TabBarTearIndicator, SE_TabBarTearIndicator,
SE_TabBarTearIndicatorLeft = SE_TabBarTearIndicator,
SE_TreeViewDisclosureItem, SE_TreeViewDisclosureItem,
@ -341,6 +345,10 @@ public:
SE_ToolBarHandle, SE_ToolBarHandle,
SE_TabBarScrollLeftButton,
SE_TabBarScrollRightButton,
SE_TabBarTearIndicatorRight,
// do not add any values below/greater than this // do not add any values below/greater than this
SE_CustomBase = 0xf0000000 SE_CustomBase = 0xf0000000
}; };

View File

@ -348,13 +348,6 @@ void QTabBar::initStyleOption(QStyleOptionTab *option, int tabIndex) const
\since 5.2 \since 5.2
*/ */
int QTabBarPrivate::extraWidth() const
{
Q_Q(const QTabBar);
return 2 * qMax(q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, 0, q),
QApplication::globalStrut().width());
}
void QTabBarPrivate::init() void QTabBarPrivate::init()
{ {
Q_Q(QTabBar); Q_Q(QTabBar);
@ -408,7 +401,6 @@ int QTabBarPrivate::indexAtPos(const QPoint &p) const
void QTabBarPrivate::layoutTabs() void QTabBarPrivate::layoutTabs()
{ {
Q_Q(QTabBar); Q_Q(QTabBar);
scrollOffset = 0;
layoutDirty = false; layoutDirty = false;
QSize size = q->size(); QSize size = q->size();
int last, available; int last, available;
@ -508,39 +500,48 @@ void QTabBarPrivate::layoutTabs()
} }
if (useScrollButtons && tabList.count() && last > available) { if (useScrollButtons && tabList.count() && last > available) {
int extra = extraWidth(); const QRect scrollRect = normalizedScrollRect(0);
if (!vertTabs) { scrollOffset = -scrollRect.left();
Qt::LayoutDirection ld = q->layoutDirection();
QRect arrows = QStyle::visualRect(ld, q->rect(),
QRect(available - extra, 0, extra, size.height()));
int buttonOverlap = q->style()->pixelMetric(QStyle::PM_TabBar_ScrollButtonOverlap, 0, q);
if (ld == Qt::LeftToRight) { Q_Q(QTabBar);
leftB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height()); QStyleOption opt;
rightB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(), opt.init(q);
extra/2, arrows.height()); QRect scrollButtonLeftRect = q->style()->subElementRect(QStyle::SE_TabBarScrollLeftButton, &opt, q);
leftB->setArrowType(Qt::LeftArrow); QRect scrollButtonRightRect = q->style()->subElementRect(QStyle::SE_TabBarScrollRightButton, &opt, q);
rightB->setArrowType(Qt::RightArrow); int scrollButtonWidth = q->style()->pixelMetric(QStyle::PM_TabBarScrollButtonWidth, &opt, q);
} else {
rightB->setGeometry(arrows.left(), arrows.top(), extra/2, arrows.height()); // Normally SE_TabBarScrollLeftButton should have the same width as PM_TabBarScrollButtonWidth.
leftB->setGeometry(arrows.right() - extra/2 + buttonOverlap, arrows.top(), // But if that is not the case, we set the actual button width to PM_TabBarScrollButtonWidth, and
extra/2, arrows.height()); // use the extra space from SE_TabBarScrollLeftButton as margins towards the tabs.
rightB->setArrowType(Qt::LeftArrow); if (vertTabs) {
leftB->setArrowType(Qt::RightArrow); scrollButtonLeftRect.setHeight(scrollButtonWidth);
} scrollButtonRightRect.setY(scrollButtonRightRect.bottom() + 1 - scrollButtonWidth);
} else { scrollButtonRightRect.setHeight(scrollButtonWidth);
QRect arrows = QRect(0, available - extra, size.width(), extra );
leftB->setGeometry(arrows.left(), arrows.top(), arrows.width(), extra/2);
leftB->setArrowType(Qt::UpArrow); leftB->setArrowType(Qt::UpArrow);
rightB->setGeometry(arrows.left(), arrows.bottom() - extra/2 + 1,
arrows.width(), extra/2);
rightB->setArrowType(Qt::DownArrow); rightB->setArrowType(Qt::DownArrow);
} else if (q->layoutDirection() == Qt::RightToLeft) {
scrollButtonRightRect.setWidth(scrollButtonWidth);
scrollButtonLeftRect.setX(scrollButtonLeftRect.right() + 1 - scrollButtonWidth);
scrollButtonLeftRect.setWidth(scrollButtonWidth);
leftB->setArrowType(Qt::RightArrow);
rightB->setArrowType(Qt::LeftArrow);
} else {
scrollButtonLeftRect.setWidth(scrollButtonWidth);
scrollButtonRightRect.setX(scrollButtonRightRect.right() + 1 - scrollButtonWidth);
scrollButtonRightRect.setWidth(scrollButtonWidth);
leftB->setArrowType(Qt::LeftArrow);
rightB->setArrowType(Qt::RightArrow);
} }
leftB->setEnabled(scrollOffset > 0);
rightB->setEnabled(last - scrollOffset >= available - extra); leftB->setGeometry(scrollButtonLeftRect);
leftB->setEnabled(false);
leftB->show(); leftB->show();
rightB->setGeometry(scrollButtonRightRect);
rightB->setEnabled(last - scrollOffset > scrollRect.x() + scrollRect.width());
rightB->show(); rightB->show();
} else { } else {
scrollOffset = 0;
rightB->hide(); rightB->hide();
leftB->hide(); leftB->hide();
} }
@ -549,6 +550,81 @@ void QTabBarPrivate::layoutTabs()
q->tabLayoutChange(); q->tabLayoutChange();
} }
QRect QTabBarPrivate::normalizedScrollRect(int index)
{
// "Normalized scroll rect" means return the free space on the tab bar
// that doesn't overlap with scroll buttons or tear indicators, and
// always return the rect as horizontal Qt::LeftToRight, even if the
// tab bar itself is in a different orientation.
Q_Q(QTabBar);
QStyleOptionTab opt;
q->initStyleOption(&opt, currentIndex);
opt.rect = q->rect();
QRect scrollButtonLeftRect = q->style()->subElementRect(QStyle::SE_TabBarScrollLeftButton, &opt, q);
QRect scrollButtonRightRect = q->style()->subElementRect(QStyle::SE_TabBarScrollRightButton, &opt, q);
QRect tearLeftRect = q->style()->subElementRect(QStyle::SE_TabBarTearIndicatorLeft, &opt, q);
QRect tearRightRect = q->style()->subElementRect(QStyle::SE_TabBarTearIndicatorRight, &opt, q);
if (verticalTabs(shape)) {
int topEdge, bottomEdge;
bool leftButtonIsOnTop = scrollButtonLeftRect.y() < q->height() / 2;
bool rightButtonIsOnTop = scrollButtonRightRect.y() < q->height() / 2;
if (leftButtonIsOnTop && rightButtonIsOnTop) {
topEdge = scrollButtonRightRect.bottom() + 1;
bottomEdge = q->height();
} else if (!leftButtonIsOnTop && !rightButtonIsOnTop) {
topEdge = 0;
bottomEdge = scrollButtonLeftRect.top();
} else {
topEdge = scrollButtonLeftRect.bottom() + 1;
bottomEdge = scrollButtonRightRect.top();
}
bool tearTopVisible = index != 0 && topEdge != -scrollOffset;
bool tearBottomVisible = index != tabList.size() - 1 && bottomEdge != tabList.last().rect.bottom() + 1 - scrollOffset;
if (tearTopVisible && !tearLeftRect.isNull())
topEdge = tearLeftRect.bottom() + 1;
if (tearBottomVisible && !tearRightRect.isNull())
bottomEdge = tearRightRect.top();
return QRect(topEdge, 0, bottomEdge - topEdge, q->height());
} else {
if (q->layoutDirection() == Qt::RightToLeft) {
scrollButtonLeftRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), scrollButtonLeftRect);
scrollButtonRightRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), scrollButtonRightRect);
tearLeftRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), tearLeftRect);
tearRightRect = QStyle::visualRect(Qt::RightToLeft, q->rect(), tearRightRect);
}
int leftEdge, rightEdge;
bool leftButtonIsOnLeftSide = scrollButtonLeftRect.x() < q->width() / 2;
bool rightButtonIsOnLeftSide = scrollButtonRightRect.x() < q->width() / 2;
if (leftButtonIsOnLeftSide && rightButtonIsOnLeftSide) {
leftEdge = scrollButtonRightRect.right() + 1;
rightEdge = q->width();
} else if (!leftButtonIsOnLeftSide && !rightButtonIsOnLeftSide) {
leftEdge = 0;
rightEdge = scrollButtonLeftRect.left();
} else {
leftEdge = scrollButtonLeftRect.right() + 1;
rightEdge = scrollButtonRightRect.left();
}
bool tearLeftVisible = index != 0 && leftEdge != -scrollOffset;
bool tearRightVisible = index != tabList.size() - 1 && rightEdge != tabList.last().rect.right() + 1 - scrollOffset;
if (tearLeftVisible && !tearLeftRect.isNull())
leftEdge = tearLeftRect.right() + 1;
if (tearRightVisible && !tearRightRect.isNull())
rightEdge = tearRightRect.left();
return QRect(leftEdge, 0, rightEdge - leftEdge, q->height());
}
}
void QTabBarPrivate::makeVisible(int index) void QTabBarPrivate::makeVisible(int index)
{ {
Q_Q(QTabBar); Q_Q(QTabBar);
@ -558,17 +634,24 @@ void QTabBarPrivate::makeVisible(int index)
const QRect tabRect = tabList.at(index).rect; const QRect tabRect = tabList.at(index).rect;
const int oldScrollOffset = scrollOffset; const int oldScrollOffset = scrollOffset;
const bool horiz = !verticalTabs(shape); const bool horiz = !verticalTabs(shape);
const int available = (horiz ? q->width() : q->height()) - extraWidth(); const int tabStart = horiz ? tabRect.left() : tabRect.top();
const int start = horiz ? tabRect.left() : tabRect.top(); const int tabEnd = horiz ? tabRect.right() : tabRect.bottom();
const int end = horiz ? tabRect.right() : tabRect.bottom(); const int lastTabEnd = horiz ? tabList.last().rect.right() : tabList.last().rect.bottom();
if (start < scrollOffset) // too far left const QRect scrollRect = normalizedScrollRect(index);
scrollOffset = start - (index ? 8 : 0); const int scrolledTabBarStart = qMax(1, scrollRect.left() + scrollOffset);
else if (end > scrollOffset + available) // too far right const int scrolledTabBarEnd = qMin(lastTabEnd - 1, scrollRect.right() + scrollOffset);
scrollOffset = end - available + 1;
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 = tabEnd - scrollRect.right();
}
leftB->setEnabled(scrollOffset > -scrollRect.left());
rightB->setEnabled(scrollOffset < lastTabEnd - scrollRect.right());
leftB->setEnabled(scrollOffset > 0);
const int last = horiz ? tabList.last().rect.right() : tabList.last().rect.bottom();
rightB->setEnabled(last - scrollOffset >= available);
if (oldScrollOffset != scrollOffset) { if (oldScrollOffset != scrollOffset) {
q->update(); q->update();
layoutWidgets(); layoutWidgets();
@ -664,39 +747,24 @@ void QTabBarPrivate::_q_scrollTabs()
{ {
Q_Q(QTabBar); Q_Q(QTabBar);
const QObject *sender = q->sender(); const QObject *sender = q->sender();
const bool horizontal = !verticalTabs(shape);
const QRect scrollRect = normalizedScrollRect();
int i = -1; int i = -1;
if (!verticalTabs(shape)) {
if (sender == leftB) { if (sender == leftB) {
for (i = tabList.count() - 1; i >= 0; --i) { for (i = tabList.count() - 1; i >= 0; --i) {
if (tabList.at(i).rect.left() - scrollOffset < 0) { int start = horizontal ? tabList.at(i).rect.left() : tabList.at(i).rect.top();
makeVisible(i); if (start < scrollRect.left() + scrollOffset) {
return; makeVisible(i);
} return;
}
} else if (sender == rightB) {
int availableWidth = q->width() - extraWidth();
for (i = 0; i < tabList.count(); ++i) {
if (tabList.at(i).rect.right() - scrollOffset > availableWidth) {
makeVisible(i);
return;
}
} }
} }
} else { // vertical } else if (sender == rightB) {
if (sender == leftB) { for (i = 0; i < tabList.count(); ++i) {
for (i = tabList.count() - 1; i >= 0; --i) { int end = horizontal ? tabList.at(i).rect.right() : tabList.at(i).rect.bottom();
if (tabList.at(i).rect.top() - scrollOffset < 0) { if (end > scrollRect.right() + scrollOffset) {
makeVisible(i); makeVisible(i);
return; return;
}
}
} else if (sender == rightB) {
int available = q->height() - extraWidth();
for (i = 0; i < tabList.count(); ++i) {
if (tabList.at(i).rect.bottom() - scrollOffset > available) {
makeVisible(i);
return;
}
} }
} }
} }
@ -1571,13 +1639,15 @@ void QTabBar::paintEvent(QPaintEvent *)
QStylePainter p(this); QStylePainter p(this);
int selected = -1; int selected = -1;
int cut = -1; int cutLeft = -1;
bool rtl = optTabBase.direction == Qt::RightToLeft; int cutRight = -1;
bool vertical = verticalTabs(d->shape); bool vertical = verticalTabs(d->shape);
QStyleOptionTab cutTab; QStyleOptionTab cutTabLeft;
QStyleOptionTab cutTabRight;
selected = d->currentIndex; selected = d->currentIndex;
if (d->dragInProgress) if (d->dragInProgress)
selected = d->pressedIndex; selected = d->pressedIndex;
const QRect scrollRect = d->normalizedScrollRect();
for (int i = 0; i < d->tabList.count(); ++i) for (int i = 0; i < d->tabList.count(); ++i)
optTabBase.tabBarRect |= tabRect(i); optTabBase.tabBarRect |= tabRect(i);
@ -1600,13 +1670,20 @@ void QTabBar::paintEvent(QPaintEvent *)
if (!(tab.state & QStyle::State_Enabled)) { if (!(tab.state & QStyle::State_Enabled)) {
tab.palette.setCurrentColorGroup(QPalette::Disabled); tab.palette.setCurrentColorGroup(QPalette::Disabled);
} }
// If this tab is partially obscured, make a note of it so that we can pass the information // If this tab is partially obscured, make a note of it so that we can pass the information
// along when we draw the tear. // along when we draw the tear.
if (((!vertical && (!rtl && tab.rect.left() < 0)) || (rtl && tab.rect.right() > width())) QRect tabRect = d->tabList[i].rect;
|| (vertical && tab.rect.top() < 0)) { int tabStart = vertical ? tabRect.top() : tabRect.left();
cut = i; int tabEnd = vertical ? tabRect.bottom() : tabRect.right();
cutTab = tab; if (tabStart < scrollRect.left() + d->scrollOffset) {
cutLeft = i;
cutTabLeft = tab;
} else if (tabEnd > scrollRect.right() + d->scrollOffset) {
cutRight = i;
cutTabRight = tab;
} }
// Don't bother drawing a tab if the entire tab is outside of the visible tab bar. // Don't bother drawing a tab if the entire tab is outside of the visible tab bar.
if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width())) if ((!vertical && (tab.rect.right() < 0 || tab.rect.left() > width()))
|| (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height()))) || (vertical && (tab.rect.bottom() < 0 || tab.rect.top() > height())))
@ -1638,10 +1715,16 @@ void QTabBar::paintEvent(QPaintEvent *)
} }
// Only draw the tear indicator if necessary. Most of the time we don't need too. // Only draw the tear indicator if necessary. Most of the time we don't need too.
if (d->leftB->isVisible() && cut >= 0) { if (d->leftB->isVisible() && cutLeft >= 0) {
cutTab.rect = rect(); cutTabLeft.rect = rect();
cutTab.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicator, &cutTab, this); cutTabLeft.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicatorLeft, &cutTabLeft, this);
p.drawPrimitive(QStyle::PE_IndicatorTabTear, cutTab); p.drawPrimitive(QStyle::PE_IndicatorTabTearLeft, cutTabLeft);
}
if (d->rightB->isVisible() && cutRight >= 0) {
cutTabRight.rect = rect();
cutTabRight.rect = style()->subElementRect(QStyle::SE_TabBarTearIndicatorRight, &cutTabRight, this);
p.drawPrimitive(QStyle::PE_IndicatorTabTearRight, cutTabRight);
} }
} }

View File

@ -150,7 +150,6 @@ public:
int calculateNewPosition(int from, int to, int index) const; int calculateNewPosition(int from, int to, int index) const;
void slide(int from, int to); void slide(int from, int to);
void init(); void init();
int extraWidth() const;
Tab *at(int index); Tab *at(int index);
const Tab *at(int index) const; const Tab *at(int index) const;
@ -178,6 +177,7 @@ public:
bool isTabInMacUnifiedToolbarArea() const; bool isTabInMacUnifiedToolbarArea() const;
void setupMovableTab(); void setupMovableTab();
void autoHideTabs(); void autoHideTabs();
QRect normalizedScrollRect(int index = -1);
void makeVisible(int index); void makeVisible(int index);
QSize iconSize; QSize iconSize;