From 16bd1a3bd2f7b00c8f8062160d5e1c0962a5a527 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 23 Mar 2017 10:23:53 +0100 Subject: [PATCH] Implemented proper hiding and showing of dock widgets --- .cproject | 313 +++++++ .project | 27 + .settings/language.settings.xml | 15 + ContainerWidget.dat | Bin 0 -> 464 bytes MainWindow.dat | Bin 0 -> 50 bytes src/DockAreaWidget.cpp | 1429 +++++++++++++++---------------- src/DockAreaWidget.h | 400 +++++---- src/DockContainerWidget.cpp | 1204 +++++++++++++------------- src/DockContainerWidget.h | 298 +++---- src/DockWidget.cpp | 762 ++++++++-------- src/DockWidget.h | 372 ++++---- src/FloatingDockContainer.cpp | 782 ++++++++--------- src/FloatingDockContainer.h | 218 ++--- 13 files changed, 3130 insertions(+), 2690 deletions(-) create mode 100644 .cproject create mode 100644 .project create mode 100644 .settings/language.settings.xml create mode 100644 ContainerWidget.dat create mode 100644 MainWindow.dat diff --git a/.cproject b/.cproject new file mode 100644 index 0000000..bad5a71 --- /dev/null +++ b/.cproject @@ -0,0 +1,313 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mingw32-make + -j + all + false + false + false + + + make + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../ads.pro + + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + mingw32-make + -j + all + false + false + false + + + make + + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../../src/src.pro + + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + mingw32-make + -j + all + false + false + false + + + make + + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../../demo/demo.pro + + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + mingw32-make + -j + all + false + false + false + + + make + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../../AdvancedDockingSystemDemo/AdvancedDockingSystemDemo.pro + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + mingw32-make + -j + all + false + false + false + + + make + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../../AdvancedDockingSystemDemo_v2/AdvancedDockingSystemDemo_v2.pro + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + mingw32-make + -j + all + false + false + false + + + make + clean + false + true + false + + + mingw32-make + -j6 + debug + false + false + false + + + qmake + -recursive ../../AdvancedDockingSystem/src.pro + + true + false + false + + + mingw32-make + -j4 + release + false + false + false + + + + + + + + + + + + + diff --git a/.project b/.project new file mode 100644 index 0000000..9c7157b --- /dev/null +++ b/.project @@ -0,0 +1,27 @@ + + + QtAdvancedDockingSystem + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml new file mode 100644 index 0000000..a8d9d50 --- /dev/null +++ b/.settings/language.settings.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/ContainerWidget.dat b/ContainerWidget.dat new file mode 100644 index 0000000000000000000000000000000000000000..a3c10ead7b47dd8a59eb5f1594f16e65a58dd900 GIT binary patch literal 464 zcmZQz5H@FEU|<4b7yz*up&T11eFaEE)i4S`#SSn)^upAFXb=XeV}|03Ksp|XK{T>F zPz_@=5WfV9L(K)t^D&e%FML D8o(ek literal 0 HcmV?d00001 diff --git a/MainWindow.dat b/MainWindow.dat new file mode 100644 index 0000000000000000000000000000000000000000..1470ba34ca97237d17fe2b2103ce52486bda5743 GIT binary patch literal 50 tcmZR)dEqnz69W)1ivo%N3=C|!Kz0-m%Q7%9$^rSQKz0yF1qiS=006{|1?2z$ literal 0 HcmV?d00001 diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 728d83c..0f57778 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1,717 +1,712 @@ -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockAreaWidget.cpp -/// \author Uwe Kindler -/// \date 24.02.2017 -/// \brief Implementation of CDockAreaWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include "DockAreaWidget.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "DockContainerWidget.h" -#include "DockWidget.h" -#include "DockWidgetTitleBar.h" -#include "FloatingDockContainer.h" -#include "DockManager.h" -#include "DockOverlay.h" - -#include - -namespace ads -{ -static const char* const INDEX_PROPERTY = "index"; -static const char* const ACTION_PROPERTY = "action"; -static const int APPEND = -1; - -/** - * Custom scroll bar implementation for dock area tab bar - * This scroll area enables floating of a whole dock area including all - * dock widgets - */ -class CTabsScrollArea : public QScrollArea -{ -private: - QPoint m_DragStartMousePos; - CDockAreaWidget* m_DockArea; - CFloatingDockContainer* m_FloatingWidget = nullptr; - -public: - CTabsScrollArea(CDockAreaWidget* parent) - : QScrollArea(parent), - m_DockArea(parent) - { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); - setFrameStyle(QFrame::NoFrame); - setWidgetResizable(true); - setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - } - -protected: - virtual void wheelEvent(QWheelEvent* Event) override - { - std::cout << "CTabsScrollArea::wheelEvent" << std::endl; - Event->accept(); - const int direction = Event->angleDelta().y(); - if (direction < 0) - { - horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20); - } - else - { - horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20); - } - } - - /** - * Stores mouse position to detect dragging - */ - virtual void mousePressEvent(QMouseEvent* ev) override - { - if (ev->button() == Qt::LeftButton) - { - ev->accept(); - m_DragStartMousePos = ev->pos(); - return; - } - QScrollArea::mousePressEvent(ev); - } - - /** - * Stores mouse position to detect dragging - */ - virtual void mouseReleaseEvent(QMouseEvent* ev) override - { - if (ev->button() == Qt::LeftButton) - { - std::cout << "CTabsScrollArea::mouseReleaseEvent" << std::endl; - ev->accept(); - m_FloatingWidget = nullptr; - m_DragStartMousePos = QPoint(); - return; - } - QScrollArea::mouseReleaseEvent(ev); - } - - /** - * Starts floating the complete docking area including all dock widgets, - * if it is not the last dock area in a floating widget - */ - virtual void mouseMoveEvent(QMouseEvent* ev) override - { - QScrollArea::mouseMoveEvent(ev); - if (ev->buttons() != Qt::LeftButton) - { - return; - } - - if (m_FloatingWidget) - { - m_FloatingWidget->moveFloating(); - return; - } - - // 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 (m_DockArea->dockContainer()->isFloating() && m_DockArea->dockContainer()->dockAreaCount() == 1) - { - return; - } - - if (!this->geometry().contains(ev->pos())) - { - std::cout << "CTabsScrollArea::startFloating" << std::endl; - startFloating(m_DragStartMousePos); - auto Overlay = m_DockArea->dockManager()->containerOverlay(); - Overlay->setAllowedAreas(OuterDockAreas); - } - - return; - } - - /** - * Double clicking the title bar also starts floating of the complete area - */ - virtual void mouseDoubleClickEvent(QMouseEvent *event) override - { - startFloating(event->pos()); - } - - /** - * Starts floating - */ - void startFloating(const QPoint& Pos) - { - QSize Size = m_DockArea->size(); - CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(m_DockArea); - FloatingWidget->startFloating(Pos, Size); - m_FloatingWidget = FloatingWidget; - } -}; // class CTabsScrollArea - - -/** - * Private data class of CDockAreaWidget class (pimpl) - */ -struct DockAreaWidgetPrivate -{ - CDockAreaWidget* _this; - QBoxLayout* Layout; - QFrame* TitleBar; - QBoxLayout* TopLayout; - QStackedLayout* ContentsLayout; - QScrollArea* TabsScrollArea; - QWidget* TabsContainerWidget; - QBoxLayout* TabsLayout; - QPushButton* TabsMenuButton; - QPushButton* CloseButton; - int TabsLayoutInitCount; - CDockManager* DockManager = nullptr; - - /** - * Private data constructor - */ - DockAreaWidgetPrivate(CDockAreaWidget* _public); - - /** - * Creates the layout for top area with tabs and close button - */ - void createTabBar(); - - /** - * Returns the dock widget with the given index - */ - CDockWidget* dockWidgetAt(int index) - { - return dynamic_cast(ContentsLayout->widget(index)); - } - - /** - * Convenience function to ease title widget access by index - */ - CDockWidgetTitleBar* titleWidgetAt(int index) - { - return dockWidgetAt(index)->titleBar(); - } - - /** - * Adds a tabs menu entry for the given dock widget - * If menu is 0, a menu entry is added to the menu of the TabsMenuButton - * member. If menu is a valid menu pointer, the entry will be added to - * the given menu - */ - void addTabsMenuEntry(CDockWidget* DockWidget, int Index = -1, QMenu* menu = 0); - - /** - * Returns the tab action of the given dock widget - */ - QAction* dockWidgetTabAction(CDockWidget* DockWidget) const - { - return qvariant_cast(DockWidget->property(ACTION_PROPERTY)); - } - - /** - * Returns the index of the given dock widget - */ - int dockWidgetIndex(CDockWidget* DockWidget) const - { - return DockWidget->property(INDEX_PROPERTY).toInt(); - } - - /** - * Update the tabs menu if dock widget order changed or if dock widget has - * been removed - */ - void updateTabsMenu(); - - /** - * Updates the tab bar visibility depending on the number of dock widgets - * in this area - */ - void updateTabBar(); -}; -// struct DockAreaWidgetPrivate - - -//============================================================================ -DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) : - _this(_public) -{ - -} - - -//============================================================================ -void DockAreaWidgetPrivate::createTabBar() -{ - TitleBar = new QFrame(_this); - TitleBar->setObjectName("dockAreaTitleBar"); - TopLayout = new QBoxLayout(QBoxLayout::LeftToRight); - TopLayout->setContentsMargins(0, 0, 0, 0); - TopLayout->setSpacing(0); - TitleBar->setLayout(TopLayout); - Layout->addWidget(TitleBar); - - TabsScrollArea = new CTabsScrollArea(_this); - TopLayout->addWidget(TabsScrollArea, 1); - - TabsContainerWidget = new QWidget(); - TabsContainerWidget->setObjectName("tabsContainerWidget"); - TabsScrollArea->setWidget(TabsContainerWidget); - - TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight); - TabsLayout->setContentsMargins(0, 0, 0, 0); - TabsLayout->setSpacing(0); - TabsLayout->addStretch(1); - TabsContainerWidget->setLayout(TabsLayout); - - TabsMenuButton = new QPushButton(); - TabsMenuButton->setObjectName("tabsMenuButton"); - TabsMenuButton->setFlat(true); - TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); - TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width()); - TabsMenuButton->setMenu(new QMenu(TabsMenuButton)); - TopLayout->addWidget(TabsMenuButton, 0); - _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), - SLOT(onTabsMenuActionTriggered(QAction*))); - - CloseButton = new QPushButton(); - CloseButton->setObjectName("closeButton"); - CloseButton->setFlat(true); - CloseButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); - CloseButton->setToolTip(_this->tr("Close")); - CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - TopLayout->addWidget(CloseButton, 0); - _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); - - TabsLayoutInitCount = TabsLayout->count(); -} - - -//============================================================================ -void DockAreaWidgetPrivate::updateTabBar() -{ - CDockContainerWidget* Container = _this->dockContainer(); - if (!Container) - { - return; - } - - if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1)) - { - TitleBar->setVisible(false); - } - else - { - TitleBar->setVisible(true); - } -} - - -//============================================================================ -void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget, - int Index, QMenu* menu) -{ - menu = menu ? menu : TabsMenuButton->menu(); - QAction* Action; - if (Index >= 0 && Index < menu->actions().count()) - { - Action = new QAction(DockWidget->windowTitle()); - menu->insertAction(menu->actions().at(Index), Action); - } - else - { - Action = menu->addAction(DockWidget->windowTitle()); - } - QVariant vAction = QVariant::fromValue(Action); - DockWidget->setProperty(ACTION_PROPERTY, vAction); -} - - -//============================================================================ -void DockAreaWidgetPrivate::updateTabsMenu() -{ - QMenu* menu = TabsMenuButton->menu(); - menu->clear(); - for (int i = 0; i < ContentsLayout->count(); ++i) - { - CDockWidget* DockWidget = dockWidgetAt(i); - addTabsMenuEntry(dockWidgetAt(i), APPEND, menu); - } -} - - -//============================================================================ -CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) : - QFrame(parent), - d(new DockAreaWidgetPrivate(this)) -{ - d->DockManager = DockManager; - d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); - d->Layout->setContentsMargins(0, 0, 0, 0); - d->Layout->setSpacing(0); - setLayout(d->Layout); - - d->createTabBar(); - - d->ContentsLayout = new QStackedLayout(); - d->ContentsLayout->setContentsMargins(0, 0, 0, 0); - d->ContentsLayout->setSpacing(0); - d->Layout->addLayout(d->ContentsLayout, 1); -} - -//============================================================================ -CDockAreaWidget::~CDockAreaWidget() -{ - std::cout << "~CDockAreaWidget()" << std::endl; - delete d; -} - - -//============================================================================ -CDockManager* CDockAreaWidget::dockManager() const -{ - return d->DockManager; -} - - -//============================================================================ -CDockContainerWidget* CDockAreaWidget::dockContainer() const -{ - QWidget* Parent = parentWidget(); - while (Parent) - { - CDockContainerWidget* Container = dynamic_cast(Parent); - if (Container) - { - return Container; - } - Parent = Parent->parentWidget(); - } - - return 0; -} - - -//============================================================================ -void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget) -{ - insertDockWidget(d->ContentsLayout->count(), DockWidget); -} - - -//============================================================================ -void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, - bool Activate) -{ - d->ContentsLayout->insertWidget(index, DockWidget); - DockWidget->titleBar()->setDockAreaWidget(this); - auto TitleBar = DockWidget->titleBar(); - d->TabsLayout->insertWidget(index, TitleBar); - TitleBar->show(); - connect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); - DockWidget->setProperty(INDEX_PROPERTY, index); - if (Activate) - { - setCurrentIndex(index); - } - d->addTabsMenuEntry(DockWidget, index); - DockWidget->setDockArea(this); -} - - -//============================================================================ -void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) -{ - std::cout << "CDockAreaWidget::removeDockWidget" << std::endl; - d->ContentsLayout->removeWidget(DockWidget); - auto TitleBar = DockWidget->titleBar(); - TitleBar->hide(); - d->TabsLayout->removeWidget(TitleBar); - disconnect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); - setCurrentIndex(d->ContentsLayout->currentIndex()); - d->updateTabsMenu(); - - if (d->ContentsLayout->isEmpty()) - { - std::cout << "Dock Area empty" << std::endl; - dockContainer()->removeDockArea(this); - this->deleteLater(); - } - - d->updateTabBar(); - DockWidget->setDockArea(nullptr); -} - - -//============================================================================ -void CDockAreaWidget::onDockWidgetTitleClicked() -{ - CDockWidgetTitleBar* TitleWidget = qobject_cast(sender()); - if (!TitleWidget) - { - return; - } - - int index = d->TabsLayout->indexOf(TitleWidget); - setCurrentIndex(index); -} - - -//============================================================================ -void CDockAreaWidget::onCloseButtonClicked() -{ - currentDockWidget()->toggleView(false); -} - - -//============================================================================ -CDockWidget* CDockAreaWidget::currentDockWidget() const -{ - return dockWidget(currentIndex()); -} - - -//============================================================================ -void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget) -{ - int Index = tabIndex(DockWidget); - if (Index < 0) - { - return; - } - setCurrentIndex(Index); -} - - -//============================================================================ -void CDockAreaWidget::setCurrentIndex(int index) -{ - if (index < 0 || index > (d->TabsLayout->count() - 1)) - { - qWarning() << Q_FUNC_INFO << "Invalid index" << index; - return; - } - - // Set active TAB and update all other tabs to be inactive - for (int i = 0; i < d->TabsLayout->count(); ++i) - { - QLayoutItem* item = d->TabsLayout->itemAt(i); - if (!item->widget()) - { - continue; - } - - auto TitleWidget = dynamic_cast(item->widget()); - if (!TitleWidget) - { - continue; - } - - if (i == index) - { - TitleWidget->show(); - TitleWidget->setActiveTab(true); - d->TabsScrollArea->ensureWidgetVisible(TitleWidget); - auto Features = TitleWidget->dockWidget()->features(); - d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable)); - } - else - { - TitleWidget->setActiveTab(false); - } - } - - d->ContentsLayout->setCurrentIndex(index); - d->ContentsLayout->currentWidget()->show(); - emit currentChanged(index); -} - - -//============================================================================ -int CDockAreaWidget::currentIndex() const -{ - return d->ContentsLayout->currentIndex(); -} - - -//============================================================================ -QRect CDockAreaWidget::titleAreaGeometry() const -{ - return d->TopLayout->geometry(); -} - -//============================================================================ -QRect CDockAreaWidget::contentAreaGeometry() const -{ - return d->ContentsLayout->geometry(); -} - - -//============================================================================ -int CDockAreaWidget::tabIndex(CDockWidget* DockWidget) -{ - return d->ContentsLayout->indexOf(DockWidget); -} - - -//============================================================================ -QList CDockAreaWidget::dockWidgets() const -{ - QList DockWidgetList; - for (int i = 0; i < d->ContentsLayout->count(); ++i) - { - DockWidgetList.append(dockWidget(i)); - } - return DockWidgetList; -} - - -//============================================================================ -QList CDockAreaWidget::openDockWidgets() const -{ - QList DockWidgetList; - for (int i = 0; i < d->ContentsLayout->count(); ++i) - { - CDockWidget* DockWidget = dockWidget(i); - if (!DockWidget->isClosed()) - { - DockWidgetList.append(dockWidget(i)); - } - } - return DockWidgetList; -} - - -//============================================================================ -int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const -{ - for (int i = 0; i < d->ContentsLayout->count(); ++i) - { - auto TitleWidget = d->titleWidgetAt(i); - if (TitleWidget->geometry().contains(p) && (!exclude || TitleWidget != exclude)) - { - return i; - } - } - return -1; -} - - -//============================================================================ -int CDockAreaWidget::count() const -{ - return d->ContentsLayout->count(); -} - - -//============================================================================ -CDockWidget* CDockAreaWidget::dockWidget(int Index) const -{ - return dynamic_cast(d->ContentsLayout->widget(Index)); -} - - -//============================================================================ -void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) -{ - if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0 - || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex) - { - qDebug() << "Invalid index for tab movement" << fromIndex << toIndex; - d->TabsLayout->update(); - return; - } - - CDockWidget* DockWidget = dockWidget(fromIndex); - - // reorder tabs menu action to match new order of contents - auto Menu = d->TabsMenuButton->menu(); - auto TabsAction = d->dockWidgetTabAction(DockWidget); - Menu->removeAction(TabsAction); - if (toIndex >= Menu->actions().count()) - { - Menu->addAction(TabsAction); - } - else - { - Menu->insertAction(Menu->actions().at(toIndex), TabsAction); - } - - - // now reorder contents and title bars - QLayoutItem* liFrom = nullptr; - liFrom = d->TabsLayout->takeAt(fromIndex); - d->TabsLayout->insertItem(toIndex, liFrom); - liFrom = d->ContentsLayout->takeAt(fromIndex); - d->ContentsLayout->insertWidget(toIndex, liFrom->widget()); - delete liFrom; -} - - -//============================================================================ -void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action) -{ - int Index = d->TabsMenuButton->menu()->actions().indexOf(Action); - setCurrentIndex(Index); -} - - -//============================================================================ -void CDockAreaWidget::updateDockArea() -{ - d->updateTabBar(); -} - - -//============================================================================ -void CDockAreaWidget::hideEvent(QHideEvent* event) -{ - QFrame::hideEvent(event); - emit visibilityChanged(isVisible()); -} - - -//============================================================================ -void CDockAreaWidget::showEvent(QShowEvent* event) -{ - QFrame::showEvent(event); - emit visibilityChanged(isVisible()); -} - -} // namespace ads - -//--------------------------------------------------------------------------- -// EOF DockAreaWidget.cpp +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaWidget.cpp +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Implementation of CDockAreaWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockAreaWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "DockContainerWidget.h" +#include "DockWidget.h" +#include "DockWidgetTitleBar.h" +#include "FloatingDockContainer.h" +#include "DockManager.h" +#include "DockOverlay.h" + +#include + +namespace ads +{ +static const char* const INDEX_PROPERTY = "index"; +static const char* const ACTION_PROPERTY = "action"; +static const int APPEND = -1; + +/** + * Custom scroll bar implementation for dock area tab bar + * This scroll area enables floating of a whole dock area including all + * dock widgets + */ +class CTabsScrollArea : public QScrollArea +{ +private: + QPoint m_DragStartMousePos; + CDockAreaWidget* m_DockArea; + CFloatingDockContainer* m_FloatingWidget = nullptr; + +public: + CTabsScrollArea(CDockAreaWidget* parent) + : QScrollArea(parent), + m_DockArea(parent) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Ignored); + setFrameStyle(QFrame::NoFrame); + setWidgetResizable(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + } + +protected: + virtual void wheelEvent(QWheelEvent* Event) override + { + std::cout << "CTabsScrollArea::wheelEvent" << std::endl; + Event->accept(); + const int direction = Event->angleDelta().y(); + if (direction < 0) + { + horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 20); + } + else + { + horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 20); + } + } + + /** + * Stores mouse position to detect dragging + */ + virtual void mousePressEvent(QMouseEvent* ev) override + { + if (ev->button() == Qt::LeftButton) + { + ev->accept(); + m_DragStartMousePos = ev->pos(); + return; + } + QScrollArea::mousePressEvent(ev); + } + + /** + * Stores mouse position to detect dragging + */ + virtual void mouseReleaseEvent(QMouseEvent* ev) override + { + if (ev->button() == Qt::LeftButton) + { + std::cout << "CTabsScrollArea::mouseReleaseEvent" << std::endl; + ev->accept(); + m_FloatingWidget = nullptr; + m_DragStartMousePos = QPoint(); + return; + } + QScrollArea::mouseReleaseEvent(ev); + } + + /** + * Starts floating the complete docking area including all dock widgets, + * if it is not the last dock area in a floating widget + */ + virtual void mouseMoveEvent(QMouseEvent* ev) override + { + QScrollArea::mouseMoveEvent(ev); + if (ev->buttons() != Qt::LeftButton) + { + return; + } + + if (m_FloatingWidget) + { + m_FloatingWidget->moveFloating(); + return; + } + + // 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 (m_DockArea->dockContainer()->isFloating() && m_DockArea->dockContainer()->dockAreaCount() == 1) + { + return; + } + + if (!this->geometry().contains(ev->pos())) + { + std::cout << "CTabsScrollArea::startFloating" << std::endl; + startFloating(m_DragStartMousePos); + auto Overlay = m_DockArea->dockManager()->containerOverlay(); + Overlay->setAllowedAreas(OuterDockAreas); + } + + return; + } + + /** + * Double clicking the title bar also starts floating of the complete area + */ + virtual void mouseDoubleClickEvent(QMouseEvent *event) override + { + startFloating(event->pos()); + } + + /** + * Starts floating + */ + void startFloating(const QPoint& Pos) + { + QSize Size = m_DockArea->size(); + CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(m_DockArea); + FloatingWidget->startFloating(Pos, Size); + m_FloatingWidget = FloatingWidget; + } +}; // class CTabsScrollArea + + +/** + * Private data class of CDockAreaWidget class (pimpl) + */ +struct DockAreaWidgetPrivate +{ + CDockAreaWidget* _this; + QBoxLayout* Layout; + QFrame* TitleBar; + QBoxLayout* TopLayout; + QStackedLayout* ContentsLayout; + QScrollArea* TabsScrollArea; + QWidget* TabsContainerWidget; + QBoxLayout* TabsLayout; + QPushButton* TabsMenuButton; + QPushButton* CloseButton; + int TabsLayoutInitCount; + CDockManager* DockManager = nullptr; + + /** + * Private data constructor + */ + DockAreaWidgetPrivate(CDockAreaWidget* _public); + + /** + * Creates the layout for top area with tabs and close button + */ + void createTabBar(); + + /** + * Returns the dock widget with the given index + */ + CDockWidget* dockWidgetAt(int index) + { + return dynamic_cast(ContentsLayout->widget(index)); + } + + /** + * Convenience function to ease title widget access by index + */ + CDockWidgetTitleBar* titleWidgetAt(int index) + { + return dockWidgetAt(index)->titleBar(); + } + + /** + * Adds a tabs menu entry for the given dock widget + * If menu is 0, a menu entry is added to the menu of the TabsMenuButton + * member. If menu is a valid menu pointer, the entry will be added to + * the given menu + */ + void addTabsMenuEntry(CDockWidget* DockWidget, int Index = -1, QMenu* menu = 0); + + /** + * Returns the tab action of the given dock widget + */ + QAction* dockWidgetTabAction(CDockWidget* DockWidget) const + { + return qvariant_cast(DockWidget->property(ACTION_PROPERTY)); + } + + /** + * Returns the index of the given dock widget + */ + int dockWidgetIndex(CDockWidget* DockWidget) const + { + return DockWidget->property(INDEX_PROPERTY).toInt(); + } + + /** + * Update the tabs menu if dock widget order changed or if dock widget has + * been removed + */ + void updateTabsMenu(); + + /** + * Updates the tab bar visibility depending on the number of dock widgets + * in this area + */ + void updateTabBar(); +}; +// struct DockAreaWidgetPrivate + + +//============================================================================ +DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockAreaWidgetPrivate::createTabBar() +{ + TitleBar = new QFrame(_this); + TitleBar->setObjectName("dockAreaTitleBar"); + TopLayout = new QBoxLayout(QBoxLayout::LeftToRight); + TopLayout->setContentsMargins(0, 0, 0, 0); + TopLayout->setSpacing(0); + TitleBar->setLayout(TopLayout); + Layout->addWidget(TitleBar); + + TabsScrollArea = new CTabsScrollArea(_this); + TopLayout->addWidget(TabsScrollArea, 1); + + TabsContainerWidget = new QWidget(); + TabsContainerWidget->setObjectName("tabsContainerWidget"); + TabsScrollArea->setWidget(TabsContainerWidget); + + TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight); + TabsLayout->setContentsMargins(0, 0, 0, 0); + TabsLayout->setSpacing(0); + TabsLayout->addStretch(1); + TabsContainerWidget->setLayout(TabsLayout); + + TabsMenuButton = new QPushButton(); + TabsMenuButton->setObjectName("tabsMenuButton"); + TabsMenuButton->setFlat(true); + TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); + TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width()); + TabsMenuButton->setMenu(new QMenu(TabsMenuButton)); + TopLayout->addWidget(TabsMenuButton, 0); + _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), + SLOT(onTabsMenuActionTriggered(QAction*))); + + CloseButton = new QPushButton(); + CloseButton->setObjectName("closeButton"); + CloseButton->setFlat(true); + CloseButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarCloseButton)); + CloseButton->setToolTip(_this->tr("Close")); + CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + TopLayout->addWidget(CloseButton, 0); + _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); + + TabsLayoutInitCount = TabsLayout->count(); +} + + +//============================================================================ +void DockAreaWidgetPrivate::updateTabBar() +{ + CDockContainerWidget* Container = _this->dockContainer(); + if (!Container) + { + return; + } + + if (Container->isFloating() && (Container->dockAreaCount() == 1) && (_this->count() == 1)) + { + TitleBar->setVisible(false); + } + else + { + TitleBar->setVisible(true); + } +} + + +//============================================================================ +void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget, + int Index, QMenu* menu) +{ + menu = menu ? menu : TabsMenuButton->menu(); + QAction* Action; + if (Index >= 0 && Index < menu->actions().count()) + { + Action = new QAction(DockWidget->windowTitle()); + menu->insertAction(menu->actions().at(Index), Action); + } + else + { + Action = menu->addAction(DockWidget->windowTitle()); + } + QVariant vAction = QVariant::fromValue(Action); + DockWidget->setProperty(ACTION_PROPERTY, vAction); +} + + +//============================================================================ +void DockAreaWidgetPrivate::updateTabsMenu() +{ + QMenu* menu = TabsMenuButton->menu(); + menu->clear(); + for (int i = 0; i < ContentsLayout->count(); ++i) + { + CDockWidget* DockWidget = dockWidgetAt(i); + addTabsMenuEntry(dockWidgetAt(i), APPEND, menu); + } +} + + +//============================================================================ +CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) : + QFrame(parent), + d(new DockAreaWidgetPrivate(this)) +{ + d->DockManager = DockManager; + d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); + d->Layout->setContentsMargins(0, 0, 0, 0); + d->Layout->setSpacing(0); + setLayout(d->Layout); + + d->createTabBar(); + + d->ContentsLayout = new QStackedLayout(); + d->ContentsLayout->setContentsMargins(0, 0, 0, 0); + d->ContentsLayout->setSpacing(0); + d->Layout->addLayout(d->ContentsLayout, 1); +} + +//============================================================================ +CDockAreaWidget::~CDockAreaWidget() +{ + std::cout << "~CDockAreaWidget()" << std::endl; + delete d; +} + + +//============================================================================ +CDockManager* CDockAreaWidget::dockManager() const +{ + return d->DockManager; +} + + +//============================================================================ +CDockContainerWidget* CDockAreaWidget::dockContainer() const +{ + QWidget* Parent = parentWidget(); + while (Parent) + { + CDockContainerWidget* Container = dynamic_cast(Parent); + if (Container) + { + return Container; + } + Parent = Parent->parentWidget(); + } + + return 0; +} + + +//============================================================================ +void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget) +{ + insertDockWidget(d->ContentsLayout->count(), DockWidget); +} + + +//============================================================================ +void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, + bool Activate) +{ + d->ContentsLayout->insertWidget(index, DockWidget); + DockWidget->titleBar()->setDockAreaWidget(this); + auto TitleBar = DockWidget->titleBar(); + d->TabsLayout->insertWidget(index, TitleBar); + TitleBar->show(); + connect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); + connect(DockWidget, SIGNAL(viewToggled(bool)), this, SLOT(onDockWidgetViewToggled(bool))); + DockWidget->setProperty(INDEX_PROPERTY, index); + if (Activate) + { + setCurrentIndex(index); + } + d->addTabsMenuEntry(DockWidget, index); + DockWidget->setDockArea(this); +} + + +//============================================================================ +void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) +{ + std::cout << "CDockAreaWidget::removeDockWidget" << std::endl; + d->ContentsLayout->removeWidget(DockWidget); + auto TitleBar = DockWidget->titleBar(); + TitleBar->hide(); + d->TabsLayout->removeWidget(TitleBar); + disconnect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); + disconnect(DockWidget, SIGNAL(viewToggled(bool)), this, SLOT(onDockWidgetViewToggled(bool))); + setCurrentIndex(d->ContentsLayout->currentIndex()); + d->updateTabsMenu(); + + if (d->ContentsLayout->isEmpty()) + { + std::cout << "Dock Area empty" << std::endl; + dockContainer()->removeDockArea(this); + this->deleteLater(); + } + + d->updateTabBar(); + DockWidget->setDockArea(nullptr); +} + + +//============================================================================ +void CDockAreaWidget::onDockWidgetTitleClicked() +{ + CDockWidgetTitleBar* TitleWidget = qobject_cast(sender()); + if (!TitleWidget) + { + return; + } + + int index = d->TabsLayout->indexOf(TitleWidget); + setCurrentIndex(index); +} + + +//============================================================================ +void CDockAreaWidget::onCloseButtonClicked() +{ + currentDockWidget()->toggleView(false); +} + + +//============================================================================ +CDockWidget* CDockAreaWidget::currentDockWidget() const +{ + return dockWidget(currentIndex()); +} + + +//============================================================================ +void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget) +{ + int Index = tabIndex(DockWidget); + if (Index < 0) + { + return; + } + setCurrentIndex(Index); +} + + +//============================================================================ +void CDockAreaWidget::setCurrentIndex(int index) +{ + if (index < 0 || index > (d->TabsLayout->count() - 1)) + { + qWarning() << Q_FUNC_INFO << "Invalid index" << index; + return; + } + + // Set active TAB and update all other tabs to be inactive + for (int i = 0; i < d->TabsLayout->count(); ++i) + { + QLayoutItem* item = d->TabsLayout->itemAt(i); + if (!item->widget()) + { + continue; + } + + auto TitleWidget = dynamic_cast(item->widget()); + if (!TitleWidget) + { + continue; + } + + if (i == index) + { + TitleWidget->show(); + TitleWidget->setActiveTab(true); + d->TabsScrollArea->ensureWidgetVisible(TitleWidget); + auto Features = TitleWidget->dockWidget()->features(); + d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable)); + } + else + { + TitleWidget->setActiveTab(false); + } + } + + d->ContentsLayout->setCurrentIndex(index); + d->ContentsLayout->currentWidget()->show(); + emit currentChanged(index); +} + + +//============================================================================ +int CDockAreaWidget::currentIndex() const +{ + return d->ContentsLayout->currentIndex(); +} + + +//============================================================================ +QRect CDockAreaWidget::titleAreaGeometry() const +{ + return d->TopLayout->geometry(); +} + +//============================================================================ +QRect CDockAreaWidget::contentAreaGeometry() const +{ + return d->ContentsLayout->geometry(); +} + + +//============================================================================ +int CDockAreaWidget::tabIndex(CDockWidget* DockWidget) +{ + return d->ContentsLayout->indexOf(DockWidget); +} + + +//============================================================================ +QList CDockAreaWidget::dockWidgets() const +{ + QList DockWidgetList; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + DockWidgetList.append(dockWidget(i)); + } + return DockWidgetList; +} + + +//============================================================================ +QList CDockAreaWidget::openedDockWidgets() const +{ + QList DockWidgetList; + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + CDockWidget* DockWidget = dockWidget(i); + if (!DockWidget->isClosed()) + { + DockWidgetList.append(dockWidget(i)); + } + } + return DockWidgetList; +} + + +//============================================================================ +int CDockAreaWidget::indexOfContentByTitlePos(const QPoint& p, QWidget* exclude) const +{ + for (int i = 0; i < d->ContentsLayout->count(); ++i) + { + auto TitleWidget = d->titleWidgetAt(i); + if (TitleWidget->geometry().contains(p) && (!exclude || TitleWidget != exclude)) + { + return i; + } + } + return -1; +} + + +//============================================================================ +int CDockAreaWidget::count() const +{ + return d->ContentsLayout->count(); +} + + +//============================================================================ +CDockWidget* CDockAreaWidget::dockWidget(int Index) const +{ + return dynamic_cast(d->ContentsLayout->widget(Index)); +} + + +//============================================================================ +void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) +{ + if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0 + || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex) + { + qDebug() << "Invalid index for tab movement" << fromIndex << toIndex; + d->TabsLayout->update(); + return; + } + + CDockWidget* DockWidget = dockWidget(fromIndex); + + // reorder tabs menu action to match new order of contents + auto Menu = d->TabsMenuButton->menu(); + auto TabsAction = d->dockWidgetTabAction(DockWidget); + Menu->removeAction(TabsAction); + if (toIndex >= Menu->actions().count()) + { + Menu->addAction(TabsAction); + } + else + { + Menu->insertAction(Menu->actions().at(toIndex), TabsAction); + } + + + // now reorder contents and title bars + QLayoutItem* liFrom = nullptr; + liFrom = d->TabsLayout->takeAt(fromIndex); + d->TabsLayout->insertItem(toIndex, liFrom); + liFrom = d->ContentsLayout->takeAt(fromIndex); + d->ContentsLayout->insertWidget(toIndex, liFrom->widget()); + delete liFrom; +} + + +//============================================================================ +void CDockAreaWidget::onTabsMenuActionTriggered(QAction* Action) +{ + int Index = d->TabsMenuButton->menu()->actions().indexOf(Action); + setCurrentIndex(Index); +} + + +//============================================================================ +void CDockAreaWidget::updateDockArea() +{ + d->updateTabBar(); +} + + +//============================================================================ +void CDockAreaWidget::onDockWidgetViewToggled(bool Open) +{ + auto DockWidget = dynamic_cast(sender()); +} + +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockAreaWidget.cpp diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 332dc5e..d95bc44 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -1,202 +1,198 @@ -#ifndef DockAreaWidgetH -#define DockAreaWidgetH -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockAreaWidget.h -/// \author Uwe Kindler -/// \date 24.02.2017 -/// \brief Declaration of CDockAreaWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include - -namespace ads -{ -struct DockAreaWidgetPrivate; -class CDockManager; -class CDockContainerWidget; -class CDockWidget; - -/** - * DockAreaWidget manages multiple instances of DckWidgets. - * It displays a title tab, which is clickable and will switch to - * the contents associated to the title when clicked. - */ -class CDockAreaWidget : public QFrame -{ - Q_OBJECT -private: - DockAreaWidgetPrivate* d; ///< private data (pimpl) - friend class DockAreaWidgetPrivate; - -private slots: - void onDockWidgetTitleClicked(); - void onTabsMenuActionTriggered(QAction* Action); - void onCloseButtonClicked(); - -protected: - virtual void hideEvent(QHideEvent *) override; - virtual void showEvent(QShowEvent *) override; - -public: - /** - * Default Constructor - */ - CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent); - - /** - * Virtual Destructor - */ - virtual ~CDockAreaWidget(); - - /** - * Returns the dock manager object this dock area belongs to - */ - CDockManager* dockManager() const; - - /** - * Returns the dock container widget this dock area widget belongs to or 0 - * if there is no - */ - CDockContainerWidget* dockContainer() const; - - /** - * Inserts a dock widget into dock area. - * All dockwidgets in the dock area tabified in a stacked layout with tabs. - * The index indicates the index of the new dockwidget in the tabbar and - * in the stacked layout. If the Activate parameter is true, the new - * DockWidget will be the active one in the stacked layout - */ - void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true); - - /** - * Add a new dock widget to dock area. - * All dockwidgets in the dock area tabified in a stacked layout with tabs - */ - void addDockWidget(CDockWidget* DockWidget); - - /** - * Removes the given dock widget from the dock area - */ - void removeDockWidget(CDockWidget* DockWidget); - - /** - * Returns the rectangle of the title area - */ - QRect titleAreaGeometry() const; - - /** - * Returns the rectangle of the content - */ - QRect contentAreaGeometry() const; - - /** - * Returns the tab index of the given DockWidget - */ - int tabIndex(CDockWidget* DockWidget); - - /** - * Returns the index of contents of the title widget that is located at - * mouse position pos - */ - int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const; - - /** - * Returns a list of all dock widgets in this dock area. - * This list contains open and closed dock widgets. - */ - QList dockWidgets() const; - - /** - * Returns a list of dock widgets that are not closed - */ - QList openDockWidgets() const; - - /** - * Returns the number of dock widgets in this area - */ - int count() const; - - /** - * Returns a dock widget by its index - */ - CDockWidget* dockWidget(int Index) const; - - /** - * Reorder the index position of DockWidget at fromIndx to toIndex. - */ - void reorderDockWidget(int fromIndex, int toIndex); - - /** - * Returns the index of the current active dock widget - */ - int currentIndex() const; - - /** - * Returns the current active dock widget - */ - CDockWidget* currentDockWidget() const; - - /** - * Shows the tab with tghe given dock widget - */ - void setCurrentDockWidget(CDockWidget* DockWidget); - -public slots: - /** - * This sets the index position of the current tab page. - */ - void setCurrentIndex(int index); - - /** - * Updates the dock area layout and components visibility - */ - void updateDockArea(); - -signals: - /** - * This signal is emitted when user clicks on a tab at an index. - */ - void tabBarClicked(int index); - - /** - * This signal is emitted when the tab bar's current tab changes. The new - * current has the given index, or -1 if there isn't a new one - * @param index - */ - void currentChanged(int index); - - /** - * This signal is emitted if a dock areas visibility changed. - * The visibility changes, if the last dock widget in a dock area is closed - * or if one dock widget in a dock area with only closed dock widgets - * becomes visible - */ - void visibilityChanged(bool Visible); -}; // class DockAreaWidget -} - // namespace ads -//----------------------------------------------------------------------------- -#endif // DockAreaWidgetH +#ifndef DockAreaWidgetH +#define DockAreaWidgetH +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockAreaWidget.h +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Declaration of CDockAreaWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ +struct DockAreaWidgetPrivate; +class CDockManager; +class CDockContainerWidget; +class CDockWidget; + +/** + * DockAreaWidget manages multiple instances of DckWidgets. + * It displays a title tab, which is clickable and will switch to + * the contents associated to the title when clicked. + */ +class CDockAreaWidget : public QFrame +{ + Q_OBJECT +private: + DockAreaWidgetPrivate* d; ///< private data (pimpl) + friend class DockAreaWidgetPrivate; + +private slots: + void onDockWidgetTitleClicked(); + void onTabsMenuActionTriggered(QAction* Action); + void onCloseButtonClicked(); + void onDockWidgetViewToggled(bool Open); + +public: + /** + * Default Constructor + */ + CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CDockAreaWidget(); + + /** + * Returns the dock manager object this dock area belongs to + */ + CDockManager* dockManager() const; + + /** + * Returns the dock container widget this dock area widget belongs to or 0 + * if there is no + */ + CDockContainerWidget* dockContainer() const; + + /** + * Inserts a dock widget into dock area. + * All dockwidgets in the dock area tabified in a stacked layout with tabs. + * The index indicates the index of the new dockwidget in the tabbar and + * in the stacked layout. If the Activate parameter is true, the new + * DockWidget will be the active one in the stacked layout + */ + void insertDockWidget(int index, CDockWidget* DockWidget, bool Activate = true); + + /** + * Add a new dock widget to dock area. + * All dockwidgets in the dock area tabified in a stacked layout with tabs + */ + void addDockWidget(CDockWidget* DockWidget); + + /** + * Removes the given dock widget from the dock area + */ + void removeDockWidget(CDockWidget* DockWidget); + + /** + * Returns the rectangle of the title area + */ + QRect titleAreaGeometry() const; + + /** + * Returns the rectangle of the content + */ + QRect contentAreaGeometry() const; + + /** + * Returns the tab index of the given DockWidget + */ + int tabIndex(CDockWidget* DockWidget); + + /** + * Returns the index of contents of the title widget that is located at + * mouse position pos + */ + int indexOfContentByTitlePos(const QPoint& pos, QWidget* exclude = nullptr) const; + + /** + * Returns a list of all dock widgets in this dock area. + * This list contains open and closed dock widgets. + */ + QList dockWidgets() 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 + */ + CDockWidget* dockWidget(int Index) const; + + /** + * Reorder the index position of DockWidget at fromIndx to toIndex. + */ + void reorderDockWidget(int fromIndex, int toIndex); + + /** + * Returns the index of the current active dock widget + */ + int currentIndex() const; + + /** + * Returns the current active dock widget + */ + CDockWidget* currentDockWidget() const; + + /** + * Shows the tab with tghe given dock widget + */ + void setCurrentDockWidget(CDockWidget* DockWidget); + +public slots: + /** + * This sets the index position of the current tab page. + */ + void setCurrentIndex(int index); + + /** + * Updates the dock area layout and components visibility + */ + void updateDockArea(); + +signals: + /** + * This signal is emitted when user clicks on a tab at an index. + */ + void tabBarClicked(int index); + + /** + * This signal is emitted when the tab bar's current tab changes. The new + * current has the given index, or -1 if there isn't a new one + * @param index + */ + void currentChanged(int index); + + /** + * This signal is emitted if the dock area is closed or opened. + * The dock area will be closed, if all dock widgets in the dock area are + * closed and will be opened, when the first dock widget is opened + */ + void viewToggled(bool Open); +}; // class DockAreaWidget +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaWidgetH diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 8df425d..21743d2 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1,594 +1,610 @@ -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockContainerWidget.cpp -/// \author Uwe Kindler -/// \date 24.02.2017 -/// \brief Implementation of CDockContainerWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include "DockContainerWidget.h" - -#include -#include -#include -#include -#include - -#include "DockManager.h" -#include "DockAreaWidget.h" -#include "DockWidget.h" -#include "FloatingDockContainer.h" -#include "DockOverlay.h" -#include "ads_globals.h" - -#include - -namespace ads -{ -static unsigned int zOrderCounter = 0; - -/** - * Helper function to ease insertion of dock area into splitter - */ -static void insertWidgetIntoSplitter(QSplitter* Splitter, QWidget* widget, bool Append) -{ - if (Append) - { - Splitter->addWidget(widget); - } - else - { - Splitter->insertWidget(0, widget); - } -} - -/** - * Private data class of CDockContainerWidget class (pimpl) - */ -struct DockContainerWidgetPrivate -{ - CDockContainerWidget* _this; - QPointer DockManager; - unsigned int zOrderIndex = 0; - QList DockAreas; - QGridLayout* Layout = nullptr; - bool isFloating = false; - - /** - * Private data constructor - */ - DockContainerWidgetPrivate(CDockContainerWidget* _public); - - /** - * Adds dock widget to container and returns the dock area that contains - * the inserted dock widget - */ - CDockAreaWidget* dockWidgetIntoContainer(DockWidgetArea area, CDockWidget* Dockwidget); - - /** - * Adds dock widget to a existing DockWidgetArea - */ - CDockAreaWidget* dockWidgetIntoDockArea(DockWidgetArea area, CDockWidget* Dockwidget, - CDockAreaWidget* TargetDockArea); - - /** - * Add dock area to this container - */ - void addDockArea(CDockAreaWidget* NewDockWidget, DockWidgetArea area = CenterDockWidgetArea); - - /** - * Drop floating widget into container - */ - void dropIntoContainer(CFloatingDockContainer* FloatingWidget, DockWidgetArea area); - - /** - * Drop floating widget into dock area - */ - void dropIntoSection(CFloatingDockContainer* FloatingWidget, - CDockAreaWidget* TargetArea, DockWidgetArea area); - - /** - * Adds new dock areas to the internal dock area list - */ - void addDockAreasToList(const QList NewDockAreas); -}; // struct DockContainerWidgetPrivate - - -//============================================================================ -DockContainerWidgetPrivate::DockContainerWidgetPrivate(CDockContainerWidget* _public) : - _this(_public) -{ - -} - - -//============================================================================ -void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* FloatingWidget, - DockWidgetArea area) -{ - auto InsertParam = internal::dockAreaInsertParameters(area); - auto NewDockAreas = FloatingWidget->dockContainer()->findChildren( - QString(), Qt::FindChildrenRecursively); - QSplitter* OldSplitter = nullptr; - - // If the container already contains dock areas, then we need to ensure that - // we have a splitter with an orientation that matches the orientation of - // the current drop action - if (!DockAreas.isEmpty()) - { - OldSplitter = _this->findChild(QString(), Qt::FindDirectChildrenOnly); - // First replace the dock widget with a splitter - if (DockAreas.count() == 1) - { - auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); - QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); - Layout->replaceWidget(DockArea, NewSplitter); - NewSplitter->addWidget(DockArea); - OldSplitter = NewSplitter; - } - else if (OldSplitter->orientation() != InsertParam.orientation()) - { - QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); - QLayoutItem* li = Layout->replaceWidget(OldSplitter, NewSplitter); - NewSplitter->addWidget(OldSplitter); - OldSplitter = NewSplitter; - } - } - - // Now we can insert the floating widget content into this container - auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); - auto FloatingSplitter = dynamic_cast(Widget); - if (DockAreas.isEmpty()) - { - auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); - Layout->addWidget(Widget, 0, 0); - } - else if (!FloatingSplitter) - { - insertWidgetIntoSplitter(OldSplitter, Widget, InsertParam.append()); - } - else if (FloatingSplitter->orientation() == InsertParam.orientation()) - { - while (FloatingSplitter->count()) - { - insertWidgetIntoSplitter(OldSplitter, FloatingSplitter->widget(0), InsertParam.append()); - } - } - else - { - insertWidgetIntoSplitter(OldSplitter, FloatingSplitter, InsertParam.append()); - } - - addDockAreasToList(NewDockAreas); - FloatingWidget->deleteLater(); -} - - -//============================================================================ -void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* FloatingWidget, - CDockAreaWidget* TargetArea, DockWidgetArea area) -{ - CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer(); - if (area == CenterDockWidgetArea) - { - auto NewDockWidgets = FloatingContainer->findChildren( - QString(), Qt::FindChildrenRecursively); - for (auto DockWidget : NewDockWidgets) - { - TargetArea->insertDockWidget(0, DockWidget, false); - } - TargetArea->setCurrentIndex(0); // make the topmost widget active - FloatingWidget->deleteLater(); - TargetArea->updateDockArea(); - return; - } - - auto InsertParam = internal::dockAreaInsertParameters(area); - auto NewDockAreas = FloatingWidget->dockContainer()->findChildren( - QString(), Qt::FindChildrenRecursively); - QSplitter* TargetAreaSplitter = internal::findParent(TargetArea); - - if (!TargetAreaSplitter) - { - QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); - Layout->replaceWidget(TargetArea, Splitter); - Splitter->addWidget(TargetArea); - TargetAreaSplitter = Splitter; - } - - int AreaIndex = TargetAreaSplitter->indexOf(TargetArea); - auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); - auto FloatingSplitter = dynamic_cast(Widget); - - if (TargetAreaSplitter->orientation() == InsertParam.orientation()) - { - if (!FloatingSplitter || FloatingSplitter->orientation() != InsertParam.orientation()) - { - TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget); - } - else - { - int InsertIndex = AreaIndex + InsertParam.insertOffset(); - while (FloatingSplitter->count()) - { - TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0)); - } - } - } - else - { - QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); - if (!FloatingSplitter || FloatingSplitter->orientation() != InsertParam.orientation()) - { - NewSplitter->addWidget(Widget); - } - else - { - while (FloatingSplitter->count()) - { - NewSplitter->addWidget(FloatingSplitter->widget(0)); - } - } - - insertWidgetIntoSplitter(NewSplitter, TargetArea, !InsertParam.append()); - TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter); - } - - FloatingWidget->deleteLater(); - addDockAreasToList(NewDockAreas); -} - - -//============================================================================ -void DockContainerWidgetPrivate::addDockAreasToList(const QList NewDockAreas) -{ - int CountBefore = DockAreas.count(); - int NewAreaCount = NewDockAreas.count(); - DockAreas.append(NewDockAreas); - - // We need to ensure, that the dock area title bar is visible. The title bar - // is invisible, if the dock are is a single dock area in a floating widget. - if (1 == CountBefore) - { - DockAreas.at(0)->updateDockArea(); - } - - if (1 == NewAreaCount) - { - DockAreas.last()->updateDockArea(); - } - - emit _this->dockAreasAdded(); -} - - -//============================================================================ -CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetArea area, - CDockWidget* Dockwidget) -{ - CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); - NewDockArea->addDockWidget(Dockwidget); - addDockArea(NewDockArea, area); - return NewDockArea; -} - - -//============================================================================ -void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockWidgetArea area) -{ - auto InsertParam = internal::dockAreaInsertParameters(area); - if (DockAreas.isEmpty()) - { - Layout->addWidget(NewDockArea, 0, 0); - } - else if (DockAreas.count() == 1) - { - QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); - auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); - Layout->replaceWidget(DockArea, Splitter); - Splitter->addWidget(DockArea); - insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); - } - else - { - QSplitter* Splitter = _this->findChild(QString(), Qt::FindDirectChildrenOnly); - if (Splitter->orientation() == InsertParam.orientation()) - { - insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); - } - else - { - QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); - if (InsertParam.append()) - { - QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter); - NewSplitter->addWidget(Splitter); - NewSplitter->addWidget(NewDockArea); - delete li; - } - else - { - NewSplitter->addWidget(NewDockArea); - QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter); - NewSplitter->addWidget(Splitter); - delete li; - } - } - } - - DockAreas.append(NewDockArea); - NewDockArea->updateDockArea(); - emit _this->dockAreasAdded(); -} - - -//============================================================================ -CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetArea area, - CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea) -{ - if (CenterDockWidgetArea == area) - { - TargetDockArea->addDockWidget(Dockwidget); - return TargetDockArea; - } - - CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); - NewDockArea->addDockWidget(Dockwidget); - auto InsertParam = internal::dockAreaInsertParameters(area); - if (DockAreas.count() == 1) - { - QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); - auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); - Layout->replaceWidget(DockArea, Splitter); - Splitter->addWidget(DockArea); - insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); - } - else - { - QSplitter* TargetAreaSplitter = internal::findParent(TargetDockArea); - int index = TargetAreaSplitter ->indexOf(TargetDockArea); - if (TargetAreaSplitter->orientation() == InsertParam.orientation()) - { - std::cout << "TargetAreaSplitter->orientation() == InsertParam.orientation()" << std::endl; - TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea); - } - else - { - std::cout << "TargetAreaSplitter->orientation() != InsertParam.orientation()" << std::endl; - QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); - NewSplitter->addWidget(TargetDockArea); - insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append()); - TargetAreaSplitter->insertWidget(index, NewSplitter); - } - } - - DockAreas.append(NewDockArea); - emit _this->dockAreasAdded(); - return NewDockArea; -} - - -//============================================================================ -CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *parent) : - QFrame(parent), - d(new DockContainerWidgetPrivate(this)) -{ - d->isFloating = dynamic_cast(parent) != 0; - - //setStyleSheet("background: green;"); - d->DockManager = DockManager; - if (DockManager != this) - { - d->DockManager->registerDockContainer(this); - } - - d->Layout = new QGridLayout(); - d->Layout->setContentsMargins(0, 1, 0, 1); - d->Layout->setSpacing(0); - setLayout(d->Layout); -} - -//============================================================================ -CDockContainerWidget::~CDockContainerWidget() -{ - if (d->DockManager) - { - d->DockManager->removeDockContainer(this); - } - delete d; -} - - -//============================================================================ -CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, - CDockAreaWidget* DockAreaWidget) -{ - CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget(); - if (OldDockArea) - { - OldDockArea->removeDockWidget(Dockwidget); - } - - Dockwidget->setDockManager(d->DockManager); - if (DockAreaWidget) - { - return d->dockWidgetIntoDockArea(area, Dockwidget, DockAreaWidget); - } - else - { - return d->dockWidgetIntoContainer(area, Dockwidget); - } -} - - -//============================================================================ -unsigned int CDockContainerWidget::zOrderIndex() const -{ - return d->zOrderIndex; -} - - -//============================================================================ -bool CDockContainerWidget::isInFrontOf(CDockContainerWidget* Other) const -{ - return this->zOrderIndex() > Other->zOrderIndex(); -} - - -//============================================================================ -bool CDockContainerWidget::event(QEvent *e) -{ - bool Result = QWidget::event(e); - if (e->type() == QEvent::WindowActivate) - { - d->zOrderIndex = ++zOrderCounter; - } - else if (e->type() == QEvent::Show && !d->zOrderIndex) - { - d->zOrderIndex = ++zOrderCounter; - } - - return Result; -} - - -//============================================================================ -void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget, - DockWidgetArea area) -{ - CDockContainerWidget* Container = DockAreaWidget->dockContainer(); - if (Container && Container != this) - { - Container->removeDockArea(DockAreaWidget); - } - - d->addDockArea(DockAreaWidget); -} - - -//============================================================================ -void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) -{ - std::cout << "CDockContainerWidget::removeDockArea" << std::endl; - d->DockAreas.removeAll(area); - QSplitter* Splitter = internal::findParent(area); - area->setParent(0); - if (!(Splitter && Splitter->count() == 1)) - { - emit dockAreasRemoved(); - return; - } - - // It the splitter contains only one single widget, then we do not need - // it anymore and can replace it with its content - std::cout << "Replacing splitter with content" << std::endl; - QWidget* widget = Splitter->widget(0); - widget->setParent(this); - QSplitter* ParentSplitter = internal::findParent(Splitter); - if (ParentSplitter) - { - internal::replaceSplitterWidget(ParentSplitter, Splitter, widget); - } - else - { - d->Layout->replaceWidget(Splitter, widget); - } - delete Splitter; - emit dockAreasRemoved(); -} - - -//============================================================================ -CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const -{ - for (const auto& DockArea : d->DockAreas) - { - if (DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos))) - { - return DockArea; - } - } - - return 0; -} - - -//============================================================================ -CDockAreaWidget* CDockContainerWidget::dockArea(int Index) const -{ - return (Index < dockAreaCount()) ? d->DockAreas[Index] : 0; -} - - -//============================================================================ -bool CDockContainerWidget::isFloating() const -{ - return d->isFloating; -} - - -//============================================================================ -int CDockContainerWidget::dockAreaCount() const -{ - return d->DockAreas.count(); -} - - -//============================================================================ -void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWidget, - const QPoint& TargetPos) -{ - std::cout << "CDockContainerWidget::dropFloatingWidget" << std::endl; - CDockAreaWidget* DockArea = dockAreaAt(TargetPos); - auto dropArea = InvalidDockWidgetArea; - if (DockArea) - { - auto dropOverlay = d->DockManager->dockAreaOverlay(); - dropOverlay->setAllowedAreas(AllDockAreas); - dropArea = dropOverlay->showOverlay(DockArea); - if (dropArea != InvalidDockWidgetArea) - { - std::cout << "Dock Area Drop Content: " << dropArea << std::endl; - d->dropIntoSection(FloatingWidget, DockArea, dropArea); - } - } - - // mouse is over container - if (InvalidDockWidgetArea == dropArea) - { - dropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); - std::cout << "Container Drop Content: " << dropArea << std::endl; - if (dropArea != InvalidDockWidgetArea) - { - d->dropIntoContainer(FloatingWidget, dropArea); - } - } -} - - -} // namespace ads - -//--------------------------------------------------------------------------- -// EOF DockContainerWidget.cpp +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockContainerWidget.cpp +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Implementation of CDockContainerWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockContainerWidget.h" + +#include +#include +#include +#include +#include + +#include "DockManager.h" +#include "DockAreaWidget.h" +#include "DockWidget.h" +#include "FloatingDockContainer.h" +#include "DockOverlay.h" +#include "ads_globals.h" + +#include + +namespace ads +{ +static unsigned int zOrderCounter = 0; + +/** + * Helper function to ease insertion of dock area into splitter + */ +static void insertWidgetIntoSplitter(QSplitter* Splitter, QWidget* widget, bool Append) +{ + if (Append) + { + Splitter->addWidget(widget); + } + else + { + Splitter->insertWidget(0, widget); + } +} + +/** + * Private data class of CDockContainerWidget class (pimpl) + */ +struct DockContainerWidgetPrivate +{ + CDockContainerWidget* _this; + QPointer DockManager; + unsigned int zOrderIndex = 0; + QList DockAreas; + QGridLayout* Layout = nullptr; + bool isFloating = false; + + /** + * Private data constructor + */ + DockContainerWidgetPrivate(CDockContainerWidget* _public); + + /** + * Adds dock widget to container and returns the dock area that contains + * the inserted dock widget + */ + CDockAreaWidget* dockWidgetIntoContainer(DockWidgetArea area, CDockWidget* Dockwidget); + + /** + * Adds dock widget to a existing DockWidgetArea + */ + CDockAreaWidget* dockWidgetIntoDockArea(DockWidgetArea area, CDockWidget* Dockwidget, + CDockAreaWidget* TargetDockArea); + + /** + * Add dock area to this container + */ + void addDockArea(CDockAreaWidget* NewDockWidget, DockWidgetArea area = CenterDockWidgetArea); + + /** + * Drop floating widget into container + */ + void dropIntoContainer(CFloatingDockContainer* FloatingWidget, DockWidgetArea area); + + /** + * Drop floating widget into dock area + */ + void dropIntoSection(CFloatingDockContainer* FloatingWidget, + CDockAreaWidget* TargetArea, DockWidgetArea area); + + /** + * Adds new dock areas to the internal dock area list + */ + void addDockAreasToList(const QList NewDockAreas); +}; // struct DockContainerWidgetPrivate + + +//============================================================================ +DockContainerWidgetPrivate::DockContainerWidgetPrivate(CDockContainerWidget* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockContainerWidgetPrivate::dropIntoContainer(CFloatingDockContainer* FloatingWidget, + DockWidgetArea area) +{ + auto InsertParam = internal::dockAreaInsertParameters(area); + auto NewDockAreas = FloatingWidget->dockContainer()->findChildren( + QString(), Qt::FindChildrenRecursively); + QSplitter* OldSplitter = nullptr; + + // If the container already contains dock areas, then we need to ensure that + // we have a splitter with an orientation that matches the orientation of + // the current drop action + if (!DockAreas.isEmpty()) + { + OldSplitter = _this->findChild(QString(), Qt::FindDirectChildrenOnly); + // First replace the dock widget with a splitter + if (DockAreas.count() == 1) + { + auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); + QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); + Layout->replaceWidget(DockArea, NewSplitter); + NewSplitter->addWidget(DockArea); + OldSplitter = NewSplitter; + } + else if (OldSplitter->orientation() != InsertParam.orientation()) + { + QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); + QLayoutItem* li = Layout->replaceWidget(OldSplitter, NewSplitter); + NewSplitter->addWidget(OldSplitter); + OldSplitter = NewSplitter; + } + } + + // Now we can insert the floating widget content into this container + auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); + auto FloatingSplitter = dynamic_cast(Widget); + if (DockAreas.isEmpty()) + { + auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); + Layout->addWidget(Widget, 0, 0); + } + else if (!FloatingSplitter) + { + insertWidgetIntoSplitter(OldSplitter, Widget, InsertParam.append()); + } + else if (FloatingSplitter->orientation() == InsertParam.orientation()) + { + while (FloatingSplitter->count()) + { + insertWidgetIntoSplitter(OldSplitter, FloatingSplitter->widget(0), InsertParam.append()); + } + } + else + { + insertWidgetIntoSplitter(OldSplitter, FloatingSplitter, InsertParam.append()); + } + + addDockAreasToList(NewDockAreas); + FloatingWidget->deleteLater(); +} + + +//============================================================================ +void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* FloatingWidget, + CDockAreaWidget* TargetArea, DockWidgetArea area) +{ + CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer(); + if (area == CenterDockWidgetArea) + { + auto NewDockWidgets = FloatingContainer->findChildren( + QString(), Qt::FindChildrenRecursively); + for (auto DockWidget : NewDockWidgets) + { + TargetArea->insertDockWidget(0, DockWidget, false); + } + TargetArea->setCurrentIndex(0); // make the topmost widget active + FloatingWidget->deleteLater(); + TargetArea->updateDockArea(); + return; + } + + auto InsertParam = internal::dockAreaInsertParameters(area); + auto NewDockAreas = FloatingWidget->dockContainer()->findChildren( + QString(), Qt::FindChildrenRecursively); + QSplitter* TargetAreaSplitter = internal::findParent(TargetArea); + + if (!TargetAreaSplitter) + { + QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); + Layout->replaceWidget(TargetArea, Splitter); + Splitter->addWidget(TargetArea); + TargetAreaSplitter = Splitter; + } + + int AreaIndex = TargetAreaSplitter->indexOf(TargetArea); + auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); + auto FloatingSplitter = dynamic_cast(Widget); + + if (TargetAreaSplitter->orientation() == InsertParam.orientation()) + { + if (!FloatingSplitter || FloatingSplitter->orientation() != InsertParam.orientation()) + { + TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget); + } + else + { + int InsertIndex = AreaIndex + InsertParam.insertOffset(); + while (FloatingSplitter->count()) + { + TargetAreaSplitter->insertWidget(InsertIndex++, FloatingSplitter->widget(0)); + } + } + } + else + { + QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); + if (!FloatingSplitter || FloatingSplitter->orientation() != InsertParam.orientation()) + { + NewSplitter->addWidget(Widget); + } + else + { + while (FloatingSplitter->count()) + { + NewSplitter->addWidget(FloatingSplitter->widget(0)); + } + } + + insertWidgetIntoSplitter(NewSplitter, TargetArea, !InsertParam.append()); + TargetAreaSplitter->insertWidget(AreaIndex, NewSplitter); + } + + FloatingWidget->deleteLater(); + addDockAreasToList(NewDockAreas); +} + + +//============================================================================ +void DockContainerWidgetPrivate::addDockAreasToList(const QList NewDockAreas) +{ + int CountBefore = DockAreas.count(); + int NewAreaCount = NewDockAreas.count(); + DockAreas.append(NewDockAreas); + + // We need to ensure, that the dock area title bar is visible. The title bar + // is invisible, if the dock are is a single dock area in a floating widget. + if (1 == CountBefore) + { + DockAreas.at(0)->updateDockArea(); + } + + if (1 == NewAreaCount) + { + DockAreas.last()->updateDockArea(); + } + + emit _this->dockAreasAdded(); +} + + +//============================================================================ +CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetArea area, + CDockWidget* Dockwidget) +{ + CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); + NewDockArea->addDockWidget(Dockwidget); + addDockArea(NewDockArea, area); + return NewDockArea; +} + + +//============================================================================ +void DockContainerWidgetPrivate::addDockArea(CDockAreaWidget* NewDockArea, DockWidgetArea area) +{ + auto InsertParam = internal::dockAreaInsertParameters(area); + if (DockAreas.isEmpty()) + { + Layout->addWidget(NewDockArea, 0, 0); + } + else if (DockAreas.count() == 1) + { + QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); + auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); + Layout->replaceWidget(DockArea, Splitter); + Splitter->addWidget(DockArea); + insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); + } + else + { + QSplitter* Splitter = _this->findChild(QString(), Qt::FindDirectChildrenOnly); + if (Splitter->orientation() == InsertParam.orientation()) + { + insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); + } + else + { + QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); + if (InsertParam.append()) + { + QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter); + NewSplitter->addWidget(Splitter); + NewSplitter->addWidget(NewDockArea); + delete li; + } + else + { + NewSplitter->addWidget(NewDockArea); + QLayoutItem* li = Layout->replaceWidget(Splitter, NewSplitter); + NewSplitter->addWidget(Splitter); + delete li; + } + } + } + + DockAreas.append(NewDockArea); + NewDockArea->updateDockArea(); + emit _this->dockAreasAdded(); +} + + +//============================================================================ +CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetArea area, + CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea) +{ + if (CenterDockWidgetArea == area) + { + TargetDockArea->addDockWidget(Dockwidget); + return TargetDockArea; + } + + CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); + NewDockArea->addDockWidget(Dockwidget); + auto InsertParam = internal::dockAreaInsertParameters(area); + if (DockAreas.count() == 1) + { + QSplitter* Splitter = internal::newSplitter(InsertParam.orientation()); + auto DockArea = dynamic_cast(Layout->itemAtPosition(0, 0)->widget()); + Layout->replaceWidget(DockArea, Splitter); + Splitter->addWidget(DockArea); + insertWidgetIntoSplitter(Splitter, NewDockArea, InsertParam.append()); + } + else + { + QSplitter* TargetAreaSplitter = internal::findParent(TargetDockArea); + int index = TargetAreaSplitter ->indexOf(TargetDockArea); + if (TargetAreaSplitter->orientation() == InsertParam.orientation()) + { + std::cout << "TargetAreaSplitter->orientation() == InsertParam.orientation()" << std::endl; + TargetAreaSplitter->insertWidget(index + InsertParam.insertOffset(), NewDockArea); + } + else + { + std::cout << "TargetAreaSplitter->orientation() != InsertParam.orientation()" << std::endl; + QSplitter* NewSplitter = internal::newSplitter(InsertParam.orientation()); + NewSplitter->addWidget(TargetDockArea); + insertWidgetIntoSplitter(NewSplitter, NewDockArea, InsertParam.append()); + TargetAreaSplitter->insertWidget(index, NewSplitter); + } + } + + DockAreas.append(NewDockArea); + emit _this->dockAreasAdded(); + return NewDockArea; +} + + +//============================================================================ +CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *parent) : + QFrame(parent), + d(new DockContainerWidgetPrivate(this)) +{ + d->isFloating = dynamic_cast(parent) != 0; + + //setStyleSheet("background: green;"); + d->DockManager = DockManager; + if (DockManager != this) + { + d->DockManager->registerDockContainer(this); + } + + d->Layout = new QGridLayout(); + d->Layout->setContentsMargins(0, 1, 0, 1); + d->Layout->setSpacing(0); + setLayout(d->Layout); +} + +//============================================================================ +CDockContainerWidget::~CDockContainerWidget() +{ + if (d->DockManager) + { + d->DockManager->removeDockContainer(this); + } + delete d; +} + + +//============================================================================ +CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, + CDockAreaWidget* DockAreaWidget) +{ + CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget(); + if (OldDockArea) + { + OldDockArea->removeDockWidget(Dockwidget); + } + + Dockwidget->setDockManager(d->DockManager); + if (DockAreaWidget) + { + return d->dockWidgetIntoDockArea(area, Dockwidget, DockAreaWidget); + } + else + { + return d->dockWidgetIntoContainer(area, Dockwidget); + } +} + + +//============================================================================ +unsigned int CDockContainerWidget::zOrderIndex() const +{ + return d->zOrderIndex; +} + + +//============================================================================ +bool CDockContainerWidget::isInFrontOf(CDockContainerWidget* Other) const +{ + return this->zOrderIndex() > Other->zOrderIndex(); +} + + +//============================================================================ +bool CDockContainerWidget::event(QEvent *e) +{ + bool Result = QWidget::event(e); + if (e->type() == QEvent::WindowActivate) + { + d->zOrderIndex = ++zOrderCounter; + } + else if (e->type() == QEvent::Show && !d->zOrderIndex) + { + d->zOrderIndex = ++zOrderCounter; + } + + return Result; +} + + +//============================================================================ +void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget, + DockWidgetArea area) +{ + CDockContainerWidget* Container = DockAreaWidget->dockContainer(); + if (Container && Container != this) + { + Container->removeDockArea(DockAreaWidget); + } + + d->addDockArea(DockAreaWidget); +} + + +//============================================================================ +void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) +{ + std::cout << "CDockContainerWidget::removeDockArea" << std::endl; + d->DockAreas.removeAll(area); + QSplitter* Splitter = internal::findParent(area); + area->setParent(0); + if (!(Splitter && Splitter->count() == 1)) + { + emit dockAreasRemoved(); + return; + } + + // It the splitter contains only one single widget, then we do not need + // it anymore and can replace it with its content + std::cout << "Replacing splitter with content" << std::endl; + QWidget* widget = Splitter->widget(0); + widget->setParent(this); + QSplitter* ParentSplitter = internal::findParent(Splitter); + if (ParentSplitter) + { + internal::replaceSplitterWidget(ParentSplitter, Splitter, widget); + } + else + { + d->Layout->replaceWidget(Splitter, widget); + } + delete Splitter; + emit dockAreasRemoved(); +} + + +//============================================================================ +CDockAreaWidget* CDockContainerWidget::dockAreaAt(const QPoint& GlobalPos) const +{ + for (const auto& DockArea : d->DockAreas) + { + if (DockArea->rect().contains(DockArea->mapFromGlobal(GlobalPos))) + { + return DockArea; + } + } + + return 0; +} + + +//============================================================================ +CDockAreaWidget* CDockContainerWidget::dockArea(int Index) const +{ + return (Index < dockAreaCount()) ? d->DockAreas[Index] : 0; +} + + +//============================================================================ +bool CDockContainerWidget::isFloating() const +{ + return d->isFloating; +} + + +//============================================================================ +int CDockContainerWidget::dockAreaCount() const +{ + return d->DockAreas.count(); +} + + +//============================================================================ +void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWidget, + const QPoint& TargetPos) +{ + std::cout << "CDockContainerWidget::dropFloatingWidget" << std::endl; + CDockAreaWidget* DockArea = dockAreaAt(TargetPos); + auto dropArea = InvalidDockWidgetArea; + if (DockArea) + { + auto dropOverlay = d->DockManager->dockAreaOverlay(); + dropOverlay->setAllowedAreas(AllDockAreas); + dropArea = dropOverlay->showOverlay(DockArea); + if (dropArea != InvalidDockWidgetArea) + { + std::cout << "Dock Area Drop Content: " << dropArea << std::endl; + d->dropIntoSection(FloatingWidget, DockArea, dropArea); + } + } + + // mouse is over container + if (InvalidDockWidgetArea == dropArea) + { + dropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); + std::cout << "Container Drop Content: " << dropArea << std::endl; + if (dropArea != InvalidDockWidgetArea) + { + d->dropIntoContainer(FloatingWidget, dropArea); + } + } +} + + +//============================================================================ +QList CDockContainerWidget::openedDockAreas() const +{ + QList Result; + for (auto DockArea : d->DockAreas) + { + if (DockArea->isVisible()) + { + Result.append(DockArea); + } + } + + return Result; +} + + +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockContainerWidget.cpp diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 1f93dfe..7688111 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -1,146 +1,152 @@ -#ifndef DockContainerWidgetH -#define DockContainerWidgetH -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockContainerWidget.h -/// \author Uwe Kindler -/// \date 24.02.2017 -/// \brief Declaration of CDockContainerWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include - -#include "ads_globals.h" - -namespace ads -{ -struct DockContainerWidgetPrivate; -class CDockAreaWidget; -class CDockWidget; -class CDockManager; -class CFloatingDockContainer; - -/** - * Container that manages a number of dock areas with single dock widgets - * or tabyfied dock widgets in each area - */ -class CDockContainerWidget : public QFrame -{ - Q_OBJECT -private: - DockContainerWidgetPrivate* d; ///< private data (pimpl) - friend class DockContainerWidgetPrivate; - -protected: - /** - * Handles activation events to update zOrderIndex - */ - virtual bool event(QEvent *e) override; - -public: - /** - * Default Constructor - */ - CDockContainerWidget(CDockManager* DockManager, QWidget* parent = 0); - - /** - * Virtual Destructor - */ - virtual ~CDockContainerWidget(); - - /** - * Drop floating widget into the container - */ - void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos); - - /** - * Adds dockwidget into the given area. - * If DockAreaWidget is not null, then the area parameter indicates the area - * into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will - * be dropped into the container. - * \return Returns the dock area widget that contains the new DockWidget - */ - CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, - CDockAreaWidget* DockAreaWidget = nullptr); - - /** - * Adds the given dock area to this container widget - */ - void addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area = CenterDockWidgetArea); - - /** - * Removes the given dock area from this container - */ - void removeDockArea(CDockAreaWidget* area); - - /** - * Returns the current zOrderIndex - */ - virtual unsigned int zOrderIndex() const; - - /** - * This function returns true if this container widgets z order index is - * higher than the index of the container widget given in Other parameter - */ - bool isInFrontOf(CDockContainerWidget* Other) const; - - /** - * Returns the dock area at teh given global position or 0 if there is no - * dock area at this position - */ - CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const; - - /** - * Returns the dock area at the given Index or 0 if the index is out of - * range - */ - CDockAreaWidget* dockArea(int Index) const; - - /** - * Returns the number of dock areas in this container - */ - int dockAreaCount() const; - - /** - * This function returns true, if this container is in a floating widget - */ - bool isFloating() const; - -signals: - /** - * This signal is emitted if one or multiple dock areas has been added to - * the internal list of dock areas. - * If multiple dock areas are inserted, this signal is emitted only once - */ - void dockAreasAdded(); - - /** - * This signal is emitted if one or multiple dock areas has been removed - */ - void dockAreasRemoved(); -}; // class DockContainerWidget -} // namespace ads -//----------------------------------------------------------------------------- -#endif // DockContainerWidgetH +#ifndef DockContainerWidgetH +#define DockContainerWidgetH +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockContainerWidget.h +/// \author Uwe Kindler +/// \date 24.02.2017 +/// \brief Declaration of CDockContainerWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +#include "ads_globals.h" + +namespace ads +{ +struct DockContainerWidgetPrivate; +class CDockAreaWidget; +class CDockWidget; +class CDockManager; +class CFloatingDockContainer; + +/** + * Container that manages a number of dock areas with single dock widgets + * or tabyfied dock widgets in each area + */ +class CDockContainerWidget : public QFrame +{ + Q_OBJECT +private: + DockContainerWidgetPrivate* d; ///< private data (pimpl) + friend class DockContainerWidgetPrivate; + +protected: + /** + * Handles activation events to update zOrderIndex + */ + virtual bool event(QEvent *e) override; + +public: + /** + * Default Constructor + */ + CDockContainerWidget(CDockManager* DockManager, QWidget* parent = 0); + + /** + * Virtual Destructor + */ + virtual ~CDockContainerWidget(); + + /** + * Drop floating widget into the container + */ + void dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos); + + /** + * Adds dockwidget into the given area. + * If DockAreaWidget is not null, then the area parameter indicates the area + * into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will + * be dropped into the container. + * \return Returns the dock area widget that contains the new DockWidget + */ + CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, + CDockAreaWidget* DockAreaWidget = nullptr); + + /** + * Adds the given dock area to this container widget + */ + void addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area = CenterDockWidgetArea); + + /** + * Removes the given dock area from this container + */ + void removeDockArea(CDockAreaWidget* area); + + /** + * Returns the current zOrderIndex + */ + virtual unsigned int zOrderIndex() const; + + /** + * This function returns true if this container widgets z order index is + * higher than the index of the container widget given in Other parameter + */ + bool isInFrontOf(CDockContainerWidget* Other) const; + + /** + * Returns the dock area at teh given global position or 0 if there is no + * dock area at this position + */ + CDockAreaWidget* dockAreaAt(const QPoint& GlobalPos) const; + + /** + * Returns the dock area at the given Index or 0 if the index is out of + * range + */ + CDockAreaWidget* dockArea(int Index) const; + + /** + * Returns the list of dock areas that are not closed + * If all dock widgets in a dock area are closed, the dock area will be closed + */ + QList openedDockAreas() const; + + /** + * Returns the number of dock areas in this container + */ + int dockAreaCount() const; + + /** + * This function returns true, if this container is in a floating widget + */ + bool isFloating() const; + +signals: + /** + * This signal is emitted if one or multiple dock areas has been added to + * the internal list of dock areas. + * If multiple dock areas are inserted, this signal is emitted only once + */ + void dockAreasAdded(); + + /** + * This signal is emitted if one or multiple dock areas has been removed + */ + void dockAreasRemoved(); +}; // class DockContainerWidget +} // namespace ads +//----------------------------------------------------------------------------- +#endif // DockContainerWidgetH diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index d15e5d5..4dcb2e3 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1,358 +1,404 @@ -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockWidget.cpp -/// \author Uwe Kindler -/// \date 26.02.2017 -/// \brief Implementation of CDockWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include "DockWidget.h" - -#include -#include -#include -#include -#include -#include - -#include - -#include "DockWidgetTitleBar.h" -#include "DockContainerWidget.h" -#include "DockAreaWidget.h" -#include "DockManager.h" -#include "FloatingDockContainer.h" - -#include "ads_globals.h" - -namespace ads -{ -/** - * Private data class of CDockWidget class (pimpl) - */ -struct DockWidgetPrivate -{ - CDockWidget* _this; - QBoxLayout* Layout; - QWidget* Widget = nullptr; - CDockWidgetTitleBar* TitleWidget; - CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures; - CDockManager* DockManager = nullptr; - CDockAreaWidget* DockArea = nullptr; - QAction* ToggleViewAction; - bool Closed = false; - struct CapturedState - { - QString DockTreePosition; - QRect GlobalGeometry; - QPointer DockContainer; - } CapturedState; - - /** - * Private data constructor - */ - DockWidgetPrivate(CDockWidget* _public); - - /** - * Saves the current state into CapturedState variable - */ - void capturedState(); - - /** - * Show dock widget - */ - void showDockWidget(); - - /** - * Hides a parent splitter if all dock widgets in the splitter are closed - */ - void hideEmptyParentSplitter(); - - /** - * Hides a dock area if all dock widgets in the area are closed - */ - void hideEmptyParentDockArea(); -}; -// struct DockWidgetPrivate - -//============================================================================ -DockWidgetPrivate::DockWidgetPrivate(CDockWidget* _public) : - _this(_public) -{ - -} - - -//============================================================================ -void DockWidgetPrivate::capturedState() -{ - QString DockTreePosition; - QTextStream stream(&DockTreePosition); - - QPoint GlobalTopLeft = _this->mapToGlobal(_this->geometry().topLeft()); - QRect Rect(GlobalTopLeft, _this->geometry().size()); - CapturedState.GlobalGeometry = Rect; - CapturedState.DockContainer = _this->dockContainer(); - - QWidget* Widget = DockArea; - QSplitter* splitter = internal::findParent(Widget); - QStack SplitterData; - while (splitter) - { - SplitterData.push(QString("%1%2") - .arg((splitter->orientation() == Qt::Horizontal) ? "H" : "V") - .arg(splitter->indexOf(Widget))); - Widget = splitter; - splitter = internal::findParent(Widget); - } - - QString Separator; - while (!SplitterData.isEmpty()) - { - stream << Separator << SplitterData.pop(); - Separator = " "; - } - this->CapturedState.DockTreePosition = DockTreePosition; - std::cout << "SerializedPosition: " << DockTreePosition.toStdString() << std::endl; -} - - -//============================================================================ -void DockWidgetPrivate::showDockWidget() -{ - DockArea->show(); - DockArea->setCurrentIndex(DockArea->tabIndex(_this)); - QSplitter* Splitter = internal::findParent(_this); - if (Splitter) - { - Splitter->show(); - } -} - - -//============================================================================ -void DockWidgetPrivate::hideEmptyParentSplitter() -{ - QSplitter* Splitter = internal::findParent(_this); - if (!Splitter) - { - return; - } - - for (int i = 0; i < Splitter->count(); ++i) - { - if (Splitter->widget(i)->isVisible()) - { - return; - } - } - - Splitter->hide(); -} - - -//============================================================================ -void DockWidgetPrivate::hideEmptyParentDockArea() -{ - auto OpenDockWidgets = DockArea->openDockWidgets(); - if (OpenDockWidgets.count() > 1) - { - CDockWidget* NextDockWidget; - if (OpenDockWidgets.last() == _this) - { - NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2]; - } - else - { - int NextIndex = OpenDockWidgets.indexOf(_this) + 1; - NextDockWidget = OpenDockWidgets[NextIndex]; - } - - DockArea->setCurrentDockWidget(NextDockWidget); - } - else - { - DockArea->hide(); - } -} - - -//============================================================================ -CDockWidget::CDockWidget(const QString &title, QWidget *parent) : - QFrame(parent), - d(new DockWidgetPrivate(this)) -{ - d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); - d->Layout->setContentsMargins(0, 0, 0, 0); - d->Layout->setSpacing(0); - setLayout(d->Layout); - setWindowTitle(title); - - d->TitleWidget = new CDockWidgetTitleBar(this); - d->ToggleViewAction = new QAction(title); - d->ToggleViewAction->setCheckable(true); - connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this, - SLOT(toggleView(bool))); -} - -//============================================================================ -CDockWidget::~CDockWidget() -{ - std::cout << "~CDockWidget()" << std::endl; - delete d; -} - - -//============================================================================ -void CDockWidget::setWidget(QWidget* widget) -{ - if (d->Widget) - { - d->Layout->replaceWidget(d->Widget, widget); - } - else - { - d->Layout->addWidget(widget); - } - - d->Widget = widget; -} - - -//============================================================================ -QWidget* CDockWidget::widget() const -{ - return d->Widget; -} - - -//============================================================================ -CDockWidgetTitleBar* CDockWidget::titleBar() const -{ - return d->TitleWidget; -} - - -//============================================================================ -void CDockWidget::setFeatures(DockWidgetFeatures features) -{ - d->Features = features; -} - - -//============================================================================ -CDockWidget::DockWidgetFeatures CDockWidget::features() const -{ - return d->Features; -} - - -//============================================================================ -CDockManager* CDockWidget::dockManager() const -{ - return d->DockManager; -} - - -//============================================================================ -void CDockWidget::setDockManager(CDockManager* DockManager) -{ - d->DockManager = DockManager; -} - - -//============================================================================ -CDockContainerWidget* CDockWidget::dockContainer() const -{ - return internal::findParent(this); -} - - -//============================================================================ -CDockAreaWidget* CDockWidget::dockAreaWidget() const -{ - return internal::findParent(this); -} - - -//============================================================================ -bool CDockWidget::isFloating() const -{ - return dockContainer() ? dockContainer()->isFloating() : false; -} - - -//============================================================================ -bool CDockWidget::isClosed() const -{ - return d->Closed; -} - - -//============================================================================ -QAction* CDockWidget::toggleViewAction() const -{ - return d->ToggleViewAction; -} - - -//============================================================================ -void CDockWidget::toggleView(bool Open) -{ - if (Open) - { - d->showDockWidget(); - } - else - { - hideDockWidget(); - } - d->Closed = !Open; -} - - -//============================================================================ -void CDockWidget::setDockArea(CDockAreaWidget* DockArea) -{ - d->DockArea = DockArea; - d->ToggleViewAction->setChecked(DockArea != nullptr); -} - - - -//============================================================================ -void CDockWidget::hideDockWidget() -{ - CDockAreaWidget* DockArea = d->DockArea; - d->ToggleViewAction->setChecked(false); - d->TitleWidget->hide(); - d->hideEmptyParentDockArea(); - d->hideEmptyParentSplitter(); -} - -} // namespace ads - -//--------------------------------------------------------------------------- -// EOF DockWidget.cpp +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockWidget.cpp +/// \author Uwe Kindler +/// \date 26.02.2017 +/// \brief Implementation of CDockWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockWidget.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "DockWidgetTitleBar.h" +#include "DockContainerWidget.h" +#include "DockAreaWidget.h" +#include "DockManager.h" +#include "FloatingDockContainer.h" + +#include "ads_globals.h" + +namespace ads +{ +/** + * Private data class of CDockWidget class (pimpl) + */ +struct DockWidgetPrivate +{ + CDockWidget* _this; + QBoxLayout* Layout; + QWidget* Widget = nullptr; + CDockWidgetTitleBar* TitleWidget; + CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures; + CDockManager* DockManager = nullptr; + CDockAreaWidget* DockArea = nullptr; + QAction* ToggleViewAction; + bool Closed = false; + struct CapturedState + { + QString DockTreePosition; + QRect GlobalGeometry; + QPointer DockContainer; + } CapturedState; + + /** + * Private data constructor + */ + DockWidgetPrivate(CDockWidget* _public); + + /** + * Saves the current state into CapturedState variable + */ + void capturedState(); + + /** + * Show dock widget + */ + void showDockWidget(); + + /** + * Hide dock widget. + */ + void hideDockWidget(); + + /** + * Hides a parent splitter if all dock widgets in the splitter are closed + */ + void hideEmptyParentSplitter(); + + /** + * Hides a dock area if all dock widgets in the area are closed + */ + void hideEmptyParentDockArea(); + + /** + * Hides a floating widget if all dock areas are empty - that means, + * if all dock widgets in all dock areas are closed + */ + void hideEmptyFloatingWidget(); +}; +// struct DockWidgetPrivate + +//============================================================================ +DockWidgetPrivate::DockWidgetPrivate(CDockWidget* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockWidgetPrivate::capturedState() +{ + QString DockTreePosition; + QTextStream stream(&DockTreePosition); + + QPoint GlobalTopLeft = _this->mapToGlobal(_this->geometry().topLeft()); + QRect Rect(GlobalTopLeft, _this->geometry().size()); + CapturedState.GlobalGeometry = Rect; + CapturedState.DockContainer = _this->dockContainer(); + + QWidget* Widget = DockArea; + QSplitter* splitter = internal::findParent(Widget); + QStack SplitterData; + while (splitter) + { + SplitterData.push(QString("%1%2") + .arg((splitter->orientation() == Qt::Horizontal) ? "H" : "V") + .arg(splitter->indexOf(Widget))); + Widget = splitter; + splitter = internal::findParent(Widget); + } + + QString Separator; + while (!SplitterData.isEmpty()) + { + stream << Separator << SplitterData.pop(); + Separator = " "; + } + this->CapturedState.DockTreePosition = DockTreePosition; + std::cout << "SerializedPosition: " << DockTreePosition.toStdString() << std::endl; +} + + +//============================================================================ +void DockWidgetPrivate::showDockWidget() +{ + DockArea->show(); + DockArea->setCurrentIndex(DockArea->tabIndex(_this)); + QSplitter* Splitter = internal::findParent(_this); + if (Splitter) + { + Splitter->show(); + } + + CDockContainerWidget* Container = DockArea->dockContainer(); + if (Container->isFloating()) + { + CFloatingDockContainer* FloatingWidget = internal::findParent< + CFloatingDockContainer*>(Container); + FloatingWidget->show(); + } +} + + +//============================================================================ +void DockWidgetPrivate::hideDockWidget() +{ + ToggleViewAction->setChecked(false); + TitleWidget->hide(); + hideEmptyParentDockArea(); + hideEmptyParentSplitter(); + hideEmptyFloatingWidget(); +} + + +//============================================================================ +void DockWidgetPrivate::hideEmptyParentSplitter() +{ + QSplitter* Splitter = internal::findParent(_this); + if (!Splitter) + { + return; + } + + for (int i = 0; i < Splitter->count(); ++i) + { + if (Splitter->widget(i)->isVisible()) + { + return; + } + } + + Splitter->hide(); +} + + +//============================================================================ +void DockWidgetPrivate::hideEmptyParentDockArea() +{ + auto OpenDockWidgets = DockArea->openedDockWidgets(); + if (OpenDockWidgets.count() > 1) + { + CDockWidget* NextDockWidget; + if (OpenDockWidgets.last() == _this) + { + NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2]; + } + else + { + int NextIndex = OpenDockWidgets.indexOf(_this) + 1; + NextDockWidget = OpenDockWidgets[NextIndex]; + } + + DockArea->setCurrentDockWidget(NextDockWidget); + } + else + { + DockArea->hide(); + } +} + + +//============================================================================ +void DockWidgetPrivate::hideEmptyFloatingWidget() +{ + CDockContainerWidget* Container = _this->dockContainer(); + if (Container->isFloating() && Container->openedDockAreas().isEmpty()) + { + CFloatingDockContainer* FloatingWidget = internal::findParent(Container); + FloatingWidget->hide(); + } +} + + +//============================================================================ +CDockWidget::CDockWidget(const QString &title, QWidget *parent) : + QFrame(parent), + d(new DockWidgetPrivate(this)) +{ + d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); + d->Layout->setContentsMargins(0, 0, 0, 0); + d->Layout->setSpacing(0); + setLayout(d->Layout); + setWindowTitle(title); + + d->TitleWidget = new CDockWidgetTitleBar(this); + d->ToggleViewAction = new QAction(title); + d->ToggleViewAction->setCheckable(true); + connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this, + SLOT(toggleView(bool))); +} + +//============================================================================ +CDockWidget::~CDockWidget() +{ + std::cout << "~CDockWidget()" << std::endl; + delete d; +} + + +//============================================================================ +void CDockWidget::setToggleViewActionChecked(bool Checked) +{ + QAction* Action = d->ToggleViewAction; + Action->blockSignals(true); + Action->setChecked(Checked); + Action->blockSignals(false); +} + + +//============================================================================ +void CDockWidget::setWidget(QWidget* widget) +{ + if (d->Widget) + { + d->Layout->replaceWidget(d->Widget, widget); + } + else + { + d->Layout->addWidget(widget); + } + + d->Widget = widget; +} + + +//============================================================================ +QWidget* CDockWidget::widget() const +{ + return d->Widget; +} + + +//============================================================================ +CDockWidgetTitleBar* CDockWidget::titleBar() const +{ + return d->TitleWidget; +} + + +//============================================================================ +void CDockWidget::setFeatures(DockWidgetFeatures features) +{ + d->Features = features; +} + + +//============================================================================ +CDockWidget::DockWidgetFeatures CDockWidget::features() const +{ + return d->Features; +} + + +//============================================================================ +CDockManager* CDockWidget::dockManager() const +{ + return d->DockManager; +} + + +//============================================================================ +void CDockWidget::setDockManager(CDockManager* DockManager) +{ + d->DockManager = DockManager; +} + + +//============================================================================ +CDockContainerWidget* CDockWidget::dockContainer() const +{ + return internal::findParent(this); +} + + +//============================================================================ +CDockAreaWidget* CDockWidget::dockAreaWidget() const +{ + return internal::findParent(this); +} + + +//============================================================================ +bool CDockWidget::isFloating() const +{ + return dockContainer() ? dockContainer()->isFloating() : false; +} + + +//============================================================================ +bool CDockWidget::isClosed() const +{ + return d->Closed; +} + + +//============================================================================ +QAction* CDockWidget::toggleViewAction() const +{ + return d->ToggleViewAction; +} + + +//============================================================================ +void CDockWidget::toggleView(bool Open) +{ + if (Open) + { + d->showDockWidget(); + } + else + { + d->hideDockWidget(); + } + d->Closed = !Open; + if (!Open) + { + emit closed(); + } + emit viewToggled(Open); +} + + +//============================================================================ +void CDockWidget::setDockArea(CDockAreaWidget* DockArea) +{ + d->DockArea = DockArea; + d->ToggleViewAction->setChecked(DockArea != nullptr); +} + + +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockWidget.cpp diff --git a/src/DockWidget.h b/src/DockWidget.h index 257b456..5911b94 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -1,180 +1,192 @@ -#ifndef DockWidgetH -#define DockWidgetH -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file DockWidget.h -/// \author Uwe Kindler -/// \date 26.02.2017 -/// \brief Declaration of CDockWidget class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include - -namespace ads -{ -struct DockWidgetPrivate; -class CDockWidgetTitleBar; -class CDockManager; -class CDockContainerWidget; -class CDockAreaWidget; - -/** - * The QDockWidget class provides a widget that can be docked inside a - * CDockManager or floated as a top-level window on the desktop. - */ -class CDockWidget : public QFrame -{ - Q_OBJECT -private: - DockWidgetPrivate* d; ///< private data (pimpl) - friend class DockWidgetPrivate; - -protected: - friend class CDockContainerWidget; - friend class CDockAreaWidget; - friend class CFloatingDockContainer; - - /** - * Assigns the dock manager that manages this dock widget - */ - void setDockManager(CDockManager* DockManager); - - /** - * If this dock widget is inserted into a dock area, the dock area will - * be registered on this widget via this function. If a dock widget is - * removed from a dock area, this function will be called with nullptr - * value. - */ - void setDockArea(CDockAreaWidget* DockArea); - - /** - * Hide dock widget. - */ - void hideDockWidget(); - -public: - enum DockWidgetFeature - { - DockWidgetClosable = 0x01, - DockWidgetMovable = 0x02, - DockWidgetFloatable = 0x04, - AllDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable, - NoDockWidgetFeatures = 0x00 - }; - Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature) - - - enum eState - { - StateHidden, - StateDocked, - StateFloating - }; - - /** - * Default Constructor - */ - CDockWidget(const QString &title, QWidget* parent = 0); - - /** - * Virtual Destructor - */ - virtual ~CDockWidget(); - - /** - * Sets the widget for the dock widget to widget. - */ - void setWidget(QWidget* widget); - - /** - * Returns the widget for the dock widget. This function returns zero if - * the widget has not been set. - */ - QWidget* widget() const; - - /** - * Returns the title bar widget of this dock widget - */ - CDockWidgetTitleBar* titleBar() const; - - /** - * Sets, whether the dock widget is movable, closable, and floatable. - */ - void setFeatures(DockWidgetFeatures features); - - /** - * This property holds whether the dock widget is movable, closable, and - * floatable. - * By default, this property is set to a combination of DockWidgetClosable, - * DockWidgetMovable and DockWidgetFloatable. - */ - DockWidgetFeatures features() const; - - /** - * Returns the dock manager that manages the dock widget or 0 if the widget - * has not been assigned to any dock manager yet - */ - CDockManager* dockManager() const; - - /** - * Returns the dock container widget this dock area widget belongs to or 0 - * if this dock widget has nt been docked yet - */ - CDockContainerWidget* dockContainer() const; - - /** - * Returns the dock area widget this dock widget belongs to or 0 - * if this dock widget has not been docked yet - */ - CDockAreaWidget* dockAreaWidget() const; - - /** - * This property holds whether the dock widget is floating. - */ - bool isFloating() const; - - /** - * Returns true, if this dock widget is closed. - */ - bool isClosed() const; - - /** - * Returns a checkable action that can be used to show or close this dock widget. - * The action's text is set to the dock widget's window title. - */ - QAction* toggleViewAction() const; - - -public slots: - /** - * This property controls whether the dock widget is open or closed. - * The toogleViewAction triggers this slot - */ - void toggleView(bool Open); -}; // class DockWidget -} - // namespace ads -//----------------------------------------------------------------------------- -#endif // DockWidgetH +#ifndef DockWidgetH +#define DockWidgetH +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file DockWidget.h +/// \author Uwe Kindler +/// \date 26.02.2017 +/// \brief Declaration of CDockWidget class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ +struct DockWidgetPrivate; +class CDockWidgetTitleBar; +class CDockManager; +class CDockContainerWidget; +class CDockAreaWidget; + +/** + * The QDockWidget class provides a widget that can be docked inside a + * CDockManager or floated as a top-level window on the desktop. + */ +class CDockWidget : public QFrame +{ + Q_OBJECT +private: + DockWidgetPrivate* d; ///< private data (pimpl) + friend class DockWidgetPrivate; + +protected: + friend class CDockContainerWidget; + friend class CDockAreaWidget; + friend class CFloatingDockContainer; + + /** + * Assigns the dock manager that manages this dock widget + */ + void setDockManager(CDockManager* DockManager); + + /** + * If this dock widget is inserted into a dock area, the dock area will + * be registered on this widget via this function. If a dock widget is + * removed from a dock area, this function will be called with nullptr + * value. + */ + void setDockArea(CDockAreaWidget* DockArea); + + /** + * This function changes the toggle view action without emitting any + * signal + */ + void setToggleViewActionChecked(bool Checked); + +public: + enum DockWidgetFeature + { + DockWidgetClosable = 0x01, + DockWidgetMovable = 0x02, + DockWidgetFloatable = 0x04, + AllDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable, + NoDockWidgetFeatures = 0x00 + }; + Q_DECLARE_FLAGS(DockWidgetFeatures, DockWidgetFeature) + + + enum eState + { + StateHidden, + StateDocked, + StateFloating + }; + + /** + * Default Constructor + */ + CDockWidget(const QString &title, QWidget* parent = 0); + + /** + * Virtual Destructor + */ + virtual ~CDockWidget(); + + /** + * Sets the widget for the dock widget to widget. + */ + void setWidget(QWidget* widget); + + /** + * Returns the widget for the dock widget. This function returns zero if + * the widget has not been set. + */ + QWidget* widget() const; + + /** + * Returns the title bar widget of this dock widget + */ + CDockWidgetTitleBar* titleBar() const; + + /** + * Sets, whether the dock widget is movable, closable, and floatable. + */ + void setFeatures(DockWidgetFeatures features); + + /** + * This property holds whether the dock widget is movable, closable, and + * floatable. + * By default, this property is set to a combination of DockWidgetClosable, + * DockWidgetMovable and DockWidgetFloatable. + */ + DockWidgetFeatures features() const; + + /** + * Returns the dock manager that manages the dock widget or 0 if the widget + * has not been assigned to any dock manager yet + */ + CDockManager* dockManager() const; + + /** + * Returns the dock container widget this dock area widget belongs to or 0 + * if this dock widget has nt been docked yet + */ + CDockContainerWidget* dockContainer() const; + + /** + * Returns the dock area widget this dock widget belongs to or 0 + * if this dock widget has not been docked yet + */ + CDockAreaWidget* dockAreaWidget() const; + + /** + * This property holds whether the dock widget is floating. + */ + bool isFloating() const; + + /** + * Returns true, if this dock widget is closed. + */ + bool isClosed() const; + + /** + * Returns a checkable action that can be used to show or close this dock widget. + * The action's text is set to the dock widget's window title. + */ + QAction* toggleViewAction() const; + + +public slots: + /** + * This property controls whether the dock widget is open or closed. + * The toogleViewAction triggers this slot + */ + void toggleView(bool Open); + +signals: + /** + * This signal is emitted if the dock widget is opened or closed + */ + void viewToggled(bool Open); + + /** + * This signal is emitted if the dock widget is closed + */ + void closed(); +}; // class DockWidget +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockWidgetH diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index b16b12d..f863252 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -1,385 +1,397 @@ -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file FloatingDockContainer.cpp -/// \author Uwe Kindler -/// \date 01.03.2017 -/// \brief Implementation of CFloatingDockContainer class -//============================================================================ - - -//============================================================================ -// INCLUDES -//============================================================================ -#include "FloatingDockContainer.h" - -#include -#include -#include -#include - -#include - -#include "DockContainerWidget.h" -#include "DockAreaWidget.h" -#include "DockManager.h" -#include "DockWidget.h" -#include "DockOverlay.h" - - -namespace ads -{ -static unsigned int zOrderCounter = 0; - -/** - * Private data class of CFloatingDockContainer class (pimpl) - */ -struct FloatingDockContainerPrivate -{ - CFloatingDockContainer* _this; - CDockContainerWidget* DockContainer; - unsigned int zOrderIndex = ++zOrderCounter; - QPointer DockManager; - bool DraggingActive = false; - QPoint DragStartMousePosition; - CDockContainerWidget* DropContainer = nullptr; - CDockAreaWidget* SingleDockArea = nullptr; - - /** - * Private data constructor - */ - FloatingDockContainerPrivate(CFloatingDockContainer* _public); - - void titleMouseReleaseEvent(); - void updateDropOverlays(const QPoint& GlobalPos); - void setDraggingActive(bool Active); -}; -// struct FloatingDockContainerPrivate - -//============================================================================ -FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContainer* _public) : - _this(_public) -{ - -} - - - -//============================================================================ -void FloatingDockContainerPrivate::titleMouseReleaseEvent() -{ - setDraggingActive(false); - if (!DropContainer) - { - return; - } - - std::cout << "Dropped" << std::endl; - DropContainer->dropFloatingWidget(_this, QCursor::pos()); - DockManager->containerOverlay()->hideOverlay(); - DockManager->dockAreaOverlay()->hideOverlay(); -} - - - -//============================================================================ -void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos) -{ - if (!_this->isVisible() || !DockManager) - { - return; - } - - auto Containers = DockManager->dockContainers(); - CDockContainerWidget* TopContainer = nullptr; - for (auto ContainerWidget : Containers) - { - if (!ContainerWidget->isVisible()) - { - continue; - } - - if (DockContainer == ContainerWidget) - { - continue; - } - - QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos); - if (ContainerWidget->rect().contains(MappedPos)) - { - if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer)) - { - TopContainer = ContainerWidget; - } - } - } - - DropContainer = TopContainer; - auto ContainerOverlay = DockManager->containerOverlay(); - auto DockAreaOverlay = DockManager->dockAreaOverlay(); - - if (!TopContainer) - { - ContainerOverlay->hideOverlay(); - DockAreaOverlay->hideOverlay(); - return; - } - - ContainerOverlay->setAllowedAreas(TopContainer->dockAreaCount() > 1 ? - OuterDockAreas : AllDockAreas); - ContainerOverlay->showOverlay(TopContainer); - ContainerOverlay->raise(); - - auto DockArea = TopContainer->dockAreaAt(GlobalPos); - if (DockArea && TopContainer->dockAreaCount() > 1) - { - DockAreaOverlay->setAllowedAreas(AllDockAreas); - DockAreaOverlay->showOverlay(DockArea); - } - else - { - DockAreaOverlay->hideOverlay(); - } -} - - -//============================================================================ -void FloatingDockContainerPrivate::setDraggingActive(bool Active) -{ - DraggingActive = Active; -} - - -//============================================================================ -CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) : - QWidget(DockManager, Qt::Window), - d(new FloatingDockContainerPrivate(this)) -{ - //setAttribute(Qt::WA_DeleteOnClose); - d->DockManager = DockManager; - QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom); - l->setContentsMargins(0, 0, 0, 0); - l->setSpacing(0); - setLayout(l); - - d->DockContainer = new CDockContainerWidget(DockManager, this); - connect(d->DockContainer, SIGNAL(dockAreasAdded()), this, SLOT(onDockAreasAddedOrRemoved())); - connect(d->DockContainer, SIGNAL(dockAreasRemoved()), this, SLOT(onDockAreasAddedOrRemoved())); - l->addWidget(d->DockContainer); - DockManager->registerFloatingWidget(this); - - // We install an event filter to detect mouse release events because we - // do not receive mouse release event if the floating widget is behind - // the drop overlay cross - qApp->installEventFilter(this); -} - - -//============================================================================ -CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget* DockArea) : - CFloatingDockContainer(DockArea->dockManager()) -{ - d->DockContainer->addDockArea(DockArea); -} - - -//============================================================================ -CFloatingDockContainer::CFloatingDockContainer(CDockWidget* DockWidget) : - CFloatingDockContainer(DockWidget->dockManager()) -{ - d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget); -} - -//============================================================================ -CFloatingDockContainer::~CFloatingDockContainer() -{ - std::cout << "~CFloatingDockContainer" << std::endl; - if (d->DockManager) - { - d->DockManager->removeFloatingWidget(this); - } - delete d; -} - - -//============================================================================ -CDockContainerWidget* CFloatingDockContainer::dockContainer() const -{ - return d->DockContainer; -} - - -//============================================================================ -void CFloatingDockContainer::changeEvent(QEvent *event) -{ - QWidget::changeEvent(event); - if ((event->type() == QEvent::ActivationChange) && isActiveWindow()) - { - std::cout << "FloatingWidget::changeEvent QEvent::ActivationChange " << std::endl; - d->zOrderIndex = ++zOrderCounter; - return; - } -} - - -//============================================================================ -void CFloatingDockContainer::moveEvent(QMoveEvent *event) -{ - QWidget::moveEvent(event); - if (!qApp->mouseButtons().testFlag(Qt::LeftButton)) - { - if (d->DraggingActive) - { - d->setDraggingActive(false); - } - return; - } - - if (d->DraggingActive) - { - d->updateDropOverlays(QCursor::pos()); - } -} - - -//============================================================================ -void CFloatingDockContainer::closeEvent(QCloseEvent *event) -{ - d->setDraggingActive(false); - if (dockContainer()->dockAreaCount() > 1 || dockContainer()->dockArea(0)->count() == 1) - { - for (int i = 0; i < dockContainer()->dockAreaCount(); ++i) - { - auto DockWidgets = dockContainer()->dockArea(i)->dockWidgets(); - for (auto DockWidget : DockWidgets) - { - DockWidget->hideDockWidget(); - } - } - QWidget::closeEvent(event); - } - else - { - auto DockArea = dockContainer()->dockArea(0); - DockArea->currentDockWidget()->hideDockWidget(); - // As long as there are open dock widgets, we do not close the floating - // window - if (DockArea->openDockWidgets().count()) - { - event->ignore(); - } - } -} - - -//============================================================================ -bool CFloatingDockContainer::event(QEvent *e) -{ - if ((e->type() == QEvent::NonClientAreaMouseButtonPress)) - { - if (QGuiApplication::mouseButtons() == Qt::LeftButton) - { - std::cout << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type() << std::endl; - d->setDraggingActive(true); - } - } - else if (e->type() == QEvent::NonClientAreaMouseButtonDblClick) - { - std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick" << std::endl; - d->setDraggingActive(false); - } - else if ((e->type() == QEvent::NonClientAreaMouseButtonRelease) && d->DraggingActive) - { - std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease" << std::endl; - d->titleMouseReleaseEvent(); - } - - return QWidget::event(e); -} - - -//============================================================================ -bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *event) -{ - if (event->type() == QEvent::MouseButtonRelease && d->DraggingActive) - { - std::cout << "FloatingWidget::eventFilter QEvent::MouseButtonRelease" << std::endl; - d->titleMouseReleaseEvent(); - } - - return false; -} - - -//============================================================================ -void CFloatingDockContainer::startFloating(const QPoint& Pos, const QSize& Size) -{ - resize(Size); - d->setDraggingActive(true); - QPoint TargetPos = QCursor::pos() - Pos; - move(TargetPos); - show(); - d->DragStartMousePosition = Pos; -} - - -//============================================================================ -void CFloatingDockContainer::moveFloating() -{ - int BorderSize = (frameSize().width() - size().width()) / 2; - const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); - move(moveToPos); -} - - -//============================================================================ -void CFloatingDockContainer::onDockAreasAddedOrRemoved() -{ - if (d->DockContainer->dockAreaCount() == 1) - { - d->SingleDockArea = d->DockContainer->dockArea(0); - this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); - connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this, - SLOT(onDockAreaCurrentChanged(int))); - } - else - { - if (d->SingleDockArea) - { - disconnect(d->SingleDockArea, SIGNAL(currentChanged(int)), this, - SLOT(onDockAreaCurrentChanged(int))); - d->SingleDockArea = nullptr; - } - this->setWindowTitle(qApp->applicationDisplayName()); - } -} - - -//============================================================================ -void CFloatingDockContainer::onDockAreaCurrentChanged(int Index) -{ - this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); -} - - -} // namespace ads - -//--------------------------------------------------------------------------- -// EOF FloatingDockContainer.cpp +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file FloatingDockContainer.cpp +/// \author Uwe Kindler +/// \date 01.03.2017 +/// \brief Implementation of CFloatingDockContainer class +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "FloatingDockContainer.h" + +#include +#include +#include +#include +#include + +#include + +#include "DockContainerWidget.h" +#include "DockAreaWidget.h" +#include "DockManager.h" +#include "DockWidget.h" +#include "DockOverlay.h" + + +namespace ads +{ +static unsigned int zOrderCounter = 0; + +/** + * Private data class of CFloatingDockContainer class (pimpl) + */ +struct FloatingDockContainerPrivate +{ + CFloatingDockContainer* _this; + CDockContainerWidget* DockContainer; + unsigned int zOrderIndex = ++zOrderCounter; + QPointer DockManager; + bool DraggingActive = false; + QPoint DragStartMousePosition; + CDockContainerWidget* DropContainer = nullptr; + CDockAreaWidget* SingleDockArea = nullptr; + + /** + * Private data constructor + */ + FloatingDockContainerPrivate(CFloatingDockContainer* _public); + + void titleMouseReleaseEvent(); + void updateDropOverlays(const QPoint& GlobalPos); + void setDraggingActive(bool Active); +}; +// struct FloatingDockContainerPrivate + +//============================================================================ +FloatingDockContainerPrivate::FloatingDockContainerPrivate(CFloatingDockContainer* _public) : + _this(_public) +{ + +} + + + +//============================================================================ +void FloatingDockContainerPrivate::titleMouseReleaseEvent() +{ + setDraggingActive(false); + if (!DropContainer) + { + return; + } + + std::cout << "Dropped" << std::endl; + DropContainer->dropFloatingWidget(_this, QCursor::pos()); + DockManager->containerOverlay()->hideOverlay(); + DockManager->dockAreaOverlay()->hideOverlay(); +} + + + +//============================================================================ +void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos) +{ + if (!_this->isVisible() || !DockManager) + { + return; + } + + auto Containers = DockManager->dockContainers(); + CDockContainerWidget* TopContainer = nullptr; + for (auto ContainerWidget : Containers) + { + if (!ContainerWidget->isVisible()) + { + continue; + } + + if (DockContainer == ContainerWidget) + { + continue; + } + + QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos); + if (ContainerWidget->rect().contains(MappedPos)) + { + if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer)) + { + TopContainer = ContainerWidget; + } + } + } + + DropContainer = TopContainer; + auto ContainerOverlay = DockManager->containerOverlay(); + auto DockAreaOverlay = DockManager->dockAreaOverlay(); + + if (!TopContainer) + { + ContainerOverlay->hideOverlay(); + DockAreaOverlay->hideOverlay(); + return; + } + + ContainerOverlay->setAllowedAreas(TopContainer->dockAreaCount() > 1 ? + OuterDockAreas : AllDockAreas); + ContainerOverlay->showOverlay(TopContainer); + ContainerOverlay->raise(); + + auto DockArea = TopContainer->dockAreaAt(GlobalPos); + if (DockArea && TopContainer->dockAreaCount() > 1) + { + DockAreaOverlay->setAllowedAreas(AllDockAreas); + DockAreaOverlay->showOverlay(DockArea); + } + else + { + DockAreaOverlay->hideOverlay(); + } +} + + +//============================================================================ +void FloatingDockContainerPrivate::setDraggingActive(bool Active) +{ + DraggingActive = Active; +} + + +//============================================================================ +CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) : + QWidget(DockManager, Qt::Window), + d(new FloatingDockContainerPrivate(this)) +{ + //setAttribute(Qt::WA_DeleteOnClose); + d->DockManager = DockManager; + QBoxLayout* l = new QBoxLayout(QBoxLayout::TopToBottom); + l->setContentsMargins(0, 0, 0, 0); + l->setSpacing(0); + setLayout(l); + + d->DockContainer = new CDockContainerWidget(DockManager, this); + connect(d->DockContainer, SIGNAL(dockAreasAdded()), this, SLOT(onDockAreasAddedOrRemoved())); + connect(d->DockContainer, SIGNAL(dockAreasRemoved()), this, SLOT(onDockAreasAddedOrRemoved())); + l->addWidget(d->DockContainer); + DockManager->registerFloatingWidget(this); + + // We install an event filter to detect mouse release events because we + // do not receive mouse release event if the floating widget is behind + // the drop overlay cross + qApp->installEventFilter(this); +} + + +//============================================================================ +CFloatingDockContainer::CFloatingDockContainer(CDockAreaWidget* DockArea) : + CFloatingDockContainer(DockArea->dockManager()) +{ + d->DockContainer->addDockArea(DockArea); +} + + +//============================================================================ +CFloatingDockContainer::CFloatingDockContainer(CDockWidget* DockWidget) : + CFloatingDockContainer(DockWidget->dockManager()) +{ + d->DockContainer->addDockWidget(CenterDockWidgetArea, DockWidget); +} + +//============================================================================ +CFloatingDockContainer::~CFloatingDockContainer() +{ + std::cout << "~CFloatingDockContainer" << std::endl; + if (d->DockManager) + { + d->DockManager->removeFloatingWidget(this); + } + delete d; +} + + +//============================================================================ +CDockContainerWidget* CFloatingDockContainer::dockContainer() const +{ + return d->DockContainer; +} + + +//============================================================================ +void CFloatingDockContainer::changeEvent(QEvent *event) +{ + QWidget::changeEvent(event); + if ((event->type() == QEvent::ActivationChange) && isActiveWindow()) + { + std::cout << "FloatingWidget::changeEvent QEvent::ActivationChange " << std::endl; + d->zOrderIndex = ++zOrderCounter; + return; + } +} + + +//============================================================================ +void CFloatingDockContainer::moveEvent(QMoveEvent *event) +{ + QWidget::moveEvent(event); + if (!qApp->mouseButtons().testFlag(Qt::LeftButton)) + { + if (d->DraggingActive) + { + d->setDraggingActive(false); + } + return; + } + + if (d->DraggingActive) + { + d->updateDropOverlays(QCursor::pos()); + } +} + + +//============================================================================ +void CFloatingDockContainer::closeEvent(QCloseEvent *event) +{ + d->setDraggingActive(false); + QWidget::closeEvent(event); + +} + + +//============================================================================ +void CFloatingDockContainer::hideEvent(QHideEvent *event) +{ + QWidget::hideEvent(event); + auto OpenDockAreas = d->DockContainer->openedDockAreas(); + for (auto DockArea : OpenDockAreas) + { + auto OpenDockWidgets = DockArea->openedDockWidgets(); + for (auto DockWidget : OpenDockWidgets) + { + DockWidget->setToggleViewActionChecked(false); + } + } +} + + +//============================================================================ +void CFloatingDockContainer::showEvent(QShowEvent *event) +{ + QWidget::showEvent(event); + CDockContainerWidget* DockContainer = dockContainer(); + for (int i = 0; i < DockContainer->dockAreaCount(); ++i) + { + auto DockArea = DockContainer->dockArea(i); + for (auto DockWidget : DockArea->openedDockWidgets()) + { + DockWidget->setToggleViewActionChecked(true); + } + } +} + + +//============================================================================ +bool CFloatingDockContainer::event(QEvent *e) +{ + if ((e->type() == QEvent::NonClientAreaMouseButtonPress)) + { + if (QGuiApplication::mouseButtons() == Qt::LeftButton) + { + std::cout << "FloatingWidget::event Event::NonClientAreaMouseButtonPress" << e->type() << std::endl; + d->setDraggingActive(true); + } + } + else if (e->type() == QEvent::NonClientAreaMouseButtonDblClick) + { + std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonDblClick" << std::endl; + d->setDraggingActive(false); + } + else if ((e->type() == QEvent::NonClientAreaMouseButtonRelease) && d->DraggingActive) + { + std::cout << "FloatingWidget::event QEvent::NonClientAreaMouseButtonRelease" << std::endl; + d->titleMouseReleaseEvent(); + } + + return QWidget::event(e); +} + + +//============================================================================ +bool CFloatingDockContainer::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() == QEvent::MouseButtonRelease && d->DraggingActive) + { + std::cout << "FloatingWidget::eventFilter QEvent::MouseButtonRelease" << std::endl; + d->titleMouseReleaseEvent(); + } + + return false; +} + + +//============================================================================ +void CFloatingDockContainer::startFloating(const QPoint& Pos, const QSize& Size) +{ + resize(Size); + d->setDraggingActive(true); + QPoint TargetPos = QCursor::pos() - Pos; + move(TargetPos); + show(); + d->DragStartMousePosition = Pos; +} + + +//============================================================================ +void CFloatingDockContainer::moveFloating() +{ + int BorderSize = (frameSize().width() - size().width()) / 2; + const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); + move(moveToPos); +} + + +//============================================================================ +void CFloatingDockContainer::onDockAreasAddedOrRemoved() +{ + if (d->DockContainer->dockAreaCount() == 1) + { + d->SingleDockArea = d->DockContainer->dockArea(0); + this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); + connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this, + SLOT(onDockAreaCurrentChanged(int))); + } + else + { + if (d->SingleDockArea) + { + disconnect(d->SingleDockArea, SIGNAL(currentChanged(int)), this, + SLOT(onDockAreaCurrentChanged(int))); + d->SingleDockArea = nullptr; + } + this->setWindowTitle(qApp->applicationDisplayName()); + } +} + + +//============================================================================ +void CFloatingDockContainer::onDockAreaCurrentChanged(int Index) +{ + this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); +} + + +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF FloatingDockContainer.cpp diff --git a/src/FloatingDockContainer.h b/src/FloatingDockContainer.h index 503aa08..0841a56 100644 --- a/src/FloatingDockContainer.h +++ b/src/FloatingDockContainer.h @@ -1,108 +1,110 @@ -#ifndef FloatingDockContainerH -#define FloatingDockContainerH -/******************************************************************************* -** QtAdcancedDockingSystem -** Copyright (C) 2017 Uwe Kindler -** -** This program is free software: you can redistribute it and/or modify -** it under the terms of the GNU General Public License as published by -** the Free Software Foundation, either version 3 of the License, or -** (at your option) any later version. -** -** This program is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -** GNU General Public License for more details. -** -** You should have received a copy of the GNU General Public License -** along with this program. If not, see . -******************************************************************************/ - - -//============================================================================ -/// \file FloatingDockContainer.h -/// \author Uwe Kindler -/// \date 01.03.2017 -/// \brief Declaration of CFloatingDockContainer class -//============================================================================ - -//============================================================================ -// INCLUDES -//============================================================================ -#include - -namespace ads -{ -struct FloatingDockContainerPrivate; -class CDockAreaWidget; -class CDockContainerWidget; -class CDockWidget; -class CDockManager; - -/** - * This implements a floating widget that is a dock container that accepts - * docking of dock widgets like the main window and that can be docked into - * another dock container - */ -class CFloatingDockContainer : public QWidget -{ - Q_OBJECT -private: - FloatingDockContainerPrivate* d; ///< private data (pimpl) - friend class FloatingDockContainerPrivate; - -private slots: - void onDockAreasAddedOrRemoved(); - void onDockAreaCurrentChanged(int Index); - -protected: - /** - * Private constructor that is called from public constructors - */ - CFloatingDockContainer(CDockManager* DockManager); - -protected: // reimplements QWidget - virtual void changeEvent(QEvent *event) override; - virtual void moveEvent(QMoveEvent *event) override; - virtual bool event(QEvent *e) override; - virtual void closeEvent(QCloseEvent *event) override; - virtual bool eventFilter(QObject *watched, QEvent *event) override; - -public: - /** - * Create floating widget with the given dock area - */ - CFloatingDockContainer(CDockAreaWidget* DockArea); - - /** - * Create floating widget with the given dock widget - */ - CFloatingDockContainer(CDockWidget* DockWidget); - - /** - * Virtual Destructor - */ - virtual ~CFloatingDockContainer(); - - /** - * Access function for the internal dock container - */ - CDockContainerWidget* dockContainer() const; - - /** - * Starts floating at the given global position. - * Use moveToGlobalPos() to move the widget to a new position - * depending on the start position given in Pos parameter - */ - void startFloating(const QPoint& Pos, const QSize& Size = QSize()); - - /** - * Moves the widget to a new position relative to the position given when - * startFloating() was called - */ - void moveFloating(); -}; // class FloatingDockContainer -} - // namespace ads -//----------------------------------------------------------------------------- -#endif // FloatingDockContainerH +#ifndef FloatingDockContainerH +#define FloatingDockContainerH +/******************************************************************************* +** QtAdcancedDockingSystem +** Copyright (C) 2017 Uwe Kindler +** +** This program is free software: you can redistribute it and/or modify +** it under the terms of the GNU General Public License as published by +** the Free Software Foundation, either version 3 of the License, or +** (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program. If not, see . +******************************************************************************/ + + +//============================================================================ +/// \file FloatingDockContainer.h +/// \author Uwe Kindler +/// \date 01.03.2017 +/// \brief Declaration of CFloatingDockContainer class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ +struct FloatingDockContainerPrivate; +class CDockAreaWidget; +class CDockContainerWidget; +class CDockWidget; +class CDockManager; + +/** + * This implements a floating widget that is a dock container that accepts + * docking of dock widgets like the main window and that can be docked into + * another dock container + */ +class CFloatingDockContainer : public QWidget +{ + Q_OBJECT +private: + FloatingDockContainerPrivate* d; ///< private data (pimpl) + friend class FloatingDockContainerPrivate; + +private slots: + void onDockAreasAddedOrRemoved(); + void onDockAreaCurrentChanged(int Index); + +protected: + /** + * Private constructor that is called from public constructors + */ + CFloatingDockContainer(CDockManager* DockManager); + +protected: // reimplements QWidget + virtual void changeEvent(QEvent *event) override; + virtual void moveEvent(QMoveEvent *event) override; + virtual bool event(QEvent *e) override; + virtual void closeEvent(QCloseEvent *event) override; + virtual void hideEvent(QHideEvent *event) override; + virtual void showEvent(QShowEvent *event) override; + virtual bool eventFilter(QObject *watched, QEvent *event) override; + +public: + /** + * Create floating widget with the given dock area + */ + CFloatingDockContainer(CDockAreaWidget* DockArea); + + /** + * Create floating widget with the given dock widget + */ + CFloatingDockContainer(CDockWidget* DockWidget); + + /** + * Virtual Destructor + */ + virtual ~CFloatingDockContainer(); + + /** + * Access function for the internal dock container + */ + CDockContainerWidget* dockContainer() const; + + /** + * Starts floating at the given global position. + * Use moveToGlobalPos() to move the widget to a new position + * depending on the start position given in Pos parameter + */ + void startFloating(const QPoint& Pos, const QSize& Size = QSize()); + + /** + * Moves the widget to a new position relative to the position given when + * startFloating() was called + */ + void moveFloating(); +}; // class FloatingDockContainer +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // FloatingDockContainerH