Implemented initial support for dragging auto hide tabs

This commit is contained in:
Uwe Kindler 2023-07-07 14:42:13 +02:00
parent 4bdc04e9d8
commit 4307f48d99
3 changed files with 230 additions and 16 deletions

View File

@ -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 <typename T>
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);
}
}

View File

@ -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;

View File

@ -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:
/**