mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2024-12-24 07:21:32 +08:00
Implemented proper tab handling
This commit is contained in:
parent
f0584ff0c5
commit
c14352e7c1
@ -37,6 +37,7 @@
|
||||
#include <QStyle>
|
||||
#include <QPushButton>
|
||||
#include <QDebug>
|
||||
#include <QMenu>
|
||||
|
||||
#include "DockContainerWidget.h"
|
||||
#include "DockWidget.h"
|
||||
@ -46,6 +47,9 @@
|
||||
|
||||
namespace ads
|
||||
{
|
||||
static const char* const INDEX_PROPERTY = "index";
|
||||
static const char* const ACTION_PROPERTY = "action";
|
||||
|
||||
/**
|
||||
* Custom scroll bar implementation for dock area tab bar
|
||||
*/
|
||||
@ -104,6 +108,43 @@ struct DockAreaWidgetPrivate
|
||||
* Creates the layout for top area with tabs and close button
|
||||
*/
|
||||
void createTabBar();
|
||||
|
||||
/**
|
||||
* Returns the dock widget with the given index
|
||||
*/
|
||||
CDockWidget* dockWidgetAt(int index)
|
||||
{
|
||||
return dynamic_cast<CDockWidget*>(ContentsLayout->widget(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience function to ease title widget access by index
|
||||
*/
|
||||
CDockWidgetTitleBar* titleWidgetAt(int index)
|
||||
{
|
||||
return dockWidgetAt(index)->titleBar();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a tabs menu entry for the given dock widget
|
||||
*/
|
||||
void addTabsMenuEntry(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Returns the tab action of the given dock widget
|
||||
*/
|
||||
QAction* dockWidgetTabAction(CDockWidget* DockWidget) const
|
||||
{
|
||||
return qvariant_cast<QAction*>(DockWidget->property(ACTION_PROPERTY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the given dock widget
|
||||
*/
|
||||
int dockWidgetIndex(CDockWidget* DockWidget) const
|
||||
{
|
||||
return DockWidget->property(INDEX_PROPERTY).toInt();
|
||||
}
|
||||
};
|
||||
// struct DockAreaWidgetPrivate
|
||||
|
||||
@ -142,7 +183,10 @@ void DockAreaWidgetPrivate::createTabBar()
|
||||
TabsMenuButton->setFlat(true);
|
||||
TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton));
|
||||
TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width());
|
||||
TabsMenuButton->setMenu(new QMenu(TabsMenuButton));
|
||||
TopLayout->addWidget(TabsMenuButton, 0);
|
||||
_this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)),
|
||||
SLOT(onTabsMenuActionTriggered(QAction*)));
|
||||
|
||||
CloseButton = new QPushButton();
|
||||
CloseButton->setObjectName("closeButton");
|
||||
@ -156,6 +200,16 @@ void DockAreaWidgetPrivate::createTabBar()
|
||||
TabsLayoutInitCount = TabsLayout->count();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget)
|
||||
{
|
||||
auto Action = TabsMenuButton->menu()->addAction(DockWidget->windowTitle());
|
||||
QVariant vAction = QVariant::fromValue(Action);
|
||||
DockWidget->setProperty(ACTION_PROPERTY, vAction);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) :
|
||||
QFrame(parent),
|
||||
@ -204,6 +258,7 @@ CDockContainerWidget* CDockAreaWidget::dockContainerWidget() const
|
||||
void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
|
||||
{
|
||||
d->ContentsLayout->addWidget(DockWidget);
|
||||
DockWidget->titleBar()->setDockAreaWidget(this);
|
||||
auto TitleBar = DockWidget->titleBar();
|
||||
d->TabsLayout->insertWidget(d->TabsLayout->count() - d->TabsLayoutInitCount,
|
||||
TitleBar);
|
||||
@ -213,6 +268,9 @@ void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
|
||||
{
|
||||
setCurrentIndex(0);
|
||||
}
|
||||
|
||||
DockWidget->setProperty(INDEX_PROPERTY, d->ContentsLayout->count() - 1);
|
||||
d->addTabsMenuEntry(DockWidget);
|
||||
}
|
||||
|
||||
|
||||
@ -259,7 +317,7 @@ void CDockAreaWidget::setCurrentIndex(int index)
|
||||
TitleWidget->setActiveTab(true);
|
||||
d->TabsScrollArea->ensureWidgetVisible(TitleWidget);
|
||||
auto Features = TitleWidget->dockWidget()->features();
|
||||
d->CloseButton->setEnabled(Features.testFlag(CDockWidget::DockWidgetClosable));
|
||||
d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -269,6 +327,114 @@ void CDockAreaWidget::setCurrentIndex(int index)
|
||||
|
||||
d->ContentsLayout->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QRect CDockAreaWidget::titleAreaGeometry() const
|
||||
{
|
||||
return d->TopLayout->geometry();
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
QRect CDockAreaWidget::contentAreaGeometry() const
|
||||
{
|
||||
return d->ContentsLayout->geometry();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::tabIndex(CDockWidget* DockWidget)
|
||||
{
|
||||
return d->ContentsLayout->indexOf(DockWidget);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
|
||||
{
|
||||
QList<CDockWidget*> DockWidgetList;
|
||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||
{
|
||||
DockWidgetList.append(dockWidget(i));
|
||||
}
|
||||
return DockWidgetList;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
||||
{
|
||||
for (int i = 0; i < d->ContentsLayout->count(); ++i)
|
||||
{
|
||||
auto TitleWidget = d->titleWidgetAt(i);
|
||||
if (TitleWidget->geometry().contains(p) && (!exclude || TitleWidget != exclude))
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
int CDockAreaWidget::count() const
|
||||
{
|
||||
return d->ContentsLayout->count();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
|
||||
{
|
||||
return dynamic_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
|
||||
{
|
||||
if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
|
||||
|| toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
|
||||
{
|
||||
qDebug() << "Invalid index for tab movement" << fromIndex << toIndex;
|
||||
d->TabsLayout->update();
|
||||
return;
|
||||
}
|
||||
|
||||
CDockWidget* DockWidget = dockWidget(fromIndex);
|
||||
|
||||
// reorder tabs menu action to match new order of contents
|
||||
auto Menu = d->TabsMenuButton->menu();
|
||||
auto TabsAction = d->dockWidgetTabAction(DockWidget);
|
||||
Menu->removeAction(TabsAction);
|
||||
if (toIndex >= Menu->actions().count())
|
||||
{
|
||||
Menu->addAction(TabsAction);
|
||||
}
|
||||
else
|
||||
{
|
||||
Menu->insertAction(Menu->actions().at(toIndex), TabsAction);
|
||||
}
|
||||
|
||||
|
||||
// now reorder contents and title bars
|
||||
QLayoutItem* liFrom = nullptr;
|
||||
liFrom = d->TabsLayout->takeAt(fromIndex);
|
||||
d->TabsLayout->insertItem(toIndex, liFrom);
|
||||
liFrom = d->ContentsLayout->takeAt(fromIndex);
|
||||
d->ContentsLayout->insertWidget(toIndex, liFrom->widget());
|
||||
delete liFrom;
|
||||
|
||||
//Menu->removeAction()
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action)
|
||||
{
|
||||
int Index = d->TabsMenuButton->menu()->actions().indexOf(Action);
|
||||
setCurrentIndex(Index);
|
||||
}
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -53,6 +53,7 @@ private:
|
||||
|
||||
private slots:
|
||||
void onDockWidgetTitleClicked();
|
||||
void onTabsMenuActionTriggered(QAction* Action);
|
||||
|
||||
public:
|
||||
/**
|
||||
@ -77,6 +78,47 @@ public:
|
||||
*/
|
||||
void addDockWidget(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Returns the rectangle of the title area
|
||||
*/
|
||||
QRect titleAreaGeometry() const;
|
||||
|
||||
/**
|
||||
* Returns the rectangle of the content
|
||||
*/
|
||||
QRect contentAreaGeometry() const;
|
||||
|
||||
/**
|
||||
* Returns the tab index of the given DockWidget
|
||||
*/
|
||||
int tabIndex(CDockWidget* DockWidget);
|
||||
|
||||
/**
|
||||
* Returns the index of contents of the title widget that is located at
|
||||
* mouse position pos
|
||||
*/
|
||||
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const;
|
||||
|
||||
/**
|
||||
* Returns a list of all dock widgets in this dock area
|
||||
*/
|
||||
QList<CDockWidget*> dockWidgets() const;
|
||||
|
||||
/**
|
||||
* Returns the number of dock widgets in this area
|
||||
*/
|
||||
int count() const;
|
||||
|
||||
/**
|
||||
* Returns a dock widget by its index
|
||||
*/
|
||||
CDockWidget* dockWidget(int Index) const;
|
||||
|
||||
/**
|
||||
* Reorder the index position of DockWidget at fromIndx to toIndex.
|
||||
*/
|
||||
void reorderDockWidget(int fromIndex, int toIndex);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* This sets the index position of the current tab page.
|
||||
|
@ -43,7 +43,7 @@ class CDockManager;
|
||||
|
||||
/**
|
||||
* Container that manages a number of dock areas with single dock widgets
|
||||
* or tabyfied dock widtes in each area
|
||||
* or tabyfied dock widgets in each area
|
||||
*/
|
||||
class CDockContainerWidget : public QFrame
|
||||
{
|
||||
|
@ -124,6 +124,7 @@ CDockWidget::DockWidgetFeatures CDockWidget::features() const
|
||||
{
|
||||
return d->Features;
|
||||
}
|
||||
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -34,8 +34,12 @@
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QStyle>
|
||||
#include <QApplication>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "DockWidget.h"
|
||||
#include "DockAreaWidget.h"
|
||||
|
||||
namespace ads
|
||||
{
|
||||
@ -50,6 +54,8 @@ struct DockWidgetTitleBarPrivate
|
||||
QLabel* TitleLabel;
|
||||
QPoint DragStartMousePosition;
|
||||
bool IsActiveTab = false;
|
||||
bool TabMoving = false;
|
||||
CDockAreaWidget* DockArea = nullptr;
|
||||
|
||||
/**
|
||||
* Private data constructor
|
||||
@ -60,6 +66,11 @@ struct DockWidgetTitleBarPrivate
|
||||
* Creates the complete layout including all controls
|
||||
*/
|
||||
void createLayout();
|
||||
|
||||
/**
|
||||
* Moves the tab depending on the position in the given mouse event
|
||||
*/
|
||||
void moveTab(QMouseEvent* ev);
|
||||
};
|
||||
// struct DockWidgetTitleBarPrivate
|
||||
|
||||
@ -90,6 +101,18 @@ void DockWidgetTitleBarPrivate::createLayout()
|
||||
TitleLabel->setText(DockWidget->windowTitle());
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev)
|
||||
{
|
||||
ev->accept();
|
||||
int left, top, right, bottom;
|
||||
_this->getContentsMargins(&left, &top, &right, &bottom);
|
||||
QPoint moveToPos = _this->mapToParent(ev->pos()) - DragStartMousePosition;
|
||||
moveToPos.setY(0);
|
||||
_this->move(moveToPos);
|
||||
_this->raise();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *parent) :
|
||||
@ -124,19 +147,57 @@ void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev)
|
||||
//============================================================================
|
||||
void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev)
|
||||
{
|
||||
// End of tab moving, change order now
|
||||
if (d->TabMoving && d->DockArea)
|
||||
{
|
||||
// Find tab under mouse
|
||||
QPoint pos = d->DockArea->mapFromGlobal(ev->globalPos());
|
||||
int fromIndex = d->DockArea->tabIndex(d->DockWidget);
|
||||
int toIndex = d->DockArea->indexOfContentByTitlePos(pos, this);
|
||||
if (-1 == toIndex)
|
||||
{
|
||||
toIndex = d->DockArea->count() - 1;
|
||||
}
|
||||
std::cout << "Move tab from " << fromIndex << " to " << toIndex << std::endl;
|
||||
d->DockArea->reorderDockWidget(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
if (!d->DragStartMousePosition.isNull())
|
||||
{
|
||||
emit clicked();
|
||||
}
|
||||
|
||||
d->DragStartMousePosition = QPoint();
|
||||
d->TabMoving = false;
|
||||
//mcw->m_SectionDropOverlay->hideDropOverlay();
|
||||
//mcw->hideContainerOverlay();
|
||||
QFrame::mouseReleaseEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev)
|
||||
{
|
||||
if (!(ev->buttons() & Qt::LeftButton))
|
||||
{
|
||||
QFrame::mouseMoveEvent(ev);
|
||||
return;
|
||||
}
|
||||
|
||||
// move tab
|
||||
if (d->TabMoving)
|
||||
{
|
||||
d->moveTab(ev);
|
||||
}
|
||||
|
||||
if ((ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance() // Wait a few pixels before start moving
|
||||
&& d->DockArea->titleAreaGeometry().contains(d->DockArea->mapFromGlobal(ev->globalPos())))
|
||||
{
|
||||
d->TabMoving = true;
|
||||
return;
|
||||
}
|
||||
|
||||
QFrame::mouseMoveEvent(ev);
|
||||
}
|
||||
|
||||
|
||||
@ -171,6 +232,13 @@ CDockWidget* CDockWidgetTitleBar::dockWidget() const
|
||||
{
|
||||
return d->DockWidget;
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
void CDockWidgetTitleBar::setDockAreaWidget(CDockAreaWidget* DockArea)
|
||||
{
|
||||
d->DockArea = DockArea;
|
||||
}
|
||||
} // namespace ads
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -35,6 +35,7 @@
|
||||
namespace ads
|
||||
{
|
||||
class CDockWidget;
|
||||
class CDockAreaWidget;
|
||||
struct DockWidgetTitleBarPrivate;
|
||||
|
||||
/**
|
||||
@ -82,6 +83,12 @@ public:
|
||||
*/
|
||||
CDockWidget* dockWidget() const;
|
||||
|
||||
/**
|
||||
* Sets the dock area widget the dockWidget returned by dockWidget()
|
||||
* function belongs to.
|
||||
*/
|
||||
void setDockAreaWidget(CDockAreaWidget* DockArea);
|
||||
|
||||
signals:
|
||||
void activeTabChanged();
|
||||
void clicked();
|
||||
|
@ -92,7 +92,9 @@ void MainWindow::createContent()
|
||||
m_DockManager->addDockWidget(ads::LeftDockWidgetArea, createLongTextLabelDockWidget(m_DockManager));
|
||||
m_DockManager->addDockWidget(ads::BottomDockWidgetArea, createFileSystemTreeDockWidget(m_DockManager));
|
||||
auto DockArea = m_DockManager->addDockWidget(ads::TopDockWidgetArea, createFileSystemTreeDockWidget(m_DockManager));
|
||||
m_DockManager->addDockWidget(ads::CenterDockWidgetArea, createCalendarDockWidget(m_DockManager), DockArea);
|
||||
DockWidget = createCalendarDockWidget(m_DockManager);
|
||||
DockWidget->setFeatures(DockWidget->features().setFlag(ads::CDockWidget::DockWidgetClosable, false));
|
||||
m_DockManager->addDockWidget(ads::CenterDockWidgetArea, DockWidget, DockArea);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user