29#include <QStylePainter>
30#include <QStyleOptionTab>
31#include <QStyleOptionTabBarBase>
32#include <QPropertyAnimation>
36#include <QApplication>
38#include <QtGuiVersion>
48 , m_mainTabBar(nullptr)
49 , m_pinnedTabBar(nullptr)
50 , m_mainBarOverFlowed(false)
51 , m_lastAppliedOverflow(false)
52 , m_usesScrollButtons(false)
53 , m_blockCurrentChangedSignal(false)
55 QObject::setObjectName(
QSL(
"tabbarwidget"));
65 connect(m_mainTabBarWidget->
scrollBar(), &QAbstractSlider::rangeChanged,
this, &ComboTabBar::setMinimumWidths);
67 connect(m_pinnedTabBarWidget->
scrollBar(), &QAbstractSlider::rangeChanged,
this, &ComboTabBar::setMinimumWidths);
72 m_pinnedTabBar->setTabsClosable(
false);
74 m_leftLayout =
new QHBoxLayout;
75 m_leftLayout->setSpacing(0);
76 m_leftLayout->setContentsMargins(0, 0, 0, 0);
77 m_leftContainer =
new QWidget(
this);
78 m_leftContainer->setLayout(m_leftLayout);
80 m_rightLayout =
new QHBoxLayout;
81 m_rightLayout->setSpacing(0);
82 m_rightLayout->setContentsMargins(0, 0, 0, 0);
83 m_rightContainer =
new QWidget(
this);
84 m_rightContainer->setLayout(m_rightLayout);
86 m_mainLayout =
new QHBoxLayout;
87 m_mainLayout->setSpacing(0);
88 m_mainLayout->setContentsMargins(0, 0, 0, 0);
89 m_mainLayout->addWidget(m_leftContainer);
90 m_mainLayout->addWidget(m_pinnedTabBarWidget);
91 m_mainLayout->addWidget(m_mainTabBarWidget);
92 m_mainLayout->addWidget(m_rightContainer);
93 setLayout(m_mainLayout);
95 connect(m_mainTabBar, &QTabBar::currentChanged,
this, &ComboTabBar::slotCurrentChanged);
96 connect(m_mainTabBar, &QTabBar::tabCloseRequested,
this, &ComboTabBar::slotTabCloseRequested);
97 connect(m_mainTabBar, &QTabBar::tabMoved,
this, &ComboTabBar::slotTabMoved);
99 connect(m_pinnedTabBar, &QTabBar::currentChanged,
this, &ComboTabBar::slotCurrentChanged);
100 connect(m_pinnedTabBar, &QTabBar::tabCloseRequested,
this, &ComboTabBar::slotTabCloseRequested);
101 connect(m_pinnedTabBar, &QTabBar::tabMoved,
this, &ComboTabBar::slotTabMoved);
103 setAutoFillBackground(
false);
104 m_mainTabBar->setAutoFillBackground(
false);
105 m_pinnedTabBar->setAutoFillBackground(
false);
107 m_mainTabBar->installEventFilter(
this);
108 m_pinnedTabBar->installEventFilter(
this);
109 m_leftContainer->installEventFilter(
this);
110 m_rightContainer->installEventFilter(
this);
111 m_mainTabBarWidget->installEventFilter(
this);
112 m_pinnedTabBarWidget->installEventFilter(
this);
133 index = m_pinnedTabBar->insertTab(index, icon, text);
136 index = m_mainTabBar->insertTab(index -
pinnedTabsCount(), icon, text);
140 if ((closeButton && closeButton->objectName() != QLatin1String(
"combotabbar_tabs_close_button")) || !closeButton) {
144 closeButton->deleteLater();
152 updatePinnedTabBarVisibility();
162 setUpdatesEnabled(
false);
164 localTabBar(index)->
removeTab(toLocalIndex(index));
165 updatePinnedTabBarVisibility();
169 setUpdatesEnabled(
true);
180 m_pinnedTabBar->moveTab(from, to);
186 return localTabBar(index)->isTabEnabled(toLocalIndex(index));
191 localTabBar(index)->setTabEnabled(toLocalIndex(index), enabled);
196 return localTabBar(index)->tabTextColor(toLocalIndex(index));
201 localTabBar(index)->setTabTextColor(toLocalIndex(index), color);
206 return mapFromLocalTabRect(localTabBar(index)->
tabRect(toLocalIndex(index)), localTabBar(index));
213 return mapFromLocalTabRect(r, m_pinnedTabBar);
215 return mapFromLocalTabRect(m_mainTabBar->
draggedTabRect(), m_mainTabBar);
220 return localTabBar(index)->
tabPixmap(toLocalIndex(index));
225 QWidget* w = QApplication::widgetAt(mapToGlobal(pos));
226 if (!qobject_cast<TabBarHelper*>(w) && !qobject_cast<TabIcon*>(w) && !qobject_cast<CloseButton*>(w))
229 if (m_pinnedTabBarWidget->geometry().contains(pos)) {
230 return m_pinnedTabBarWidget->
tabAt(m_pinnedTabBarWidget->mapFromParent(pos));
231 }
else if (m_mainTabBarWidget->geometry().contains(pos)) {
232 int index = m_mainTabBarWidget->
tabAt(m_mainTabBarWidget->mapFromParent(pos));
243 if (
tabAt(pos) != -1)
246 return qobject_cast<TabBarHelper*>(QApplication::widgetAt(mapToGlobal(pos)));
251 return (m_mainTabBar->currentIndex() == -1 ? -1 :
pinnedTabsCount() + m_mainTabBar->currentIndex());
257 return m_pinnedTabBar->currentIndex();
260 return (m_mainTabBar->currentIndex() == -1 ? -1 :
pinnedTabsCount() + m_mainTabBar->currentIndex());
269void ComboTabBar::slotCurrentChanged(
int index)
271 if (m_blockCurrentChangedSignal) {
275 if (sender() == m_pinnedTabBar) {
276 if (index == -1 && m_mainTabBar->count() > 0) {
301void ComboTabBar::slotTabCloseRequested(
int index)
303 if (sender() == m_pinnedTabBar) {
311void ComboTabBar::slotTabMoved(
int from,
int to)
313 if (sender() == m_pinnedTabBar) {
321void ComboTabBar::closeTabFromButton()
323 QWidget* button = qobject_cast<QWidget*>(sender());
327 for (
int i = 0;
i < m_mainTabBar->count(); ++
i) {
334 if (tabToClose != -1) {
339void ComboTabBar::updateTabBars()
341 m_mainTabBar->update();
342 m_pinnedTabBar->update();
345void ComboTabBar::emitOverFlowChanged()
347 if (m_mainBarOverFlowed != m_lastAppliedOverflow) {
349 m_lastAppliedOverflow = m_mainBarOverFlowed;
360 m_mainTabBar->setDrawBase(drawTheBase);
361 m_pinnedTabBar->setDrawBase(drawTheBase);
366 return m_mainTabBar->drawBase();
371 return m_mainTabBar->elideMode();
376 m_mainTabBar->setElideMode(elide);
377 m_pinnedTabBar->setElideMode(elide);
382 return localTabBar(index)->tabText(toLocalIndex(index));
387 localTabBar(index)->setTabText(toLocalIndex(index), text);
392 localTabBar(index)->setTabToolTip(toLocalIndex(index), tip);
397 return localTabBar(index)->tabToolTip(toLocalIndex(index));
402 return m_mainTabBar->tabsClosable();
413 for (
int i = 0;
i < m_mainTabBar->count(); ++
i) {
416 if (closeButton->objectName() == QLatin1String(
"combotabbar_tabs_close_button")) {
423 closeButton->deleteLater();
427 m_mainTabBar->setTabsClosable(closable);
434 localTabBar(index)->
setTabButton(toLocalIndex(index), position, widget);
439 return localTabBar(index)->tabButton(toLocalIndex(index), position);
444 return m_mainTabBar->selectionBehaviorOnRemove();
449 m_mainTabBar->setSelectionBehaviorOnRemove(behavior);
450 m_pinnedTabBar->setSelectionBehaviorOnRemove(behavior);
455 return m_mainTabBar->expanding();
460 m_mainTabBar->setExpanding(enabled);
461 m_pinnedTabBar->setExpanding(enabled);
466 return m_mainTabBar->isMovable();
471 m_mainTabBar->setMovable(movable);
472 m_pinnedTabBar->setMovable(movable);
477 return m_mainTabBar->documentMode();
482 m_mainTabBar->setDocumentMode(set);
483 m_pinnedTabBar->setDocumentMode(set);
488 return m_pinnedTabBar->count();
493 return m_mainTabBar->count();
503 QWidget::setFocusPolicy(policy);
504 m_mainTabBar->setFocusPolicy(policy);
505 m_pinnedTabBar->setFocusPolicy(policy);
510 m_mainTabBar->setObjectName(name);
511 m_pinnedTabBar->setObjectName(name);
516 m_mainTabBarWidget->
scrollArea()->setMouseTracking(enable);
517 m_mainTabBarWidget->setMouseTracking(enable);
518 m_mainTabBar->setMouseTracking(enable);
520 m_pinnedTabBarWidget->
scrollArea()->setMouseTracking(enable);
521 m_pinnedTabBarWidget->setMouseTracking(enable);
522 m_pinnedTabBar->setMouseTracking(enable);
524 QWidget::setMouseTracking(enable);
529 int height = qMax(m_mainTabBar->height(), m_pinnedTabBar->height());
532 height = qMax(m_mainTabBar->sizeHint().height(), m_pinnedTabBar->sizeHint().height());
537 height = qMax(5, height);
539 setFixedHeight(height);
540 m_leftContainer->setFixedHeight(height);
541 m_rightContainer->setFixedHeight(height);
547 if (isVisible() && height > 5) {
549 m_mainTabBar->setFixedHeight(height);
550 m_pinnedTabBar->setFixedHeight(height);
561 QAbstractButton* closeButton =
new CloseButton(
this);
563 closeButton->setToolTip(m_closeButtonsToolTip);
564 connect(closeButton, &QAbstractButton::clicked,
this, &ComboTabBar::closeTabFromButton);
570 m_closeButtonsToolTip = tip;
575 return m_mainTabBar->width();
580 return m_pinnedTabBarWidget->isHidden() ? 0 : m_pinnedTabBarWidget->width();
585 const bool res = QWidget::event(
event);
587 switch (
event->type()) {
588 case QEvent::ToolTip:
590 int index =
tabAt(mapFromGlobal(QCursor::pos()));
592 QToolTip::showText(QCursor::pos(),
tabToolTip(index));
601 if (!
event->spontaneous())
608 QTimer::singleShot(100,
this, &ComboTabBar::updateTabBars);
643 if (m_mainTabBarWidget->underMouse()) {
651 else if (m_pinnedTabBarWidget->underMouse()) {
663 if (obj == m_mainTabBar && ev->type() == QEvent::Resize) {
664 auto*
event =
static_cast<QResizeEvent*
>(ev);
665 if (
event->oldSize().height() !=
event->size().height()) {
671 if (ev->type() == QEvent::Wheel) {
676 return QWidget::eventFilter(obj, ev);
685 option.initFrom(
this);
687 style()->drawPrimitive(QStyle::PE_Widget, &option, &p,
this);
691 QStyleOptionTabBarBase opt;
695 opt.rect.setX(m_leftContainer->x());
696 opt.rect.setWidth(m_leftContainer->width());
697 style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
700 opt.rect.setX(m_rightContainer->x());
701 opt.rect.setWidth(m_rightContainer->width());
702 style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
704 if (m_mainBarOverFlowed) {
708 opt.rect.setX(m_mainTabBarWidget->x());
709 opt.rect.setWidth(scrollButtonWidth);
710 style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
713 opt.rect.setX(m_mainTabBarWidget->x() + m_mainTabBarWidget->width() - scrollButtonWidth);
714 opt.rect.setWidth(scrollButtonWidth);
715 style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
720 opt.rect.setX(m_mainTabBarWidget->x());
721 opt.rect.setWidth(m_mainTabBarWidget->width());
722 style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
753 return (
closeButtonPosition() == QTabBar::RightSide ? QTabBar::LeftSide : QTabBar::RightSide);
758 return (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition,
nullptr, m_mainTabBar);
764 s.setWidth(qMax(16, s.width()));
765 s.setHeight(qMax(16, s.height()));
771 int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth,
nullptr,
this);
772 int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight,
nullptr,
this);
773 return QSize(width, height);
778 return (index >= 0 && index <
count());
825 return m_mainBarOverFlowed;
830 if (corner == Qt::TopLeftCorner) {
831 return m_leftContainer->width();
833 else if (corner == Qt::TopRightCorner) {
834 return m_rightContainer->width();
837 qFatal(
"ComboTabBar::cornerWidth Only TopLeft and TopRight corners are implemented!");
843 if (corner == Qt::TopLeftCorner) {
844 m_leftLayout->addWidget(widget);
846 else if (corner == Qt::TopRightCorner) {
847 m_rightLayout->addWidget(widget);
850 qFatal(
"ComboTabBar::addCornerWidget Only TopLeft and TopRight corners are implemented!");
910 return m_pinnedTabBar;
914int ComboTabBar::toLocalIndex(
int globalIndex)
const
916 if (globalIndex < 0) {
928QRect ComboTabBar::mapFromLocalTabRect(
const QRect &rect, QWidget *tabBar)
const
930 if (!rect.isValid()) {
936 if (tabBar == m_mainTabBar) {
937 r.moveLeft(r.x() + mapFromGlobal(m_mainTabBar->mapToGlobal(QPoint(0, 0))).x());
938 QRect widgetRect = m_mainTabBarWidget->
scrollArea()->viewport()->rect();
939 widgetRect.moveLeft(widgetRect.x() + mapFromGlobal(m_mainTabBarWidget->
scrollArea()->viewport()->mapToGlobal(QPoint(0, 0))).x());
940 r = r.intersected(widgetRect);
942 r.moveLeft(r.x() + mapFromGlobal(m_pinnedTabBar->mapToGlobal(QPoint(0, 0))).x());
943 QRect widgetRect = m_pinnedTabBarWidget->
scrollArea()->viewport()->rect();
944 widgetRect.moveLeft(widgetRect.x() + mapFromGlobal(m_pinnedTabBarWidget->
scrollArea()->viewport()->mapToGlobal(QPoint(0, 0))).x());
945 r = r.intersected(widgetRect);
951void ComboTabBar::updatePinnedTabBarVisibility()
956void ComboTabBar::setMinimumWidths()
962 const int tabBarsSpacing = 3;
964 m_pinnedTabBar->setMinimumWidth(pinnedTabBarWidth);
965 m_pinnedTabBarWidget->setFixedWidth(pinnedTabBarWidth + tabBarsSpacing);
973 int realTabBarWidth =
mainTabBarWidth + m_pinnedTabBarWidget->width() +
978 if (realTabBarWidth <= width()) {
979 if (m_mainBarOverFlowed) {
980 m_mainBarOverFlowed =
false;
981 QTimer::singleShot(0,
this, &ComboTabBar::emitOverFlowChanged);
988 if (!m_mainBarOverFlowed) {
989 m_mainBarOverFlowed =
true;
990 QTimer::singleShot(0,
this, &ComboTabBar::emitOverFlowChanged);
1001 : QTabBar(comboTabBar)
1002 , m_comboTabBar(comboTabBar)
1003 , m_scrollArea(nullptr)
1004 , m_pressedIndex(-1)
1005 , m_dragInProgress(false)
1006 , m_activeTabBar(false)
1007 , m_isPinnedTabBar(isPinnedTabBar)
1008 , m_useFastTabSizeHint(false)
1014 return m_tabPadding;
1019 m_tabPadding = padding;
1029 m_baseColor = color;
1034 QTabBar::setTabButton(index, position, widget);
1039 if (
this == m_comboTabBar->mainTabBar()) {
1042 return m_comboTabBar->
tabSizeHint(index, m_useFastTabSizeHint);
1047 return QTabBar::tabSizeHint(index);
1052 if (!m_dragInProgress) {
1056 QStyleOptionTab tab;
1057 initStyleOption(&tab, m_pressedIndex);
1059 const int tabDragOffset = dragOffset(&tab, m_pressedIndex);
1060 if (tabDragOffset != 0) {
1061 tab.rect.moveLeft(tab.rect.x() + tabDragOffset);
1068 QStyleOptionTab tab;
1069 initStyleOption(&tab, index);
1071 tab.state &= ~QStyle::State_MouseOver;
1072 tab.position = QStyleOptionTab::OnlyOneTab;
1073 tab.leftButtonSize = QSize();
1074 tab.rightButtonSize = QSize();
1080 const QPixmap pix = iconButton->grab();
1081 if (!pix.isNull()) {
1083 tab.iconSize = pix.size() / pix.devicePixelRatioF();
1088 const int width = tab.fontMetrics.horizontalAdvance(tab.text) + closeButton->width();
1089 tab.text = tab.fontMetrics.elidedText(tabText(index), Qt::ElideRight, width);
1092 QPixmap out(tab.rect.size() * devicePixelRatioF());
1093 out.setDevicePixelRatio(devicePixelRatioF());
1094 out.fill(Qt::transparent);
1095 tab.rect = QRect(QPoint(0, 0), tab.rect.size());
1098 style()->drawControl(QStyle::CE_TabBarTab, &tab, &p,
this);
1106 return m_activeTabBar;
1111 if (m_activeTabBar != activate) {
1112 m_activeTabBar = activate;
1118 if (!m_activeTabBar) {
1119 m_comboTabBar->m_blockCurrentChangedSignal =
true;
1121 m_comboTabBar->m_blockCurrentChangedSignal =
false;
1133 m_comboTabBar->m_blockCurrentChangedSignal =
true;
1135 QTabBar::removeTab(index);
1137 m_comboTabBar->m_blockCurrentChangedSignal =
false;
1142 m_scrollArea = scrollArea;
1147 m_useFastTabSizeHint = enabled;
1152 m_dropIndicatorIndex = index;
1153 m_dropIndicatorPosition = position;
1159 m_dropIndicatorIndex = -1;
1165 bool isVisible =
true;
1168 if (globalRight < m_scrollArea->viewport()->mapToGlobal(QPoint(0, 0)).x() ||
1169 globalLeft > m_scrollArea->viewport()->mapToGlobal(m_scrollArea->viewport()->rect().topRight()).x()
1180 return m_dragInProgress;
1185 if (index == currentIndex() && !m_activeTabBar) {
1186 Q_EMIT currentChanged(currentIndex());
1189 QTabBar::setCurrentIndex(index);
1192bool TabBarHelper::event(QEvent* ev)
1194 switch (ev->type()) {
1195 case QEvent::ToolTip:
1209int TabBarHelper::dragOffset(QStyleOptionTab *option,
int tabIndex)
const
1212 QWidget *button = tabButton(tabIndex, QTabBar::LeftSide);
1214 rect = style()->subElementRect(QStyle::SE_TabBarTabLeftButton, option,
this);
1216 if (!rect.isValid()) {
1217 button = tabButton(tabIndex, QTabBar::RightSide);
1218 rect = style()->subElementRect(QStyle::SE_TabBarTabRightButton, option,
this);
1220 if (!button || !rect.isValid()) {
1223 return button->pos().x() - rect.topLeft().x();
1229 QStyleOptionTab tabOverlap;
1230 tabOverlap.shape = tabbar->shape();
1231 int overlap = tabbar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, tabbar);
1232 QWidget* theParent = tabbar->parentWidget();
1233 optTabBase->initFrom(tabbar);
1234 optTabBase->shape = tabbar->shape();
1235 optTabBase->documentMode = tabbar->documentMode();
1236 if (theParent && overlap > 0) {
1238 switch (tabOverlap.shape) {
1239 case QTabBar::RoundedNorth:
1240 case QTabBar::TriangularNorth:
1241 rect.setRect(0, size.height() - overlap, size.width(), overlap);
1243 case QTabBar::RoundedSouth:
1244 case QTabBar::TriangularSouth:
1245 rect.setRect(0, 0, size.width(), overlap);
1247 case QTabBar::RoundedEast:
1248 case QTabBar::TriangularEast:
1249 rect.setRect(0, 0, overlap, size.height());
1251 case QTabBar::RoundedWest:
1252 case QTabBar::TriangularWest:
1253 rect.setRect(size.width() - overlap, 0, overlap, size.height());
1256 optTabBase->rect = rect;
1262void TabBarHelper::paintEvent(QPaintEvent *)
1264 QStyleOptionTabBarBase optTabBase;
1267 QStylePainter p(
this);
1268 int selected = currentIndex();
1270 for (
int i = 0;
i < count(); ++
i) {
1271 optTabBase.tabBarRect |= tabRect(
i);
1274 if (m_activeTabBar) {
1275 optTabBase.selectedTabRect = tabRect(selected);
1279 p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
1282 const QPoint cursorPos = QCursor::pos();
1283 int indexUnderMouse =
isDisplayedOnViewPort(cursorPos.x(), cursorPos.x()) ? tabAt(mapFromGlobal(cursorPos)) : -1;
1285 for (
int i = 0;
i < count(); ++
i) {
1286 if (
i == selected) {
1290 QStyleOptionTab tab;
1291 initStyleOption(&tab,
i);
1293 const int tabDragOffset = dragOffset(&tab,
i);
1294 if (tabDragOffset != 0) {
1295 tab.rect.moveLeft(tab.rect.x() + tabDragOffset);
1299 if (!
isDisplayedOnViewPort(mapToGlobal(tab.rect.topLeft()).x(), mapToGlobal(tab.rect.topRight()).x())) {
1303 if (!m_activeTabBar) {
1304 tab.selectedPosition = QStyleOptionTab::NotAdjacent;
1307 if (!(tab.state & QStyle::State_Enabled)) {
1308 tab.palette.setCurrentColorGroup(QPalette::Disabled);
1312 if (!m_dragInProgress &&
i == indexUnderMouse) {
1313 tab.state |= QStyle::State_MouseOver;
1315 tab.state &= ~QStyle::State_MouseOver;
1318 p.drawControl(QStyle::CE_TabBarTab, tab);
1322 if (selected >= 0) {
1323 QStyleOptionTab tab;
1324 initStyleOption(&tab, selected);
1326 const int tabDragOffset = dragOffset(&tab, selected);
1327 if (tabDragOffset != 0) {
1328 tab.rect.moveLeft(tab.rect.x() + tabDragOffset);
1332 if (selected == indexUnderMouse) {
1333 tab.state |= QStyle::State_MouseOver;
1335 tab.state &= ~QStyle::State_MouseOver;
1338 if (!m_activeTabBar) {
1342 QStyleOptionTab tb = tab;
1343 tb.rect.moveRight((rect().x() + rect().width()) * 2);
1344 p.drawControl(QStyle::CE_TabBarTab, tb);
1347 tab.state = tab.state & ~QStyle::State_Selected;
1350 if (!m_movingTab || !m_movingTab->isVisible()) {
1351 p.drawControl(QStyle::CE_TabBarTab, tab);
1353 int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap,
nullptr,
this);
1354 m_movingTab->setGeometry(tab.rect.adjusted(-taboverlap, 0, taboverlap, 0));
1356 QRect grabRect = tabRect(selected);
1357 grabRect.adjust(-taboverlap, 0, taboverlap, 0);
1358 QPixmap grabImage(grabRect.size() * devicePixelRatioF());
1359 grabImage.setDevicePixelRatio(devicePixelRatioF());
1360 grabImage.fill(Qt::transparent);
1361 QStylePainter p(&grabImage,
this);
1362 if (tabDragOffset != 0) {
1363 tab.position = QStyleOptionTab::OnlyOneTab;
1365 tab.rect.moveTopLeft(QPoint(taboverlap, 0));
1366 p.drawControl(QStyle::CE_TabBarTab, tab);
1368 m_movingTab->update();
1373 if (m_dropIndicatorIndex != -1) {
1374 const QRect tr = tabRect(m_dropIndicatorIndex);
1377 r = QRect(qMax(0, tr.left() - 1), tr.top(), 3, tr.height());
1379 const int rightOffset = m_dropIndicatorIndex == count() - 1 ? -2 : 0;
1380 r = QRect(tr.right() + rightOffset, tr.top(), 3, tr.height());
1386void TabBarHelper::mousePressEvent(QMouseEvent* event)
1389 if (event->buttons() == Qt::LeftButton) {
1390 m_pressedIndex = tabAt(event->position().toPoint());
1391 if (m_pressedIndex != -1) {
1392 m_dragStartPosition =
event->position().toPoint();
1394 if (m_pressedIndex == currentIndex() && !m_activeTabBar) {
1395 Q_EMIT currentChanged(currentIndex());
1400 QTabBar::mousePressEvent(event);
1403void TabBarHelper::mouseMoveEvent(QMouseEvent *event)
1405 if (!m_dragInProgress && m_pressedIndex != -1) {
1406 if ((event->position().toPoint() - m_dragStartPosition).manhattanLength() > QApplication::startDragDistance()) {
1407 m_dragInProgress =
true;
1411 QTabBar::mouseMoveEvent(event);
1414 if (m_dragInProgress && !m_movingTab) {
1415 const auto objects = children();
1416 const int taboverlap = style()->pixelMetric(QStyle::PM_TabBarTabOverlap,
nullptr,
this);
1417 QRect grabRect = tabRect(currentIndex());
1418 grabRect.adjust(-taboverlap, 0, taboverlap, 0);
1419 for (QObject *
object : objects) {
1420 QWidget *widget = qobject_cast<QWidget*>(
object);
1421 if (widget && widget->geometry() == grabRect) {
1429 if (m_dragInProgress && m_movingTab) {
1431 if (isRightToLeft()) {
1434 QRect r = tabRect(m_pressedIndex);
1435 r.moveLeft(r.x() + (event->position().toPoint().x() - m_dragStartPosition.x()));
1436 bool sendEvent =
false;
1437 int diff = r.topRight().x() - tabRect(count() - 1).topRight().x();
1441 diff = r.topLeft().x() - tabRect(0).topLeft().x();
1447 QPoint pos =
event->position().toPoint();
1448 pos.setX(pos.x() - diff);
1449 QMouseEvent ev(event->type(), pos, event->globalPosition(), event->button(), event->buttons(), event->modifiers());
1450 QTabBar::mouseMoveEvent(&ev);
1455void TabBarHelper::mouseReleaseEvent(QMouseEvent* event)
1459 if (event->button() == Qt::LeftButton) {
1460 m_pressedIndex = -1;
1461 m_dragInProgress =
false;
1462 m_dragStartPosition = QPoint();
1465 QTabBar::mouseReleaseEvent(event);
1470void TabBarHelper::initStyleOption(QStyleOptionTab* option,
int tabIndex)
const
1472 QTabBar::initStyleOption(option, tabIndex);
1476 const QRect textRect = style()->subElementRect(QStyle::SE_TabBarTabText, option,
this);
1477 const int width = textRect.width() - 2 * m_tabPadding;
1478 option->text = option->fontMetrics.elidedText(tabText(tabIndex), elideMode(), width, Qt::TextShowMnemonic);
1482 static int isBespin = -1;
1485 isBespin =
mApp->styleName() ==
QL1S(
"bespin");
1490 int index = m_isPinnedTabBar ? tabIndex : m_comboTabBar->
pinnedTabsCount() + tabIndex;
1492 if (m_comboTabBar->
count() > 1) {
1494 option->position = QStyleOptionTab::Beginning;
1495 else if (index == m_comboTabBar->
count() - 1)
1496 option->position = QStyleOptionTab::End;
1498 option->position = QStyleOptionTab::Middle;
1501 option->position = QStyleOptionTab::OnlyOneTab;
1507 : QScrollBar(Qt::Horizontal, parent)
1509 m_animation =
new QPropertyAnimation(
this,
"value",
this);
1517 return m_animation->state() == QPropertyAnimation::Running;
1522 to = qBound(minimum(), to, maximum());
1523 int length = qAbs(to -
value());
1524 int duration = qMin(1500, 200 + length / 2);
1526 m_animation->stop();
1527 m_animation->setEasingCurve(type);
1528 m_animation->setDuration(duration);
1529 m_animation->setStartValue(
value());
1530 m_animation->setEndValue(to);
1531 m_animation->start();
1538 , m_usesScrollButtons(false)
1539 , m_totalVerticalDeltas(0)
1541 m_scrollArea =
new QScrollArea(
this);
1542 m_scrollArea->setFocusPolicy(Qt::NoFocus);
1543 m_scrollArea->setFrameStyle(QFrame::NoFrame);
1544 m_scrollArea->setWidgetResizable(
true);
1545 m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1546 m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
1549 m_scrollArea->setHorizontalScrollBar(m_scrollBar);
1550 m_scrollArea->setWidget(m_tabBar);
1553 m_leftScrollButton->setFocusPolicy(Qt::NoFocus);
1554 m_leftScrollButton->setAutoRaise(
true);
1555 m_leftScrollButton->setObjectName(
"tabbar-button-left");
1556 m_leftScrollButton->setAutoRepeat(
true);
1557 m_leftScrollButton->setAutoRepeatDelay(200);
1558 m_leftScrollButton->setAutoRepeatInterval(200);
1559 connect(m_leftScrollButton, &QAbstractButton::pressed,
this, &TabBarScrollWidget::scrollStart);
1561 connect(m_leftScrollButton, SIGNAL(middleMouseClicked()),
this, SLOT(
ensureVisible()));
1564 m_rightScrollButton->setFocusPolicy(Qt::NoFocus);
1565 m_rightScrollButton->setAutoRaise(
true);
1566 m_rightScrollButton->setObjectName(
"tabbar-button-right");
1567 m_rightScrollButton->setAutoRepeat(
true);
1568 m_rightScrollButton->setAutoRepeatDelay(200);
1569 m_rightScrollButton->setAutoRepeatInterval(200);
1570 connect(m_rightScrollButton, &QAbstractButton::pressed,
this, &TabBarScrollWidget::scrollStart);
1572 connect(m_rightScrollButton, SIGNAL(middleMouseClicked()),
this, SLOT(
ensureVisible()));
1574 auto* hLayout =
new QHBoxLayout;
1575 hLayout->setSpacing(0);
1576 hLayout->setContentsMargins(0, 0, 0, 0);
1577 hLayout->addWidget(m_leftScrollButton);
1578 hLayout->addWidget(m_scrollArea);
1579 hLayout->addWidget(m_rightScrollButton);
1582 m_scrollArea->viewport()->setAutoFillBackground(
false);
1583 connect(m_scrollBar, &QAbstractSlider::valueChanged,
this, &TabBarScrollWidget::updateScrollButtonsState);
1585 updateScrollButtonsState();
1586 overFlowChanged(
false);
1596 return m_scrollArea;
1607 index = m_tabBar->currentIndex();
1610 if (index < 0 || index >= m_tabBar->count()) {
1613 xmargin = qMin(xmargin, m_scrollArea->viewport()->width() / 2);
1617 const QRect logicalTabRect = QStyle::visualRect(m_tabBar->layoutDirection(), m_tabBar->rect(), m_tabBar->tabRect(index));
1618 int logicalX = QStyle::visualPos(Qt::LeftToRight, m_scrollArea->viewport()->rect(), logicalTabRect.center()).x();
1620 if (logicalX - xmargin < m_scrollBar->
value()) {
1623 else if (logicalX > m_scrollBar->value() + m_scrollArea->viewport()->width() - xmargin) {
1624 m_scrollBar->
animateToValue(qMin(logicalX - m_scrollArea->viewport()->width() + xmargin,
1625 m_scrollBar->maximum()));
1632 m_scrollBar->
animateToValue(m_scrollBar->value() - n * m_scrollBar->singleStep(), type);
1638 m_scrollBar->
animateToValue(m_scrollBar->value() + n * m_scrollBar->singleStep(), type);
1653 const int height = m_tabBar->height();
1655 setFixedHeight(height);
1658void TabBarScrollWidget::updateScrollButtonsState()
1660 m_leftScrollButton->setEnabled(m_scrollBar->value() != m_scrollBar->minimum());
1661 m_rightScrollButton->setEnabled(m_scrollBar->value() != m_scrollBar->maximum());
1664void TabBarScrollWidget::overFlowChanged(
bool overflowed)
1666 bool showScrollButtons = overflowed && m_usesScrollButtons;
1668 m_leftScrollButton->setVisible(showScrollButtons);
1669 m_rightScrollButton->setVisible(showScrollButtons);
1672void TabBarScrollWidget::scrollStart()
1674 bool ctrlModifier = QApplication::keyboardModifiers() & Qt::ControlModifier;
1676 if (sender() == m_leftScrollButton) {
1684 else if (sender() == m_rightScrollButton) {
1700 if (event->angleDelta().x() > 0) {
1703 else if (event->angleDelta().x() < 0) {
1707 auto verticalDelta =
event->angleDelta().y();
1708 if (verticalDelta == 0) {
1713 if (m_totalVerticalDeltas * verticalDelta < 0) {
1714 m_totalVerticalDeltas = 0;
1717 m_totalVerticalDeltas += verticalDelta;
1720 if (event->modifiers() == Qt::ControlModifier) {
1721 if (verticalDelta > 0) {
1724 else if (verticalDelta < 0) {
1731 int factor = qMax(qRound(m_scrollBar->pageStep() / 1.5), m_scrollBar->singleStep());
1732 if ((event->modifiers() & Qt::ControlModifier) || (event->modifiers() & Qt::ShiftModifier)) {
1733 factor = m_scrollBar->pageStep();
1736 int offset = (m_totalVerticalDeltas / 120) * factor;
1738 if (isRightToLeft()) {
1745 m_totalVerticalDeltas -= (offset / factor) * 120;
1752 return m_leftScrollButton->width();
1757 return m_usesScrollButtons;
1762 if (useButtons != m_usesScrollButtons) {
1763 m_usesScrollButtons = useButtons;
1764 updateScrollButtonsState();
1765 m_tabBar->setElideMode(m_tabBar->elideMode());
1771 return m_tabBar->count() > 0 && m_scrollBar->minimum() != m_scrollBar->maximum();
1776 if (m_leftScrollButton->isVisible() && (m_leftScrollButton->rect().contains(pos) ||
1777 m_rightScrollButton->rect().contains(pos))) {
1781 return m_tabBar->tabAt(m_tabBar->mapFromGlobal(mapToGlobal(pos)));
1784void TabBarScrollWidget::mouseMoveEvent(QMouseEvent* event)
1789void TabBarScrollWidget::resizeEvent(QResizeEvent* event)
1791 QWidget::resizeEvent(event);
1793 updateScrollButtonsState();
1798 : QAbstractButton(parent)
1800 setObjectName(
"combotabbar_tabs_close_button");
1801 setFocusPolicy(Qt::NoFocus);
1802 setCursor(Qt::ArrowCursor);
1809 int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth,
nullptr,
this);
1810 int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight,
nullptr,
this);
1811 return QSize(width, height);
1820 QAbstractButton::enterEvent(event);
1829 QAbstractButton::leaveEvent(event);
1837 opt.state |= QStyle::State_AutoRaise;
1840 bool isUnderMouse = rect().contains(mapFromGlobal(QCursor::pos()));
1842 if (isEnabled() && isUnderMouse && !isChecked() && !isDown()) {
1843 opt.state |= QStyle::State_Raised;
1846 opt.state |= QStyle::State_On;
1849 opt.state |= QStyle::State_Sunken;
1852 if (
auto* tb = qobject_cast<TabBarHelper*>(parent())) {
1853 int index = tb->currentIndex();
1854 auto closeSide = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition,
nullptr, tb);
1855 if (tb->tabButton(index, closeSide) ==
this && tb->isActiveTabBar()) {
1856 opt.state |= QStyle::State_Selected;
1860 style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p,
this);
bool validIndex(int index) const
virtual int comboTabBarPixelMetric(SizeType sizeType) const
int addTab(const QString &text)
int tabAt(const QPoint &pos) const
QTabBar::ButtonPosition iconButtonPosition() const
void setMovable(bool movable)
void tabCloseRequested(int index)
bool isDragInProgress() const
bool documentMode() const
QColor tabTextColor(int index) const
QSize closeButtonSize() const
virtual void tabRemoved(int index)
int insertTab(int index, const QString &text)
int normalTabsCount() const
void setMouseTracking(bool enable)
friend class TabBarHelper
QString tabText(int index) const
bool eventFilter(QObject *obj, QEvent *ev) override
void clearDropIndicator()
void addCornerWidget(QWidget *widget, Qt::Corner corner)
void moveTab(int from, int to)
int mainTabBarCurrentIndex() const
QTabBar::SelectionBehavior selectionBehaviorOnRemove() const
void showDropIndicator(int index, DropIndicatorPosition position)
void removeTab(int index)
QString tabToolTip(int index) const
void scrollBarValueChanged(int value)
QPixmap tabPixmap(int index) const
bool isPinned(int index) const
void setExpanding(bool enabled)
void setElideMode(Qt::TextElideMode elide)
QWidget * tabButton(int index, QTabBar::ButtonPosition position) const
QRect tabRect(int index) const
QSize iconButtonSize() const
void setTabTextColor(int index, const QColor &color)
void ensureVisible(int index=-1, int xmargin=-1)
QTabBar::ButtonPosition closeButtonPosition() const
void paintEvent(QPaintEvent *ev) override
int pinnedTabsCount() const
QRect draggedTabRect() const
void setTabButton(int index, QTabBar::ButtonPosition position, QWidget *widget)
bool isMainBarOverflowed() const
void currentChanged(int index)
void setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior behavior)
void setDrawBase(bool drawTheBase)
int pinTabBarWidth() const
int cornerWidth(Qt::Corner corner) const
void overFlowChanged(bool overFlow)
void setFocusPolicy(Qt::FocusPolicy policy)
void tabMoved(int from, int to)
void setTabToolTip(int index, const QString &tip)
ComboTabBar(QWidget *parent=nullptr)
bool usesScrollButtons() const
virtual void tabInserted(int index)
virtual QSize tabSizeHint(int index, bool fast=false) const
void setCloseButtonsToolTip(const QString &tip)
bool event(QEvent *event) override
void setTabText(int index, const QString &text)
bool isTabEnabled(int index) const
void wheelEvent(QWheelEvent *event) override
int mainTabBarWidth() const
void setTabsClosable(bool closable)
void setObjectName(const QString &name)
bool emptyArea(const QPoint &pos) const
void setUsesScrollButtons(bool useButtons)
bool tabsClosable() const
void setTabEnabled(int index, bool enabled)
void setDocumentMode(bool set)
void insertCloseButton(int index)
Qt::TextElideMode elideMode() const
bool isScrollInProgress() const
void setCurrentNextEnabledIndex(int offset)
void setCurrentIndex(int index)
static int slideAnimationDuration()
QSize baseClassTabSizeHint(int index) const
void setScrollArea(QScrollArea *scrollArea)
void setBaseColor(const QColor &color)
static void initStyleBaseOption(QStyleOptionTabBarBase *optTabBase, QTabBar *tabbar, QSize size)
bool isDisplayedOnViewPort(int globalLeft, int globalRight)
void setTabButton(int index, QTabBar::ButtonPosition position, QWidget *widget)
void useFastTabSizeHint(bool enabled)
void showDropIndicator(int index, ComboTabBar::DropIndicatorPosition position)
QPixmap tabPixmap(int index) const
bool isDragInProgress() const
void setActiveTabBar(bool activate)
void setTabPadding(int padding)
void clearDropIndicator()
QRect draggedTabRect() const
QSize tabSizeHint(int index) const override
void removeTab(int index)
void setCurrentIndex(int index)
TabBarHelper(bool isPinnedTabBar, ComboTabBar *comboTabBar)
Direction takeDirection()
void processEvent(QWheelEvent *event)
int value(const QColor &c)