From 9bfb3fbea10d92640522be4a433d84fa321f8e02 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 12 Oct 2018 13:37:37 +0200 Subject: [PATCH] Created new DockAreaTitleBar class to encapsulate all title bar functionality --- src/DockAreaTabBar.cpp | 45 ++++++-- src/DockAreaTabBar.h | 29 ++++++ src/DockAreaTitleBar.cpp | 199 ++++++++++++++++++++++++++++++++++++ src/DockAreaTitleBar.h | 57 +++++++++++ src/DockAreaWidget.cpp | 74 +------------- src/FloatingDockContainer.h | 4 + src/src.pro | 6 +- 7 files changed, 330 insertions(+), 84 deletions(-) create mode 100644 src/DockAreaTitleBar.cpp create mode 100644 src/DockAreaTitleBar.h diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index f717c58..1844295 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -39,8 +39,6 @@ struct DockAreaTabBarPrivate QWidget* TabsContainerWidget; QBoxLayout* TabsLayout; int CurrentIndex = -1; - bool MenuOutdated = true; - QMenu* TabsMenu; /** * Private data constructor @@ -266,7 +264,7 @@ void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab) connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked())); connect(Tab, SIGNAL(moved(const QPoint&)), this, SLOT(onTabWidgetMoved(const QPoint&))); Tab->installEventFilter(this); - d->MenuOutdated = true; + emit tabInserted(Index); if (Index <= d->CurrentIndex) { setCurrentIndex(d->CurrentIndex++); @@ -320,10 +318,10 @@ void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab) } } + emit removingTab(RemoveIndex); d->TabsLayout->removeWidget(Tab); Tab->disconnect(this); Tab->removeEventFilter(this); - d->MenuOutdated = true; qDebug() << "NewCurrentIndex " << NewCurrentIndex; if (NewCurrentIndex != d->CurrentIndex) { @@ -448,7 +446,14 @@ void CDockAreaTabBar::closeTab(int Index) { return; } + + auto Tab = tab(Index); + if (!Tab->isVisibleTo(this)) + { + return; + } emit tabCloseRequested(Index); + Tab->hide(); } @@ -456,20 +461,40 @@ void CDockAreaTabBar::closeTab(int Index) bool CDockAreaTabBar::eventFilter(QObject *watched, QEvent *event) { bool Result = Super::eventFilter(watched, event); - if (event->type() != QEvent::Hide) - { - return Result; - } - CDockWidgetTab* Tab = qobject_cast(watched); if (!Tab) { return Result; } - qDebug() << "Hide event for tab " << Tab->text(); + if (event->type() == QEvent::Hide) + { + return Result; + } + + int TabIndex = d->TabsLayout->indexOf(Tab); + switch (event->type()) + { + case QEvent::Hide: emit tabClosed(TabIndex); break; + case QEvent::Show: emit tabOpened(TabIndex); break; + default: + break; + } + return Result; } + + +//=========================================================================== +bool CDockAreaTabBar::isTabOpen(int Index) const +{ + if (Index < 0 || Index >= count()) + { + return false; + } + + return tab(Index)->isVisibleTo(this); +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockAreaTabBar.h b/src/DockAreaTabBar.h index cb73e6b..bcb0628 100644 --- a/src/DockAreaTabBar.h +++ b/src/DockAreaTabBar.h @@ -111,6 +111,13 @@ public: */ virtual bool eventFilter(QObject *watched, QEvent *event) override; + /** + * This function returns true if the tab is open, that means if it is + * visible to the user. If the function returns false, the tab is + * closed + */ + bool isTabOpen(int Index) const; + public slots: /** * This property sets the index of the tab bar's visible tab @@ -147,11 +154,33 @@ signals: */ void tabCloseRequested(int index); + /** + * This signal is emitted if a tab has been closed + */ + void tabClosed(int index); + + /** + * This signal is emitted if a tab has been opened. + * A tab is opened if it has been made visible + */ + void tabOpened(int index); + /** * This signal is emitted when the tab has moved the tab at index position * from to index position to. */ void tabMoved(int from, int to); + + /** + * This signal is emitted, just before the tab with the given index is + * removed + */ + void removingTab(int index); + + /** + * This signal is emitted if a tab has been inserted + */ + void tabInserted(int index); }; // class CDockAreaTabBar } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp new file mode 100644 index 0000000..62a89c9 --- /dev/null +++ b/src/DockAreaTitleBar.cpp @@ -0,0 +1,199 @@ +//============================================================================ +/// \file DockAreaTitleBar.cpp +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Implementation of CDockAreaTitleBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockAreaTitleBar.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "FloatingDockContainer.h" +#include "DockAreaWidget.h" +#include "DockOverlay.h" +#include "DockManager.h" +#include "DockWidget.h" +#include "DockWidgetTab.h" +#include "DockAreaTabBar.h" + +#include + +namespace ads +{ +/** + * Private data class of CDockAreaTitleBar class (pimpl) + */ +struct DockAreaTitleBarPrivate +{ + CDockAreaTitleBar* _this; + QPushButton* TabsMenuButton; + QPushButton* CloseButton; + QBoxLayout* TopLayout; + CDockAreaWidget* DockArea; + CDockAreaTabBar* TabBar; + bool MenuOutdated = true; + QMenu* TabsMenu; + + /** + * Private data constructor + */ + DockAreaTitleBarPrivate(CDockAreaTitleBar* _public); + + /** + * Creates the title bar close and menu buttons + */ + void createButtons(); + + /** + * Creates the internal TabBar + */ + void createTabBar(); +};// struct DockAreaTitleBarPrivate + + + +//============================================================================ +DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) : + _this(_public) +{ + +} + + +//============================================================================ +void DockAreaTitleBarPrivate::createButtons() +{ + TabsMenuButton = new QPushButton(); + TabsMenuButton->setObjectName("tabsMenuButton"); + TabsMenuButton->setFlat(true); + TabsMenuButton->setIcon(_this->style()->standardIcon(QStyle::SP_TitleBarUnshadeButton)); + TabsMenuButton->setMaximumWidth(TabsMenuButton->iconSize().width()); + + QMenu* TabsMenu = new QMenu(TabsMenuButton); + _this->connect(TabsMenu, SIGNAL(aboutToShow()), SLOT(onTabsMenuAboutToShow())); + TabsMenuButton->setMenu(TabsMenu); + TopLayout->addWidget(TabsMenuButton, 0); + TabsMenuButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + _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(QObject::tr("Close")); + CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + TopLayout->addWidget(CloseButton, 0); + _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); +} + + +//============================================================================ +void DockAreaTitleBarPrivate::createTabBar() +{ + TabBar = new CDockAreaTabBar(DockArea); + TopLayout->addWidget(TabBar); + _this->connect(TabBar, SIGNAL(tabClosed()), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabOpened()), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabInserted()), SLOT(markTabsMenuOutdated())); + _this->connect(TabBar, SIGNAL(tabRemoved()), SLOT(markTabsMenuOutdated())); +} + + +//============================================================================ +CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) : + QFrame(parent), + d(new DockAreaTitleBarPrivate(this)) +{ + d->DockArea = parent; + + setObjectName("dockAreaTitleBar"); + d->TopLayout = new QBoxLayout(QBoxLayout::LeftToRight); + d->TopLayout->setContentsMargins(0, 0, 0, 0); + d->TopLayout->setSpacing(0); + setLayout(d->TopLayout); + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + + d->createTabBar(); + d->createButtons(); + +} + + +//============================================================================ +CDockAreaTitleBar::~CDockAreaTitleBar() +{ + delete d; +} + + +//============================================================================ +CDockAreaTabBar* CDockAreaTitleBar::tabBar() const +{ + return d->TabBar; +} + + +//============================================================================ +void CDockAreaTitleBar::markTabsMenuOutdated() +{ + qDebug() << "CDockAreaTitleBar::markTabsMenuOutdated()"; + d->MenuOutdated = true; +} + + +//============================================================================ +void CDockAreaTitleBar::onTabsMenuAboutToShow() +{ + if (!d->MenuOutdated) + { + return; + } + + QMenu* menu = d->TabsMenuButton->menu(); + menu->clear(); + for (int i = 0; i < d->TabBar->count(); ++i) + { + if (!d->TabBar->isTabOpen(i)) + { + continue; + } + auto Tab = d->TabBar->tab(i); + QAction* Action = menu->addAction(Tab->icon(), Tab->text()); + Action->setData(i); + } + + d->MenuOutdated = false; +} + + +//============================================================================ +void CDockAreaTitleBar::onCloseButtonClicked() +{ + qDebug() << "CDockAreaTitleBar::onCloseButtonClicked"; + d->TabBar->closeTab(d->TabBar->currentIndex()); +} + + +//============================================================================ +void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action) +{ + int Index = Action->data().toInt(); + d->TabBar->setCurrentIndex(Index); +} + + +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF DockAreaTitleBar.cpp diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h new file mode 100644 index 0000000..1b15956 --- /dev/null +++ b/src/DockAreaTitleBar.h @@ -0,0 +1,57 @@ +#ifndef DockAreaTitleBarH +#define DockAreaTitleBarH +//============================================================================ +/// \file DockAreaTitleBar.h +/// \author Uwe Kindler +/// \date 12.10.2018 +/// \brief Declaration of CDockAreaTitleBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ +class CDockAreaTabBar; +class CDockAreaWidget; +struct DockAreaTitleBarPrivate; + +/** + * Title bar of a dock area + */ +class CDockAreaTitleBar : public QFrame +{ + Q_OBJECT +private: + DockAreaTitleBarPrivate* d; ///< private data (pimpl) + friend class DockAreaTitleBarPrivate; + +private slots: + void markTabsMenuOutdated(); + void onTabsMenuAboutToShow(); + void onCloseButtonClicked(); + void onTabsMenuActionTriggered(QAction* Action); + +public: + using Super = QFrame; + /** + * Default Constructor + */ + CDockAreaTitleBar(CDockAreaWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CDockAreaTitleBar(); + + /** + * Returns the pointer to the tabBar() + */ + CDockAreaTabBar* tabBar() const; +}; // class name +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // DockAreaTitleBarH diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 7045db3..ef3c52d 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -65,77 +65,8 @@ static const int APPEND = -1; /** - * Default stack area layout - */ -class CStackedDockAreaLayout -{ -private: - QStackedLayout* Layout; - -public: - CStackedDockAreaLayout(QBoxLayout* ParentLayout) - { - Layout = new QStackedLayout(); - Layout->setContentsMargins(0, 0, 0, 0); - Layout->setSpacing(0); - Layout->setSizeConstraint(QLayout::SetNoConstraint); - ParentLayout->addLayout(Layout, 1); - } - - int count() const - { - return Layout->count(); - } - - void insertWidget(int index, QWidget* Widget) - { - Layout->insertWidget(index, Widget); - } - - void removeWidget(QWidget* Widget) - { - Layout->removeWidget(Widget); - } - - void setCurrentIndex(int Index) - { - Layout->setCurrentIndex(Index); - } - - int currentIndex() const - { - return Layout->currentIndex(); - } - - QWidget* currentWidget() const - { - return Layout->currentWidget(); - } - - bool isEmpty() const - { - return Layout->isEmpty(); - } - - int indexOf(QWidget* w) const - { - return Layout->indexOf(w); - } - - QWidget* widget(int index) const - { - return Layout->widget(index); - } - - QRect geometry() const - { - return Layout->geometry(); - } -}; - - -/** - * New dock area layout + * New dock area layout mimics stack layout but ony inserts the current + * widget */ class CDockAreaLayout { @@ -284,7 +215,6 @@ struct DockAreaWidgetPrivate CDockAreaTabBar* TabBar; QPushButton* TabsMenuButton; QPushButton* CloseButton; - //int TabsLayoutInitCount; CDockManager* DockManager = nullptr; bool MenuOutdated = true; diff --git a/src/FloatingDockContainer.h b/src/FloatingDockContainer.h index dd03ec6..aef853e 100644 --- a/src/FloatingDockContainer.h +++ b/src/FloatingDockContainer.h @@ -47,6 +47,8 @@ class CDockManager; class CDockAreaTabBar; class CDockWidgetTab; struct DockWidgetTabPrivate; +class CDockAreaTitleBar; +struct DockAreaTitleBarPrivate; /** * This implements a floating widget that is a dock container that accepts @@ -64,6 +66,8 @@ private: friend class CDockAreaTabBar; friend struct DockWidgetTabPrivate; friend class CDockWidgetTab; + friend class CDockAreaTitleBar; + friend struct DockAreaTitleBarPrivate; private slots: void onDockAreasAddedOrRemoved(); diff --git a/src/src.pro b/src/src.pro index 6033707..e29a73d 100644 --- a/src/src.pro +++ b/src/src.pro @@ -40,7 +40,8 @@ HEADERS += \ DockWidgetTab.h \ FloatingDockContainer.h \ DockOverlay.h \ - DockSplitter.h + DockSplitter.h \ + DockAreaTitleBar.h @@ -54,4 +55,5 @@ SOURCES += \ DockWidgetTab.cpp \ FloatingDockContainer.cpp \ DockOverlay.cpp \ - DockSplitter.cpp + DockSplitter.cpp \ + DockAreaTitleBar.cpp