diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index ce807f3..5679186 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -39,6 +39,8 @@ #include "DockAreaWidget.h" #include "DockManager.h" #include "DockWidget.h" +#include "FloatingDragPreview.h" +#include "DockOverlay.h" namespace ads { @@ -54,6 +56,11 @@ struct AutoHideTabPrivate CAutoHideSideBar* SideBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; QElapsedTimer TimeSinceHoverMousePress; + bool MousePressed = false; + eDragState DragState = DraggingInactive; + QPoint GlobalDragStartMousePosition; + QPoint DragStartMousePosition; + IFloatingWidget* FloatingWidget = nullptr; /** * Private data constructor @@ -99,6 +106,41 @@ struct AutoHideTabPrivate Action->setEnabled(Location != _this->sideBarLocation()); return Action; } + + /** + * Test function for current drag state + */ + bool isDraggingState(eDragState dragState) const + { + return this->DragState == dragState; + } + + /** + * Saves the drag start position in global and local coordinates + */ + void saveDragStartMousePosition(const QPoint& GlobalPos) + { + GlobalDragStartMousePosition = GlobalPos; + DragStartMousePosition = _this->mapFromGlobal(GlobalPos); + } + + /** + * Starts floating of the dock widget that belongs to this title bar + * Returns true, if floating has been started and false if floating + * is not possible for any reason + */ + bool startFloating(eDragState DraggingState = DraggingFloatingWidget); + + template + IFloatingWidget* createFloatingWidget(T* Widget) + { + auto w = new CFloatingDragPreview(Widget); + _this->connect(w, &CFloatingDragPreview::draggingCanceled, [=]() + { + DragState = DraggingInactive; + }); + return w; + } }; // struct DockWidgetTabPrivate @@ -127,6 +169,52 @@ void AutoHideTabPrivate::updateOrientation() } +//============================================================================ +bool AutoHideTabPrivate::startFloating(eDragState DraggingState) +{ + auto DockArea = DockWidget->dockAreaWidget(); + ADS_PRINT("isFloating " << dockContainer->isFloating()); + + ADS_PRINT("startFloating"); + DragState = DraggingState; + IFloatingWidget* FloatingWidget = nullptr; + FloatingWidget = createFloatingWidget(DockArea); + auto Size = DockArea->size(); + auto StartPos = DragStartMousePosition; + auto AutoHideContainer = DockWidget->autoHideDockContainer(); + switch (SideBar->sideBarLocation()) + { + case SideBarLeft: + StartPos.rx() = AutoHideContainer->rect().left() + 10; + break; + + case SideBarRight: + StartPos.rx() = AutoHideContainer->rect().right() - 10; + break; + + case SideBarTop: + StartPos.ry() = AutoHideContainer->rect().top() + 10; + break; + + case SideBarBottom: + StartPos.ry() = AutoHideContainer->rect().bottom() - 10; + break; + + case SideBarNone: + return false; + } + FloatingWidget->startFloating(StartPos, Size, DraggingFloatingWidget, _this); + auto DockManager = DockWidget->dockManager(); + auto Overlay = DockManager->containerOverlay(); + Overlay->setAllowedAreas(OuterDockAreas); + this->FloatingWidget = FloatingWidget; + qApp->postEvent(DockWidget, new QEvent((QEvent::Type)internal::DockedWidgetDragStartEvent)); + + return true; +} + + + //============================================================================ void CAutoHideTab::setSideBar(CAutoHideSideBar* SideTabBar) { @@ -267,22 +355,6 @@ bool CAutoHideTab::event(QEvent* event) d->forwardEventToDockContainer(event); break; - case QEvent::MouseButtonPress: - // If AutoHideShowOnMouseOver is active, then the showing is triggered - // by a MousePressEvent sent to this tab. To prevent accidental hiding - // of the tab by a mouse click, we wait at least 500 ms before we accept - // the mouse click - if (!event->spontaneous()) - { - d->TimeSinceHoverMousePress.restart(); - d->forwardEventToDockContainer(event); - } - else if (d->TimeSinceHoverMousePress.hasExpired(500)) - { - d->forwardEventToDockContainer(event); - } - break; - default: break; } @@ -360,4 +432,139 @@ void CAutoHideTab::onAutoHideToActionClicked() } +//============================================================================ +void CAutoHideTab::mousePressEvent(QMouseEvent* ev) +{ + // If AutoHideShowOnMouseOver is active, then the showing is triggered + // by a MousePressEvent sent to this tab. To prevent accidental hiding + // of the tab by a mouse click, we wait at least 500 ms before we accept + // the mouse click + if (!ev->spontaneous()) + { + d->TimeSinceHoverMousePress.restart(); + d->forwardEventToDockContainer(ev); + } + else if (d->TimeSinceHoverMousePress.hasExpired(500)) + { + d->forwardEventToDockContainer(ev); + } + + if (ev->button() == Qt::LeftButton) + { + ev->accept(); + d->MousePressed = true; + d->saveDragStartMousePosition(internal::globalPositionOf(ev)); + d->DragState = DraggingMousePressed; + } + Super::mousePressEvent(ev); +} + + + +//============================================================================ +void CAutoHideTab::mouseReleaseEvent(QMouseEvent* ev) +{ + if (ev->button() == Qt::LeftButton) + { + d->MousePressed = false; + auto CurrentDragState = d->DragState; + d->GlobalDragStartMousePosition = QPoint(); + d->DragStartMousePosition = QPoint(); + d->DragState = DraggingInactive; + + switch (CurrentDragState) + { + case DraggingTab: + // End of tab moving, emit signal + /*if (d->DockArea) + { + ev->accept(); + Q_EMIT moved(internal::globalPositionOf(ev)); + }*/ + break; + + case DraggingFloatingWidget: + ev->accept(); + d->FloatingWidget->finishDragging(); + break; + + default: + /*if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting)) + { + d->focusController()->setDockWidgetTabPressed(false); + }*/ + break; // do nothing + } + } + + Super::mouseReleaseEvent(ev); +} + + +//============================================================================ +void CAutoHideTab::mouseMoveEvent(QMouseEvent* ev) +{ + std::cout << "CAutoHideTab::mouseMoveEvent" << std::endl; + 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()); + std::cout << "DragDistanceY " << DragDistanceY << " MouseOutsideBar " << MouseOutsideBar << std::endl; + 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))) + { + // If we undock, we need to restore the initial position of this + // tab because it looks strange if it remains on its dragged position + /*if (d->isDraggingState(DraggingTab)) + { + parentWidget()->layout()->update(); + }*/ + d->startFloating(); + } + return; + } + /*else if (d->DockArea->openDockWidgetsCount() > 1 + && (internal::globalPositionOf(ev) - d->GlobalDragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving + { + // If we start dragging the tab, we save its inital position to + // restore it later + if (DraggingTab != d->DragState) + { + d->TabDragStartPosition = this->pos(); + } + d->DragState = DraggingTab; + return; + }*/ + + Super::mouseMoveEvent(ev); +} + + } diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index c9c6e0e..f883b5b 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -73,6 +73,9 @@ protected: void removeFromSideBar(); virtual bool event(QEvent* event) override; virtual void contextMenuEvent(QContextMenuEvent* ev) override; + virtual void mousePressEvent(QMouseEvent* ev) override; + virtual void mouseReleaseEvent(QMouseEvent* ev) override; + virtual void mouseMoveEvent(QMouseEvent* ev) override; public: using Super = CPushButton; diff --git a/src/DockManager.h b/src/DockManager.h index 8085f1c..55894fc 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -55,6 +55,8 @@ class CIconProvider; class CDockComponentsFactory; class CDockFocusController; class CAutoHideSideBar; +class CAutoHideTab; +struct AutoHideTabPrivate; /** * The central dock manager that maintains the complete docking system. @@ -87,6 +89,8 @@ private: friend class CDockAreaTitleBar; friend class CAutoHideDockContainer; friend CAutoHideSideBar; + friend CAutoHideTab; + friend AutoHideTabPrivate; public Q_SLOTS: /**