QDockWidget: fix positioning after unplugging from floating tab

A floating tab is a QDockWidgetGroupWindow, containing a
QMainWindowTabBar, with each tab representing a dock widget.
Users can unplug dock widgets from the floating tab, by dragging
the respective tab of the tab bar. Such a drag triggers an internal
move of the tab at first. When a tab is dragged outside the tab
bar, the dock widget is unplugged and becomes floating. It is
supposed to be placed with its title bar under the mouse cursor,
so the drag can seemlessly continue and move the newly unplugged
dock widget.

To position the dock widget's title bar under the mouse cursor,
QTabBarPrivate::dragStartPosition was deducted from the mouse move
event's global position.

QTabBarPrivate::dragStartPosition holds the the position of the tab
at the time when the drag had started. It is used, to restore its
position, when a move is aborted. Using this point to calculate an
unplug position is wrong. It results in random positions, away from the
mouse cursor, especially if the tab has been dragged over a longer
distance.

Implement a helper function, that positions the dockwidget with its
title bar under a given position.
Use QDockWdget::titleBarWidget()->rect.center(), if it has a title bar
widget.
Otherwise, use QApplication::startDragDistance() as an offset on the
short side and the middle of the long side as coordinates.

The behavior can't be autotested, because
- mouse move emulation doesn't follow a line.
- drag and drop can't be tested on Windows platforms

The dockwidgets manual test (former dockwidgets example) can be used
for verification.

Fixes: QTBUG-126084
Pick-to: 6.7 6.5 6.2
Change-Id: I276cb6ade3944921d747bf5e73b7b6fe402d10c5
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
(cherry picked from commit 37861df8e5a41f0f654e15776c631da95ba26c03)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Axel Spoerl 2024-06-04 17:21:46 +02:00 committed by Qt Cherry-pick Bot
parent 9f1b4d4e09
commit f54e50e513

View File

@ -1954,6 +1954,30 @@ QDockWidget *QMainWindowTabBar::dockAt(int index) const
return nullptr;
}
/*!
\internal
Move \a dockWidget to its ideal unplug position.
\list
\li If \a dockWidget has a title bar widget, place its center under the mouse cursor.
\li Otherwise place it in the middle of the title bar's long side, with a
QApplication::startDragDistance() offset on the short side.
\endlist
*/
static void moveToUnplugPosition(QPoint mouse, QDockWidget *dockWidget)
{
Q_ASSERT(dockWidget);
if (auto *tbWidget = dockWidget->titleBarWidget()) {
dockWidget->move(mouse - tbWidget->rect().center());
return;
}
const bool vertical = dockWidget->features().testFlag(QDockWidget::DockWidgetVerticalTitleBar);
const int deltaX = vertical ? QApplication::startDragDistance() : dockWidget->width() / 2;
const int deltaY = vertical ? dockWidget->height() / 2 : QApplication::startDragDistance();
dockWidget->move(mouse - QPoint(deltaX, deltaY));
}
void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
{
// The QTabBar handles the moving (reordering) of tabs.
@ -1991,9 +2015,8 @@ void QMainWindowTabBar::mouseMoveEvent(QMouseEvent *e)
if (draggingDock) {
QDockWidgetPrivate *dockPriv = static_cast<QDockWidgetPrivate *>(QObjectPrivate::get(draggingDock));
if (dockPriv->state && dockPriv->state->dragging) {
QPoint pos = e->globalPosition().toPoint() - dockPriv->state->pressPos;
draggingDock->move(pos);
// move will call QMainWindowLayout::hover
moveToUnplugPosition(e->globalPosition().toPoint(), draggingDock);
}
}
QTabBar::mouseMoveEvent(e);