diff --git a/AdvancedDockingSystem/src/ads/section_title_widget.cpp b/AdvancedDockingSystem/src/ads/section_title_widget.cpp index 0ff382a..98fb3f7 100644 --- a/AdvancedDockingSystem/src/ads/section_title_widget.cpp +++ b/AdvancedDockingSystem/src/ads/section_title_widget.cpp @@ -42,6 +42,7 @@ static void deleteEmptySplitter(ContainerWidget* container) SectionTitleWidget::SectionTitleWidget(SectionContent::RefPtr content, QWidget* parent) : QFrame(parent), _content(content), + _tabMoving(false), _activeTab(false) { auto l = new QBoxLayout(QBoxLayout::LeftToRight); @@ -83,10 +84,7 @@ void SectionTitleWidget::mousePressEvent(QMouseEvent* ev) void SectionTitleWidget::mouseReleaseEvent(QMouseEvent* ev) { // qDebug() << Q_FUNC_INFO << ev->pos(); - if (!_dragStartPos.isNull()) - { - emit clicked(); - } + SectionWidget* section = NULL; // Drop contents of FloatingWidget into SectionWidget. 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 _dragStartPos = QPoint(); + _tabMoving = false; hideDropOverlay(); QFrame::mouseReleaseEvent(ev); } @@ -207,15 +224,11 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev) ev->accept(); 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. - else if (!_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton) && (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance() - && (section = findParentSectionWidget(this)) != NULL) + else if (!_fw && !_dragStartPos.isNull() && (ev->buttons() & Qt::LeftButton) + //&& (ev->globalPos() - _dragStartPos).manhattanLength() >= QApplication::startDragDistance() + && (section = findParentSectionWidget(this)) != NULL + && !section->titleAreaGeometry().contains(section->mapFromGlobal(ev->globalPos()))) { // Create floating widget. auto data = section->take(_content->uid(), false); @@ -241,6 +254,27 @@ void SectionTitleWidget::mouseMoveEvent(QMouseEvent* ev) ev->accept(); 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); } diff --git a/AdvancedDockingSystem/src/ads/section_title_widget.h b/AdvancedDockingSystem/src/ads/section_title_widget.h index d3ca7fb..1ae282a 100644 --- a/AdvancedDockingSystem/src/ads/section_title_widget.h +++ b/AdvancedDockingSystem/src/ads/section_title_widget.h @@ -19,9 +19,15 @@ class SectionTitleWidget : public QFrame friend class SectionWidget; SectionContent::RefPtr _content; + + // Drag & Drop (Floating) QPointer _fw; QPoint _dragStartPos; + // Drag & Drop (Title/Tabs) + bool _tabMoving; + + // Property values bool _activeTab; public: diff --git a/AdvancedDockingSystem/src/ads/section_widget.cpp b/AdvancedDockingSystem/src/ads/section_widget.cpp index 639fbb2..42a3007 100644 --- a/AdvancedDockingSystem/src/ads/section_widget.cpp +++ b/AdvancedDockingSystem/src/ads/section_widget.cpp @@ -189,9 +189,52 @@ InternalContentData SectionWidget::take(int uid, bool del) 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) { // Set active TAB. + qDebug() << Q_FUNC_INFO << index; for (int i = 0; i < _tabsLayout->count(); ++i) { auto item = _tabsLayout->itemAt(i); diff --git a/AdvancedDockingSystem/src/ads/section_widget.h b/AdvancedDockingSystem/src/ads/section_widget.h index 5da4fb3..17186f6 100644 --- a/AdvancedDockingSystem/src/ads/section_widget.h +++ b/AdvancedDockingSystem/src/ads/section_widget.h @@ -39,6 +39,10 @@ public: void addContent(SectionContent::RefPtr c); void addContent(const InternalContentData& data, bool autoActivate); 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: void setCurrentIndex(int index); diff --git a/AdvancedDockingSystemDemo/src/main.cpp b/AdvancedDockingSystemDemo/src/main.cpp index 994b8fa..2b89a3b 100644 --- a/AdvancedDockingSystemDemo/src/main.cpp +++ b/AdvancedDockingSystemDemo/src/main.cpp @@ -39,27 +39,27 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(ads); // Development style. -// a.setStyleSheet("" -// " QSplitter::handle { border: 1px solid #000000; background: #000000; } " -// " ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; } " -// " ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; } " -// " ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; } " -// " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; } " -// " ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; } " -// ); + a.setStyleSheet("" + " QSplitter::handle { border: 1px solid #000000; background: #000000; } " + " ads--ContainerWidget { border: 1px solid #ff0000; background: #FFE6E6; padding: 6px; } " + " ads--SectionWidget { border: 1px solid #00ff00; background: #E6FFE6; padding: 6px; } " + " ads--SectionTitleWidget { border: 1px solid #0000ff; background: #E6E6FF; padding: 6px; } " + " ads--SectionTitleWidget[activeTab=\"true\"] { border: 1px solid #0000ff; background: #9696FF; padding: 6px; } " + " ads--SectionContentWidget { border: 1px solid #FFFF00; background: #FFFFE6; padding: 6px; } " + ); // PARTsolutions style. - a.setStyleSheet("" - " QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } " - " QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } " - " ads--ContainerWidget { border: 0; background: #9ab6ca; } " - " 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[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } " - " ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } " - " ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } " - " ads--FloatingWidget QPushButton { background: #E7F3F8; } " - ); +// a.setStyleSheet("" +// " QSplitter::handle:vertical { image: url(:/img/splitter-horizontal.png); } " +// " QSplitter::handle:horizontal { image: url(:/img/splitter-vertical.png); } " +// " ads--ContainerWidget { border: 0; background: #9ab6ca; } " +// " 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[activeTab=\"true\"] { border: 1px solid #E7F3F8; background: #E7F3F8; } " +// " ads--SectionTitleWidget IconTitleWidget QLabel { color: #000000; } " +// " ads--SectionContentWidget { border: 0px solid #E7F3F8; background: #ffffff; } " +// " ads--FloatingWidget QPushButton { background: #E7F3F8; } " +// ); MainWindow mw; resizeWidgetPerCent(&mw, 60, 80);