From 1c6d86e70f2783318eb6ddc1175c0d7fc7d35f96 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 7 Jul 2023 11:21:54 +0200 Subject: [PATCH] Added support for make auto hide widget floating via double click or context menu --- src/AutoHideDockContainer.cpp | 14 ++++++++- src/AutoHideTab.cpp | 56 +++++++++++++++++++++++++++++++++++ src/AutoHideTab.h | 9 +++++- src/DockAreaTitleBar.cpp | 22 ++++++++++++++ src/DockAreaTitleBar.h | 6 ++++ src/DockAreaWidget.cpp | 7 +++++ src/DockAreaWidget.h | 6 ++++ src/DockOverlay.cpp | 7 ----- src/DockWidget.cpp | 10 ++++++- src/FloatingDockContainer.cpp | 40 ++++++++++++++----------- 10 files changed, 149 insertions(+), 28 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 56c1541..c25d60b 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -230,7 +230,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarL //============================================================================ void CAutoHideDockContainer::updateSize() { - std::cout << "CAutoHideDockContainer::updateSize()" << std::endl; + qDebug() << "CAutoHideDockContainer::updateSize()"; auto dockContainerParent = dockContainer(); if (!dockContainerParent) { @@ -239,6 +239,10 @@ void CAutoHideDockContainer::updateSize() auto rect = dockContainerParent->contentRect(); qDebug() << "dockContainerParent->contentRect() " << rect; + qDebug() << "dockWidget()->rect()" << dockWidget()->rect(); + qDebug() << "dockAreaWidget()->rect(): " << dockAreaWidget()->rect(); + qDebug() << "CAutoHideDockContainer::isVisible " << this->isVisible(); + qDebug() << "CAutoHideDockContainer::rect " << this->rect(); switch (sideBarLocation()) { @@ -273,6 +277,9 @@ void CAutoHideDockContainer::updateSize() default: break; } + + qDebug() << "CAutoHideDockContainer::rect (after): " << this->rect(); + qDebug() << "dockAreaWidget()->rect(): " << dockAreaWidget()->rect(); } //============================================================================ @@ -326,6 +333,7 @@ CDockWidget* CAutoHideDockContainer::dockWidget() const //============================================================================ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) { + std::cout << "CAutoHideDockContainer::addDockWidget " << std::endl; if (d->DockWidget) { // Remove the old dock widget at this area @@ -346,6 +354,10 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockArea->addDockWidget(DockWidget); updateSize(); + // The dock area is not visible and will not update the size when updateSize() + // is called for this auto hide container. Therefore we explicitely resize + // it here. As soon as it will become visible, it will get the right size + d->DockArea->resize(size()); } diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index a6f7cc4..bee969b 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include "AutoHideDockContainer.h" #include "AutoHideSideBar.h" @@ -272,10 +273,65 @@ bool CAutoHideTab::event(QEvent* event) return Super::event(event); } + //============================================================================ bool CAutoHideTab::iconOnly() const { return CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideSideBarsIconOnly) && !icon().isNull(); } + +//============================================================================ +void CAutoHideTab::contextMenuEvent(QContextMenuEvent* ev) +{ + ev->accept(); + //d->saveDragStartMousePosition(ev->globalPos()); + + const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable); + QAction* Action; + QMenu Menu(this); + + + Action = Menu.addAction(tr("Detach"), this, SLOT(setDockWidgetFloating())); + Action->setEnabled(isFloatable); + auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable); + Action->setEnabled(IsPinnable); + + auto menu = Menu.addMenu(tr("Pin To...")); + menu->setEnabled(IsPinnable); + //d->createAutoHideToAction(tr("Top"), SideBarTop, menu); + //d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); + //d->createAutoHideToAction(tr("Right"), SideBarRight, menu); + //d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu); + + /*Menu.addSeparator(); + Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested())); + Action->setEnabled(isClosable()); + if (d->DockArea->openDockWidgetsCount() > 1) + { + Action = Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested())); + }*/ + Menu.exec(ev->globalPos()); +} + + +//============================================================================ +void CAutoHideTab::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + { + setDockWidgetFloating(); + } + + Super::mouseDoubleClickEvent(event); +} + + +//============================================================================ +void CAutoHideTab::setDockWidgetFloating() +{ + dockWidget()->setFloating(); +} + + } diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index ca8bb56..1e4a374 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -65,11 +65,12 @@ private: friend class CDockContainerWidget; friend DockContainerWidgetPrivate; - protected: void setSideBar(CAutoHideSideBar *SideTabBar); void removeFromSideBar(); virtual bool event(QEvent* event) override; + virtual void contextMenuEvent(QContextMenuEvent* ev) override; + virtual void mouseDoubleClickEvent(QMouseEvent *event) override; public: using Super = CPushButton; @@ -133,6 +134,12 @@ public: * not in a side bar */ CAutoHideSideBar* sideBar() const; + +public Q_SLOTS: + /** + * Set the dock widget floating, if it is floatable + */ + void setDockWidgetFloating(); }; // class AutoHideTab } // namespace ads diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index d5af9bf..defb664 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -260,6 +260,7 @@ void DockAreaTitleBarPrivate::createTabBar() //============================================================================ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, eDragState DragState) { + qDebug() << "DockAreaTitleBarPrivate::makeAreaFloating " << DockArea->size(); QSize Size = DockArea->size(); this->DragState = DragState; bool CreateFloatingDockContainer = (DraggingFloatingWidget != DragState); @@ -660,6 +661,7 @@ void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev) //============================================================================ void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event) { + std::cout << "CDockAreaTitleBar::mouseDoubleClickEvent" << std::endl; // If this is the last dock area in a dock container it does not make // sense to move it to a new floating widget and leave this one // empty @@ -677,6 +679,26 @@ void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event) } +//============================================================================ +void CDockAreaTitleBar::setAreaFloating() +{ + // If this is the last dock area in a dock container it does not make + // sense to move it to a new floating widget and leave this one + // empty + if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->dockAreaCount() == 1) + { + return; + } + + if (!d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)) + { + return; + } + + d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive); +} + + //============================================================================ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) { diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index a314640..76987a4 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -163,6 +163,12 @@ public: */ QString titleBarButtonToolTip(TitleBarButton Button) const; + /** + * Moves the dock area into its own floating widget if the area + * DockWidgetFloatable flag is true + */ + void setAreaFloating(); + Q_SIGNALS: /** * This signal is emitted if a tab in the tab bar is clicked by the user diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index c1d8d55..4cd8b86 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1442,6 +1442,13 @@ bool CDockAreaWidget::isTopLevelArea() const } +//============================================================================ +void CDockAreaWidget::setFloating() +{ + d->TitleBar->setAreaFloating(); +} + + #ifdef Q_OS_WIN //============================================================================ bool CDockAreaWidget::event(QEvent *e) diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index a3ef76c..d95f519 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -414,6 +414,12 @@ public Q_SLOTS: */ void closeOtherAreas(); + /** + * Moves the dock area into its own floating widget if the area + * DockWidgetFloatable flag is true + */ + void setFloating(); + Q_SIGNALS: /** * This signal is emitted when user clicks on a tab at an index. diff --git a/src/DockOverlay.cpp b/src/DockOverlay.cpp index d04e839..096bc17 100644 --- a/src/DockOverlay.cpp +++ b/src/DockOverlay.cpp @@ -475,7 +475,6 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const auto DockArea = qobject_cast(d->TargetWidget.data()); if (!DockArea && CDockManager::autoHideConfigFlags().testFlag(CDockManager::AutoHideFeatureEnabled)) { - std::cout << d->Mode << " Find out side bar area " << std::endl; auto Rect = rect(); const QPoint pos = mapFromGlobal(QCursor::pos()); if (pos.x() < d->sideBarMouseZone(SideBarLeft)) @@ -488,7 +487,6 @@ DockWidgetArea CDockOverlay::dropAreaUnderCursor() const } else if (pos.y() < d->sideBarMouseZone(SideBarTop)) { - std::cout << d->Mode << " TopAutoHideArea " << std::endl; return TopAutoHideArea; } else if (pos.y() > (Rect.height() - d->sideBarMouseZone(SideBarBottom))) @@ -534,14 +532,12 @@ DockWidgetArea CDockOverlay::visibleDropAreaUnderCursor() const //============================================================================ DockWidgetArea CDockOverlay::showOverlay(QWidget* target) { - std::cout << d->Mode << " CDockOverlay::showOverlay()" << target << " " << target->objectName().toStdString() << std::endl; if (d->TargetWidget == target) { // Hint: We could update geometry of overlay here. DockWidgetArea da = dropAreaUnderCursor(); if (da != d->LastLocation) { - std::cout << d->Mode << " repaint()" << std::endl; repaint(); d->LastLocation = da; } @@ -566,7 +562,6 @@ DockWidgetArea CDockOverlay::showOverlay(QWidget* target) //============================================================================ void CDockOverlay::hideOverlay() { - std::cout << d->Mode << " CDockOverlay::hideOverlay()" << std::endl; hide(); d->TargetWidget.clear(); d->LastLocation = InvalidDockWidgetArea; @@ -578,7 +573,6 @@ void CDockOverlay::hideOverlay() void CDockOverlay::enableDropPreview(bool Enable) { d->DropPreviewEnabled = Enable; - std::cout << d->Mode << " update() " << Enable << std::endl; update(); } @@ -606,7 +600,6 @@ void CDockOverlay::paintEvent(QPaintEvent* event) double Factor = (CDockOverlay::ModeContainerOverlay == d->Mode) ? 3 : 2; - std::cout << "CDockOverlay::paintEvent da: " << da << std::endl; switch (da) { case TopDockWidgetArea: r.setHeight(r.height() / Factor); break; diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 9dde469..f16a187 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1021,7 +1021,15 @@ void CDockWidget::setFloating() { return; } - d->TabWidget->detachDockWidget(); + + if (this->isAutoHide()) + { + dockAreaWidget()->setFloating(); + } + else + { + d->TabWidget->detachDockWidget(); + } } diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 41db1d2..405ae46 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -499,10 +499,8 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent() return; } - if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() - != InvalidDockWidgetArea - || DockManager->containerOverlay()->dropAreaUnderCursor() - != InvalidDockWidgetArea) + if (DockManager->dockAreaOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea + || DockManager->containerOverlay()->dropAreaUnderCursor() != InvalidDockWidgetArea) { CDockOverlay *Overlay = DockManager->containerOverlay(); if (!Overlay->dropOverlayRect().isValid()) @@ -510,21 +508,26 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent() Overlay = DockManager->dockAreaOverlay(); } - // Resize the floating widget to the size of the highlighted drop area - // rectangle - QRect Rect = Overlay->dropOverlayRect(); - int FrameWidth = (_this->frameSize().width() - _this->rect().width()) - / 2; - int TitleBarHeight = _this->frameSize().height() - - _this->rect().height() - FrameWidth; - if (Rect.isValid()) + // Do not resize if we drop into an autohide sidebar area to preserve + // the dock area size for the initial size of the auto hide area + if (!ads::internal::isSideBarArea(Overlay->dropAreaUnderCursor())) { - QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft()); - TopLeft.ry() += TitleBarHeight; - _this->setGeometry( - QRect(TopLeft, - QSize(Rect.width(), Rect.height() - TitleBarHeight))); - QApplication::processEvents(); + // Resize the floating widget to the size of the highlighted drop area + // rectangle + QRect Rect = Overlay->dropOverlayRect(); + int FrameWidth = (_this->frameSize().width() - _this->rect().width()) + / 2; + int TitleBarHeight = _this->frameSize().height() + - _this->rect().height() - FrameWidth; + if (Rect.isValid()) + { + QPoint TopLeft = Overlay->mapToGlobal(Rect.topLeft()); + TopLeft.ry() += TitleBarHeight; + _this->setGeometry( + QRect(TopLeft, + QSize(Rect.width(), Rect.height() - TitleBarHeight))); + QApplication::processEvents(); + } } DropContainer->dropFloatingWidget(_this, QCursor::pos()); } @@ -533,6 +536,7 @@ void FloatingDockContainerPrivate::titleMouseReleaseEvent() DockManager->dockAreaOverlay()->hideOverlay(); } + //============================================================================ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint &GlobalPos) {