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

This commit is contained in:
Uwe Kindler 2018-09-14 08:46:10 +02:00
parent b93e723a83
commit 6ec38b48ef
7 changed files with 110 additions and 58 deletions

View File

@ -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<CDockWidget*> 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<CDockSplitter*>(this);
while (Splitter && Splitter->isVisible())
{
if (!Splitter->hasVisibleContent())
{
Splitter->hide();
}
Splitter = internal::findParent<CDockSplitter*>(Splitter);
}
//Hide empty floating widget
CDockContainerWidget* Container = this->dockContainer();
if (Container->isFloating() && Container->openedDockAreas().isEmpty())
{
CFloatingDockContainer* FloatingWidget = internal::findParent<CFloatingDockContainer*>(Container);
FloatingWidget->hide();
}
}
//============================================================================
void CDockAreaWidget::hideAreaIfNoVisibleContent()
{
if (openedDockWidgets().isEmpty())
{
hideAreaIfNoVisibleContent();
}
}
//============================================================================
void CDockAreaWidget::onDockWidgetTitleClicked()
{
@ -512,6 +555,21 @@ QList<CDockWidget*> 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<CDockWidget*> 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();
}

View File

@ -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<CDockWidget*> 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<CDockWidget*> openedDockWidgets() const;
/**
* Returns the number of dock widgets in this area
*/
int count() const;
/**
* Returns a dock widget by its index
*/

View File

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

View File

@ -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<CDockSplitter*>(_this);
while (Splitter && Splitter->isVisible())
{
if (!Splitter->hasVisibleContent())
{
Splitter->hide();
}
Splitter = internal::findParent<CDockSplitter*>(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<CFloatingDockContainer*>(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;
}

View File

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

View File

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

View File

@ -39,6 +39,8 @@
#define ADS_EXPORT Q_DECL_IMPORT
#endif
#define ADS_DEBUG_LEVEL 0
class QSplitter;
namespace ads