From e8332575f8a6a912ce10d36d09b3a33ba0240f70 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 19 Feb 2020 22:07:17 +0100 Subject: [PATCH] Improved tab dragging, added support for undocking if mouse leaves tabbar during tb dragging --- demo/MainWindow.cpp | 2 +- src/DockAreaTabBar.cpp | 44 ++++++++++++++++++++---------------------- src/DockWidgetTab.cpp | 8 ++++++-- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 300fd1c..f8835a7 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -488,7 +488,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line if you want to use opaque undocking and // opaque splitter resizing - // CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); + //CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); // uncomment the following line if you want a fixed tab width that does // not change if the visibility of the close button changes diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index 1666283..53096b7 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "FloatingDockContainer.h" #include "DockAreaWidget.h" @@ -69,6 +70,16 @@ struct DockAreaTabBarPrivate * The function reassigns the stylesheet to update the tabs */ void updateTabs(); + + /** + * Convenience function to access first tab + */ + CDockWidgetTab* firstTab() const {return _this->tab(0);} + + /** + * Convenience function to access last tab + */ + CDockWidgetTab* lastTab() const {return _this->tab(_this->count() - 1);} }; // struct DockAreaTabBarPrivate @@ -366,6 +377,8 @@ void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos) int fromIndex = d->TabsLayout->indexOf(MovingTab); auto MousePos = mapFromGlobal(GlobalPos); + MousePos.rx() = qMax(d->firstTab()->geometry().left(), MousePos.x()); + MousePos.rx() = qMin(d->lastTab()->geometry().right(), MousePos.x()); int toIndex = -1; // Find tab under mouse for (int i = 0; i < count(); ++i) @@ -381,38 +394,23 @@ void CDockAreaTabBar::onTabWidgetMoved(const QPoint& GlobalPos) if (toIndex == fromIndex) { toIndex = -1; - continue; - } - - if (toIndex < 0) - { - toIndex = 0; } break; } - // Now check if the mouse is behind the last tab - if (toIndex < 0) - { - if (MousePos.x() > tab(count() - 1)->geometry().right()) - { - ADS_PRINT("after all tabs"); - toIndex = count() - 1; - } - else - { - toIndex = fromIndex; - } - } - - d->TabsLayout->removeWidget(MovingTab); - d->TabsLayout->insertWidget(toIndex, MovingTab); - if (toIndex >= 0) + if (toIndex > -1) { + d->TabsLayout->removeWidget(MovingTab); + d->TabsLayout->insertWidget(toIndex, MovingTab); ADS_PRINT("tabMoved from " << fromIndex << " to " << toIndex); emit tabMoved(fromIndex, toIndex); setCurrentIndex(toIndex); } + else + { + // Ensure that the moved tab is reset to its start position + d->TabsLayout->update(); + } } //=========================================================================== diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index d979c8a..b568556 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -215,6 +215,8 @@ void DockWidgetTabPrivate::moveTab(QMouseEvent* ev) QPoint Distance = ev->globalPos() - GlobalDragStartMousePosition; Distance.setY(0); auto TargetPos = Distance + TabDragStartPosition; + TargetPos.rx() = qMax(TargetPos.x(), 0); + TargetPos.rx() = qMin(_this->parentWidget()->rect().right() - _this->width() + 1, TargetPos.rx()); _this->move(TargetPos); _this->raise(); } @@ -364,9 +366,11 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev) d->moveTab(ev); } + auto MappedPos = mapToParent(ev->pos()); + bool MouseOutsideBar = (MappedPos.x() < 0) || (MappedPos.x() > parentWidget()->rect().right()); // Maybe a fixed drag distance is better here ? int DragDistanceY = qAbs(d->GlobalDragStartMousePosition.y() - ev->globalPos().y()); - if (DragDistanceY >= CDockManager::startDragDistance()) + if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar) { // If this is the last dock area in a dock container with only // one single dock widget it does not make sense to move it to a new @@ -390,7 +394,7 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev) // tab because it looks strange if it remains on its dragged position if (d->isDraggingState(DraggingTab) && !CDockManager::configFlags().testFlag(CDockManager::OpaqueUndocking)) { - this->move(d->TabDragStartPosition); + parentWidget()->layout()->update(); } d->startFloating(); }