From 2c9ceb864558fc377406e62cbaca4cc52895c8cb Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 1 Mar 2017 14:09:56 +0100 Subject: [PATCH] Implemented initial support for floating widgets --- AdvancedDockingSystem/src/FloatingWidget.cpp | 42 ++- .../src/v2/DockAreaWidget.cpp | 61 +++- AdvancedDockingSystem/src/v2/DockAreaWidget.h | 12 +- .../src/v2/DockContainerWidget.cpp | 68 ++++- .../src/v2/DockContainerWidget.h | 10 + AdvancedDockingSystem/src/v2/DockManager.cpp | 15 + AdvancedDockingSystem/src/v2/DockManager.h | 10 +- AdvancedDockingSystem/src/v2/DockWidget.cpp | 32 ++ AdvancedDockingSystem/src/v2/DockWidget.h | 28 ++ .../src/v2/DockWidgetTitleBar.cpp | 107 ++++++- .../src/v2/DockWidgetTitleBar.h | 7 + .../src/v2/FloatingDockContainer.cpp | 283 +++++++++++++++++- .../src/v2/FloatingDockContainer.h | 64 +++- AdvancedDockingSystem/src/v2/ads_globals.cpp | 26 +- AdvancedDockingSystem/src/v2/ads_globals.h | 27 +- 15 files changed, 722 insertions(+), 70 deletions(-) diff --git a/AdvancedDockingSystem/src/FloatingWidget.cpp b/AdvancedDockingSystem/src/FloatingWidget.cpp index 6f63229..31a5e5c 100644 --- a/AdvancedDockingSystem/src/FloatingWidget.cpp +++ b/AdvancedDockingSystem/src/FloatingWidget.cpp @@ -229,6 +229,26 @@ void FloatingWidget::onCloseButtonClicked() } +void FloatingWidget::setDraggingActive(bool Active) +{ + if (m_DraggingActive == Active) + { + return; + } + + m_DraggingActive = Active; + if (Active) + { + std::cout << "FloatingWidget:: InstallEventFilter" << std::endl; + qApp->installEventFilter(this); + } + else + { + std::cout << "FloatingWidget:: RemoveEventFilter" << std::endl; + qApp->removeEventFilter(this); + } +} + void FloatingWidget::changeEvent(QEvent *event) { QWidget::changeEvent(event); @@ -251,28 +271,6 @@ void FloatingWidget::moveEvent(QMoveEvent *event) } } - -void FloatingWidget::setDraggingActive(bool Active) -{ - if (m_DraggingActive == Active) - { - return; - } - - m_DraggingActive = Active; - if (Active) - { - std::cout << "FloatingWidget:: InstallEventFilter" << std::endl; - qApp->installEventFilter(this); - } - else - { - std::cout << "FloatingWidget:: RemoveEventFilter" << std::endl; - qApp->removeEventFilter(this); - } -} - - bool FloatingWidget::event(QEvent *e) { if ((e->type() == QEvent::NonClientAreaMouseButtonPress)) diff --git a/AdvancedDockingSystem/src/v2/DockAreaWidget.cpp b/AdvancedDockingSystem/src/v2/DockAreaWidget.cpp index b90de5e..00028ea 100644 --- a/AdvancedDockingSystem/src/v2/DockAreaWidget.cpp +++ b/AdvancedDockingSystem/src/v2/DockAreaWidget.cpp @@ -98,6 +98,7 @@ struct DockAreaWidgetPrivate QPushButton* TabsMenuButton; QPushButton* CloseButton; int TabsLayoutInitCount; + CDockManager* DockManager = nullptr; /** * Private data constructor @@ -127,8 +128,11 @@ struct DockAreaWidgetPrivate /** * 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); + void addTabsMenuEntry(CDockWidget* DockWidget, QMenu* menu = 0); /** * Returns the tab action of the given dock widget @@ -145,6 +149,12 @@ struct DockAreaWidgetPrivate { return DockWidget->property(INDEX_PROPERTY).toInt(); } + + /** + * Update the tabs menu if dock widget order changed or if dock widget has + * been removed + */ + void updateTabsMenu(); }; // struct DockAreaWidgetPrivate @@ -202,19 +212,35 @@ void DockAreaWidgetPrivate::createTabBar() //============================================================================ -void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget) +void DockAreaWidgetPrivate::addTabsMenuEntry(CDockWidget* DockWidget, + QMenu* menu) { - auto Action = TabsMenuButton->menu()->addAction(DockWidget->windowTitle()); + menu = menu ? menu : TabsMenuButton->menu(); + auto 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), menu); + } +} + + //============================================================================ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) : QFrame(parent), d(new DockAreaWidgetPrivate(this)) { + d->DockManager = DockManager; setStyleSheet("ads--CDockAreaWidget {border: 1px solid white;}"); d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); d->Layout->setContentsMargins(0, 0, 0, 0); @@ -232,12 +258,20 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget //============================================================================ CDockAreaWidget::~CDockAreaWidget() { + std::cout << "~CDockAreaWidget()" << std::endl; delete d; } //============================================================================ -CDockContainerWidget* CDockAreaWidget::dockContainerWidget() const +CDockManager* CDockAreaWidget::dockManager() const +{ + return d->DockManager; +} + + +//============================================================================ +CDockContainerWidget* CDockAreaWidget::dockContainer() const { QWidget* Parent = parentWidget(); while (Parent) @@ -274,6 +308,25 @@ void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget) } +//============================================================================ +void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) +{ + std::cout << "CDockAreaWidget::removeDockWidget" << std::endl; + d->ContentsLayout->removeWidget(DockWidget); + auto TitleBar = DockWidget->titleBar(); + d->TabsLayout->removeWidget(TitleBar); + disconnect(TitleBar, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); + d->updateTabsMenu(); + + if (d->ContentsLayout->isEmpty()) + { + std::cout << "Dock Area empty" << std::endl; + dockContainer()->removeDockArea(this); + this->deleteLater(); + } +} + + //============================================================================ void CDockAreaWidget::onDockWidgetTitleClicked() { diff --git a/AdvancedDockingSystem/src/v2/DockAreaWidget.h b/AdvancedDockingSystem/src/v2/DockAreaWidget.h index 3c74347..984c998 100644 --- a/AdvancedDockingSystem/src/v2/DockAreaWidget.h +++ b/AdvancedDockingSystem/src/v2/DockAreaWidget.h @@ -66,11 +66,16 @@ public: */ 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* dockContainerWidget() const; + CDockContainerWidget* dockContainer() const; /** * Add a new dock widget to dock area. @@ -78,6 +83,11 @@ public: */ void addDockWidget(CDockWidget* DockWidget); + /** + * Removes the given dock widget from the dock area + */ + void removeDockWidget(CDockWidget* DockWidget); + /** * Returns the rectangle of the title area */ diff --git a/AdvancedDockingSystem/src/v2/DockContainerWidget.cpp b/AdvancedDockingSystem/src/v2/DockContainerWidget.cpp index e8bc112..142b627 100644 --- a/AdvancedDockingSystem/src/v2/DockContainerWidget.cpp +++ b/AdvancedDockingSystem/src/v2/DockContainerWidget.cpp @@ -37,6 +37,7 @@ #include "DockManager.h" #include "DockAreaWidget.h" +#include "DockWidget.h" #include "ads_globals.h" #include @@ -97,6 +98,11 @@ struct DockContainerWidgetPrivate */ CDockAreaWidget* dockWidgetIntoDockArea(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* TargetDockArea); + + /** + * Add dock area to this container + */ + void addDockArea(CDockAreaWidget* NewDockWidget, DockWidgetArea area = CenterDockWidgetArea); }; // struct DockContainerWidgetPrivate @@ -114,8 +120,15 @@ CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetA { CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); NewDockArea->addDockWidget(Dockwidget); - auto InsertParam = internal::dockAreaInsertParameters(area); + 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); @@ -156,7 +169,6 @@ CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoContainer(DockWidgetA } DockAreas.append(NewDockArea); - return NewDockArea; } @@ -173,7 +185,7 @@ CDockAreaWidget* DockContainerWidgetPrivate::dockWidgetIntoDockArea(DockWidgetAr CDockAreaWidget* NewDockArea = new CDockAreaWidget(DockManager, _this); NewDockArea->addDockWidget(Dockwidget); auto InsertParam = internal::dockAreaInsertParameters(area); - QSplitter* TargetAreaSplitter = internal::findParentSplitter(TargetDockArea); + QSplitter* TargetAreaSplitter = internal::findParent(TargetDockArea); int index = TargetAreaSplitter ->indexOf(TargetDockArea); if (TargetAreaSplitter->orientation() == InsertParam.orientation()) { @@ -219,6 +231,13 @@ CDockContainerWidget::~CDockContainerWidget() 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); @@ -259,6 +278,49 @@ bool CDockContainerWidget::event(QEvent *e) 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) +{ + d->DockAreas.removeAll(area); + QSplitter* Splitter = internal::findParent(area); + area->setParent(0); + if (!(Splitter && Splitter->count() == 1)) + { + 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; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/DockContainerWidget.h b/AdvancedDockingSystem/src/v2/DockContainerWidget.h index cbff95e..0d0341e 100644 --- a/AdvancedDockingSystem/src/v2/DockContainerWidget.h +++ b/AdvancedDockingSystem/src/v2/DockContainerWidget.h @@ -78,6 +78,16 @@ public: 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 */ diff --git a/AdvancedDockingSystem/src/v2/DockManager.cpp b/AdvancedDockingSystem/src/v2/DockManager.cpp index 0c0dae5..5a6a639 100644 --- a/AdvancedDockingSystem/src/v2/DockManager.cpp +++ b/AdvancedDockingSystem/src/v2/DockManager.cpp @@ -31,6 +31,11 @@ #include "DockManager.h" #include +#include + +#include + +#include "FloatingDockContainer.h" namespace ads { @@ -40,6 +45,7 @@ namespace ads struct DockManagerPrivate { CDockManager* _this; + QList FloatingWidgets; /** * Private data constructor @@ -73,6 +79,15 @@ CDockManager::~CDockManager() { delete d; } + + +//============================================================================ +void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget) +{ + d->FloatingWidgets.append(FloatingWidget); + std::cout << "d->FloatingWidgets.count() " << d->FloatingWidgets.count() + << std::endl; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/DockManager.h b/AdvancedDockingSystem/src/v2/DockManager.h index 5b87bc3..cd821fd 100644 --- a/AdvancedDockingSystem/src/v2/DockManager.h +++ b/AdvancedDockingSystem/src/v2/DockManager.h @@ -35,6 +35,7 @@ namespace ads { struct DockManagerPrivate; +class CFloatingDockContainer; /** * The central dock manager that maintains the complete docking system @@ -46,10 +47,11 @@ private: DockManagerPrivate* d; ///< private data (pimpl) friend class DockManagerPrivate; protected: + public: /** * Default Constructor. - * If the given parent is a QMainWindow, the dck manager sets itself as the + * If the given parent is a QMainWindow, the dock manager sets itself as the * central widget */ CDockManager(QWidget* parent = 0); @@ -58,6 +60,12 @@ public: * Virtual Destructor */ virtual ~CDockManager(); + + /** + * Registers the given floating widget in the internal list of + * floating widgets + */ + void registerFloatingWidget(CFloatingDockContainer* FloatingWidget); }; // class DockManager } // namespace ads //----------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/DockWidget.cpp b/AdvancedDockingSystem/src/v2/DockWidget.cpp index 9d0c0a9..c562233 100644 --- a/AdvancedDockingSystem/src/v2/DockWidget.cpp +++ b/AdvancedDockingSystem/src/v2/DockWidget.cpp @@ -33,6 +33,9 @@ #include #include "DockWidgetTitleBar.h" +#include "DockContainerWidget.h" +#include "DockAreaWidget.h" +#include "ads_globals.h" namespace ads { @@ -46,6 +49,7 @@ struct DockWidgetPrivate QWidget* Widget = nullptr; CDockWidgetTitleBar* TitleWidget; CDockWidget::DockWidgetFeatures Features = CDockWidget::AllDockWidgetFeatures; + CDockManager* DockManager = nullptr; /** * Private data constructor @@ -125,6 +129,34 @@ 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); +} + } // namespace ads //--------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/DockWidget.h b/AdvancedDockingSystem/src/v2/DockWidget.h index 8905fa8..6974149 100644 --- a/AdvancedDockingSystem/src/v2/DockWidget.h +++ b/AdvancedDockingSystem/src/v2/DockWidget.h @@ -36,6 +36,9 @@ namespace ads { struct DockWidgetPrivate; class CDockWidgetTitleBar; +class CDockManager; +class CDockContainerWidget; +class CDockAreaWidget; /** * The QDockWidget class provides a widget that can be docked inside a @@ -47,7 +50,14 @@ class CDockWidget : public QFrame private: DockWidgetPrivate* d; ///< private data (pimpl) friend class DockWidgetPrivate; + protected: + friend class CDockContainerWidget; + /** + * Assigns the dock manager that manages this dock widget + */ + void setDockManager(CDockManager* DockManager); + public: enum DockWidgetFeature { @@ -97,6 +107,24 @@ public: * 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; }; // class DockWidget } // namespace ads diff --git a/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.cpp b/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.cpp index 3438429..f99a38a 100644 --- a/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.cpp +++ b/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.cpp @@ -35,14 +35,29 @@ #include #include #include +#include #include +#include "ads_globals.h" #include "DockWidget.h" #include "DockAreaWidget.h" +#include "FloatingDockContainer.h" namespace ads { +/** + * The different dragging states + */ +enum eDragState +{ + DraggingInactive, //!< DraggingInactive + DraggingMousePressed, //!< DraggingMousePressed + DraggingTab, //!< DraggingTab + DraggingFloatingWidget//!< DraggingFloatingWidget +}; + + /** * Private data class of CDockWidgetTitleBar class (pimpl) */ @@ -54,8 +69,8 @@ struct DockWidgetTitleBarPrivate QLabel* TitleLabel; QPoint DragStartMousePosition; bool IsActiveTab = false; - bool TabMoving = false; CDockAreaWidget* DockArea = nullptr; + eDragState DragState = DraggingInactive; /** * Private data constructor @@ -71,6 +86,29 @@ struct DockWidgetTitleBarPrivate * Moves the tab depending on the position in the given mouse event */ void moveTab(QMouseEvent* ev); + + /** + * Test function for current drag state + */ + bool isDraggingState(eDragState dragState) + { + return this->DragState == dragState; + } + + /** + * Returns true if the given global point is inside the title area geometry + * rectangle. + * The position is given as global position. + */ + bool titleAreaGeometryContains(const QPoint& GlobalPos) const + { + return DockArea->titleAreaGeometry().contains(DockArea->mapFromGlobal(GlobalPos)); + } + + /** + * Starts floating of the dock widget that belongs to this title bar + */ + void startFloating(const QPoint& GlobalPos); }; // struct DockWidgetTitleBarPrivate @@ -114,6 +152,39 @@ void DockWidgetTitleBarPrivate::moveTab(QMouseEvent* ev) } +//============================================================================ +void DockWidgetTitleBarPrivate::startFloating(const QPoint& GlobalPos) +{ + std::cout << "startFloating" << std::endl; + DragState = DraggingFloatingWidget; + QSize Size = DockArea->size(); + CFloatingDockContainer* FloatingWidget = nullptr; + if (DockArea->count() > 1) + { + // If section widget has multiple tabs, we take only one tab + FloatingWidget = new CFloatingDockContainer(DockWidget); + } + else + { + // If section widget has only one content widget, we can move the complete + // section widget into floating widget + auto splitter = internal::findParent(DockArea); + FloatingWidget = new CFloatingDockContainer(DockArea); + } + + FloatingWidget->resize(Size); + FloatingWidget->setObjectName("FloatingWidget"); + FloatingWidget->startFloating(DragStartMousePosition); + + /* + * DropOverlay* ContainerDropOverlay = cw->dropOverlay(); + ContainerDropOverlay->setAllowedAreas(OuterAreas); + ContainerDropOverlay->showDropOverlay(this); + ContainerDropOverlay->raise(); + */ +} + + //============================================================================ CDockWidgetTitleBar::CDockWidgetTitleBar(CDockWidget* DockWidget, QWidget *parent) : QFrame(parent), @@ -137,6 +208,7 @@ void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev) { ev->accept(); d->DragStartMousePosition = ev->pos(); + d->DragState = DraggingMousePressed; return; } QFrame::mousePressEvent(ev); @@ -148,7 +220,7 @@ void CDockWidgetTitleBar::mousePressEvent(QMouseEvent* ev) void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev) { // End of tab moving, change order now - if (d->TabMoving && d->DockArea) + if (d->isDraggingState(DraggingTab) && d->DockArea) { // Find tab under mouse QPoint pos = d->DockArea->mapFromGlobal(ev->globalPos()); @@ -168,7 +240,7 @@ void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev) } d->DragStartMousePosition = QPoint(); - d->TabMoving = false; + d->DragState = DraggingInactive; //mcw->m_SectionDropOverlay->hideDropOverlay(); //mcw->hideContainerOverlay(); QFrame::mouseReleaseEvent(ev); @@ -178,22 +250,34 @@ void CDockWidgetTitleBar::mouseReleaseEvent(QMouseEvent* ev) //============================================================================ void CDockWidgetTitleBar::mouseMoveEvent(QMouseEvent* ev) { - if (!(ev->buttons() & Qt::LeftButton)) + if (!(ev->buttons() & Qt::LeftButton) || d->isDraggingState(DraggingInactive)) + { + d->DragState = DraggingInactive; + QFrame::mouseMoveEvent(ev); + return; + } + + if (d->isDraggingState(DraggingFloatingWidget)) { QFrame::mouseMoveEvent(ev); return; } // move tab - if (d->TabMoving) + if (d->isDraggingState(DraggingTab)) { d->moveTab(ev); } - if ((ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance() // Wait a few pixels before start moving - && d->DockArea->titleAreaGeometry().contains(d->DockArea->mapFromGlobal(ev->globalPos()))) + bool MouseInsideTitleArea = d->titleAreaGeometryContains(ev->globalPos()); + if (!MouseInsideTitleArea) { - d->TabMoving = true; + d->startFloating(ev->globalPos()); + return; + } + else if ((ev->pos() - d->DragStartMousePosition).manhattanLength() >= QApplication::startDragDistance()) // Wait a few pixels before start moving + { + d->DragState = DraggingTab; return; } @@ -239,6 +323,13 @@ void CDockWidgetTitleBar::setDockAreaWidget(CDockAreaWidget* DockArea) { d->DockArea = DockArea; } + + +//============================================================================ +CDockAreaWidget* CDockWidgetTitleBar::dockAreaWidget() const +{ + return d->DockArea; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.h b/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.h index 8198afc..1b6fcb8 100644 --- a/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.h +++ b/AdvancedDockingSystem/src/v2/DockWidgetTitleBar.h @@ -89,6 +89,13 @@ public: */ void setDockAreaWidget(CDockAreaWidget* DockArea); + /** + * Returns the dock area widget this title bar belongs to. + * \return This function returns 0 if the dock widget that owns this title + * bar widget has not been added to any dock area yet. + */ + CDockAreaWidget* dockAreaWidget() const; + signals: void activeTabChanged(); void clicked(); diff --git a/AdvancedDockingSystem/src/v2/FloatingDockContainer.cpp b/AdvancedDockingSystem/src/v2/FloatingDockContainer.cpp index 686098f..fe83a3f 100644 --- a/AdvancedDockingSystem/src/v2/FloatingDockContainer.cpp +++ b/AdvancedDockingSystem/src/v2/FloatingDockContainer.cpp @@ -20,8 +20,8 @@ //============================================================================ /// \file FloatingDockContainer.cpp /// \author Uwe Kindler -/// \date 23.02.2017 -/// \brief Implementation of CFloatingDockContainer +/// \date 01.03.2017 +/// \brief Implementation of CFloatingDockContainer class //============================================================================ @@ -30,9 +30,288 @@ //============================================================================ #include "FloatingDockContainer.h" +#include +#include +#include + +#include + +#include "DockContainerWidget.h" +#include "DockAreaWidget.h" +#include "DockManager.h" +#include "DockWidget.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; + CDockManager* DockManager = nullptr; + bool DraggingActive = false; + QPoint DragStartMousePosition; + + /** + * 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 (!m_DropContainer) + { + return; + } + + std::cout << "Dropped" << std::endl; + CMainContainerWidget* MainContainerWidget = mainContainerWidget(); + m_DropContainer->dropFloatingWidget(this, QCursor::pos()); + MainContainerWidget->dropOverlay()->hideDropOverlay(); + MainContainerWidget->sectionDropOverlay()->hideDropOverlay();*/ +} + + + +//============================================================================ +void FloatingDockContainerPrivate::updateDropOverlays(const QPoint& GlobalPos) +{ + /*if (!isVisible()) + { + return; + } + CMainContainerWidget* MainContainerWidget = mainContainerWidget(); + auto Containers = MainContainerWidget->m_Containers; + CContainerWidget* TopContainer = nullptr; + for (auto ContainerWidget : Containers) + { + if (!ContainerWidget->isVisible()) + { + continue; + } + + if (containerWidget() == ContainerWidget) + { + continue; + } + + QPoint MappedPos = ContainerWidget->mapFromGlobal(GlobalPos); + if (ContainerWidget->rect().contains(MappedPos)) + { + std::cout << "Container " << ContainerWidget << " contains mousepos" << std::endl; + if (!TopContainer || ContainerWidget->isInFrontOf(TopContainer)) + { + TopContainer = ContainerWidget; + } + } + } + + m_DropContainer = TopContainer; + DropOverlay* ContainerDropOverlay = MainContainerWidget->dropOverlay(); + DropOverlay* SectionDropOverlay = MainContainerWidget->sectionDropOverlay(); + + if (!TopContainer) + { + ContainerDropOverlay->hideDropOverlay(); + SectionDropOverlay->hideDropOverlay(); + return; + } + + ContainerDropOverlay->showDropOverlay(TopContainer); + ContainerDropOverlay->raise(); + + SectionWidget* sectionwidget = TopContainer->sectionWidgetAt(GlobalPos); + if (sectionwidget) + { + SectionDropOverlay->setAllowedAreas(AllAreas); + SectionDropOverlay->showDropOverlay(sectionwidget); + } + else + { + SectionDropOverlay->hideDropOverlay(); + } + + + if (TopContainer) + { + ContainerDropOverlay->showDropOverlay(TopContainer); + ContainerDropOverlay->raise(); + } + else + { + ContainerDropOverlay->hideDropOverlay(); + }*/ +} + + +//============================================================================ +void FloatingDockContainerPrivate::setDraggingActive(bool Active) +{ + if (DraggingActive == Active) + { + return; + } + + DraggingActive = Active; + if (Active) + { + std::cout << "FloatingWidget:: InstallEventFilter" << std::endl; + qApp->installEventFilter(_this); + } + else + { + std::cout << "FloatingWidget:: RemoveEventFilter" << std::endl; + qApp->removeEventFilter(_this); + } +} + + +//============================================================================ +CFloatingDockContainer::CFloatingDockContainer(CDockManager* DockManager) : + QWidget(DockManager, Qt::Window), + d(new FloatingDockContainerPrivate(this)) +{ + 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); + l->addWidget(d->DockContainer); + DockManager->registerFloatingWidget(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() +{ + 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 (d->DraggingActive && qApp->mouseButtons().testFlag(Qt::LeftButton)) + { + //updateDropOverlays(QCursor::pos()); + } +} + + +//============================================================================ +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) + { + std::cout << "FloatingWidget::eventFilter QEvent::MouseButtonRelease" << std::endl; + d->titleMouseReleaseEvent(); + } + else if ((event->type() == QEvent::MouseMove) && d->DraggingActive) + { + QMouseEvent* MouseEvent = dynamic_cast(event); + int BorderSize = (frameSize().width() - size().width()) / 2; + const QPoint moveToPos = QCursor::pos() - d->DragStartMousePosition - QPoint(BorderSize, 0); + move(moveToPos); + return true; + } + return false; +} + + +//============================================================================ +void CFloatingDockContainer::startFloating(const QPoint& Pos) +{ + d->setDraggingActive(true); + QPoint TargetPos = QCursor::pos() - Pos; + move(TargetPos); + show(); + d->DragStartMousePosition = Pos; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/AdvancedDockingSystem/src/v2/FloatingDockContainer.h b/AdvancedDockingSystem/src/v2/FloatingDockContainer.h index 17a8537..76374ca 100644 --- a/AdvancedDockingSystem/src/v2/FloatingDockContainer.h +++ b/AdvancedDockingSystem/src/v2/FloatingDockContainer.h @@ -22,25 +22,73 @@ //============================================================================ /// \file FloatingDockContainer.h /// \author Uwe Kindler -/// \date 23.02.2017 -/// \brief Declaration of CFloatingDockContainer +/// \date 01.03.2017 +/// \brief Declaration of CFloatingDockContainer class //============================================================================ - //============================================================================ // INCLUDES //============================================================================ +#include + namespace ads { +struct FloatingDockContainerPrivate; +class CDockAreaWidget; +class CDockContainerWidget; +class CDockWidget; +class CDockManager; /** - * @brief + * 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 +class CFloatingDockContainer : public QWidget { -}; + Q_OBJECT +private: + FloatingDockContainerPrivate* d; ///< private data (pimpl) + friend class FloatingDockContainerPrivate; +protected: + /** + * Private constructor that is called from public constructors + */ + CFloatingDockContainer(CDockManager* DockManager); -} // namespace ads +protected: // reimplements QWidget + virtual void changeEvent(QEvent *event) override; + virtual void moveEvent(QMoveEvent *event) override; + virtual bool event(QEvent *e) 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 + */ + void startFloating(const QPoint& Pos); +}; // class FloatingDockContainer +} + // namespace ads +//----------------------------------------------------------------------------- #endif // FloatingDockContainerH diff --git a/AdvancedDockingSystem/src/v2/ads_globals.cpp b/AdvancedDockingSystem/src/v2/ads_globals.cpp index aeb77d7..7784b2b 100644 --- a/AdvancedDockingSystem/src/v2/ads_globals.cpp +++ b/AdvancedDockingSystem/src/v2/ads_globals.cpp @@ -48,6 +48,14 @@ QSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent) return s; } +//============================================================================ +void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To) +{ + int index = Splitter->indexOf(From); + From->setParent(0); + Splitter->insertWidget(index, To); +} + //============================================================================ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area) { @@ -64,24 +72,6 @@ CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area) return CDockInsertParam(Qt::Vertical, false); } - -//============================================================================ -QSplitter* findParentSplitter(QWidget* w) -{ - QWidget* parentWidget = w; - do - { - QSplitter* splitter = dynamic_cast(parentWidget); - if (splitter) - { - return splitter; - } - parentWidget = parentWidget->parentWidget(); - } - while (parentWidget); - return 0; -} - } // namespace internal } // namespace ads diff --git a/AdvancedDockingSystem/src/v2/ads_globals.h b/AdvancedDockingSystem/src/v2/ads_globals.h index 8bffee2..d9b8183 100644 --- a/AdvancedDockingSystem/src/v2/ads_globals.h +++ b/AdvancedDockingSystem/src/v2/ads_globals.h @@ -57,6 +57,11 @@ namespace internal */ QSplitter* newSplitter(Qt::Orientation orientation, QWidget* parent = 0); +/** + * Replace the from widget in the given splitter with the To widget + */ +void replaceSplitterWidget(QSplitter* Splitter, QWidget* From, QWidget* To); + /** * Convenience class for QPair to provide better naming than first and * second @@ -76,10 +81,26 @@ public: CDockInsertParam dockAreaInsertParameters(DockWidgetArea Area); /** - * Returns the parent splitter of the given widget or 0 if the widget is not - * child of any splitter + * Searches for the parent widget of the given type. + * Returns the parent widget of the given widget or 0 if the widget is not + * child of any widget of type T */ -QSplitter* findParentSplitter(QWidget* w); +template +T findParent(const QWidget* w) +{ + QWidget* parentWidget = w->parentWidget(); + while (parentWidget) + { + T ParentImpl = dynamic_cast(parentWidget); + if (ParentImpl) + { + return ParentImpl; + } + parentWidget = parentWidget->parentWidget(); + } + return 0; +} + } // namespace internal } // namespace ads