From f4fc0dab292f47cfdea6dda94a34139c7f1c74a5 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 12 Jul 2023 09:39:20 +0200 Subject: [PATCH] Added support for dropping dock widget to a certain tab postion of a dock area --- src/DockAreaTabBar.cpp | 25 +++++++++++++++++++ src/DockAreaTabBar.h | 8 ++++++ src/DockContainerWidget.cpp | 50 +++++++++++++++++++++++-------------- src/DockContainerWidget.h | 3 ++- src/DockOverlay.cpp | 16 +++++++++++- src/DockOverlay.h | 11 ++++++++ src/FloatingDragPreview.cpp | 3 ++- 7 files changed, 94 insertions(+), 22 deletions(-) diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index 48e3c22..85215a1 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -504,6 +504,31 @@ QSize CDockAreaTabBar::sizeHint() const return d->TabsContainerWidget->sizeHint(); } + +//=========================================================================== +int CDockAreaTabBar::tabAt(const QPoint& Pos) const +{ + if (!isVisible()) + { + return -2; + } + + if (Pos.x() < tab(0)->geometry().x()) + { + return -1; + } + + for (int i = 0; i < count(); ++i) + { + if (tab(i)->geometry().contains(Pos)) + { + return i; + } + } + + return count(); +} + } // namespace ads diff --git a/src/DockAreaTabBar.h b/src/DockAreaTabBar.h index 781f5e9..aeab66f 100644 --- a/src/DockAreaTabBar.h +++ b/src/DockAreaTabBar.h @@ -113,6 +113,14 @@ public: */ CDockWidgetTab* tab(int Index) const; + /** + * Returns the tab at the given position. + * Returns -1 if the position is left of the first tab and count() if the + * position is right of the last tab. Returns -2 to indicate an invalid + * value. + */ + int tabAt(const QPoint& Pos) const; + /** * Filters the tab widget events */ diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 860c666..8156d3b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -190,19 +190,20 @@ public: * Creates a new tab for a widget dropped into the center of a section */ void dropIntoCenterOfSection(CFloatingDockContainer* FloatingWidget, - CDockAreaWidget* TargetArea); + CDockAreaWidget* TargetArea, int TabIndex = -2); /** * Drop floating widget into dock area */ void dropIntoSection(CFloatingDockContainer* FloatingWidget, - CDockAreaWidget* TargetArea, DockWidgetArea area); + CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex = -2); /** * Moves the dock widget or dock area given in Widget parameter to a * new dock widget area */ - void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area); + void moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area, + int TabIndex = -2); /** * Moves the dock widget or dock area given in Widget parameter to a @@ -213,7 +214,7 @@ public: /** * Creates a new tab for a widget dropped into the center of a section */ - void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea); + void moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea, int TabIndex = -2); /** * Moves the dock widget or dock area given in Widget parameter to @@ -535,12 +536,13 @@ void DockContainerWidgetPrivate::dropIntoAutoHideSideBar(CFloatingDockContainer* //============================================================================ void DockContainerWidgetPrivate::dropIntoCenterOfSection( - CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea) + CFloatingDockContainer* FloatingWidget, CDockAreaWidget* TargetArea, int TabIndex) { CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer(); auto NewDockWidgets = FloatingContainer->dockWidgets(); auto TopLevelDockArea = FloatingContainer->topLevelDockArea(); int NewCurrentIndex = -1; + TabIndex = (TabIndex < 0) ? 0 : TabIndex; // If the floating widget contains only one single dock are, then the // current dock widget of the dock area will also be the future current @@ -553,7 +555,7 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection( for (int i = 0; i < NewDockWidgets.count(); ++i) { CDockWidget* DockWidget = NewDockWidgets[i]; - TargetArea->insertDockWidget(i, DockWidget, false); + TargetArea->insertDockWidget(TabIndex + i, DockWidget, false); // If the floating widget contains multiple visible dock areas, then we // simply pick the first visible open dock widget and make it // the current one. @@ -562,7 +564,7 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection( NewCurrentIndex = i; } } - TargetArea->setCurrentIndex(NewCurrentIndex); + TargetArea->setCurrentIndex(NewCurrentIndex + TabIndex); TargetArea->updateTitleBarVisibility(); return; } @@ -570,13 +572,14 @@ void DockContainerWidgetPrivate::dropIntoCenterOfSection( //============================================================================ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* FloatingWidget, - CDockAreaWidget* TargetArea, DockWidgetArea area) + CDockAreaWidget* TargetArea, DockWidgetArea area, int TabIndex) { + qDebug() << "DockContainerWidgetPrivate::dropIntoSection TabIndex: " << TabIndex; // Dropping into center means all dock widgets in the dropped floating // widget will become tabs of the drop area if (CenterDockWidgetArea == area) { - dropIntoCenterOfSection(FloatingWidget, TargetArea); + dropIntoCenterOfSection(FloatingWidget, TargetArea, TabIndex); return; } @@ -666,11 +669,15 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin //============================================================================ -void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea) +void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockAreaWidget* TargetArea, + int TabIndex) { + qDebug() << "DockContainerWidgetPrivate::moveIntoCenterOfSection TabIndex: " + << TabIndex; auto DroppedDockWidget = qobject_cast(Widget); auto DroppedArea = qobject_cast(Widget); + TabIndex = (TabIndex < 0) ? 0 : TabIndex; if (DroppedDockWidget) { CDockAreaWidget* OldDockArea = DroppedDockWidget->dockAreaWidget(); @@ -683,7 +690,7 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA { OldDockArea->removeDockWidget(DroppedDockWidget); } - TargetArea->insertDockWidget(0, DroppedDockWidget, true); + TargetArea->insertDockWidget(TabIndex, DroppedDockWidget, true); } else { @@ -692,9 +699,9 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA for (int i = 0; i < NewDockWidgets.count(); ++i) { CDockWidget* DockWidget = NewDockWidgets[i]; - TargetArea->insertDockWidget(i, DockWidget, false); + TargetArea->insertDockWidget(TabIndex + i, DockWidget, false); } - TargetArea->setCurrentIndex(NewCurrentIndex); + TargetArea->setCurrentIndex(TabIndex + NewCurrentIndex); DroppedArea->dockContainer()->removeDockArea(DroppedArea); DroppedArea->deleteLater(); } @@ -705,13 +712,16 @@ void DockContainerWidgetPrivate::moveIntoCenterOfSection(QWidget* Widget, CDockA //============================================================================ -void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area) +void DockContainerWidgetPrivate::moveToNewSection(QWidget* Widget, CDockAreaWidget* TargetArea, DockWidgetArea area, + int TabIndex) { + qDebug() << "DockContainerWidgetPrivate::moveToNewSection TabIndex: " + << TabIndex; // Dropping into center means all dock widgets in the dropped floating // widget will become tabs of the drop area if (CenterDockWidgetArea == area) { - moveIntoCenterOfSection(Widget, TargetArea); + moveIntoCenterOfSection(Widget, TargetArea, TabIndex); return; } @@ -1705,7 +1715,6 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi bool Dropped = false; CDockAreaWidget* DockArea = dockAreaAt(TargetPos); - std::cout << "DockArea: " << DockArea << " dropArea: " << dropArea << std::endl; if (DockArea) { auto dropOverlay = d->DockManager->dockAreaOverlay(); @@ -1720,7 +1729,8 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi if (dropArea != InvalidDockWidgetArea) { ADS_PRINT("Dock Area Drop Content: " << dropArea); - d->dropIntoSection(FloatingWidget, DockArea, dropArea); + int TabIndex = d->DockManager->dockAreaOverlay()->tabIndexUnderCursor(); + d->dropIntoSection(FloatingWidget, DockArea, dropArea, TabIndex); Dropped = true; } } @@ -1773,12 +1783,14 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi //============================================================================ -void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget) +void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget, + int TabIndex) { + qDebug() << "CDockContainerWidget::dropWidget TabIndex: " << TabIndex; CDockWidget* SingleDockWidget = topLevelDockWidget(); if (TargetAreaWidget) { - d->moveToNewSection(Widget, TargetAreaWidget, DropArea); + d->moveToNewSection(Widget, TargetAreaWidget, DropArea, TabIndex); } else if (internal::isSideBarArea(DropArea)) { diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 6cc522b..700a8cb 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -132,7 +132,8 @@ protected: * a nullptr, then the DropArea indicates the drop area in the given * TargetAreaWidget */ - void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget); + void dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget, + int TabIndex = -2); /** * Adds the given dock area to this container widget diff --git a/src/DockOverlay.cpp b/src/DockOverlay.cpp index e750264..e54a14c 100644 --- a/src/DockOverlay.cpp +++ b/src/DockOverlay.cpp @@ -41,6 +41,7 @@ #include "DockContainerWidget.h" #include "AutoHideSideBar.h" #include "DockManager.h" +#include "DockAreaTabBar.h" #include @@ -48,6 +49,7 @@ namespace ads { static const int AutoHideAreaWidth = 32; static const int AutoHideAreaMouseZone = 8; +static const int InvalidTabIndex = -2; /** * Private data class of CDockOverlay @@ -62,6 +64,7 @@ struct DockOverlayPrivate bool DropPreviewEnabled = true; CDockOverlay::eMode Mode = CDockOverlay::ModeDockAreaOverlay; QRect DropAreaRect; + int TabIndex = InvalidTabIndex; /** * Private data constructor @@ -456,6 +459,7 @@ DockWidgetAreas CDockOverlay::allowedAreas() const //============================================================================ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const { + d->TabIndex = InvalidTabIndex; if (!d->TargetWidget) { return InvalidDockWidgetArea; @@ -503,10 +507,13 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const return Result; } + auto CursorPos = QCursor::pos(); if (DockArea->allowedAreas().testFlag(CenterDockWidgetArea) && !DockArea->titleBar()->isHidden() - && DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(QCursor::pos()))) + && DockArea->titleBarGeometry().contains(DockArea->mapFromGlobal(CursorPos))) { + auto TabBar = DockArea->titleBar()->tabBar(); + d->TabIndex = TabBar->tabAt(TabBar->mapFromGlobal(CursorPos)); return CenterDockWidgetArea; } @@ -514,6 +521,13 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const } +//============================================================================ +int CDockOverlay::tabIndexUnderCursor() const +{ + return d->TabIndex; +} + + //============================================================================ DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const { diff --git a/src/DockOverlay.h b/src/DockOverlay.h index 3fe0ba9..36376f5 100644 --- a/src/DockOverlay.h +++ b/src/DockOverlay.h @@ -87,6 +87,17 @@ public: */ DockWidgetArea dropAreaUnderCursor() const; + /** + * If the drop area is the CenterDockWidgetArea or a sidebar area, + * then this function returns the index of the tab under cursor. + * Call this function after call to dropAreaUnderCursor() because this + * function updates the tab index. + * A value of -1 indicates a position before the first tab and a value of + * tabCount() indicates a position behind the last tab. + * A value of -2 indicates an valid value + */ + int tabIndexUnderCursor() const; + /** * This function returns the same like dropAreaUnderCursor() if this * overlay is not hidden and if drop preview is enabled and returns diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 52303ad..b1c18e1 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -396,7 +396,8 @@ void CFloatingDragPreview::finishDragging() } else if (DockDropArea != InvalidDockWidgetArea) { - d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos())); + d->DropContainer->dropWidget(d->Content, DockDropArea, d->DropContainer->dockAreaAt(QCursor::pos()), + d->DockManager->dockAreaOverlay()->tabIndexUnderCursor()); } else if (ContainerDropArea != InvalidDockWidgetArea) {