2018-08-24 19:41:58 +08:00
|
|
|
//============================================================================
|
|
|
|
/// \file DockAreaTabBar.cpp
|
|
|
|
/// \author Uwe Kindler
|
|
|
|
/// \date 24.08.2018
|
|
|
|
/// \brief Implementation of CDockAreaTabBar class
|
|
|
|
//============================================================================
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// INCLUDES
|
|
|
|
//============================================================================
|
|
|
|
#include "DockAreaTabBar.h"
|
|
|
|
|
|
|
|
#include <QMouseEvent>
|
|
|
|
#include <QScrollBar>
|
|
|
|
#include <QDebug>
|
2018-10-10 21:15:59 +08:00
|
|
|
#include <QBoxLayout>
|
2018-10-11 14:54:32 +08:00
|
|
|
#include <QMenu>
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
#include "FloatingDockContainer.h"
|
|
|
|
#include "DockAreaWidget.h"
|
|
|
|
#include "DockOverlay.h"
|
|
|
|
#include "DockManager.h"
|
2018-09-07 17:10:14 +08:00
|
|
|
#include "DockWidget.h"
|
2018-10-10 21:15:59 +08:00
|
|
|
#include "DockWidgetTab.h"
|
|
|
|
|
|
|
|
#include <iostream>
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
namespace ads
|
|
|
|
{
|
|
|
|
/**
|
|
|
|
* Private data class of CDockAreaTabBar class (pimpl)
|
|
|
|
*/
|
|
|
|
struct DockAreaTabBarPrivate
|
|
|
|
{
|
|
|
|
CDockAreaTabBar* _this;
|
|
|
|
QPoint DragStartMousePos;
|
|
|
|
CDockAreaWidget* DockArea;
|
|
|
|
CFloatingDockContainer* FloatingWidget = nullptr;
|
2018-10-10 21:15:59 +08:00
|
|
|
QWidget* TabsContainerWidget;
|
|
|
|
QBoxLayout* TabsLayout;
|
|
|
|
int CurrentIndex = -1;
|
2018-10-11 14:54:32 +08:00
|
|
|
bool MenuOutdated = true;
|
|
|
|
QMenu* TabsMenu;
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Private data constructor
|
|
|
|
*/
|
|
|
|
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
|
|
|
|
};
|
|
|
|
// struct DockAreaTabBarPrivate
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
|
|
|
|
_this(_public)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
|
|
|
|
QScrollArea(parent),
|
|
|
|
d(new DockAreaTabBarPrivate(this))
|
|
|
|
{
|
|
|
|
d->DockArea = parent;
|
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored);
|
|
|
|
setFrameStyle(QFrame::NoFrame);
|
|
|
|
setWidgetResizable(true);
|
|
|
|
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
2018-10-10 21:15:59 +08:00
|
|
|
|
|
|
|
d->TabsContainerWidget = new QWidget();
|
|
|
|
d->TabsContainerWidget->setObjectName("tabsContainerWidget");
|
|
|
|
setWidget(d->TabsContainerWidget);
|
|
|
|
|
|
|
|
d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight);
|
|
|
|
d->TabsLayout->setContentsMargins(0, 0, 0, 0);
|
|
|
|
d->TabsLayout->setSpacing(0);
|
|
|
|
d->TabsLayout->addStretch(1);
|
|
|
|
d->TabsContainerWidget->setLayout(d->TabsLayout);
|
2018-08-24 19:41:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
CDockAreaTabBar::~CDockAreaTabBar()
|
|
|
|
{
|
|
|
|
delete d;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::wheelEvent(QWheelEvent* Event)
|
|
|
|
{
|
|
|
|
Event->accept();
|
|
|
|
const int direction = Event->angleDelta().y();
|
|
|
|
if (direction < 0)
|
|
|
|
{
|
|
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mousePressEvent(QMouseEvent* ev)
|
|
|
|
{
|
2018-10-11 14:54:32 +08:00
|
|
|
std::cout << "CDockAreaTabBar::mousePressEvent" << std::endl;
|
2018-08-24 19:41:58 +08:00
|
|
|
if (ev->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
ev->accept();
|
|
|
|
d->DragStartMousePos = ev->pos();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QScrollArea::mousePressEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mouseReleaseEvent(QMouseEvent* ev)
|
|
|
|
{
|
|
|
|
if (ev->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
qDebug() << "CTabsScrollArea::mouseReleaseEvent";
|
|
|
|
ev->accept();
|
|
|
|
d->FloatingWidget = nullptr;
|
|
|
|
d->DragStartMousePos = QPoint();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
QScrollArea::mouseReleaseEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
|
|
|
|
{
|
|
|
|
QScrollArea::mouseMoveEvent(ev);
|
|
|
|
if (ev->buttons() != Qt::LeftButton)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d->FloatingWidget)
|
|
|
|
{
|
|
|
|
d->FloatingWidget->moveFloating();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If this is the last dock area in a dock container it does not make
|
|
|
|
// sense to move it to a new floating widget and leave this one
|
|
|
|
// empty
|
|
|
|
if (d->DockArea->dockContainer()->isFloating()
|
|
|
|
&& d->DockArea->dockContainer()->visibleDockAreaCount() == 1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this->geometry().contains(ev->pos()))
|
|
|
|
{
|
|
|
|
qDebug() << "CTabsScrollArea::startFloating";
|
|
|
|
startFloating(d->DragStartMousePos);
|
|
|
|
auto Overlay = d->DockArea->dockManager()->containerOverlay();
|
|
|
|
Overlay->setAllowedAreas(OuterDockAreas);
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mouseDoubleClickEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
// If this is the last dock area in a dock container it does not make
|
|
|
|
// sense to move it to a new floating widget and leave this one
|
|
|
|
// empty
|
|
|
|
if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
startFloating(event->pos());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::startFloating(const QPoint& Pos)
|
|
|
|
{
|
|
|
|
QSize Size = d->DockArea->size();
|
|
|
|
CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(d->DockArea);
|
|
|
|
FloatingWidget->startFloating(Pos, Size);
|
|
|
|
d->FloatingWidget = FloatingWidget;
|
2018-09-26 15:57:36 +08:00
|
|
|
auto TopLevelDockWidget = d->FloatingWidget->topLevelDockWidget();
|
|
|
|
if (TopLevelDockWidget)
|
2018-09-07 17:10:14 +08:00
|
|
|
{
|
2018-09-26 15:57:36 +08:00
|
|
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
2018-09-07 17:10:14 +08:00
|
|
|
}
|
2018-08-24 19:41:58 +08:00
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::setCurrentIndex(int index)
|
|
|
|
{
|
2018-10-11 16:55:36 +08:00
|
|
|
std::cout << "CDockAreaTabBar::setCurrentIndex " << index << std::endl;
|
2018-10-10 21:15:59 +08:00
|
|
|
if (index == d->CurrentIndex)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-11 21:23:19 +08:00
|
|
|
if (index < 0 || index > (count() - 1))
|
2018-10-10 21:15:59 +08:00
|
|
|
{
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit currentChanging(index);
|
|
|
|
|
|
|
|
// Set active TAB and update all other tabs to be inactive
|
2018-10-11 21:23:19 +08:00
|
|
|
for (int i = 0; i < count(); ++i)
|
2018-10-10 21:15:59 +08:00
|
|
|
{
|
|
|
|
QLayoutItem* item = d->TabsLayout->itemAt(i);
|
|
|
|
if (!item->widget())
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto TabWidget = dynamic_cast<CDockWidgetTab*>(item->widget());
|
|
|
|
if (!TabWidget)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == index)
|
|
|
|
{
|
|
|
|
TabWidget->show();
|
|
|
|
TabWidget->setActiveTab(true);
|
|
|
|
ensureWidgetVisible(TabWidget);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TabWidget->setActiveTab(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
d->CurrentIndex = index;
|
|
|
|
emit currentChanged(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
int CDockAreaTabBar::count() const
|
|
|
|
{
|
2018-10-11 21:23:19 +08:00
|
|
|
// The tab bar contains a stretch item as last item
|
|
|
|
return d->TabsLayout->count() - 1;
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab)
|
|
|
|
{
|
|
|
|
d->TabsLayout->insertWidget(Index, Tab);
|
|
|
|
connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
|
2018-10-11 21:23:19 +08:00
|
|
|
connect(Tab, SIGNAL(moved()), this, SLOT(onTabMoved()));
|
2018-10-11 14:54:32 +08:00
|
|
|
d->MenuOutdated = true;
|
2018-10-11 15:21:01 +08:00
|
|
|
if (Index <= d->CurrentIndex)
|
|
|
|
{
|
|
|
|
d->CurrentIndex++;
|
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab)
|
|
|
|
{
|
2018-10-11 16:55:36 +08:00
|
|
|
std::cout << "CDockAreaTabBar::removeTab " << std::endl;
|
2018-10-10 21:15:59 +08:00
|
|
|
d->TabsLayout->removeWidget(Tab);
|
|
|
|
disconnect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked()));
|
2018-10-11 21:23:19 +08:00
|
|
|
disconnect(Tab, SIGNAL(moved()), this, SLOT(onTabMoved()));
|
2018-10-11 14:54:32 +08:00
|
|
|
d->MenuOutdated = true;
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
int CDockAreaTabBar::currentIndex() const
|
|
|
|
{
|
|
|
|
return d->CurrentIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
CDockWidgetTab* CDockAreaTabBar::currentTab() const
|
|
|
|
{
|
|
|
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::onTabClicked()
|
|
|
|
{
|
|
|
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
|
|
|
if (!Tab)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int index = d->TabsLayout->indexOf(Tab);
|
2018-10-11 16:55:36 +08:00
|
|
|
if (index < 0)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
setCurrentIndex(index);
|
|
|
|
std::cout << "emit tabBarClicked " << index << std::endl;
|
|
|
|
emit tabBarClicked(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-10-11 21:23:19 +08:00
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::onTabMoved()
|
|
|
|
{
|
|
|
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
|
|
|
if (!Tab)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find tab under mouse
|
|
|
|
int fromIndex = d->TabsLayout->indexOf(Tab);
|
|
|
|
std::cout << "d->TabsLayout->count() " << count() << std::endl;
|
|
|
|
for (int i = 0; i < count(); ++i)
|
|
|
|
{
|
|
|
|
CDockWidgetTab* Tab2 = qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(i)->widget());
|
|
|
|
if (Tab2 == Tab || !Tab)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::cout << "Tab.left " << Tab->pos().x() << " Tab2.left " << Tab2->pos().x()
|
|
|
|
<< std::endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
|
|
|
{
|
|
|
|
auto TabWidget = d->tabWidgetAt(i);
|
|
|
|
if (TabWidget->isVisible() && TabWidget->geometry().contains(p) && (!exclude || TabWidget != exclude))
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
std::cout << "CDockAreaTabBar::onTabMoved from " << fromIndex << std::endl;
|
|
|
|
|
|
|
|
/*QPoint pos = d->DockArea->mapFromGlobal(ev->globalPos());
|
|
|
|
int fromIndex = d->DockArea->index(d->DockWidget);
|
|
|
|
int toIndex = d->DockArea->indexOfContentByTitlePos(pos, this);
|
|
|
|
if (-1 == toIndex)
|
|
|
|
{
|
|
|
|
toIndex = d->DockArea->dockWidgetsCount() - 1;
|
|
|
|
}
|
|
|
|
qDebug() << "Move tab from " << fromIndex << " to " << toIndex;
|
|
|
|
d->DockArea->reorderDockWidget(fromIndex, toIndex);*/
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-10-11 14:54:32 +08:00
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::closeTab(int Index)
|
2018-10-10 21:15:59 +08:00
|
|
|
{
|
2018-10-11 21:23:19 +08:00
|
|
|
if (Index < 0 || Index >= count())
|
2018-10-11 14:54:32 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
emit tabCloseRequested(Index);
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
2018-08-24 19:41:58 +08:00
|
|
|
} // namespace ads
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// EOF DockAreaTabBar.cpp
|