2018-11-05 19:00:56 +08:00
|
|
|
/*******************************************************************************
|
|
|
|
** Qt Advanced Docking System
|
|
|
|
** Copyright (C) 2017 Uwe Kindler
|
|
|
|
**
|
|
|
|
** This library is free software; you can redistribute it and/or
|
|
|
|
** modify it under the terms of the GNU Lesser General Public
|
|
|
|
** License as published by the Free Software Foundation; either
|
|
|
|
** version 2.1 of the License, or (at your option) any later version.
|
|
|
|
**
|
|
|
|
** This library 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
|
|
|
|
** Lesser General Public License for more details.
|
|
|
|
**
|
|
|
|
** You should have received a copy of the GNU Lesser General Public
|
|
|
|
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
|
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-11-05 16:58:46 +08:00
|
|
|
#include <QApplication>
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
#include "FloatingDockContainer.h"
|
2019-11-26 21:40:56 +08:00
|
|
|
#include "FloatingOverlay.h"
|
2018-08-24 19:41:58 +08:00
|
|
|
#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"
|
|
|
|
|
2018-11-09 17:07:56 +08:00
|
|
|
#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;
|
2019-11-26 21:40:56 +08:00
|
|
|
IFloatingWidget* FloatingWidget = nullptr;
|
2018-10-10 21:15:59 +08:00
|
|
|
QWidget* TabsContainerWidget;
|
|
|
|
QBoxLayout* TabsLayout;
|
|
|
|
int CurrentIndex = -1;
|
2019-12-16 15:41:15 +08:00
|
|
|
eDragState DragState = DraggingInactive;
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Private data constructor
|
|
|
|
*/
|
|
|
|
DockAreaTabBarPrivate(CDockAreaTabBar* _public);
|
2018-10-12 16:41:19 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Update tabs after current index changed or when tabs are removed.
|
|
|
|
* The function reassigns the stylesheet to update the tabs
|
|
|
|
*/
|
|
|
|
void updateTabs();
|
2019-12-16 15:41:15 +08:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Test function for current drag state
|
|
|
|
*/
|
|
|
|
bool isDraggingState(eDragState dragState) const
|
|
|
|
{
|
|
|
|
return this->DragState == dragState;
|
|
|
|
}
|
2018-08-24 19:41:58 +08:00
|
|
|
};
|
|
|
|
// struct DockAreaTabBarPrivate
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
DockAreaTabBarPrivate::DockAreaTabBarPrivate(CDockAreaTabBar* _public) :
|
|
|
|
_this(_public)
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2018-10-12 16:41:19 +08:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void DockAreaTabBarPrivate::updateTabs()
|
|
|
|
{
|
|
|
|
// Set active TAB and update all other tabs to be inactive
|
|
|
|
for (int i = 0; i < _this->count(); ++i)
|
|
|
|
{
|
|
|
|
auto TabWidget = _this->tab(i);
|
|
|
|
if (!TabWidget)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i == CurrentIndex)
|
|
|
|
{
|
|
|
|
TabWidget->show();
|
|
|
|
TabWidget->setActiveTab(true);
|
|
|
|
_this->ensureWidgetVisible(TabWidget);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TabWidget->setActiveTab(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-08-24 19:41:58 +08:00
|
|
|
//============================================================================
|
|
|
|
CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) :
|
|
|
|
QScrollArea(parent),
|
|
|
|
d(new DockAreaTabBarPrivate(this))
|
|
|
|
{
|
|
|
|
d->DockArea = parent;
|
2019-09-13 16:25:33 +08:00
|
|
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
2018-08-24 19:41:58 +08:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
if (ev->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
ev->accept();
|
|
|
|
d->DragStartMousePos = ev->pos();
|
2019-12-16 15:41:15 +08:00
|
|
|
d->DragState = DraggingMousePressed;
|
2018-08-24 19:41:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
QScrollArea::mousePressEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mouseReleaseEvent(QMouseEvent* ev)
|
|
|
|
{
|
|
|
|
if (ev->button() == Qt::LeftButton)
|
|
|
|
{
|
2019-12-10 19:47:55 +08:00
|
|
|
ADS_PRINT("CDockAreaTabBar::mouseReleaseEvent");
|
2018-08-24 19:41:58 +08:00
|
|
|
ev->accept();
|
2019-12-16 15:41:15 +08:00
|
|
|
auto CurrentDragState = d->DragState;
|
2018-08-24 19:41:58 +08:00
|
|
|
d->DragStartMousePos = QPoint();
|
2019-12-16 15:41:15 +08:00
|
|
|
d->DragState = DraggingInactive;
|
|
|
|
if (DraggingFloatingWidget == CurrentDragState)
|
2019-12-13 18:52:50 +08:00
|
|
|
{
|
2019-12-16 15:41:15 +08:00
|
|
|
d->FloatingWidget->finishDragging();
|
2019-12-13 18:52:50 +08:00
|
|
|
}
|
2018-08-24 19:41:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
QScrollArea::mouseReleaseEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::mouseMoveEvent(QMouseEvent* ev)
|
|
|
|
{
|
|
|
|
QScrollArea::mouseMoveEvent(ev);
|
2019-12-16 18:10:59 +08:00
|
|
|
if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive))
|
2018-08-24 19:41:58 +08:00
|
|
|
{
|
2019-12-16 18:10:59 +08:00
|
|
|
d->DragState = DraggingInactive;
|
2018-08-24 19:41:58 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-12-16 15:41:15 +08:00
|
|
|
// move floating window
|
|
|
|
if (d->isDraggingState(DraggingFloatingWidget))
|
|
|
|
{
|
|
|
|
d->FloatingWidget->moveFloating();
|
|
|
|
return;
|
|
|
|
}
|
2018-08-24 19:41:58 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2019-07-11 21:12:39 +08:00
|
|
|
// If one single dock widget in this area is not floatable then the whole
|
|
|
|
// area is not floatable
|
|
|
|
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-05 16:58:46 +08:00
|
|
|
int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength();
|
|
|
|
if (DragDistance >= CDockManager::startDragDistance())
|
2018-08-24 19:41:58 +08:00
|
|
|
{
|
2019-07-21 15:53:24 +08:00
|
|
|
ADS_PRINT("CTabsScrollArea::startFloating");
|
2018-08-24 19:41:58 +08:00
|
|
|
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;
|
|
|
|
}
|
2019-07-11 21:12:39 +08:00
|
|
|
|
|
|
|
if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable))
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2018-12-20 23:25:30 +08:00
|
|
|
makeAreaFloating(event->pos(), DraggingInactive);
|
2018-08-24 19:41:58 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
2019-11-26 21:40:56 +08:00
|
|
|
IFloatingWidget* CDockAreaTabBar::makeAreaFloating(const QPoint& Offset, eDragState DragState)
|
2018-08-24 19:41:58 +08:00
|
|
|
{
|
|
|
|
QSize Size = d->DockArea->size();
|
2019-12-16 15:41:15 +08:00
|
|
|
d->DragState = DragState;
|
2019-11-26 21:40:56 +08:00
|
|
|
bool OpaqueUndocking = CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking) ||
|
|
|
|
(DraggingFloatingWidget != DragState);
|
|
|
|
CFloatingDockContainer* FloatingDockContainer = nullptr;
|
|
|
|
IFloatingWidget* FloatingWidget;
|
|
|
|
if (OpaqueUndocking)
|
|
|
|
{
|
|
|
|
FloatingWidget = FloatingDockContainer = new CFloatingDockContainer(d->DockArea);
|
|
|
|
}
|
|
|
|
else
|
2018-09-07 17:10:14 +08:00
|
|
|
{
|
2019-12-16 18:10:59 +08:00
|
|
|
auto w = new CFloatingOverlay(d->DockArea);
|
|
|
|
connect(w, &CFloatingOverlay::draggingCanceled, [=]()
|
|
|
|
{
|
|
|
|
d->DragState = DraggingInactive;
|
|
|
|
});
|
|
|
|
FloatingWidget = w;
|
2018-09-07 17:10:14 +08:00
|
|
|
}
|
2018-11-04 03:51:02 +08:00
|
|
|
|
2019-11-26 21:40:56 +08:00
|
|
|
FloatingWidget->startFloating(Offset, Size, DragState, nullptr);
|
|
|
|
if (FloatingDockContainer)
|
|
|
|
{
|
|
|
|
auto TopLevelDockWidget = FloatingDockContainer->topLevelDockWidget();
|
|
|
|
if (TopLevelDockWidget)
|
|
|
|
{
|
|
|
|
TopLevelDockWidget->emitTopLevelChanged(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-04 03:51:02 +08:00
|
|
|
return FloatingWidget;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
2018-12-20 22:29:38 +08:00
|
|
|
void CDockAreaTabBar::startFloating(const QPoint& Offset)
|
2018-11-04 03:51:02 +08:00
|
|
|
{
|
2018-12-20 23:25:30 +08:00
|
|
|
d->FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget);
|
2018-08-24 19:41:58 +08:00
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
void CDockAreaTabBar::setCurrentIndex(int index)
|
|
|
|
{
|
|
|
|
if (index == d->CurrentIndex)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-11-04 04:48:35 +08:00
|
|
|
if (index < -1 || index > (count() - 1))
|
2018-10-10 21:15:59 +08:00
|
|
|
{
|
|
|
|
qWarning() << Q_FUNC_INFO << "Invalid index" << index;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
emit currentChanging(index);
|
|
|
|
d->CurrentIndex = index;
|
2018-10-12 16:41:19 +08:00
|
|
|
d->updateTabs();
|
2018-10-10 21:15:59 +08:00
|
|
|
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-11-09 17:07:56 +08:00
|
|
|
connect(Tab, SIGNAL(closeRequested()), this, SLOT(onTabCloseRequested()));
|
|
|
|
connect(Tab, SIGNAL(closeOtherTabsRequested()), this, SLOT(onCloseOtherTabsRequested()));
|
2018-10-12 15:17:14 +08:00
|
|
|
connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&)));
|
2018-10-12 17:51:35 +08:00
|
|
|
Tab->installEventFilter(this);
|
2018-10-12 19:37:37 +08:00
|
|
|
emit tabInserted(Index);
|
2018-10-11 15:21:01 +08:00
|
|
|
if (Index <= d->CurrentIndex)
|
|
|
|
{
|
2018-11-04 04:48:35 +08:00
|
|
|
setCurrentIndex(d->CurrentIndex + 1);
|
2018-10-11 15:21:01 +08:00
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab)
|
|
|
|
{
|
2018-10-12 16:41:19 +08:00
|
|
|
if (!count())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2019-07-21 15:53:24 +08:00
|
|
|
ADS_PRINT("CDockAreaTabBar::removeTab ");
|
2018-10-12 16:41:19 +08:00
|
|
|
int NewCurrentIndex = currentIndex();
|
|
|
|
int RemoveIndex = d->TabsLayout->indexOf(Tab);
|
|
|
|
if (count() == 1)
|
|
|
|
{
|
|
|
|
NewCurrentIndex = -1;
|
|
|
|
}
|
|
|
|
if (NewCurrentIndex > RemoveIndex)
|
|
|
|
{
|
|
|
|
NewCurrentIndex--;
|
|
|
|
}
|
|
|
|
else if (NewCurrentIndex == RemoveIndex)
|
|
|
|
{
|
|
|
|
NewCurrentIndex = -1;
|
|
|
|
// First we walk to the right to search for the next visible tab
|
|
|
|
for (int i = (RemoveIndex + 1); i < count(); ++i)
|
|
|
|
{
|
|
|
|
if (tab(i)->isVisibleTo(this))
|
|
|
|
{
|
|
|
|
NewCurrentIndex = i - 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If there is no visible tab right to this tab then we walk to
|
|
|
|
// the left to find a visible tab
|
|
|
|
if (NewCurrentIndex < 0)
|
|
|
|
{
|
|
|
|
for (int i = (RemoveIndex - 1); i >= 0; --i)
|
|
|
|
{
|
|
|
|
if (tab(i)->isVisibleTo(this))
|
|
|
|
{
|
|
|
|
NewCurrentIndex = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-12 19:37:37 +08:00
|
|
|
emit removingTab(RemoveIndex);
|
2018-10-10 21:15:59 +08:00
|
|
|
d->TabsLayout->removeWidget(Tab);
|
2018-10-12 15:17:14 +08:00
|
|
|
Tab->disconnect(this);
|
2018-10-12 17:51:35 +08:00
|
|
|
Tab->removeEventFilter(this);
|
2019-07-21 15:53:24 +08:00
|
|
|
ADS_PRINT("NewCurrentIndex " << NewCurrentIndex);
|
2018-10-12 16:41:19 +08:00
|
|
|
if (NewCurrentIndex != d->CurrentIndex)
|
|
|
|
{
|
|
|
|
setCurrentIndex(NewCurrentIndex);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
d->updateTabs();
|
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
int CDockAreaTabBar::currentIndex() const
|
|
|
|
{
|
|
|
|
return d->CurrentIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
CDockWidgetTab* CDockAreaTabBar::currentTab() const
|
|
|
|
{
|
2018-11-04 04:48:35 +08:00
|
|
|
if (d->CurrentIndex < 0)
|
|
|
|
{
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(d->CurrentIndex)->widget());
|
|
|
|
}
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
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);
|
|
|
|
emit tabBarClicked(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-11-08 17:04:29 +08:00
|
|
|
//===========================================================================
|
2018-11-09 17:07:56 +08:00
|
|
|
void CDockAreaTabBar::onTabCloseRequested()
|
2018-11-08 17:04:29 +08:00
|
|
|
{
|
2018-11-09 17:07:56 +08:00
|
|
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(sender());
|
|
|
|
int Index = d->TabsLayout->indexOf(Tab);
|
|
|
|
closeTab(Index);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::onCloseOtherTabsRequested()
|
|
|
|
{
|
|
|
|
auto Sender = qobject_cast<CDockWidgetTab*>(sender());
|
|
|
|
for (int i = 0; i < count(); ++i)
|
|
|
|
{
|
|
|
|
auto Tab = tab(i);
|
|
|
|
if (Tab->isClosable() && !Tab->isHidden() && Tab != Sender)
|
|
|
|
{
|
2019-12-11 22:50:13 +08:00
|
|
|
// If the dock widget is deleted with the closeTab() call, its tab
|
|
|
|
// it will no longer be in the layout, and thus the index needs to
|
|
|
|
// be updated to not skip any tabs
|
|
|
|
int Offset = Tab->dockWidget()->features().testFlag(
|
|
|
|
CDockWidget::DockWidgetDeleteOnClose) ? 1 : 0;
|
2018-11-09 17:07:56 +08:00
|
|
|
closeTab(i);
|
2019-12-11 22:50:13 +08:00
|
|
|
i -= Offset;
|
2018-11-09 17:07:56 +08:00
|
|
|
}
|
|
|
|
}
|
2018-11-08 17:04:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-10-11 21:23:19 +08:00
|
|
|
//===========================================================================
|
2018-10-12 15:17:14 +08:00
|
|
|
CDockWidgetTab* CDockAreaTabBar::tab(int Index) const
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
2018-11-04 04:48:35 +08:00
|
|
|
if (Index >= count() || Index < 0)
|
2018-10-12 15:17:14 +08:00
|
|
|
{
|
2018-11-04 04:48:35 +08:00
|
|
|
return nullptr;
|
2018-10-12 15:17:14 +08:00
|
|
|
}
|
|
|
|
return qobject_cast<CDockWidgetTab*>(d->TabsLayout->itemAt(Index)->widget());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos)
|
|
|
|
{
|
|
|
|
CDockWidgetTab* MovingTab = qobject_cast<CDockWidgetTab*>(sender());
|
|
|
|
if (!MovingTab)
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-12 15:17:14 +08:00
|
|
|
int fromIndex = d->TabsLayout->indexOf(MovingTab);
|
|
|
|
auto MousePos = mapFromGlobal(GlobalPos);
|
|
|
|
int toIndex = -1;
|
2018-10-11 21:23:19 +08:00
|
|
|
// Find tab under mouse
|
|
|
|
for (int i = 0; i < count(); ++i)
|
|
|
|
{
|
2018-10-12 15:17:14 +08:00
|
|
|
CDockWidgetTab* DropTab = tab(i);
|
|
|
|
if (DropTab == MovingTab || !DropTab->isVisibleTo(this)
|
|
|
|
|| !DropTab->geometry().contains(MousePos))
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2018-10-12 15:17:14 +08:00
|
|
|
toIndex = d->TabsLayout->indexOf(DropTab);
|
|
|
|
if (toIndex == fromIndex)
|
|
|
|
{
|
|
|
|
toIndex = -1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (toIndex < 0)
|
|
|
|
{
|
|
|
|
toIndex = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2018-10-11 21:23:19 +08:00
|
|
|
|
2018-10-12 15:17:14 +08:00
|
|
|
// Now check if the mouse is behind the last tab
|
|
|
|
if (toIndex < 0)
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
2018-10-12 15:17:14 +08:00
|
|
|
if (MousePos.x() > tab(count() - 1)->geometry().right())
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
2019-07-21 15:53:24 +08:00
|
|
|
ADS_PRINT("after all tabs");
|
2018-10-12 15:17:14 +08:00
|
|
|
toIndex = count() - 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
toIndex = fromIndex;
|
2018-10-11 21:23:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-12 15:17:14 +08:00
|
|
|
d->TabsLayout->removeWidget(MovingTab);
|
|
|
|
d->TabsLayout->insertWidget(toIndex, MovingTab);
|
|
|
|
if (toIndex >= 0)
|
2018-10-11 21:23:19 +08:00
|
|
|
{
|
2019-07-21 15:53:24 +08:00
|
|
|
ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex);
|
2018-10-12 15:17:14 +08:00
|
|
|
emit tabMoved(fromIndex, toIndex);
|
2018-10-12 16:41:19 +08:00
|
|
|
setCurrentIndex(toIndex);
|
2018-10-11 21:23:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2018-10-12 19:37:37 +08:00
|
|
|
|
|
|
|
auto Tab = tab(Index);
|
2018-11-04 04:48:35 +08:00
|
|
|
if (Tab->isHidden())
|
2018-10-12 19:37:37 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Tab->hide();
|
2019-11-14 21:59:03 +08:00
|
|
|
emit tabCloseRequested(Index);
|
2018-10-10 21:15:59 +08:00
|
|
|
}
|
2018-10-12 17:51:35 +08:00
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event)
|
|
|
|
{
|
|
|
|
bool Result = Super::eventFilter(watched, event);
|
2018-10-12 19:37:37 +08:00
|
|
|
CDockWidgetTab* Tab = qobject_cast<CDockWidgetTab*>(watched);
|
|
|
|
if (!Tab)
|
2018-10-12 17:51:35 +08:00
|
|
|
{
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2018-10-12 19:37:37 +08:00
|
|
|
switch (event->type())
|
|
|
|
{
|
2018-10-12 20:51:57 +08:00
|
|
|
case QEvent::Hide:
|
|
|
|
emit tabClosed(d->TabsLayout->indexOf(Tab)); break;
|
|
|
|
case QEvent::Show:
|
|
|
|
emit tabOpened(d->TabsLayout->indexOf(Tab)); break;
|
2018-10-12 19:37:37 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-10-12 17:51:35 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2018-10-12 19:37:37 +08:00
|
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
bool CDockAreaTabBar::isTabOpen(int Index) const
|
|
|
|
{
|
|
|
|
if (Index < 0 || Index >= count())
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-11-04 04:48:35 +08:00
|
|
|
return !tab(Index)->isHidden();
|
2018-10-12 19:37:37 +08:00
|
|
|
}
|
2018-11-09 17:07:56 +08:00
|
|
|
|
2019-09-13 16:25:33 +08:00
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
QSize CDockAreaTabBar::minimumSizeHint() const
|
|
|
|
{
|
|
|
|
QSize Size = sizeHint();
|
|
|
|
Size.setWidth(Super::minimumSizeHint().width());// this defines the minimum width of a dock area
|
|
|
|
return Size;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
QSize CDockAreaTabBar::sizeHint() const
|
|
|
|
{
|
|
|
|
QSize Size = Super::sizeHint();
|
|
|
|
Size.setHeight(d->TabsContainerWidget->sizeHint().height());
|
|
|
|
return Size;
|
|
|
|
}
|
|
|
|
|
2018-08-24 19:41:58 +08:00
|
|
|
} // namespace ads
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// EOF DockAreaTabBar.cpp
|