From 6ec38b48ef5dcf3a2ff299af633773732dc29077 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 14 Sep 2018 08:46:10 +0200 Subject: [PATCH] Fixed proper hiding of dock areas without any visible content when dragging out singkle widgets, prevente single dock widget from dragging if it is the last dock widget in a floating widget --- src/DockAreaWidget.cpp | 64 +++++++++++++++++++++++++++++++++-- src/DockAreaWidget.h | 28 ++++++++++++--- src/DockContainerWidget.cpp | 4 ++- src/DockWidget.cpp | 44 ++---------------------- src/DockWidgetTab.cpp | 22 ++++++++---- src/FloatingDockContainer.cpp | 4 ++- src/ads_globals.h | 2 ++ 7 files changed, 110 insertions(+), 58 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 624ed6e..2d69865 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -49,6 +49,7 @@ #include "DockManager.h" #include "DockOverlay.h" #include "DockAreaTabBar.h" +#include "DockSplitter.h" namespace ads @@ -76,7 +77,6 @@ struct DockAreaWidgetPrivate QPushButton* CloseButton; int TabsLayoutInitCount; CDockManager* DockManager = nullptr; - QVector OpenDockWidgets; bool MenuOutdated = true; /** @@ -216,7 +216,7 @@ void DockAreaWidgetPrivate::updateTabBar() return; } - if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1)) + if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->dockWidgetsCount() == 1)) { TitleBar->setVisible(false); } @@ -380,6 +380,13 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) dockContainer()->removeDockArea(this); this->deleteLater();; } + else if (!NextDockWidget) + { + // if contents layout is not empty but there are no more open dock + // widgets, then we need to hide the dock area because it does not + // contain any visible content + hideAreaWithNoVisibleContent(); + } d->updateTabBar(); DockWidget->setDockArea(nullptr); @@ -387,6 +394,42 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) } +//============================================================================ +void CDockAreaWidget::hideAreaWithNoVisibleContent() +{ + this->hide(); + + // Hide empty parent splitter + auto Splitter = internal::findParent(this); + while (Splitter && Splitter->isVisible()) + { + if (!Splitter->hasVisibleContent()) + { + Splitter->hide(); + } + Splitter = internal::findParent(Splitter); + } + + //Hide empty floating widget + CDockContainerWidget* Container = this->dockContainer(); + if (Container->isFloating() && Container->openedDockAreas().isEmpty()) + { + CFloatingDockContainer* FloatingWidget = internal::findParent(Container); + FloatingWidget->hide(); + } +} + + +//============================================================================ +void CDockAreaWidget::hideAreaIfNoVisibleContent() +{ + if (openedDockWidgets().isEmpty()) + { + hideAreaIfNoVisibleContent(); + } +} + + //============================================================================ void CDockAreaWidget::onDockWidgetTitleClicked() { @@ -512,6 +555,21 @@ QList CDockAreaWidget::dockWidgets() const } +//============================================================================ +int CDockAreaWidget::openDockWidgetsCount() const +{ + int Count = 0; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + if (!dockWidget(i)->isClosed()) + { + ++Count; + } + } + return Count; +} + + //============================================================================ QList CDockAreaWidget::openedDockWidgets() const { @@ -544,7 +602,7 @@ int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) //============================================================================ -int CDockAreaWidget::count() const +int CDockAreaWidget::dockWidgetsCount() const { return d->ContentsLayout->count(); } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 5a07155..8f0731e 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -118,6 +118,19 @@ protected: */ int index(CDockWidget* DockWidget); + /** + * Call this function, if you already know, that the dock does not + * contain any visible content (any open dock widgets). + */ + void hideAreaWithNoVisibleContent(); + + /** + * This function checks, if the dock area has visible content, that means + * if any dock widget is open, and then calls hideAreaWithNoVisibleContent() + * if it does not find any visible content + */ + void hideAreaIfNoVisibleContent(); + public: /** * Default Constructor @@ -150,22 +163,27 @@ public: */ QRect contentAreaGeometry() const; + /** + * Returns the number of dock widgets in this area + */ + int dockWidgetsCount() const; + /** * Returns a list of all dock widgets in this dock area. * This list contains open and closed dock widgets. */ QList dockWidgets() const; + /** + * Returns the number of dock widgets in this area + */ + int openDockWidgetsCount() const; + /** * Returns a list of dock widgets that are not closed */ QList openedDockWidgets() const; - /** - * Returns the number of dock widgets in this area - */ - int count() const; - /** * Returns a dock widget by its index */ diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index a71aa37..2dd67b7 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -537,7 +537,7 @@ bool DockContainerWidgetPrivate::restoreDockArea(QXmlStreamReader& s, return true; } - if (!DockArea->count()) + if (!DockArea->dockWidgetsCount()) { delete DockArea; DockArea = nullptr; @@ -1073,9 +1073,11 @@ QSplitter* CDockContainerWidget::rootSplitter() const //============================================================================ void CDockContainerWidget::dumpLayout() { +#if (ADS_DEBUG_LEVEL > 0) qDebug("\n\nDumping layout --------------------------"); d->dumpRecursive(0, d->RootSplitter); qDebug("--------------------------\n\n"); +#endif } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index f41bf08..8e9d5e0 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -91,11 +91,6 @@ struct DockWidgetPrivate */ void hideDockWidget(); - /** - * Hides a parent splitter if all dock widgets in the splitter are closed - */ - void hideEmptyParentSplitters(); - /** * Hides a dock area if all dock widgets in the area are closed. * This function updates the current selected tab and hides the parent @@ -103,12 +98,6 @@ struct DockWidgetPrivate */ void updateParentDockArea(); - /** - * Hides a floating widget if all dock areas are empty - that means, - * if all dock widgets in all dock areas are closed - */ - void hideEmptyFloatingWidget(); - /** * Setup the top tool bar */ @@ -165,23 +154,6 @@ void DockWidgetPrivate::hideDockWidget() { TabWidget->hide(); updateParentDockArea(); - hideEmptyParentSplitters(); - hideEmptyFloatingWidget(); -} - - -//============================================================================ -void DockWidgetPrivate::hideEmptyParentSplitters() -{ - auto Splitter = internal::findParent(_this); - while (Splitter && Splitter->isVisible()) - { - if (!Splitter->hasVisibleContent()) - { - Splitter->hide(); - } - Splitter = internal::findParent(Splitter); - } } @@ -195,19 +167,7 @@ void DockWidgetPrivate::updateParentDockArea() } else { - DockArea->hide(); - } -} - - -//============================================================================ -void DockWidgetPrivate::hideEmptyFloatingWidget() -{ - CDockContainerWidget* Container = _this->dockContainer(); - if (Container->isFloating() && Container->openedDockAreas().isEmpty()) - { - CFloatingDockContainer* FloatingWidget = internal::findParent(Container); - FloatingWidget->hide(); + DockArea->hideAreaWithNoVisibleContent(); } } @@ -385,7 +345,7 @@ bool CDockWidget::isFloating() const return false; } - if (dockContainer()->dockArea(0)->count() != 1) + if (dockContainer()->dockArea(0)->dockWidgetsCount() != 1) { return false; } diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index 5040c60..c253ab6 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -164,13 +164,13 @@ bool DockWidgetTabPrivate::startFloating() { qDebug() << "isFloating " << DockWidget->dockContainer()->isFloating(); qDebug() << "areaCount " << DockWidget->dockContainer()->dockAreaCount(); - qDebug() << "widgetCount " << DockWidget->dockAreaWidget()->count(); + qDebug() << "widgetCount " << DockWidget->dockAreaWidget()->dockWidgetsCount(); // if this is the last dock widget inside of this floating widget, // then it does not make any sense, to make it floating because // it is already floating if (DockWidget->dockContainer()->isFloating() && (DockWidget->dockContainer()->visibleDockAreaCount() == 1) - && (DockWidget->dockAreaWidget()->count() == 1)) + && (DockWidget->dockAreaWidget()->dockWidgetsCount() == 1)) { return false; } @@ -179,7 +179,7 @@ bool DockWidgetTabPrivate::startFloating() DragState = DraggingFloatingWidget; QSize Size = DockArea->size(); CFloatingDockContainer* FloatingWidget = nullptr; - if (DockArea->count() > 1) + if (DockArea->dockWidgetsCount() > 1) { // If section widget has multiple tabs, we take only one tab FloatingWidget = new CFloatingDockContainer(DockWidget); @@ -248,7 +248,7 @@ void CDockWidgetTab::mouseReleaseEvent(QMouseEvent* ev) int toIndex = d->DockArea->indexOfContentByTitlePos(pos, this); if (-1 == toIndex) { - toIndex = d->DockArea->count() - 1; + toIndex = d->DockArea->dockWidgetsCount() - 1; } qDebug() << "Move tab from " << fromIndex << " to " << toIndex; d->DockArea->reorderDockWidget(fromIndex, toIndex); @@ -294,6 +294,16 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev) bool MouseInsideTitleArea = d->titleAreaGeometryContains(ev->globalPos()); if (!MouseInsideTitleArea) { + // If this is the last dock area in a dock container with only + // one single dock widget 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->openDockWidgetsCount() == 1 + && d->DockArea->dockContainer()->visibleDockAreaCount() == 1) + { + return; + } + // Floating is only allowed for widgets that are movable if (d->DockWidget->features().testFlag(CDockWidget::DockWidgetMovable)) { @@ -301,7 +311,7 @@ void CDockWidgetTab::mouseMoveEvent(QMouseEvent* ev) } return; } - else if (d->DockArea->count() > 1 + else if (d->DockArea->openDockWidgetsCount() > 1 && (ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving { d->DragState = DraggingTab; @@ -381,7 +391,7 @@ void CDockWidgetTab::mouseDoubleClickEvent(QMouseEvent *event) // 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->count() > 1) + if (!d->DockArea->dockContainer()->isFloating() || d->DockArea->dockWidgetsCount() > 1) { d->startFloating(); } diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 4e869bb..6268e5d 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -409,7 +409,9 @@ bool CFloatingDockContainer::event(QEvent *e) break; } +#if (ADS_DEBUG_LEVEL > 0) qDebug() << "CFloatingDockContainer::event " << e->type(); +#endif return QWidget::event(e); } @@ -520,7 +522,7 @@ bool CFloatingDockContainer::hasSingleDockWidget() const return false; } - return d->DockContainer->dockArea(0)->count() == 1; + return d->DockContainer->dockArea(0)->dockWidgetsCount() == 1; } diff --git a/src/ads_globals.h b/src/ads_globals.h index d8a49c5..127a469 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -39,6 +39,8 @@ #define ADS_EXPORT Q_DECL_IMPORT #endif +#define ADS_DEBUG_LEVEL 0 + class QSplitter; namespace ads