mirror of
https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System.git
synced 2025-04-16 10:24:45 +08:00
Implements tab-movement, changing the order of tabs by dragging with mouse.
This commit is contained in:
parent
863d3233ad
commit
bc14d9255f
@ -42,6 +42,7 @@ static void deleteEmptySplitter(ContainerWidget* container)
|
|||||||
SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) :
|
SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) :
|
||||||
QFrame(parent),
|
QFrame(parent),
|
||||||
_content(content),
|
_content(content),
|
||||||
|
_tabMoving(false),
|
||||||
_activeTab(false)
|
_activeTab(false)
|
||||||
{
|
{
|
||||||
auto l = new QBoxLayout(QBoxLayout::LeftToRight);
|
auto l = new QBoxLayout(QBoxLayout::LeftToRight);
|
||||||
@ -83,10 +84,7 @@ void SectionTitleWidget::mousePressEvent(QMouseEvent* ev)
|
|||||||
void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
|
void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
|
||||||
{
|
{
|
||||||
// qDebug() << Q_FUNC_INFO << ev->pos();
|
// qDebug() << Q_FUNC_INFO << ev->pos();
|
||||||
if (!_dragStartPos.isNull())
|
SectionWidget* section = NULL;
|
||||||
{
|
|
||||||
emit clicked();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Drop contents of FloatingWidget into SectionWidget.
|
// Drop contents of FloatingWidget into SectionWidget.
|
||||||
if (_fw)
|
if (_fw)
|
||||||
@ -153,9 +151,28 @@ void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// End of tab moving, change order now
|
||||||
|
else if (_tabMoving
|
||||||
|
&& (section = findParentSectionWidget(this)) != NULL)
|
||||||
|
{
|
||||||
|
qDebug() << "Stop tab move";
|
||||||
|
|
||||||
|
// Find tab under mouse
|
||||||
|
QPoint pos = ev->globalPos();
|
||||||
|
pos = section->mapFromGlobal(pos);
|
||||||
|
const int fromIndex = section->indexOfContent(_content);
|
||||||
|
const int toIndex = section->indexOfContentByTitlePos(pos, this);
|
||||||
|
qDebug() << "from" << fromIndex << "to" << toIndex;
|
||||||
|
section->moveContent(fromIndex, toIndex);
|
||||||
|
section->layout()->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_dragStartPos.isNull())
|
||||||
|
emit clicked();
|
||||||
|
|
||||||
// Reset
|
// Reset
|
||||||
_dragStartPos = QPoint();
|
_dragStartPos = QPoint();
|
||||||
|
_tabMoving = false;
|
||||||
hideDropOverlay();
|
hideDropOverlay();
|
||||||
QFrame::mouseReleaseEvent(ev);
|
QFrame::mouseReleaseEvent(ev);
|
||||||
}
|
}
|
||||||
@ -207,15 +224,11 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
|
|||||||
ev->accept();
|
ev->accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
|
|
||||||
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
|
|
||||||
&& (section = findParentSectionWidget(this)) != NULL && section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
|
|
||||||
{
|
|
||||||
// qDebug() << "Move inside title area" << ev->pos();
|
|
||||||
}
|
|
||||||
// Begin to drag/float the SectionContent.
|
// Begin to drag/float the SectionContent.
|
||||||
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton) && (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
|
else if (!_fw && !_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
|
||||||
&& (section = findParentSectionWidget(this)) != NULL)
|
//&& (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance()
|
||||||
|
&& (section = findParentSectionWidget(this)) != NULL
|
||||||
|
&& !section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
|
||||||
{
|
{
|
||||||
// Create floating widget.
|
// Create floating widget.
|
||||||
auto data = section->take(_content->uid(), false);
|
auto data = section->take(_content->uid(), false);
|
||||||
@ -241,6 +254,27 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev)
|
|||||||
ev->accept();
|
ev->accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Handle movement of this tab
|
||||||
|
else if (_tabMoving
|
||||||
|
&& (section = findParentSectionWidget(this)) != NULL)
|
||||||
|
{
|
||||||
|
int left, top, right, bottom;
|
||||||
|
getContentsMargins(&left, &top, &right, &bottom);
|
||||||
|
QPoint moveToPos = mapToParent(ev->pos()) - _dragStartPos;
|
||||||
|
moveToPos.setY(0 + top);
|
||||||
|
move(moveToPos);
|
||||||
|
ev->accept();
|
||||||
|
}
|
||||||
|
// Begin to drag title inside the title area to switch its position inside the SectionWidget.
|
||||||
|
else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton)
|
||||||
|
&& (section = findParentSectionWidget(this)) != NULL
|
||||||
|
&& section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos())))
|
||||||
|
{
|
||||||
|
// Raise current title-widget above other tabs
|
||||||
|
_tabMoving = true;
|
||||||
|
raise();
|
||||||
|
ev->accept();
|
||||||
|
}
|
||||||
QFrame::mouseMoveEvent(ev);
|
QFrame::mouseMoveEvent(ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,9 +19,15 @@ class SectionTitleWidget : public QFrame
|
|||||||
friend class SectionWidget;
|
friend class SectionWidget;
|
||||||
|
|
||||||
SectionContent::RefPtr _content;
|
SectionContent::RefPtr _content;
|
||||||
|
|
||||||
|
// Drag & Drop (Floating)
|
||||||
QPointer<FloatingWidget> _fw;
|
QPointer<FloatingWidget> _fw;
|
||||||
QPoint _dragStartPos;
|
QPoint _dragStartPos;
|
||||||
|
|
||||||
|
// Drag & Drop (Title/Tabs)
|
||||||
|
bool _tabMoving;
|
||||||
|
|
||||||
|
// Property values
|
||||||
bool _activeTab;
|
bool _activeTab;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -189,9 +189,52 @@ InternalContentData SectionWidget::take(int uid, bool del)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SectionWidget::indexOfContent(SectionContent::RefPtr c) const
|
||||||
|
{
|
||||||
|
return _contents.indexOf(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
int SectionWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const
|
||||||
|
{
|
||||||
|
int index = -1;
|
||||||
|
for (int i = 0; i < _sectionTitles.size(); ++i)
|
||||||
|
{
|
||||||
|
if (_sectionTitles[i]->geometry().contains(p) && (exclude == NULL || _sectionTitles[i] != exclude))
|
||||||
|
{
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SectionWidget::moveContent(int from, int to)
|
||||||
|
{
|
||||||
|
if (from >= _contents.size() || from < 0 || to >= _contents.size() || to < 0 || from == to)
|
||||||
|
{
|
||||||
|
qCritical() << "Invalid index for tab movement" << from << to;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SectionContent::RefPtr sc = _contents.at(from);
|
||||||
|
_contents.move(from, to);
|
||||||
|
_sectionTitles.move(from, to);
|
||||||
|
_sectionContents.move(from, to);
|
||||||
|
|
||||||
|
QLayoutItem* liFrom = NULL;
|
||||||
|
|
||||||
|
liFrom = _tabsLayout->takeAt(from);
|
||||||
|
_tabsLayout->insertItem(to, liFrom);
|
||||||
|
|
||||||
|
liFrom = _contentsLayout->takeAt(from);
|
||||||
|
_contentsLayout->insertWidget(to, liFrom->widget());
|
||||||
|
delete liFrom;
|
||||||
|
}
|
||||||
|
|
||||||
void SectionWidget::setCurrentIndex(int index)
|
void SectionWidget::setCurrentIndex(int index)
|
||||||
{
|
{
|
||||||
// Set active TAB.
|
// Set active TAB.
|
||||||
|
qDebug() << Q_FUNC_INFO << index;
|
||||||
for (int i = 0; i < _tabsLayout->count(); ++i)
|
for (int i = 0; i < _tabsLayout->count(); ++i)
|
||||||
{
|
{
|
||||||
auto item = _tabsLayout->itemAt(i);
|
auto item = _tabsLayout->itemAt(i);
|
||||||
|
@ -39,6 +39,10 @@ public:
|
|||||||
void addContent(SectionContent::RefPtr c);
|
void addContent(SectionContent::RefPtr c);
|
||||||
void addContent(const InternalContentData& data, bool autoActivate);
|
void addContent(const InternalContentData& data, bool autoActivate);
|
||||||
InternalContentData take(int uid, bool del = true);
|
InternalContentData take(int uid, bool del = true);
|
||||||
|
int indexOfContent(SectionContent::RefPtr c) const;
|
||||||
|
int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = NULL) const;
|
||||||
|
|
||||||
|
void moveContent(int from, int to);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void setCurrentIndex(int index);
|
void setCurrentIndex(int index);
|
||||||
|
@ -39,27 +39,27 @@ int main(int argc, char *argv[])
|
|||||||
Q_INIT_RESOURCE(ads);
|
Q_INIT_RESOURCE(ads);
|
||||||
|
|
||||||
// Development style.
|
// Development style.
|
||||||
// a.setStyleSheet(""
|
a.setStyleSheet(""
|
||||||
// " QSplitter::handle { border: 1px solid #000000; background: #000000; } "
|
" QSplitter::handle { border: 1px solid #000000; background: #000000; } "
|
||||||
// " ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; } "
|
" ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; padding: 6px; } "
|
||||||
// " ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; } "
|
" ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; padding: 6px; } "
|
||||||
// " ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; } "
|
" ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; padding: 6px; } "
|
||||||
// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; } "
|
" ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; padding: 6px; } "
|
||||||
// " ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; } "
|
" ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; padding: 6px; } "
|
||||||
// );
|
);
|
||||||
|
|
||||||
// PARTsolutions style.
|
// PARTsolutions style.
|
||||||
a.setStyleSheet(""
|
// a.setStyleSheet(""
|
||||||
" QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } "
|
// " QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } "
|
||||||
" QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } "
|
// " QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } "
|
||||||
" ads--ContainerWidget { border: 0; background: #9ab6ca; } "
|
// " ads--ContainerWidget { border: 0; background: #9ab6ca; } "
|
||||||
" ads--SectionWidget { border-width: 1px; border-color: #ffffff; border-style: solid; background: #7c9eb3; padding: 0; margin: 0; } "
|
// " ads--SectionWidget { border-width: 1px; border-color: #ffffff; border-style: solid; background: #7c9eb3; padding: 0; margin: 0; } "
|
||||||
" ads--SectionTitleWidget { border-right: 1px solid #E7F3F8; background: #7c9eb3; } "
|
// " ads--SectionTitleWidget { border-right: 1px solid #E7F3F8; background: #7c9eb3; } "
|
||||||
" ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } "
|
// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } "
|
||||||
" ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } "
|
// " ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } "
|
||||||
" ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } "
|
// " ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } "
|
||||||
" ads--FloatingWidget QPushButton { background: #E7F3F8; } "
|
// " ads--FloatingWidget QPushButton { background: #E7F3F8; } "
|
||||||
);
|
// );
|
||||||
|
|
||||||
MainWindow mw;
|
MainWindow mw;
|
||||||
resizeWidgetPerCent(&mw, 60, 80);
|
resizeWidgetPerCent(&mw, 60, 80);
|
||||||
|
Loading…
Reference in New Issue
Block a user