2013-11-26 14:14:36 +01:00
|
|
|
/* ============================================================
|
2017-01-21 12:23:24 +01:00
|
|
|
* QupZilla - Qt web browser
|
2016-04-24 10:17:13 +02:00
|
|
|
* Copyright (C) 2013-2014 S. Razi Alavizadeh <s.r.alavizadeh@gmail.com>
|
2017-01-21 12:23:24 +01:00
|
|
|
* Copyright (C) 2014-2017 David Rosca <nowrep@gmail.com>
|
2013-11-26 14:14:36 +01:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
* ============================================================ */
|
|
|
|
#include "combotabbar.h"
|
|
|
|
#include "toolbutton.h"
|
2014-05-02 13:35:01 +02:00
|
|
|
#include "tabicon.h"
|
2013-12-23 20:07:08 +01:00
|
|
|
#include "mainapplication.h"
|
|
|
|
#include "proxystyle.h"
|
2014-01-12 16:39:23 +01:00
|
|
|
#include "qzsettings.h"
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
#include <QIcon>
|
|
|
|
#include <QHBoxLayout>
|
|
|
|
#include <QStylePainter>
|
|
|
|
#include <QStyleOptionTabV3>
|
|
|
|
#include <QStyleOptionTabBarBaseV2>
|
|
|
|
#include <QPropertyAnimation>
|
|
|
|
#include <QScrollArea>
|
|
|
|
#include <QTimer>
|
|
|
|
#include <QTabBar>
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QApplication>
|
2015-10-11 10:51:16 +02:00
|
|
|
#include <QToolTip>
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
ComboTabBar::ComboTabBar(QWidget* parent)
|
|
|
|
: QWidget(parent)
|
|
|
|
, m_mainTabBar(0)
|
|
|
|
, m_pinnedTabBar(0)
|
|
|
|
, m_mainBarOverFlowed(false)
|
2014-03-30 16:40:36 +02:00
|
|
|
, m_lastAppliedOverflow(false)
|
2013-11-26 14:14:36 +01:00
|
|
|
, m_usesScrollButtons(false)
|
2014-04-01 18:47:19 +02:00
|
|
|
, m_blockCurrentChangedSignal(false)
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
2014-04-20 13:03:08 +02:00
|
|
|
QObject::setObjectName(QSL("tabbarwidget"));
|
|
|
|
|
2014-05-02 22:16:48 +02:00
|
|
|
m_mainTabBar = new TabBarHelper(/*isPinnedTabBar*/ false, this);
|
|
|
|
m_pinnedTabBar = new TabBarHelper(/*isPinnedTabBar*/ true, this);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBarWidget = new TabBarScrollWidget(m_mainTabBar, this);
|
|
|
|
m_pinnedTabBarWidget = new TabBarScrollWidget(m_pinnedTabBar, this);
|
|
|
|
|
|
|
|
m_mainTabBar->setScrollArea(m_mainTabBarWidget->scrollArea());
|
|
|
|
m_pinnedTabBar->setScrollArea(m_pinnedTabBarWidget->scrollArea());
|
|
|
|
|
2013-12-24 12:28:51 +01:00
|
|
|
connect(m_mainTabBarWidget->scrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(setMinimumWidths()));
|
2013-11-26 14:14:36 +01:00
|
|
|
connect(m_mainTabBarWidget->scrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrollBarValueChanged(int)));
|
2013-12-24 12:28:51 +01:00
|
|
|
connect(m_pinnedTabBarWidget->scrollBar(), SIGNAL(rangeChanged(int,int)), this, SLOT(setMinimumWidths()));
|
2013-11-26 14:14:36 +01:00
|
|
|
connect(m_pinnedTabBarWidget->scrollBar(), SIGNAL(valueChanged(int)), this, SIGNAL(scrollBarValueChanged(int)));
|
|
|
|
connect(this, SIGNAL(overFlowChanged(bool)), m_mainTabBarWidget, SLOT(overFlowChanged(bool)));
|
|
|
|
|
|
|
|
m_mainTabBar->setActiveTabBar(true);
|
|
|
|
m_pinnedTabBar->setTabsClosable(false);
|
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
m_leftLayout = new QHBoxLayout;
|
|
|
|
m_leftLayout->setSpacing(0);
|
|
|
|
m_leftLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
m_leftContainer = new QWidget(this);
|
|
|
|
m_leftContainer->setLayout(m_leftLayout);
|
|
|
|
|
|
|
|
m_rightLayout = new QHBoxLayout;
|
|
|
|
m_rightLayout->setSpacing(0);
|
|
|
|
m_rightLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
m_rightContainer = new QWidget(this);
|
|
|
|
m_rightContainer->setLayout(m_rightLayout);
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainLayout = new QHBoxLayout;
|
|
|
|
m_mainLayout->setSpacing(0);
|
|
|
|
m_mainLayout->setContentsMargins(0, 0, 0, 0);
|
2014-03-18 17:35:44 +01:00
|
|
|
m_mainLayout->addWidget(m_leftContainer);
|
|
|
|
m_mainLayout->addWidget(m_pinnedTabBarWidget);
|
|
|
|
m_mainLayout->addWidget(m_mainTabBarWidget);
|
|
|
|
m_mainLayout->addWidget(m_rightContainer);
|
2013-11-26 14:14:36 +01:00
|
|
|
setLayout(m_mainLayout);
|
|
|
|
|
|
|
|
connect(m_mainTabBar, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)));
|
|
|
|
connect(m_mainTabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(slotTabCloseRequested(int)));
|
|
|
|
connect(m_mainTabBar, SIGNAL(tabMoved(int,int)), this, SLOT(slotTabMoved(int,int)));
|
|
|
|
|
|
|
|
connect(m_pinnedTabBar, SIGNAL(currentChanged(int)), this, SLOT(slotCurrentChanged(int)));
|
|
|
|
connect(m_pinnedTabBar, SIGNAL(tabCloseRequested(int)), this, SLOT(slotTabCloseRequested(int)));
|
|
|
|
connect(m_pinnedTabBar, SIGNAL(tabMoved(int,int)), this, SLOT(slotTabMoved(int,int)));
|
|
|
|
|
|
|
|
setAutoFillBackground(false);
|
|
|
|
m_mainTabBar->setAutoFillBackground(false);
|
|
|
|
m_pinnedTabBar->setAutoFillBackground(false);
|
|
|
|
|
|
|
|
m_mainTabBar->installEventFilter(this);
|
2014-02-12 16:20:13 +01:00
|
|
|
m_pinnedTabBar->installEventFilter(this);
|
2014-05-28 17:53:28 +02:00
|
|
|
m_leftContainer->installEventFilter(this);
|
|
|
|
m_rightContainer->installEventFilter(this);
|
|
|
|
m_mainTabBarWidget->installEventFilter(this);
|
|
|
|
m_pinnedTabBarWidget->installEventFilter(this);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::addTab(const QString &text)
|
|
|
|
{
|
|
|
|
return insertTab(-1, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::addTab(const QIcon &icon, const QString &text)
|
|
|
|
{
|
|
|
|
return insertTab(-1, icon, text);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::insertTab(int index, const QString &text)
|
|
|
|
{
|
|
|
|
return insertTab(index, QIcon(), text);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::insertTab(int index, const QIcon &icon, const QString &text, bool pinned)
|
|
|
|
{
|
|
|
|
if (pinned) {
|
|
|
|
index = m_pinnedTabBar->insertTab(index, icon, text);
|
|
|
|
}
|
|
|
|
else {
|
2014-01-01 15:57:17 +01:00
|
|
|
index = m_mainTabBar->insertTab(index - pinnedTabsCount(), icon, text);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
if (tabsClosable()) {
|
|
|
|
QWidget* closeButton = m_mainTabBar->tabButton(index, closeButtonPosition());
|
2014-03-18 17:35:44 +01:00
|
|
|
if ((closeButton && closeButton->objectName() != QLatin1String("combotabbar_tabs_close_button")) || !closeButton) {
|
2013-11-26 14:14:36 +01:00
|
|
|
// insert our close button
|
|
|
|
insertCloseButton(index + pinnedTabsCount());
|
|
|
|
if (closeButton) {
|
|
|
|
closeButton->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
index += pinnedTabsCount();
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePinnedTabBarVisibility();
|
|
|
|
tabInserted(index);
|
2013-12-24 12:28:51 +01:00
|
|
|
setMinimumWidths();
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::removeTab(int index)
|
|
|
|
{
|
|
|
|
if (validIndex(index)) {
|
2014-02-09 14:26:03 +01:00
|
|
|
setUpdatesEnabled(false);
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
localTabBar(index)->removeTab(toLocalIndex(index));
|
|
|
|
updatePinnedTabBarVisibility();
|
|
|
|
tabRemoved(index);
|
2013-12-24 12:28:51 +01:00
|
|
|
setMinimumWidths();
|
2014-02-09 14:26:03 +01:00
|
|
|
|
2014-03-13 11:11:52 +01:00
|
|
|
setUpdatesEnabled(true);
|
|
|
|
updateTabBars();
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::moveTab(int from, int to)
|
|
|
|
{
|
|
|
|
if (from >= pinnedTabsCount() && to >= pinnedTabsCount()) {
|
|
|
|
m_mainTabBar->moveTab(from - pinnedTabsCount(), to - pinnedTabsCount());
|
|
|
|
}
|
|
|
|
else if (from < pinnedTabsCount() && to < pinnedTabsCount()) {
|
|
|
|
m_pinnedTabBar->moveTab(from, to);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::isTabEnabled(int index) const
|
|
|
|
{
|
|
|
|
return localTabBar(index)->isTabEnabled(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabEnabled(int index, bool enabled)
|
|
|
|
{
|
|
|
|
localTabBar(index)->setTabEnabled(toLocalIndex(index), enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
QColor ComboTabBar::tabTextColor(int index) const
|
|
|
|
{
|
|
|
|
return localTabBar(index)->tabTextColor(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabTextColor(int index, const QColor &color)
|
|
|
|
{
|
|
|
|
localTabBar(index)->setTabTextColor(toLocalIndex(index), color);
|
|
|
|
}
|
|
|
|
|
|
|
|
QRect ComboTabBar::tabRect(int index) const
|
|
|
|
{
|
|
|
|
QRect rect;
|
|
|
|
if (index != -1) {
|
|
|
|
bool mainTabBar = index >= pinnedTabsCount();
|
|
|
|
rect = localTabBar(index)->tabRect(toLocalIndex(index));
|
|
|
|
|
|
|
|
if (mainTabBar) {
|
|
|
|
rect.moveLeft(rect.x() + mapFromGlobal(m_mainTabBar->mapToGlobal(QPoint(0, 0))).x());
|
|
|
|
QRect widgetRect = m_mainTabBarWidget->scrollArea()->viewport()->rect();
|
|
|
|
widgetRect.moveLeft(widgetRect.x() + mapFromGlobal(m_mainTabBarWidget->scrollArea()->viewport()->mapToGlobal(QPoint(0, 0))).x());
|
2013-12-24 17:21:10 +01:00
|
|
|
rect = rect.intersected(widgetRect);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
rect.moveLeft(rect.x() + mapFromGlobal(m_pinnedTabBar->mapToGlobal(QPoint(0, 0))).x());
|
|
|
|
QRect widgetRect = m_pinnedTabBarWidget->scrollArea()->viewport()->rect();
|
|
|
|
widgetRect.moveLeft(widgetRect.x() + mapFromGlobal(m_pinnedTabBarWidget->scrollArea()->viewport()->mapToGlobal(QPoint(0, 0))).x());
|
2013-12-24 17:21:10 +01:00
|
|
|
rect = rect.intersected(widgetRect);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::tabAt(const QPoint &pos) const
|
|
|
|
{
|
2014-05-02 13:35:01 +02:00
|
|
|
QWidget* w = QApplication::widgetAt(mapToGlobal(pos));
|
|
|
|
if (!qobject_cast<TabBarHelper*>(w) && !qobject_cast<TabIcon*>(w))
|
2014-04-19 18:47:44 +02:00
|
|
|
return -1;
|
2013-12-23 21:24:41 +01:00
|
|
|
|
2014-04-19 18:47:44 +02:00
|
|
|
int index = m_pinnedTabBarWidget->tabAt(m_pinnedTabBarWidget->mapFromParent(pos));
|
|
|
|
if (index != -1)
|
2013-12-24 00:01:18 +01:00
|
|
|
return index;
|
|
|
|
|
2014-02-14 18:48:16 +01:00
|
|
|
index = m_mainTabBarWidget->tabAt(m_mainTabBarWidget->mapFromParent(pos));
|
2014-04-19 18:47:44 +02:00
|
|
|
if (index != -1)
|
2013-12-24 00:01:18 +01:00
|
|
|
index += pinnedTabsCount();
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
return index;
|
|
|
|
}
|
|
|
|
|
2014-03-15 23:46:10 +01:00
|
|
|
bool ComboTabBar::emptyArea(const QPoint &pos) const
|
|
|
|
{
|
2014-04-19 18:47:44 +02:00
|
|
|
if (tabAt(pos) != -1)
|
2014-03-15 23:46:10 +01:00
|
|
|
return false;
|
|
|
|
|
|
|
|
return qobject_cast<TabBarHelper*>(QApplication::widgetAt(mapToGlobal(pos)));
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
int ComboTabBar::mainTabBarCurrentIndex() const
|
|
|
|
{
|
|
|
|
return (m_mainTabBar->currentIndex() == -1 ? -1 : pinnedTabsCount() + m_mainTabBar->currentIndex());
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::currentIndex() const
|
|
|
|
{
|
|
|
|
if (m_pinnedTabBar->isActiveTabBar()) {
|
|
|
|
return m_pinnedTabBar->currentIndex();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return (m_mainTabBar->currentIndex() == -1 ? -1 : pinnedTabsCount() + m_mainTabBar->currentIndex());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setCurrentIndex(int index)
|
|
|
|
{
|
|
|
|
return localTabBar(index)->setCurrentIndex(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::slotCurrentChanged(int index)
|
|
|
|
{
|
2014-04-01 18:47:19 +02:00
|
|
|
if (m_blockCurrentChangedSignal) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
if (sender() == m_pinnedTabBar) {
|
|
|
|
if (index == -1 && m_mainTabBar->count() > 0) {
|
|
|
|
m_mainTabBar->setActiveTabBar(true);
|
|
|
|
m_pinnedTabBar->setActiveTabBar(false);
|
|
|
|
emit currentChanged(pinnedTabsCount());
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_pinnedTabBar->setActiveTabBar(true);
|
|
|
|
m_mainTabBar->setActiveTabBar(false);
|
|
|
|
emit currentChanged(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (index == -1 && pinnedTabsCount() > 0) {
|
|
|
|
m_pinnedTabBar->setActiveTabBar(true);
|
|
|
|
m_mainTabBar->setActiveTabBar(false);
|
|
|
|
emit currentChanged(pinnedTabsCount() - 1);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_mainTabBar->setActiveTabBar(true);
|
|
|
|
m_pinnedTabBar->setActiveTabBar(false);
|
|
|
|
emit currentChanged(index + pinnedTabsCount());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::slotTabCloseRequested(int index)
|
|
|
|
{
|
|
|
|
if (sender() == m_pinnedTabBar) {
|
|
|
|
emit tabCloseRequested(index);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit tabCloseRequested(index + pinnedTabsCount());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::slotTabMoved(int from, int to)
|
|
|
|
{
|
|
|
|
if (sender() == m_pinnedTabBar) {
|
|
|
|
emit tabMoved(from, to);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
emit tabMoved(from + pinnedTabsCount(), to + pinnedTabsCount());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::closeTabFromButton()
|
|
|
|
{
|
|
|
|
QWidget* button = qobject_cast<QWidget*>(sender());
|
|
|
|
|
|
|
|
int tabToClose = -1;
|
|
|
|
|
|
|
|
for (int i = 0; i < m_mainTabBar->count(); ++i) {
|
|
|
|
if (m_mainTabBar->tabButton(i, closeButtonPosition()) == button) {
|
|
|
|
tabToClose = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tabToClose != -1) {
|
|
|
|
emit tabCloseRequested(tabToClose + pinnedTabsCount());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
void ComboTabBar::updateTabBars()
|
|
|
|
{
|
|
|
|
m_mainTabBar->update();
|
|
|
|
m_pinnedTabBar->update();
|
|
|
|
}
|
|
|
|
|
2014-03-30 16:40:36 +02:00
|
|
|
void ComboTabBar::emitOverFlowChanged()
|
|
|
|
{
|
|
|
|
if (m_mainBarOverFlowed != m_lastAppliedOverflow) {
|
|
|
|
emit overFlowChanged(m_mainBarOverFlowed);
|
|
|
|
m_lastAppliedOverflow = m_mainBarOverFlowed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
int ComboTabBar::count() const
|
|
|
|
{
|
|
|
|
return pinnedTabsCount() + m_mainTabBar->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setDrawBase(bool drawTheBase)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setDrawBase(drawTheBase);
|
|
|
|
m_pinnedTabBar->setDrawBase(drawTheBase);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::drawBase() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->drawBase();
|
|
|
|
}
|
|
|
|
|
|
|
|
Qt::TextElideMode ComboTabBar::elideMode() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->elideMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setElideMode(Qt::TextElideMode elide)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setElideMode(elide);
|
|
|
|
m_pinnedTabBar->setElideMode(elide);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString ComboTabBar::tabText(int index) const
|
|
|
|
{
|
|
|
|
return localTabBar(index)->tabText(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabText(int index, const QString &text)
|
|
|
|
{
|
|
|
|
localTabBar(index)->setTabText(toLocalIndex(index), text);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabToolTip(int index, const QString &tip)
|
|
|
|
{
|
|
|
|
localTabBar(index)->setTabToolTip(toLocalIndex(index), tip);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString ComboTabBar::tabToolTip(int index) const
|
|
|
|
{
|
|
|
|
return localTabBar(index)->tabToolTip(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::tabsClosable() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->tabsClosable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabsClosable(bool closable)
|
|
|
|
{
|
|
|
|
if (closable == tabsClosable()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (closable) {
|
|
|
|
// insert our close button
|
|
|
|
for (int i = 0; i < m_mainTabBar->count(); ++i) {
|
|
|
|
QWidget* closeButton = m_mainTabBar->tabButton(i, closeButtonPosition());
|
|
|
|
if (closeButton) {
|
2014-01-01 15:57:17 +01:00
|
|
|
if (closeButton->objectName() == QLatin1String("combotabbar_tabs_close_button")) {
|
2013-11-26 14:14:36 +01:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
insertCloseButton(i + pinnedTabsCount());
|
|
|
|
if (closeButton) {
|
|
|
|
closeButton->deleteLater();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_mainTabBar->setTabsClosable(closable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setTabButton(int index, QTabBar::ButtonPosition position, QWidget* widget)
|
|
|
|
{
|
2016-01-25 13:33:05 +01:00
|
|
|
if (widget)
|
|
|
|
widget->setMinimumSize(closeButtonSize());
|
2013-11-26 14:14:36 +01:00
|
|
|
localTabBar(index)->setTabButton(toLocalIndex(index), position, widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
QWidget* ComboTabBar::tabButton(int index, QTabBar::ButtonPosition position) const
|
|
|
|
{
|
|
|
|
return localTabBar(index)->tabButton(toLocalIndex(index), position);
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar::SelectionBehavior ComboTabBar::selectionBehaviorOnRemove() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->selectionBehaviorOnRemove();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setSelectionBehaviorOnRemove(QTabBar::SelectionBehavior behavior)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setSelectionBehaviorOnRemove(behavior);
|
|
|
|
m_pinnedTabBar->setSelectionBehaviorOnRemove(behavior);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::expanding() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->expanding();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setExpanding(bool enabled)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setExpanding(enabled);
|
|
|
|
m_pinnedTabBar->setExpanding(enabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::isMovable() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->isMovable();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setMovable(bool movable)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setMovable(movable);
|
|
|
|
m_pinnedTabBar->setMovable(movable);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::documentMode() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->documentMode();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setDocumentMode(bool set)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setDocumentMode(set);
|
|
|
|
m_pinnedTabBar->setDocumentMode(set);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::pinnedTabsCount() const
|
|
|
|
{
|
|
|
|
return m_pinnedTabBar->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::normalTabsCount() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->count();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::isPinned(int index) const
|
|
|
|
{
|
|
|
|
return index >= 0 && index < pinnedTabsCount();
|
|
|
|
}
|
|
|
|
|
2017-01-27 16:51:14 +01:00
|
|
|
void ComboTabBar::setFocusPolicy(Qt::FocusPolicy policy)
|
|
|
|
{
|
|
|
|
QWidget::setFocusPolicy(policy);
|
|
|
|
m_mainTabBar->setFocusPolicy(policy);
|
|
|
|
m_pinnedTabBar->setFocusPolicy(policy);
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void ComboTabBar::setObjectName(const QString &name)
|
|
|
|
{
|
|
|
|
m_mainTabBar->setObjectName(name);
|
|
|
|
m_pinnedTabBar->setObjectName(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setMouseTracking(bool enable)
|
|
|
|
{
|
|
|
|
m_mainTabBarWidget->scrollArea()->setMouseTracking(enable);
|
|
|
|
m_mainTabBarWidget->setMouseTracking(enable);
|
|
|
|
m_mainTabBar->setMouseTracking(enable);
|
|
|
|
|
|
|
|
m_pinnedTabBarWidget->scrollArea()->setMouseTracking(enable);
|
|
|
|
m_pinnedTabBarWidget->setMouseTracking(enable);
|
|
|
|
m_pinnedTabBar->setMouseTracking(enable);
|
|
|
|
|
|
|
|
QWidget::setMouseTracking(enable);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setUpLayout()
|
|
|
|
{
|
2013-12-26 19:46:56 +01:00
|
|
|
int height = qMax(m_mainTabBar->height(), m_pinnedTabBar->height());
|
2013-12-23 20:07:08 +01:00
|
|
|
|
2013-12-26 19:52:07 +01:00
|
|
|
// Workaround for Oxygen theme. For some reason, QTabBar::height() returns bigger
|
|
|
|
// height than it actually should.
|
2014-03-10 00:47:07 +01:00
|
|
|
if (mApp->styleName() == QLatin1String("oxygen")) {
|
2013-12-23 20:07:08 +01:00
|
|
|
height -= 4;
|
|
|
|
}
|
|
|
|
|
2013-12-24 12:28:51 +01:00
|
|
|
// We need to setup heights even before m_mainTabBar->height() has correct value
|
|
|
|
// So lets just set minimum 5px height
|
|
|
|
height = qMax(5, height);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
setFixedHeight(height);
|
|
|
|
m_pinnedTabBar->setFixedHeight(height);
|
2014-03-18 17:35:44 +01:00
|
|
|
m_leftContainer->setFixedHeight(height);
|
|
|
|
m_rightContainer->setFixedHeight(height);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBarWidget->setUpLayout();
|
|
|
|
m_pinnedTabBarWidget->setUpLayout();
|
|
|
|
|
2013-12-24 12:28:51 +01:00
|
|
|
setMinimumWidths();
|
2014-02-11 10:53:50 +01:00
|
|
|
|
2014-02-13 14:47:18 +01:00
|
|
|
if (isVisible() && m_mainTabBar->count() > 0) {
|
2014-02-11 10:53:50 +01:00
|
|
|
// ComboTabBar is now visible, we can sync heights of both tabbars
|
2014-05-02 21:25:49 +02:00
|
|
|
m_pinnedTabBar->setFixedHeight(m_mainTabBar->sizeHint().height());
|
|
|
|
m_mainTabBar->setFixedHeight(m_mainTabBar->sizeHint().height());
|
2014-02-11 10:53:50 +01:00
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::insertCloseButton(int index)
|
|
|
|
{
|
|
|
|
index -= pinnedTabsCount();
|
|
|
|
if (index < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
QAbstractButton* closeButton = new CloseButton(this);
|
2016-01-25 13:33:05 +01:00
|
|
|
closeButton->setFixedSize(closeButtonSize());
|
2013-11-26 14:14:36 +01:00
|
|
|
closeButton->setToolTip(m_closeButtonsToolTip);
|
|
|
|
connect(closeButton, SIGNAL(clicked()), this, SLOT(closeTabFromButton()));
|
|
|
|
m_mainTabBar->setTabButton(index, closeButtonPosition(), closeButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setCloseButtonsToolTip(const QString &tip)
|
|
|
|
{
|
|
|
|
m_closeButtonsToolTip = tip;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::mainTabBarWidth() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->width();
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::pinTabBarWidth() const
|
|
|
|
{
|
|
|
|
return m_pinnedTabBarWidget->isHidden() ? 0 : m_pinnedTabBarWidget->width();
|
|
|
|
}
|
|
|
|
|
2015-10-11 10:51:16 +02:00
|
|
|
bool ComboTabBar::event(QEvent *event)
|
|
|
|
{
|
2016-08-15 14:47:30 +02:00
|
|
|
const bool res = QWidget::event(event);
|
|
|
|
|
2015-10-11 10:51:16 +02:00
|
|
|
switch (event->type()) {
|
|
|
|
case QEvent::ToolTip:
|
|
|
|
if (!isDragInProgress() && !isScrollInProgress()) {
|
|
|
|
int index = tabAt(mapFromGlobal(QCursor::pos()));
|
|
|
|
if (index >= 0)
|
|
|
|
QToolTip::showText(QCursor::pos(), tabToolTip(index));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2015-11-06 18:10:02 +01:00
|
|
|
case QEvent::Resize:
|
|
|
|
ensureVisible();
|
|
|
|
break;
|
|
|
|
|
2015-11-06 18:12:48 +01:00
|
|
|
case QEvent::Show:
|
|
|
|
if (!event->spontaneous())
|
|
|
|
QTimer::singleShot(0, this, &ComboTabBar::setUpLayout);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case QEvent::Enter:
|
|
|
|
case QEvent::Leave:
|
|
|
|
// Make sure tabs are painted with correct mouseover state
|
|
|
|
QTimer::singleShot(100, this, &ComboTabBar::updateTabBars);
|
|
|
|
break;
|
|
|
|
|
2015-10-11 10:51:16 +02:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-08-15 14:47:30 +02:00
|
|
|
return res;
|
2015-10-11 10:51:16 +02:00
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void ComboTabBar::wheelEvent(QWheelEvent* event)
|
|
|
|
{
|
|
|
|
event->accept();
|
2014-01-12 16:39:23 +01:00
|
|
|
|
2017-01-21 12:23:24 +01:00
|
|
|
if (qzSettings->alwaysSwitchTabsWithWheel || (!m_mainTabBarWidget->isOverflowed() && !m_pinnedTabBarWidget->isOverflowed())) {
|
|
|
|
m_wheelHelper.processEvent(event);
|
|
|
|
while (WheelHelper::Direction direction = m_wheelHelper.takeDirection()) {
|
|
|
|
switch (direction) {
|
|
|
|
case WheelHelper::WheelUp:
|
|
|
|
case WheelHelper::WheelLeft:
|
|
|
|
setCurrentNextEnabledIndex(-1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case WheelHelper::WheelDown:
|
|
|
|
case WheelHelper::WheelRight:
|
|
|
|
setCurrentNextEnabledIndex(1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-01-12 16:39:23 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
if (m_mainTabBarWidget->underMouse()) {
|
2014-01-22 16:57:04 +01:00
|
|
|
if (m_mainTabBarWidget->isOverflowed()) {
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBarWidget->scrollByWheel(event);
|
|
|
|
}
|
2014-01-22 16:57:04 +01:00
|
|
|
else if (m_pinnedTabBarWidget->isOverflowed()) {
|
2013-11-26 14:14:36 +01:00
|
|
|
m_pinnedTabBarWidget->scrollByWheel(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (m_pinnedTabBarWidget->underMouse()) {
|
2014-01-22 16:57:04 +01:00
|
|
|
if (m_pinnedTabBarWidget->isOverflowed()) {
|
2013-11-26 14:14:36 +01:00
|
|
|
m_pinnedTabBarWidget->scrollByWheel(event);
|
|
|
|
}
|
2014-01-22 16:57:04 +01:00
|
|
|
else if (m_mainTabBarWidget->isOverflowed()) {
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBarWidget->scrollByWheel(event);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::eventFilter(QObject* obj, QEvent* ev)
|
|
|
|
{
|
|
|
|
if (obj == m_mainTabBar && ev->type() == QEvent::Resize) {
|
|
|
|
QResizeEvent* event = static_cast<QResizeEvent*>(ev);
|
|
|
|
if (event->oldSize().height() != event->size().height()) {
|
|
|
|
setUpLayout();
|
|
|
|
}
|
|
|
|
}
|
2014-03-18 17:35:44 +01:00
|
|
|
|
2014-03-31 09:45:41 +02:00
|
|
|
// Handle wheel events exclusively in ComboTabBar
|
2014-02-12 16:20:13 +01:00
|
|
|
if (ev->type() == QEvent::Wheel) {
|
|
|
|
wheelEvent(static_cast<QWheelEvent*>(ev));
|
|
|
|
return true;
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
return QWidget::eventFilter(obj, ev);
|
|
|
|
}
|
|
|
|
|
2014-03-31 09:45:41 +02:00
|
|
|
void ComboTabBar::paintEvent(QPaintEvent* ev)
|
|
|
|
{
|
2014-04-20 13:03:08 +02:00
|
|
|
Q_UNUSED(ev);
|
|
|
|
|
|
|
|
// This is needed to apply style sheets
|
|
|
|
QStyleOption option;
|
|
|
|
option.init(this);
|
|
|
|
QPainter p(this);
|
|
|
|
style()->drawPrimitive(QStyle::PE_Widget, &option, &p, this);
|
2014-03-31 09:45:41 +02:00
|
|
|
|
2017-02-10 19:00:58 +01:00
|
|
|
#ifndef Q_OS_MACOS
|
2014-03-31 09:45:41 +02:00
|
|
|
// Draw tabbar base even on parts of ComboTabBar that are not directly QTabBar
|
2016-04-24 10:17:13 +02:00
|
|
|
QStyleOptionTabBarBase opt;
|
2014-03-31 09:45:41 +02:00
|
|
|
TabBarHelper::initStyleBaseOption(&opt, m_mainTabBar, size());
|
|
|
|
|
|
|
|
// Left container
|
|
|
|
opt.rect.setX(m_leftContainer->x());
|
|
|
|
opt.rect.setWidth(m_leftContainer->width());
|
|
|
|
style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
|
|
|
|
|
|
|
|
// Right container
|
|
|
|
opt.rect.setX(m_rightContainer->x());
|
|
|
|
opt.rect.setWidth(m_rightContainer->width());
|
|
|
|
style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
|
|
|
|
|
|
|
|
if (m_mainBarOverFlowed) {
|
|
|
|
const int scrollButtonWidth = m_mainTabBarWidget->scrollButtonsWidth();
|
|
|
|
|
|
|
|
// Left scroll button
|
|
|
|
opt.rect.setX(m_mainTabBarWidget->x());
|
|
|
|
opt.rect.setWidth(scrollButtonWidth);
|
|
|
|
style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
|
|
|
|
|
|
|
|
// Right scroll button
|
|
|
|
opt.rect.setX(m_mainTabBarWidget->x() + m_mainTabBarWidget->width() - scrollButtonWidth);
|
|
|
|
opt.rect.setWidth(scrollButtonWidth);
|
|
|
|
style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
|
|
|
|
}
|
2014-05-02 21:39:08 +02:00
|
|
|
|
|
|
|
// Draw base even when main tabbar is empty
|
|
|
|
if (normalTabsCount() == 0) {
|
|
|
|
opt.rect.setX(m_mainTabBarWidget->x());
|
|
|
|
opt.rect.setWidth(m_mainTabBarWidget->width());
|
|
|
|
style()->drawPrimitive(QStyle::PE_FrameTabBarBase, &opt, &p);
|
|
|
|
}
|
2014-04-15 09:58:12 +02:00
|
|
|
#endif
|
2014-03-31 09:45:41 +02:00
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
int ComboTabBar::comboTabBarPixelMetric(ComboTabBar::SizeType sizeType) const
|
|
|
|
{
|
|
|
|
switch (sizeType) {
|
|
|
|
case ExtraReservedWidth:
|
|
|
|
return 0;
|
2013-11-27 22:27:24 +01:00
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
case NormalTabMaximumWidth:
|
|
|
|
return 150;
|
2013-11-27 22:27:24 +01:00
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
case ActiveTabMinimumWidth:
|
2013-11-27 22:27:24 +01:00
|
|
|
case NormalTabMinimumWidth:
|
2013-11-26 14:14:36 +01:00
|
|
|
case OverflowedTabWidth:
|
|
|
|
return 100;
|
2013-11-27 22:27:24 +01:00
|
|
|
|
|
|
|
case PinnedTabWidth:
|
|
|
|
return 30;
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2016-01-25 13:33:05 +01:00
|
|
|
QTabBar::ButtonPosition ComboTabBar::iconButtonPosition() const
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
return (closeButtonPosition() == QTabBar::RightSide ? QTabBar::LeftSide : QTabBar::RightSide);
|
|
|
|
}
|
|
|
|
|
2016-01-25 13:33:05 +01:00
|
|
|
QTabBar::ButtonPosition ComboTabBar::closeButtonPosition() const
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
return (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
|
|
|
|
}
|
|
|
|
|
2016-01-25 13:33:05 +01:00
|
|
|
QSize ComboTabBar::iconButtonSize() const
|
|
|
|
{
|
|
|
|
QSize s = closeButtonSize();
|
2017-01-21 21:22:11 +01:00
|
|
|
s.setWidth(qMax(16, s.width()));
|
|
|
|
s.setHeight(qMax(16, s.height()));
|
2016-01-25 13:33:05 +01:00
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize ComboTabBar::closeButtonSize() const
|
|
|
|
{
|
|
|
|
int width = style()->pixelMetric(QStyle::PM_TabCloseIndicatorWidth, 0, this);
|
|
|
|
int height = style()->pixelMetric(QStyle::PM_TabCloseIndicatorHeight, 0, this);
|
|
|
|
return QSize(width, height);
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
bool ComboTabBar::validIndex(int index) const
|
|
|
|
{
|
|
|
|
return (index >= 0 && index < count());
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setCurrentNextEnabledIndex(int offset)
|
|
|
|
{
|
|
|
|
for (int index = currentIndex() + offset; validIndex(index); index += offset) {
|
|
|
|
if (isTabEnabled(index)) {
|
|
|
|
setCurrentIndex(index);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ComboTabBar::usesScrollButtons() const
|
|
|
|
{
|
|
|
|
return m_mainTabBarWidget->usesScrollButtons();
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::setUsesScrollButtons(bool useButtons)
|
|
|
|
{
|
|
|
|
m_mainTabBarWidget->setUsesScrollButtons(useButtons);
|
|
|
|
}
|
|
|
|
|
2014-02-13 15:42:25 +01:00
|
|
|
bool ComboTabBar::isDragInProgress() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar->isDragInProgress() || m_pinnedTabBar->isDragInProgress();
|
|
|
|
}
|
|
|
|
|
2015-10-11 10:51:16 +02:00
|
|
|
bool ComboTabBar::isScrollInProgress() const
|
|
|
|
{
|
|
|
|
return m_mainTabBarWidget->scrollBar()->isScrolling() || m_pinnedTabBarWidget->scrollBar()->isScrolling();
|
|
|
|
}
|
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
bool ComboTabBar::isMainBarOverflowed() const
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
2014-03-18 17:35:44 +01:00
|
|
|
return m_mainBarOverFlowed;
|
|
|
|
}
|
|
|
|
|
2014-03-31 09:50:54 +02:00
|
|
|
int ComboTabBar::cornerWidth(Qt::Corner corner) const
|
|
|
|
{
|
|
|
|
if (corner == Qt::TopLeftCorner) {
|
|
|
|
return m_leftContainer->width();
|
|
|
|
}
|
|
|
|
else if (corner == Qt::TopRightCorner) {
|
|
|
|
return m_rightContainer->width();
|
|
|
|
}
|
|
|
|
|
|
|
|
qFatal("ComboTabBar::cornerWidth Only TopLeft and TopRight corners are implemented!");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
void ComboTabBar::addCornerWidget(QWidget* widget, Qt::Corner corner)
|
|
|
|
{
|
|
|
|
if (corner == Qt::TopLeftCorner) {
|
|
|
|
m_leftLayout->addWidget(widget);
|
|
|
|
}
|
|
|
|
else if (corner == Qt::TopRightCorner) {
|
|
|
|
m_rightLayout->addWidget(widget);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
else {
|
2014-03-31 09:50:54 +02:00
|
|
|
qFatal("ComboTabBar::addCornerWidget Only TopLeft and TopRight corners are implemented!");
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-28 10:31:45 +01:00
|
|
|
// static
|
|
|
|
int ComboTabBar::slideAnimationDuration()
|
|
|
|
{
|
|
|
|
// taken from qtabbar_p.h
|
|
|
|
return 250;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void ComboTabBar::ensureVisible(int index, int xmargin)
|
|
|
|
{
|
|
|
|
if (index == -1) {
|
|
|
|
index = currentIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < pinnedTabsCount()) {
|
|
|
|
if (xmargin == -1) {
|
|
|
|
xmargin = qMax(20, comboTabBarPixelMetric(PinnedTabWidth));
|
|
|
|
}
|
|
|
|
m_pinnedTabBarWidget->ensureVisible(index, xmargin);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
if (xmargin == -1) {
|
|
|
|
xmargin = comboTabBarPixelMetric(OverflowedTabWidth);
|
|
|
|
}
|
|
|
|
index -= pinnedTabsCount();
|
|
|
|
m_mainTabBarWidget->ensureVisible(index, xmargin);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize ComboTabBar::tabSizeHint(int index, bool fast) const
|
|
|
|
{
|
|
|
|
Q_UNUSED(fast)
|
|
|
|
|
|
|
|
return localTabBar(index)->baseClassTabSizeHint(toLocalIndex(index));
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::tabInserted(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::tabRemoved(int index)
|
|
|
|
{
|
|
|
|
Q_UNUSED(index)
|
|
|
|
}
|
|
|
|
|
2014-03-13 12:07:05 +01:00
|
|
|
TabBarHelper* ComboTabBar::mainTabBar() const
|
|
|
|
{
|
|
|
|
return m_mainTabBar;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
TabBarHelper* ComboTabBar::localTabBar(int index) const
|
|
|
|
{
|
|
|
|
if (index < 0 || index >= pinnedTabsCount()) {
|
|
|
|
return m_mainTabBar;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return m_pinnedTabBar;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ComboTabBar::toLocalIndex(int globalIndex) const
|
|
|
|
{
|
|
|
|
if (globalIndex < 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (globalIndex >= pinnedTabsCount()) {
|
|
|
|
return globalIndex - pinnedTabsCount();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return globalIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ComboTabBar::updatePinnedTabBarVisibility()
|
|
|
|
{
|
|
|
|
m_pinnedTabBarWidget->setVisible(pinnedTabsCount() > 0);
|
|
|
|
}
|
|
|
|
|
2013-12-24 12:28:51 +01:00
|
|
|
void ComboTabBar::setMinimumWidths()
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
if (!isVisible() || comboTabBarPixelMetric(PinnedTabWidth) < 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-01-31 12:37:02 +01:00
|
|
|
const int tabBarsSpacing = 3; // To distinguish tabbars
|
2013-11-26 14:14:36 +01:00
|
|
|
int pinnedTabBarWidth = pinnedTabsCount() * comboTabBarPixelMetric(PinnedTabWidth);
|
|
|
|
m_pinnedTabBar->setMinimumWidth(pinnedTabBarWidth);
|
2016-01-31 12:37:02 +01:00
|
|
|
m_pinnedTabBarWidget->setFixedWidth(pinnedTabBarWidth + tabBarsSpacing);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
// Width that is needed by main tabbar
|
2013-11-27 22:27:24 +01:00
|
|
|
int mainTabBarWidth = comboTabBarPixelMetric(NormalTabMinimumWidth) * (m_mainTabBar->count() - 1) +
|
2013-11-26 14:14:36 +01:00
|
|
|
comboTabBarPixelMetric(ActiveTabMinimumWidth) +
|
|
|
|
comboTabBarPixelMetric(ExtraReservedWidth);
|
2013-11-27 22:27:24 +01:00
|
|
|
|
2014-03-31 10:33:17 +02:00
|
|
|
// This is the full width that would be needed for the tabbar (including pinned tabbar and corner widgets)
|
2014-03-31 09:50:54 +02:00
|
|
|
int realTabBarWidth = mainTabBarWidth + m_pinnedTabBarWidget->width() +
|
2014-03-31 10:33:17 +02:00
|
|
|
cornerWidth(Qt::TopLeftCorner) +
|
|
|
|
cornerWidth(Qt::TopRightCorner);
|
2014-03-18 17:35:44 +01:00
|
|
|
|
|
|
|
// Does it fit in our widget?
|
|
|
|
if (realTabBarWidth <= width()) {
|
2014-03-10 09:36:37 +01:00
|
|
|
if (m_mainBarOverFlowed) {
|
|
|
|
m_mainBarOverFlowed = false;
|
2014-03-30 16:40:36 +02:00
|
|
|
QTimer::singleShot(0, this, SLOT(emitOverFlowChanged()));
|
2014-03-10 09:36:37 +01:00
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBar->useFastTabSizeHint(false);
|
|
|
|
m_mainTabBar->setMinimumWidth(mainTabBarWidth);
|
|
|
|
}
|
|
|
|
else {
|
2014-03-10 09:36:37 +01:00
|
|
|
if (!m_mainBarOverFlowed) {
|
|
|
|
m_mainBarOverFlowed = true;
|
2014-03-30 16:40:36 +02:00
|
|
|
QTimer::singleShot(0, this, SLOT(emitOverFlowChanged()));
|
2014-03-10 09:36:37 +01:00
|
|
|
}
|
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
// All tabs have now same width, we can use fast tabSizeHint
|
2013-11-26 14:14:36 +01:00
|
|
|
m_mainTabBar->useFastTabSizeHint(true);
|
2014-03-18 17:35:44 +01:00
|
|
|
m_mainTabBar->setMinimumWidth(m_mainTabBar->count() * comboTabBarPixelMetric(OverflowedTabWidth));
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-05-02 22:16:48 +02:00
|
|
|
TabBarHelper::TabBarHelper(bool isPinnedTabBar, ComboTabBar* comboTabBar)
|
2013-11-26 14:14:36 +01:00
|
|
|
: QTabBar(comboTabBar)
|
|
|
|
, m_comboTabBar(comboTabBar)
|
|
|
|
, m_scrollArea(0)
|
|
|
|
, m_pressedIndex(-1)
|
|
|
|
, m_pressedGlobalX(-1)
|
|
|
|
, m_dragInProgress(false)
|
|
|
|
, m_activeTabBar(false)
|
2014-05-02 22:16:48 +02:00
|
|
|
, m_isPinnedTabBar(isPinnedTabBar)
|
2013-11-26 14:14:36 +01:00
|
|
|
, m_useFastTabSizeHint(false)
|
|
|
|
{
|
2014-12-25 12:46:31 +01:00
|
|
|
connect(this, SIGNAL(tabMoved(int,int)), this, SLOT(tabWasMoved(int,int)));
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::setTabButton(int index, QTabBar::ButtonPosition position, QWidget* widget)
|
|
|
|
{
|
|
|
|
QTabBar::setTabButton(index, position, widget);
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize TabBarHelper::tabSizeHint(int index) const
|
|
|
|
{
|
|
|
|
if (this == m_comboTabBar->mainTabBar()) {
|
|
|
|
index += m_comboTabBar->pinnedTabsCount();
|
|
|
|
}
|
|
|
|
return m_comboTabBar->tabSizeHint(index, m_useFastTabSizeHint);
|
|
|
|
}
|
|
|
|
|
|
|
|
QSize TabBarHelper::baseClassTabSizeHint(int index) const
|
|
|
|
{
|
|
|
|
return QTabBar::tabSizeHint(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TabBarHelper::isActiveTabBar()
|
|
|
|
{
|
|
|
|
return m_activeTabBar;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::setActiveTabBar(bool activate)
|
|
|
|
{
|
|
|
|
if (m_activeTabBar != activate) {
|
|
|
|
m_activeTabBar = activate;
|
2014-05-02 20:01:35 +02:00
|
|
|
|
|
|
|
// If the last tab in a tabbar is closed, the selection jumps to the other
|
|
|
|
// tabbar. The stacked widget automatically selects the next tab, which is
|
|
|
|
// either the last tab in pinned tabbar or the first one in main tabbar.
|
|
|
|
|
|
|
|
if (!m_activeTabBar) {
|
|
|
|
m_comboTabBar->m_blockCurrentChangedSignal = true;
|
2014-05-02 22:16:48 +02:00
|
|
|
setCurrentIndex(m_isPinnedTabBar ? count() - 1 : 0);
|
2014-05-02 20:01:35 +02:00
|
|
|
m_comboTabBar->m_blockCurrentChangedSignal = false;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-10 19:49:09 +01:00
|
|
|
void TabBarHelper::removeTab(int index)
|
|
|
|
{
|
|
|
|
// Removing tab in inactive tabbar will change current index and thus
|
|
|
|
// changing active tabbar, which is really not wanted.
|
2014-05-02 20:01:35 +02:00
|
|
|
if (!m_activeTabBar)
|
2014-04-01 18:47:19 +02:00
|
|
|
m_comboTabBar->m_blockCurrentChangedSignal = true;
|
2014-02-10 19:49:09 +01:00
|
|
|
|
|
|
|
QTabBar::removeTab(index);
|
|
|
|
|
2014-04-01 18:47:19 +02:00
|
|
|
m_comboTabBar->m_blockCurrentChangedSignal = false;
|
2014-02-10 19:49:09 +01:00
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabBarHelper::setScrollArea(QScrollArea* scrollArea)
|
|
|
|
{
|
|
|
|
m_scrollArea = scrollArea;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::useFastTabSizeHint(bool enabled)
|
|
|
|
{
|
|
|
|
m_useFastTabSizeHint = enabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TabBarHelper::isDisplayedOnViewPort(int globalLeft, int globalRight)
|
|
|
|
{
|
|
|
|
bool isVisible = true;
|
|
|
|
|
|
|
|
if (m_scrollArea) {
|
|
|
|
if (globalRight < m_scrollArea->viewport()->mapToGlobal(QPoint(0, 0)).x() ||
|
2014-04-05 14:42:19 +02:00
|
|
|
globalLeft > m_scrollArea->viewport()->mapToGlobal(m_scrollArea->viewport()->rect().topRight()).x()
|
|
|
|
) {
|
2013-11-26 14:14:36 +01:00
|
|
|
isVisible = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return isVisible;
|
|
|
|
}
|
|
|
|
|
2014-02-13 15:42:25 +01:00
|
|
|
bool TabBarHelper::isDragInProgress() const
|
|
|
|
{
|
|
|
|
return m_dragInProgress;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabBarHelper::setCurrentIndex(int index)
|
|
|
|
{
|
|
|
|
if (index == currentIndex() && !m_activeTabBar) {
|
|
|
|
emit currentChanged(currentIndex());
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar::setCurrentIndex(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TabBarHelper::event(QEvent* ev)
|
|
|
|
{
|
|
|
|
switch (ev->type()) {
|
|
|
|
case QEvent::ToolTip:
|
|
|
|
ev->ignore();
|
|
|
|
return false;
|
2014-02-11 23:28:41 +01:00
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar::event(ev);
|
|
|
|
ev->ignore();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-03-31 09:45:41 +02:00
|
|
|
// Taken from qtabbar.cpp
|
2016-04-24 10:17:13 +02:00
|
|
|
void TabBarHelper::initStyleBaseOption(QStyleOptionTabBarBase *optTabBase, QTabBar* tabbar, QSize size)
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
QStyleOptionTab tabOverlap;
|
|
|
|
tabOverlap.shape = tabbar->shape();
|
|
|
|
int overlap = tabbar->style()->pixelMetric(QStyle::PM_TabBarBaseOverlap, &tabOverlap, tabbar);
|
|
|
|
QWidget* theParent = tabbar->parentWidget();
|
|
|
|
optTabBase->init(tabbar);
|
|
|
|
optTabBase->shape = tabbar->shape();
|
|
|
|
optTabBase->documentMode = tabbar->documentMode();
|
|
|
|
if (theParent && overlap > 0) {
|
|
|
|
QRect rect;
|
|
|
|
switch (tabOverlap.shape) {
|
|
|
|
case QTabBar::RoundedNorth:
|
|
|
|
case QTabBar::TriangularNorth:
|
|
|
|
rect.setRect(0, size.height() - overlap, size.width(), overlap);
|
|
|
|
break;
|
|
|
|
case QTabBar::RoundedSouth:
|
|
|
|
case QTabBar::TriangularSouth:
|
|
|
|
rect.setRect(0, 0, size.width(), overlap);
|
|
|
|
break;
|
|
|
|
case QTabBar::RoundedEast:
|
|
|
|
case QTabBar::TriangularEast:
|
|
|
|
rect.setRect(0, 0, overlap, size.height());
|
|
|
|
break;
|
|
|
|
case QTabBar::RoundedWest:
|
|
|
|
case QTabBar::TriangularWest:
|
|
|
|
rect.setRect(size.width() - overlap, 0, overlap, size.height());
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
optTabBase->rect = rect;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-31 09:45:41 +02:00
|
|
|
// Adapted from qtabbar.cpp
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabBarHelper::paintEvent(QPaintEvent* event)
|
|
|
|
{
|
2014-03-31 09:45:41 +02:00
|
|
|
// Note: this code doesn't support vertical tabs
|
2014-02-11 23:28:41 +01:00
|
|
|
if (m_dragInProgress) {
|
|
|
|
QTabBar::paintEvent(event);
|
|
|
|
return;
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2016-04-24 10:17:13 +02:00
|
|
|
QStyleOptionTabBarBase optTabBase;
|
2014-02-11 23:28:41 +01:00
|
|
|
initStyleBaseOption(&optTabBase, this, size());
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
QStylePainter p(this);
|
|
|
|
int selected = currentIndex();
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
for (int i = 0; i < count(); ++i) {
|
|
|
|
optTabBase.tabBarRect |= tabRect(i);
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2017-01-27 14:06:06 +01:00
|
|
|
if (m_activeTabBar) {
|
|
|
|
optTabBase.selectedTabRect = tabRect(selected);
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
if (drawBase()) {
|
|
|
|
p.drawPrimitive(QStyle::PE_FrameTabBarBase, optTabBase);
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
const QPoint cursorPos = QCursor::pos();
|
|
|
|
int indexUnderMouse = isDisplayedOnViewPort(cursorPos.x(), cursorPos.x()) ? tabAt(mapFromGlobal(cursorPos)) : -1;
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
for (int i = 0; i < count(); ++i) {
|
2016-04-24 10:17:13 +02:00
|
|
|
QStyleOptionTab tab;
|
2014-02-11 23:28:41 +01:00
|
|
|
initStyleOption(&tab, i);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
if (i == selected) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
// Don't bother drawing a tab if the entire tab is outside of the visible tab bar.
|
|
|
|
if (!isDisplayedOnViewPort(mapToGlobal(tab.rect.topLeft()).x(), mapToGlobal(tab.rect.topRight()).x())) {
|
|
|
|
continue;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
2017-01-27 14:24:03 +01:00
|
|
|
if (!m_activeTabBar) {
|
|
|
|
tab.selectedPosition = QStyleOptionTab::NotAdjacent;
|
|
|
|
}
|
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
if (!(tab.state & QStyle::State_Enabled)) {
|
|
|
|
tab.palette.setCurrentColorGroup(QPalette::Disabled);
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
// Update mouseover state when scrolling
|
|
|
|
if (i == indexUnderMouse) {
|
|
|
|
tab.state |= QStyle::State_MouseOver;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
2014-02-11 23:28:41 +01:00
|
|
|
else {
|
|
|
|
tab.state &= ~QStyle::State_MouseOver;
|
|
|
|
}
|
|
|
|
|
|
|
|
p.drawControl(QStyle::CE_TabBarTab, tab);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
// Draw the selected tab last to get it "on top"
|
|
|
|
if (selected >= 0) {
|
2016-04-24 10:17:13 +02:00
|
|
|
QStyleOptionTab tab;
|
2014-02-11 23:28:41 +01:00
|
|
|
initStyleOption(&tab, selected);
|
|
|
|
|
|
|
|
// Update mouseover state when scrolling
|
|
|
|
if (selected == indexUnderMouse) {
|
|
|
|
tab.state |= QStyle::State_MouseOver;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
tab.state &= ~QStyle::State_MouseOver;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
2014-02-11 23:28:41 +01:00
|
|
|
if (!m_activeTabBar) {
|
|
|
|
// If this is inactive tab, we still need to draw selected tab outside the tabbar
|
|
|
|
// Some themes (eg. Oxygen) draws line under tabs with selected tab
|
|
|
|
// Let's just move it outside rect(), it appears to work
|
2016-04-24 10:17:13 +02:00
|
|
|
QStyleOptionTab tb = tab;
|
2014-02-11 23:28:41 +01:00
|
|
|
tb.rect.moveRight((rect().x() + rect().width()) * 2);
|
|
|
|
p.drawControl(QStyle::CE_TabBarTab, tb);
|
|
|
|
|
|
|
|
// Draw the tab without selected state
|
|
|
|
tab.state = tab.state & ~QStyle::State_Selected;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
2014-02-11 23:28:41 +01:00
|
|
|
|
|
|
|
p.drawControl(QStyle::CE_TabBarTab, tab);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::mousePressEvent(QMouseEvent* event)
|
|
|
|
{
|
|
|
|
event->ignore();
|
2014-03-01 14:12:50 +01:00
|
|
|
if (event->buttons() == Qt::LeftButton) {
|
2013-11-26 14:14:36 +01:00
|
|
|
m_pressedIndex = tabAt(event->pos());
|
|
|
|
if (m_pressedIndex != -1) {
|
|
|
|
m_pressedGlobalX = event->globalX();
|
|
|
|
m_dragInProgress = true;
|
|
|
|
// virtualize selecting tab by click
|
|
|
|
if (m_pressedIndex == currentIndex() && !m_activeTabBar) {
|
|
|
|
emit currentChanged(currentIndex());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar::mousePressEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::mouseReleaseEvent(QMouseEvent* event)
|
|
|
|
{
|
|
|
|
event->ignore();
|
2014-12-25 12:46:31 +01:00
|
|
|
if (event->button() != Qt::LeftButton) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
QTabBar::mouseReleaseEvent(event);
|
|
|
|
|
2014-12-25 12:46:31 +01:00
|
|
|
if (m_pressedIndex >= 0 && m_pressedIndex < count()) {
|
2017-01-28 10:31:45 +01:00
|
|
|
QTimer::singleShot(ComboTabBar::slideAnimationDuration(), this, &TabBarHelper::resetDragState);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
m_pressedIndex = -1;
|
|
|
|
m_pressedGlobalX = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-02 22:15:36 +02:00
|
|
|
void TabBarHelper::initStyleOption(QStyleOptionTab* option, int tabIndex) const
|
|
|
|
{
|
|
|
|
QTabBar::initStyleOption(option, tabIndex);
|
|
|
|
|
2014-05-03 11:40:14 +02:00
|
|
|
// Bespin doesn't highlight current tab when there is only one tab in tabbar
|
|
|
|
static int isBespin = -1;
|
|
|
|
|
|
|
|
if (isBespin == -1)
|
|
|
|
isBespin = mApp->styleName() == QL1S("bespin");
|
|
|
|
|
|
|
|
if (!isBespin)
|
|
|
|
return;
|
|
|
|
|
2014-05-02 22:16:48 +02:00
|
|
|
int index = m_isPinnedTabBar ? tabIndex : m_comboTabBar->pinnedTabsCount() + tabIndex;
|
2014-05-02 22:15:36 +02:00
|
|
|
|
|
|
|
if (m_comboTabBar->count() > 1) {
|
|
|
|
if (index == 0)
|
|
|
|
option->position = QStyleOptionTab::Beginning;
|
|
|
|
else if (index == m_comboTabBar->count() - 1)
|
|
|
|
option->position = QStyleOptionTab::End;
|
|
|
|
else
|
|
|
|
option->position = QStyleOptionTab::Middle;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
option->position = QStyleOptionTab::OnlyOneTab;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabBarHelper::resetDragState()
|
|
|
|
{
|
|
|
|
if (m_pressedIndex == -1) {
|
|
|
|
m_dragInProgress = false;
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-12-25 12:46:31 +01:00
|
|
|
void TabBarHelper::tabWasMoved(int from, int to)
|
|
|
|
{
|
|
|
|
if (m_pressedIndex != -1) {
|
|
|
|
if (m_pressedIndex == from) {
|
|
|
|
m_pressedIndex = to;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const int start = qMin(from, to);
|
|
|
|
const int end = qMax(from, to);
|
|
|
|
|
|
|
|
if (m_pressedIndex >= start && m_pressedIndex <= end) {
|
|
|
|
m_pressedIndex += (from < to) ? -1 : 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::tabInserted(int index)
|
|
|
|
{
|
|
|
|
if (m_pressedIndex != -1 && index <= m_pressedIndex) {
|
|
|
|
++m_pressedIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarHelper::tabRemoved(int index)
|
|
|
|
{
|
|
|
|
if (m_pressedIndex != -1) {
|
|
|
|
if (index < m_pressedIndex) {
|
|
|
|
--m_pressedIndex;
|
|
|
|
}
|
|
|
|
else if (index == m_pressedIndex) {
|
|
|
|
m_pressedIndex = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
TabScrollBar::TabScrollBar(QWidget* parent)
|
|
|
|
: QScrollBar(Qt::Horizontal, parent)
|
|
|
|
{
|
2014-02-12 16:20:13 +01:00
|
|
|
m_animation = new QPropertyAnimation(this, "value", this);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
TabScrollBar::~TabScrollBar()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-10-11 10:51:16 +02:00
|
|
|
bool TabScrollBar::isScrolling() const
|
|
|
|
{
|
|
|
|
return m_animation->state() == QPropertyAnimation::Running;
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabScrollBar::animateToValue(int to, QEasingCurve::Type type)
|
|
|
|
{
|
|
|
|
to = qBound(minimum(), to, maximum());
|
2014-02-12 16:20:13 +01:00
|
|
|
int lenght = qAbs(to - value());
|
2013-11-26 14:14:36 +01:00
|
|
|
int duration = qMin(1500, 200 + lenght / 2);
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
m_animation->stop();
|
|
|
|
m_animation->setEasingCurve(type);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_animation->setDuration(duration);
|
2014-02-12 16:20:13 +01:00
|
|
|
m_animation->setStartValue(value());
|
2013-11-26 14:14:36 +01:00
|
|
|
m_animation->setEndValue(to);
|
|
|
|
m_animation->start();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TabBarScrollWidget::TabBarScrollWidget(QTabBar* tabBar, QWidget* parent)
|
|
|
|
: QWidget(parent)
|
|
|
|
, m_tabBar(tabBar)
|
|
|
|
, m_usesScrollButtons(false)
|
2014-02-12 16:20:13 +01:00
|
|
|
, m_totalDeltas(0)
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
m_scrollArea = new QScrollArea(this);
|
2016-12-26 15:18:34 +01:00
|
|
|
m_scrollArea->setFocusPolicy(Qt::NoFocus);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_scrollArea->setFrameStyle(QFrame::NoFrame);
|
|
|
|
m_scrollArea->setWidgetResizable(true);
|
|
|
|
m_scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
m_scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
|
|
|
|
m_scrollBar = new TabScrollBar(m_scrollArea);
|
|
|
|
m_scrollArea->setHorizontalScrollBar(m_scrollBar);
|
|
|
|
m_scrollArea->setWidget(m_tabBar);
|
|
|
|
|
|
|
|
m_leftScrollButton = new ToolButton(this);
|
2017-08-12 15:56:26 +02:00
|
|
|
m_leftScrollButton->setFocusPolicy(Qt::NoFocus);
|
2013-12-23 20:28:14 +01:00
|
|
|
m_leftScrollButton->setAutoRaise(true);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_leftScrollButton->setObjectName("tabbar-button-left");
|
2014-02-12 16:20:13 +01:00
|
|
|
m_leftScrollButton->setAutoRepeat(true);
|
|
|
|
m_leftScrollButton->setAutoRepeatDelay(200);
|
|
|
|
m_leftScrollButton->setAutoRepeatInterval(200);
|
2013-11-26 14:14:36 +01:00
|
|
|
connect(m_leftScrollButton, SIGNAL(pressed()), this, SLOT(scrollStart()));
|
2013-12-24 00:57:01 +01:00
|
|
|
connect(m_leftScrollButton, SIGNAL(doubleClicked()), this, SLOT(scrollToLeftEdge()));
|
2014-01-01 15:42:30 +01:00
|
|
|
connect(m_leftScrollButton, SIGNAL(middleMouseClicked()), this, SLOT(ensureVisible()));
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
m_rightScrollButton = new ToolButton(this);
|
2017-08-12 15:56:26 +02:00
|
|
|
m_rightScrollButton->setFocusPolicy(Qt::NoFocus);
|
2013-12-23 20:28:14 +01:00
|
|
|
m_rightScrollButton->setAutoRaise(true);
|
2013-11-26 14:14:36 +01:00
|
|
|
m_rightScrollButton->setObjectName("tabbar-button-right");
|
2014-02-12 16:20:13 +01:00
|
|
|
m_rightScrollButton->setAutoRepeat(true);
|
|
|
|
m_rightScrollButton->setAutoRepeatDelay(200);
|
|
|
|
m_rightScrollButton->setAutoRepeatInterval(200);
|
2013-11-26 14:14:36 +01:00
|
|
|
connect(m_rightScrollButton, SIGNAL(pressed()), this, SLOT(scrollStart()));
|
2013-12-24 00:57:01 +01:00
|
|
|
connect(m_rightScrollButton, SIGNAL(doubleClicked()), this, SLOT(scrollToRightEdge()));
|
2014-01-01 15:42:30 +01:00
|
|
|
connect(m_rightScrollButton, SIGNAL(middleMouseClicked()), this, SLOT(ensureVisible()));
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
QHBoxLayout* hLayout = new QHBoxLayout;
|
|
|
|
hLayout->setSpacing(0);
|
|
|
|
hLayout->setContentsMargins(0, 0, 0, 0);
|
2014-03-18 17:35:44 +01:00
|
|
|
hLayout->addWidget(m_leftScrollButton);
|
2013-11-26 14:14:36 +01:00
|
|
|
hLayout->addWidget(m_scrollArea);
|
2014-03-18 17:35:44 +01:00
|
|
|
hLayout->addWidget(m_rightScrollButton);
|
2013-11-26 14:14:36 +01:00
|
|
|
setLayout(hLayout);
|
|
|
|
|
|
|
|
m_scrollArea->viewport()->setAutoFillBackground(false);
|
2014-03-30 16:40:36 +02:00
|
|
|
connect(m_scrollBar, SIGNAL(valueChanged(int)), this, SLOT(updateScrollButtonsState()));
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-03-30 16:40:36 +02:00
|
|
|
updateScrollButtonsState();
|
2013-11-26 14:14:36 +01:00
|
|
|
overFlowChanged(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
QTabBar* TabBarScrollWidget::tabBar()
|
|
|
|
{
|
|
|
|
return m_tabBar;
|
|
|
|
}
|
|
|
|
|
|
|
|
QScrollArea* TabBarScrollWidget::scrollArea()
|
|
|
|
{
|
|
|
|
return m_scrollArea;
|
|
|
|
}
|
|
|
|
|
|
|
|
TabScrollBar* TabBarScrollWidget::scrollBar()
|
|
|
|
{
|
|
|
|
return m_scrollBar;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::ensureVisible(int index, int xmargin)
|
|
|
|
{
|
|
|
|
if (index == -1) {
|
|
|
|
index = m_tabBar->currentIndex();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (index < 0 || index >= m_tabBar->count()) {
|
|
|
|
return;
|
|
|
|
}
|
2013-11-30 23:28:26 +01:00
|
|
|
xmargin = qMin(xmargin, m_scrollArea->viewport()->width() / 2);
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
// Qt Bug? the following lines were taken from QScrollArea::ensureVisible() and
|
|
|
|
// then were fixed. The original version caculates wrong values in RTL layouts.
|
2013-12-30 13:43:48 +01:00
|
|
|
const QRect logicalTabRect = QStyle::visualRect(m_tabBar->layoutDirection(), m_tabBar->rect(), m_tabBar->tabRect(index));
|
2013-11-26 14:14:36 +01:00
|
|
|
int logicalX = QStyle::visualPos(Qt::LeftToRight, m_scrollArea->viewport()->rect(), logicalTabRect.center()).x();
|
|
|
|
|
|
|
|
if (logicalX - xmargin < m_scrollBar->value()) {
|
|
|
|
m_scrollBar->animateToValue(qMax(0, logicalX - xmargin));
|
|
|
|
}
|
|
|
|
else if (logicalX > m_scrollBar->value() + m_scrollArea->viewport()->width() - xmargin) {
|
|
|
|
m_scrollBar->animateToValue(qMin(logicalX - m_scrollArea->viewport()->width() + xmargin,
|
|
|
|
m_scrollBar->maximum()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
void TabBarScrollWidget::scrollToLeft(int n, QEasingCurve::Type type)
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
n = qMax(1, n);
|
2014-02-12 16:20:13 +01:00
|
|
|
m_scrollBar->animateToValue(m_scrollBar->value() - n * m_scrollBar->singleStep(), type);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
void TabBarScrollWidget::scrollToRight(int n, QEasingCurve::Type type)
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
n = qMax(1, n);
|
2014-02-12 16:20:13 +01:00
|
|
|
m_scrollBar->animateToValue(m_scrollBar->value() + n * m_scrollBar->singleStep(), type);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::scrollToLeftEdge()
|
|
|
|
{
|
|
|
|
m_scrollBar->animateToValue(m_scrollBar->minimum());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::scrollToRightEdge()
|
|
|
|
{
|
|
|
|
m_scrollBar->animateToValue(m_scrollBar->maximum());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::setUpLayout()
|
|
|
|
{
|
|
|
|
const int height = m_tabBar->height();
|
|
|
|
|
|
|
|
setFixedHeight(height);
|
|
|
|
}
|
|
|
|
|
2014-03-30 16:40:36 +02:00
|
|
|
void TabBarScrollWidget::updateScrollButtonsState()
|
2013-11-26 14:14:36 +01:00
|
|
|
{
|
|
|
|
m_leftScrollButton->setEnabled(m_scrollBar->value() != m_scrollBar->minimum());
|
|
|
|
m_rightScrollButton->setEnabled(m_scrollBar->value() != m_scrollBar->maximum());
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::overFlowChanged(bool overflowed)
|
|
|
|
{
|
2014-03-18 17:35:44 +01:00
|
|
|
bool showScrollButtons = overflowed && m_usesScrollButtons;
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-03-18 17:35:44 +01:00
|
|
|
m_leftScrollButton->setVisible(showScrollButtons);
|
|
|
|
m_rightScrollButton->setVisible(showScrollButtons);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::scrollStart()
|
|
|
|
{
|
2014-02-12 16:20:13 +01:00
|
|
|
bool ctrlModifier = QApplication::keyboardModifiers() & Qt::ControlModifier;
|
|
|
|
|
|
|
|
if (sender() == m_leftScrollButton) {
|
|
|
|
if (ctrlModifier) {
|
2013-11-26 14:14:36 +01:00
|
|
|
scrollToLeftEdge();
|
|
|
|
}
|
2014-02-12 16:20:13 +01:00
|
|
|
else {
|
|
|
|
scrollToLeft(5, QEasingCurve::Linear);
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (sender() == m_rightScrollButton) {
|
2014-02-12 16:20:13 +01:00
|
|
|
if (ctrlModifier) {
|
|
|
|
scrollToRightEdge();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
scrollToRight(5, QEasingCurve::Linear);
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::scrollByWheel(QWheelEvent* event)
|
|
|
|
{
|
|
|
|
event->accept();
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
// Check if direction has changed from last time
|
|
|
|
if (m_totalDeltas * event->delta() < 0) {
|
|
|
|
m_totalDeltas = 0;
|
|
|
|
}
|
2013-11-26 14:14:36 +01:00
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
m_totalDeltas += event->delta();
|
|
|
|
|
|
|
|
// Slower scrolling for horizontal wheel scrolling
|
|
|
|
if (event->orientation() == Qt::Horizontal) {
|
|
|
|
if (event->delta() > 0) {
|
|
|
|
scrollToLeft();
|
|
|
|
}
|
|
|
|
else if (event->delta() < 0) {
|
|
|
|
scrollToRight();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Faster scrolling with control modifier
|
|
|
|
if (event->orientation() == Qt::Vertical && event->modifiers() == Qt::ControlModifier) {
|
|
|
|
if (event->delta() > 0) {
|
|
|
|
scrollToLeft(10);
|
|
|
|
}
|
|
|
|
else if (event->delta() < 0) {
|
|
|
|
scrollToRight(10);
|
|
|
|
}
|
|
|
|
return;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
// Fast scrolling with just wheel scroll
|
2017-01-27 15:43:21 +01:00
|
|
|
int factor = qMax(qRound(m_scrollBar->pageStep() / 1.5), m_scrollBar->singleStep());
|
2013-11-26 14:14:36 +01:00
|
|
|
if ((event->modifiers() & Qt::ControlModifier) || (event->modifiers() & Qt::ShiftModifier)) {
|
|
|
|
factor = m_scrollBar->pageStep();
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
int offset = (m_totalDeltas / 120) * factor;
|
2013-11-26 14:14:36 +01:00
|
|
|
if (offset != 0) {
|
|
|
|
if (isRightToLeft()) {
|
|
|
|
m_scrollBar->animateToValue(m_scrollBar->value() + offset);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
m_scrollBar->animateToValue(m_scrollBar->value() - offset);
|
|
|
|
}
|
|
|
|
|
2014-02-12 16:20:13 +01:00
|
|
|
m_totalDeltas -= (offset / factor) * 120;
|
2013-11-26 14:14:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-31 09:45:41 +02:00
|
|
|
int TabBarScrollWidget::scrollButtonsWidth() const
|
|
|
|
{
|
|
|
|
// Assumes both buttons have the same width
|
|
|
|
return m_leftScrollButton->width();
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
bool TabBarScrollWidget::usesScrollButtons() const
|
|
|
|
{
|
|
|
|
return m_usesScrollButtons;
|
|
|
|
}
|
|
|
|
|
|
|
|
void TabBarScrollWidget::setUsesScrollButtons(bool useButtons)
|
|
|
|
{
|
|
|
|
if (useButtons != m_usesScrollButtons) {
|
|
|
|
m_usesScrollButtons = useButtons;
|
2014-03-30 16:40:36 +02:00
|
|
|
updateScrollButtonsState();
|
2013-11-26 14:14:36 +01:00
|
|
|
m_tabBar->setElideMode(m_tabBar->elideMode());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-22 16:57:04 +01:00
|
|
|
bool TabBarScrollWidget::isOverflowed() const
|
|
|
|
{
|
|
|
|
return m_tabBar->count() > 0 && m_scrollBar->minimum() != m_scrollBar->maximum();
|
|
|
|
}
|
|
|
|
|
2013-12-24 00:01:18 +01:00
|
|
|
int TabBarScrollWidget::tabAt(const QPoint &pos) const
|
2013-12-23 21:24:41 +01:00
|
|
|
{
|
2014-02-14 18:48:16 +01:00
|
|
|
if (m_leftScrollButton->isVisible() && (m_leftScrollButton->rect().contains(pos) ||
|
|
|
|
m_rightScrollButton->rect().contains(pos))) {
|
2013-12-24 00:01:18 +01:00
|
|
|
return -1;
|
2013-12-23 21:24:41 +01:00
|
|
|
}
|
|
|
|
|
2013-12-24 00:01:18 +01:00
|
|
|
return m_tabBar->tabAt(m_tabBar->mapFromGlobal(mapToGlobal(pos)));
|
2013-12-23 21:24:41 +01:00
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
void TabBarScrollWidget::mouseMoveEvent(QMouseEvent* event)
|
|
|
|
{
|
|
|
|
event->ignore();
|
|
|
|
}
|
|
|
|
|
2014-03-30 16:40:36 +02:00
|
|
|
void TabBarScrollWidget::resizeEvent(QResizeEvent* event)
|
|
|
|
{
|
|
|
|
QWidget::resizeEvent(event);
|
|
|
|
|
|
|
|
updateScrollButtonsState();
|
|
|
|
}
|
|
|
|
|
2013-11-26 14:14:36 +01:00
|
|
|
|
|
|
|
CloseButton::CloseButton(QWidget* parent)
|
|
|
|
: QAbstractButton(parent)
|
|
|
|
{
|
|
|
|
setObjectName("combotabbar_tabs_close_button");
|
|
|
|
setFocusPolicy(Qt::NoFocus);
|
|
|
|
setCursor(Qt::ArrowCursor);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CloseButton::enterEvent(QEvent* event)
|
|
|
|
{
|
|
|
|
if (isEnabled()) {
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
QAbstractButton::enterEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CloseButton::leaveEvent(QEvent* event)
|
|
|
|
{
|
|
|
|
if (isEnabled()) {
|
|
|
|
update();
|
|
|
|
}
|
|
|
|
|
|
|
|
QAbstractButton::leaveEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CloseButton::paintEvent(QPaintEvent*)
|
|
|
|
{
|
|
|
|
QPainter p(this);
|
|
|
|
QStyleOption opt;
|
|
|
|
opt.init(this);
|
|
|
|
opt.state |= QStyle::State_AutoRaise;
|
|
|
|
|
|
|
|
// update raised state on scrolling
|
|
|
|
bool isUnderMouse = rect().contains(mapFromGlobal(QCursor::pos()));
|
|
|
|
|
|
|
|
if (isEnabled() && isUnderMouse && !isChecked() && !isDown()) {
|
|
|
|
opt.state |= QStyle::State_Raised;
|
|
|
|
}
|
|
|
|
if (isChecked()) {
|
|
|
|
opt.state |= QStyle::State_On;
|
|
|
|
}
|
|
|
|
if (isDown()) {
|
|
|
|
opt.state |= QStyle::State_Sunken;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (TabBarHelper* tb = qobject_cast<TabBarHelper*>(parent())) {
|
|
|
|
int index = tb->currentIndex();
|
|
|
|
QTabBar::ButtonPosition closeSide = (QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, tb);
|
|
|
|
if (tb->tabButton(index, closeSide) == this && tb->isActiveTabBar()) {
|
|
|
|
opt.state |= QStyle::State_Selected;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
style()->drawPrimitive(QStyle::PE_IndicatorTabClose, &opt, &p, this);
|
|
|
|
}
|