diff --git a/README.md b/README.md index 0158a49..4a4ae05 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,53 @@ # Advanced Docking System for Qt -Manages content widgets more like Visual Studio or similar programs. -I also try to get everything done with basic Qt functionality. -Basic usage of QWidgets an QLayouts and using basic styles as much as possible. +Qt Advanced Docking System lets you create customizable layouts using a full +featured window docking system similar to what is found in many popular +integrated development environements (IDEs) such as Visual Studio. +Everything is implemented with standard Qt functionality without any +platform specific code. Basic usage of QWidgets an QLayouts and using basic +styles as much as possible. + +This work is based on and inspired by the +[Advanced Docking System for Qt](https://github.com/mfreiholz/Qt-Advanced-Docking-System) +from Manuel Freiholz. I did an almost complete rewrite of his code to improve +code quality, readibility and to fix all issues from the issue tracker +of his docking system project. + +## Features +### Docking everywhere - no central widget +There is no central widget like in the Qt docking system. You can dock on every +border of the main window or you can dock into each dock area - so you are +free to dock almost everywhere. + +![Layout of widgets](preview.png) -![Layout of widgets](preview.png) ![Dropping widgets](preview-dragndrop.png) +### Docking inside floating windows +There is no difference between the main window and a floating window. Docking +into floating windows is supported. + +![Docking inside floating windows](floating-widget-dragndrop.png) + +### Grouped dragging +When dragging the titlebar of a dock, all the tabs that are tabbed with it are +going to be dragged. So you can move complete groups of tabbed widgets into +a floating widget or from one dock area to another one. + +![Grouped dragging](grouped-dragging.png) + + ## Tested Compatible Environments - Windows 10 ## Build -Open the `build.pro` with QtCreator and start the build, that's it. +Open the `ads.pro` with QtCreator and start the build, that's it. You can run the demo project and test it yourself. -## Release & Development -The `master` branch is not guaranteed to be stable or does not even build, since it is the main working branch. -If you want a version that builds, you should always use a release/beta tag. - ## Developers - Uwe Kindler, Project Maintainer - Manuel Freiholz ## License information -This project uses the [GPLv3 license] (gnu-gpl-v3.0.md) +This project uses the [GPLv3 license](gnu-gpl-v3.0.md) diff --git a/floating-widget-dragndrop.png b/floating-widget-dragndrop.png new file mode 100644 index 0000000..b91cc6d Binary files /dev/null and b/floating-widget-dragndrop.png differ diff --git a/grouped-dragging.png b/grouped-dragging.png new file mode 100644 index 0000000..19db07c Binary files /dev/null and b/grouped-dragging.png differ diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 042e5b0..17e3636 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -433,6 +433,7 @@ bool DockContainerWidgetPrivate::restoreDockArea(QDataStream& stream, DockArea->addDockWidget(DockWidget); DockArea->hide(); + DockWidget->setToggleViewActionChecked(!Closed); DockWidget->setProperty("closed", Closed); DockWidget->setProperty("dirty", false); } @@ -762,6 +763,21 @@ int CDockContainerWidget::dockAreaCount() const } +//============================================================================ +int CDockContainerWidget::visibleDockAreaCount() const +{ + // TODO Cache or precalculate this to speed it up because it is used during + // movement of floating widget + int Result = 0; + for (auto DockArea : d->DockAreas) + { + Result += DockArea->isVisible() ? 1 : 0; + } + + return Result; +} + + //============================================================================ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos) diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 891fcce..1160f89 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -134,6 +134,11 @@ public: */ int dockAreaCount() const; + /** + * Returns the number of visible dock areas + */ + int visibleDockAreaCount() const; + /** * This function returns true, if this container is in a floating widget */ diff --git a/src/DockSplitter.cpp b/src/DockSplitter.cpp index efccbbd..c9f27fa 100644 --- a/src/DockSplitter.cpp +++ b/src/DockSplitter.cpp @@ -21,6 +21,22 @@ CDockSplitter::~CDockSplitter() qDebug() << "~CDockSplitter"; } + +//============================================================================ +bool CDockSplitter::hasVisibleContent() const +{ + // TODO Cache or precalculate this to speed up + for (int i = 0; i < count(); ++i) + { + if (widget(i)->isVisibleTo(this)) + { + return true; + } + } + + return false; +} + } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockSplitter.h b/src/DockSplitter.h index 17383c5..40c8fb4 100644 --- a/src/DockSplitter.h +++ b/src/DockSplitter.h @@ -28,6 +28,11 @@ public: * Prints debug info */ virtual ~CDockSplitter(); + + /** + * Returns true, if any of the internal widgets is visible + */ + bool hasVisibleContent() const; }; // class CDockSplitter } // namespace ads diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 489538d..4250fc8 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -45,6 +45,7 @@ #include "DockManager.h" #include "FloatingDockContainer.h" #include "DockStateSerialization.h" +#include "DockSplitter.h" #include "ads_globals.h" namespace ads @@ -82,7 +83,7 @@ struct DockWidgetPrivate /** * Hides a parent splitter if all dock widgets in the splitter are closed */ - void hideEmptyParentSplitter(); + void hideEmptyParentSplitters(); /** * Hides a dock area if all dock widgets in the area are closed @@ -119,9 +120,10 @@ void DockWidgetPrivate::showDockWidget() DockArea->show(); DockArea->setCurrentIndex(DockArea->tabIndex(_this)); QSplitter* Splitter = internal::findParent(_this); - if (Splitter) + while (Splitter && !Splitter->isVisible()) { Splitter->show(); + Splitter = internal::findParent(Splitter); } CDockContainerWidget* Container = DockArea->dockContainer(); @@ -138,32 +140,25 @@ void DockWidgetPrivate::showDockWidget() //============================================================================ void DockWidgetPrivate::hideDockWidget() { - ToggleViewAction->setChecked(false); TitleWidget->hide(); hideEmptyParentDockArea(); - hideEmptyParentSplitter(); + hideEmptyParentSplitters(); hideEmptyFloatingWidget(); } //============================================================================ -void DockWidgetPrivate::hideEmptyParentSplitter() +void DockWidgetPrivate::hideEmptyParentSplitters() { - QSplitter* Splitter = internal::findParent(_this); - if (!Splitter) + auto Splitter = internal::findParent(_this); + while (Splitter && Splitter->isVisible()) { - return; - } - - for (int i = 0; i < Splitter->count(); ++i) - { - if (Splitter->widget(i)->isVisibleTo(Splitter)) + if (!Splitter->hasVisibleContent()) { - return; + Splitter->hide(); } + Splitter = internal::findParent(Splitter); } - - Splitter->hide(); } @@ -346,6 +341,9 @@ void CDockWidget::toggleView(bool Open) d->hideDockWidget(); } d->Closed = !Open; + d->ToggleViewAction->blockSignals(true); + d->ToggleViewAction->setChecked(Open); + d->ToggleViewAction->blockSignals(false); if (!Open) { emit closed(); diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index c195021..ff1bee9 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -131,7 +131,6 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos) } DropContainer = TopContainer; - //std::cout << "TopContainer " << TopContainer << std::endl; auto ContainerOverlay = DockManager->containerOverlay(); auto DockAreaOverlay = DockManager->dockAreaOverlay(); @@ -142,15 +141,15 @@ void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos) return; } - ContainerOverlay->setAllowedAreas(TopContainer->dockAreaCount() > 1 ? + int VisibleDockAreas = TopContainer->visibleDockAreaCount(); + ContainerOverlay->setAllowedAreas(VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas); ContainerOverlay->showOverlay(TopContainer); - //ContainerOverlay->raise(); auto DockArea = TopContainer->dockAreaAt(GlobalPos); - if (DockArea && TopContainer->dockAreaCount() > 0) + if (DockArea && DockArea->isVisible() && VisibleDockAreas > 0) { - DockAreaOverlay->setAllowedAreas((TopContainer->dockAreaCount() == 1) ? + DockAreaOverlay->setAllowedAreas((VisibleDockAreas == 1) ? NoDockWidgetArea : AllDockAreas); DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea); ContainerOverlay->enableDropPreview(InvalidDockWidgetArea == Area);