From f964ce2c68c72f3d54c61d2993346a40cb6bb88e Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 28 Oct 2024 15:39:29 +0100 Subject: [PATCH] Refactored, fixed and improved drag hover functionality --- src/AutoHideDockContainer.cpp | 3 +- src/AutoHideTab.cpp | 154 ++++++++++++++++++++-------------- src/AutoHideTab.h | 2 +- 3 files changed, 91 insertions(+), 68 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7dabcfe..c073791 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -660,8 +660,7 @@ bool CAutoHideDockContainer::event(QEvent* event) //============================================================================ void CAutoHideDockContainer::dragLeaveEvent(QDragLeaveEvent*) { - if (CDockManager::testAutoHideConfigFlag( - CDockManager::AutoHideOpenOnDragHover)) + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) { collapseView(true); } diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index c555b10..3b0ee0e 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "AutoHideDockContainer.h" #include "AutoHideSideBar.h" @@ -57,7 +58,7 @@ struct AutoHideTabPrivate CAutoHideSideBar* SideBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; QElapsedTimer TimeSinceHoverMousePress; - QElapsedTimer TimeSinceDragOver; + QTimer DragOverTimer; bool MousePressed = false; eDragState DragState = DraggingInactive; QPoint GlobalDragStartMousePosition; @@ -258,6 +259,11 @@ CAutoHideTab::CAutoHideTab(QWidget* parent) : if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) { setAcceptDrops(true); } + + d->DragOverTimer.setInterval(CDockManager::configParam( + CDockManager::AutoHideOpenOnDragHoverDelay_ms, 500).toInt()); + d->DragOverTimer.setSingleShot(true); + connect(&d->DragOverTimer, &QTimer::timeout, this, &CAutoHideTab::onDragHoverDelayExpired); } @@ -498,81 +504,76 @@ void CAutoHideTab::mouseReleaseEvent(QMouseEvent* ev) //============================================================================ -void CAutoHideTab::mouseMoveEvent(QMouseEvent* ev) +void CAutoHideTab::mouseMoveEvent(QMouseEvent *ev) { - if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive)) - { - d->DragState = DraggingInactive; - Super::mouseMoveEvent(ev); - return; - } - - // move floating window - if (d->isDraggingState(DraggingFloatingWidget)) - { - d->FloatingWidget->moveFloating(); - Super::mouseMoveEvent(ev); - return; - } - - // move tab - if (d->isDraggingState(DraggingTab)) - { - // Moving the tab is always allowed because it does not mean moving the - // dock widget around - //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() - internal::globalPositionOf(ev).y()); - if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar) + if (!(ev->buttons() & Qt::LeftButton) + || d->isDraggingState(DraggingInactive)) { - // Floating is only allowed for widgets that are floatable - // We can create the drag preview if the widget is movable. - auto Features = d->DockWidget->features(); - if (Features.testFlag(CDockWidget::DockWidgetFloatable) || (Features.testFlag(CDockWidget::DockWidgetMovable))) - { - d->startFloating(); - } - return; + d->DragState = DraggingInactive; + Super::mouseMoveEvent(ev); + return; } - Super::mouseMoveEvent(ev); + // move floating window + if (d->isDraggingState(DraggingFloatingWidget)) + { + d->FloatingWidget->moveFloating(); + Super::mouseMoveEvent(ev); + return; + } + + // move tab + if (d->isDraggingState(DraggingTab)) + { + // Moving the tab is always allowed because it does not mean moving the + // dock widget around + //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() + - internal::globalPositionOf(ev).y()); + if (DragDistanceY >= CDockManager::startDragDistance() || MouseOutsideBar) + { + // Floating is only allowed for widgets that are floatable + // We can create the drag preview if the widget is movable. + auto Features = d->DockWidget->features(); + if (Features.testFlag(CDockWidget::DockWidgetFloatable) + || (Features.testFlag(CDockWidget::DockWidgetMovable))) + { + d->startFloating(); + } + return; + } + + Super::mouseMoveEvent(ev); } //============================================================================ -void CAutoHideTab::dragEnterEvent(QDragEnterEvent* ev) { - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) { - if (!d->TimeSinceDragOver.isValid()) { - d->TimeSinceDragOver.restart(); - ev->accept(); - } - else if (d->TimeSinceDragOver.hasExpired(500)) { - ev->accept(); - } - } +void CAutoHideTab::dragEnterEvent(QDragEnterEvent *ev) +{ + Q_UNUSED(ev); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) + { + d->DragOverTimer.start(); + ev->accept(); + } } //============================================================================ -void CAutoHideTab::dragLeaveEvent(QDragLeaveEvent* ev) { - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) { - d->TimeSinceDragOver.invalidate(); - d->forwardEventToDockContainer(ev); - } +void CAutoHideTab::dragLeaveEvent(QDragLeaveEvent *ev) +{ + Q_UNUSED(ev); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover)) + { + d->DragOverTimer.stop(); + } } -//============================================================================ -void CAutoHideTab::dragMoveEvent(QDragMoveEvent* ev) { - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideOpenOnDragHover) - && d->TimeSinceDragOver.isValid() - && d->TimeSinceDragOver.hasExpired(500)) { - d->TimeSinceDragOver.invalidate(); - d->DockWidget->autoHideDockContainer()->collapseView(false); - ev->accept(); - } -} //============================================================================ void CAutoHideTab::requestCloseDockWidget() @@ -580,7 +581,6 @@ void CAutoHideTab::requestCloseDockWidget() d->DockWidget->requestCloseDockWidget(); } - //============================================================================ int CAutoHideTab::tabIndex() const { @@ -593,4 +593,28 @@ int CAutoHideTab::tabIndex() const } +//============================================================================ +void CAutoHideTab::onDragHoverDelayExpired() +{ + static const char* const PropertyId = "ActiveDragOverAutoHideContainer"; + + // First we check if there is an active auto hide container that is visible + // In this case, we collapse it before we open the new one + auto v = d->DockWidget->dockManager()->property(PropertyId); + if (v.isValid()) + { + auto ActiveAutoHideContainer = v.value>(); + if (ActiveAutoHideContainer) + { + ActiveAutoHideContainer->collapseView(true); + } + } + + auto AutoHideContainer = d->DockWidget->autoHideDockContainer(); + AutoHideContainer->collapseView(false); + d->DockWidget->dockManager()->setProperty(PropertyId, + QVariant::fromValue(QPointer(AutoHideContainer))); +} + + } diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index 07d4344..20ee70a 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -67,6 +67,7 @@ private: private Q_SLOTS: void onAutoHideToActionClicked(); + void onDragHoverDelayExpired(); protected: void setSideBar(CAutoHideSideBar *SideTabBar); @@ -78,7 +79,6 @@ protected: virtual void mouseMoveEvent(QMouseEvent* ev) override; virtual void dragEnterEvent(QDragEnterEvent* ev) override; virtual void dragLeaveEvent(QDragLeaveEvent* ev) override; - virtual void dragMoveEvent(QDragMoveEvent* ev) override; public: using Super = CPushButton;