diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index a3b2e97..cbb3927 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -13,12 +13,16 @@ #include #include #include +#include #include "FloatingDockContainer.h" #include "DockAreaWidget.h" #include "DockOverlay.h" #include "DockManager.h" #include "DockWidget.h" +#include "DockWidgetTab.h" + +#include namespace ads { @@ -31,6 +35,9 @@ struct DockAreaTabBarPrivate QPoint DragStartMousePos; CDockAreaWidget* DockArea; CFloatingDockContainer* FloatingWidget = nullptr; + QWidget* TabsContainerWidget; + QBoxLayout* TabsLayout; + int CurrentIndex = -1; /** * Private data constructor @@ -57,6 +64,16 @@ CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) : setWidgetResizable(true); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + d->TabsContainerWidget = new QWidget(); + d->TabsContainerWidget->setObjectName("tabsContainerWidget"); + setWidget(d->TabsContainerWidget); + + d->TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight); + d->TabsLayout->setContentsMargins(0, 0, 0, 0); + d->TabsLayout->setSpacing(0); + d->TabsLayout->addStretch(1); + d->TabsContainerWidget->setLayout(d->TabsLayout); } //============================================================================ @@ -173,6 +190,113 @@ void CDockAreaTabBar::startFloating(const QPoint& Pos) TopLevelDockWidget->emitTopLevelChanged(true); } } + + +//============================================================================ +void CDockAreaTabBar::setCurrentIndex(int index) +{ + if (index == d->CurrentIndex) + { + return; + } + + if (index < 0 || index > (d->TabsLayout->count() - 1)) + { + qWarning() << Q_FUNC_INFO << "Invalid index" << index; + return; + } + + emit currentChanging(index); + + // 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 TabWidget = dynamic_cast(item->widget()); + if (!TabWidget) + { + continue; + } + + if (i == index) + { + TabWidget->show(); + TabWidget->setActiveTab(true); + ensureWidgetVisible(TabWidget); + } + else + { + TabWidget->setActiveTab(false); + } + } + + d->CurrentIndex = index; + emit currentChanged(index); +} + + +//============================================================================ +int CDockAreaTabBar::count() const +{ + return d->TabsLayout->count(); +} + + +//=========================================================================== +void CDockAreaTabBar::insertTab(int Index, CDockWidgetTab* Tab) +{ + d->TabsLayout->insertWidget(Index, Tab); + connect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked())); +} + + +//=========================================================================== +void CDockAreaTabBar::removeTab(CDockWidgetTab* Tab) +{ + d->TabsLayout->removeWidget(Tab); + disconnect(Tab, SIGNAL(clicked()), this, SLOT(onTabClicked())); +} + + +//=========================================================================== +int CDockAreaTabBar::currentIndex() const +{ + return d->CurrentIndex; +} + + +//=========================================================================== +CDockWidgetTab* CDockAreaTabBar::currentTab() const +{ + return qobject_cast(d->TabsLayout->itemAt(d->CurrentIndex)->widget()); +} + + +//=========================================================================== +void CDockAreaTabBar::onTabClicked() +{ + CDockWidgetTab* Tab = qobject_cast(sender()); + if (!Tab) + { + return; + } + + int index = d->TabsLayout->indexOf(Tab); + setCurrentIndex(index); + std::cout << "emit tabBarClicked " << index << std::endl; + emit tabBarClicked(index); +} + + +void CDockAreaTabBar::closeTabe(int Index) +{ + +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockAreaTabBar.h b/src/DockAreaTabBar.h index ad51043..7f0e21a 100644 --- a/src/DockAreaTabBar.h +++ b/src/DockAreaTabBar.h @@ -15,6 +15,7 @@ namespace ads { class CDockAreaWidget; +class CDockWidgetTab; struct DockAreaTabBarPrivate; /** @@ -29,6 +30,9 @@ private: DockAreaTabBarPrivate* d; ///< private data (pimpl) friend class DockAreaTabBarPrivate; +private slots: + void onTabClicked(); + protected: virtual void wheelEvent(QWheelEvent* Event) override; /** @@ -67,6 +71,61 @@ public: * Virtual Destructor */ virtual ~CDockAreaTabBar(); + + /** + * Inserts the given dock widget tab at the given position + */ + void insertTab(int Index, CDockWidgetTab* Tab); + + /** + * Removes the given DockWidgetTab from the tabbar + */ + void removeTab(CDockWidgetTab* Tab); + + /** + * Returns the number of tabs in this tabbar + */ + int count() const; + + /** + * Returns the current index + */ + int currentIndex() const; + + /** + * Returns the current tab + */ + CDockWidgetTab* currentTab() const; + +public slots: + /** + * This property sets the index of the tab bar's visible tab + */ + void setCurrentIndex(int Index); + + /** + * This function will close the tab given in Index param. + * Closing a tab means, the tab will be hidden, it will not be removed + */ + void closeTabe(int Index); + +signals: + /** + * This signal is emitted when the tab bar's current tab is about to be changed. The new + * current has the given index, or -1 if there isn't a new one. + */ + void currentChanging(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 + */ + void currentChanged(int Index); + + /** + * This signal is emitted when user clicks on a tab at an index. + */ + void tabBarClicked(int index); }; // class CDockAreaTabBar } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index c295c29..291933c 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -42,6 +42,8 @@ #include #include #include +#include + #include "DockContainerWidget.h" #include "DockWidget.h" @@ -51,6 +53,8 @@ #include "DockAreaTabBar.h" #include "DockSplitter.h" +#include + namespace ads { @@ -60,6 +64,210 @@ static const char* const DOCKWIDGET_PROPERTY = "dockwidget"; 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 + */ +class CDockAreaLayout +{ +private: + QBoxLayout* m_ParentLayout; + QList m_Widgets; + int m_CurrentIndex = -1; + QWidget* m_CurrentWidget = nullptr; + +public: + CDockAreaLayout(QBoxLayout* ParentLayout) + : m_ParentLayout(ParentLayout) + { + + } + + int count() const + { + return m_Widgets.count(); + } + + void insertWidget(int index, QWidget* Widget) + { + if (index < 0) + { + index = m_Widgets.count(); + } + m_Widgets.insert(index, Widget); + if (m_CurrentIndex < 0) + { + setCurrentIndex(index); + } + else + { + if (index <= m_CurrentIndex ) + { + ++m_CurrentIndex; + } + } + } + + void removeWidget(QWidget* Widget) + { + if (currentWidget() == Widget) + { + auto LayoutItem = m_ParentLayout->takeAt(1); + if (LayoutItem) + { + LayoutItem->widget()->setParent(0); + } + } + m_Widgets.removeOne(Widget); + //setCurrentIndex(0); + } + + QWidget* currentWidget() const + { + return m_CurrentWidget; + } + + void setCurrentIndex(int index) + { + std::cout << "setCurrentIndex" << std::endl; + QWidget *prev = currentWidget(); + QWidget *next = widget(index); + if (!next || (next == prev && !m_CurrentWidget)) + { + return; + } + + bool reenableUpdates = false; + QWidget *parent = m_ParentLayout->parentWidget(); + + if (parent && parent->updatesEnabled()) + { + reenableUpdates = true; + parent->setUpdatesEnabled(false); + } + + std::cout << "m_ParentLayout->addWidget(next)" << std::endl; + auto LayoutItem = m_ParentLayout->takeAt(1); + if (LayoutItem) + { + LayoutItem->widget()->setParent(0); + } + + m_ParentLayout->addWidget(next); + if (prev) + { + prev->hide(); + } + m_CurrentIndex = index; + m_CurrentWidget = next; + + + if (reenableUpdates) + { + parent->setUpdatesEnabled(true); + } + } + + int currentIndex() const + { + return m_CurrentIndex; + } + + bool isEmpty() const + { + return m_Widgets.empty(); + } + + int indexOf(QWidget* w) const + { + return m_Widgets.indexOf(w); + } + + QWidget* widget(int index) const + { + return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr; + } + + QRect geometry() const + { + return m_Widgets.empty() ? QRect() : currentWidget()->geometry(); + } +}; + + + +using DockAreaLayout = CDockAreaLayout; + + /** * Private data class of CDockAreaWidget class (pimpl) */ @@ -69,13 +277,11 @@ struct DockAreaWidgetPrivate QBoxLayout* Layout; QFrame* TitleBar; QBoxLayout* TopLayout; - QStackedLayout* ContentsLayout; + DockAreaLayout* ContentsLayout; CDockAreaTabBar* TabBar; - QWidget* TabsContainerWidget; - QBoxLayout* TabsLayout; QPushButton* TabsMenuButton; QPushButton* CloseButton; - int TabsLayoutInitCount; + //int TabsLayoutInitCount; CDockManager* DockManager = nullptr; bool MenuOutdated = true; @@ -167,19 +373,11 @@ void DockAreaWidgetPrivate::createTabBar() TopLayout->setSpacing(0); TitleBar->setLayout(TopLayout); Layout->addWidget(TitleBar); + TitleBar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); TabBar = new CDockAreaTabBar(_this); TopLayout->addWidget(TabBar, 1); - - TabsContainerWidget = new QWidget(); - TabsContainerWidget->setObjectName("tabsContainerWidget"); - TabBar->setWidget(TabsContainerWidget); - - TabsLayout = new QBoxLayout(QBoxLayout::LeftToRight); - TabsLayout->setContentsMargins(0, 0, 0, 0); - TabsLayout->setSpacing(0); - TabsLayout->addStretch(1); - TabsContainerWidget->setLayout(TabsLayout); + _this->connect(TabBar, SIGNAL(tabBarClicked(int)), SLOT(setCurrentIndex(int))); TabsMenuButton = new QPushButton(); TabsMenuButton->setObjectName("tabsMenuButton"); @@ -202,8 +400,6 @@ void DockAreaWidgetPrivate::createTabBar() CloseButton->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); TopLayout->addWidget(CloseButton, 0); _this->connect(CloseButton, SIGNAL(clicked()), SLOT(onCloseButtonClicked())); - - TabsLayoutInitCount = TabsLayout->count(); } @@ -283,18 +479,14 @@ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget setLayout(d->Layout); d->createTabBar(); - - d->ContentsLayout = new QStackedLayout(); - d->ContentsLayout->setContentsMargins(0, 0, 0, 0); - d->ContentsLayout->setSpacing(0); - d->ContentsLayout->setSizeConstraint(QLayout::SetNoConstraint); - d->Layout->addLayout(d->ContentsLayout, 1); + d->ContentsLayout = new DockAreaLayout(d->Layout); } //============================================================================ CDockAreaWidget::~CDockAreaWidget() { qDebug() << "~CDockAreaWidget()"; + delete d->ContentsLayout; delete d; } @@ -309,18 +501,7 @@ CDockManager* CDockAreaWidget::dockManager() const //============================================================================ CDockContainerWidget* CDockAreaWidget::dockContainer() const { - QWidget* Parent = parentWidget(); - while (Parent) - { - CDockContainerWidget* Container = dynamic_cast(Parent); - if (Container) - { - return Container; - } - Parent = Parent->parentWidget(); - } - - return 0; + return internal::findParent(this); } @@ -338,10 +519,10 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, d->ContentsLayout->insertWidget(index, DockWidget); DockWidget->tabWidget()->setDockAreaWidget(this); auto TabWidget = DockWidget->tabWidget(); - d->TabsLayout->insertWidget(index, TabWidget); + d->TabBar->insertTab(index, TabWidget); TabWidget->setVisible(!DockWidget->isClosed()); - connect(TabWidget, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); DockWidget->setProperty(INDEX_PROPERTY, index); + d->markTabsMenuOutdated(); if (Activate) { setCurrentIndex(index); @@ -359,8 +540,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) d->ContentsLayout->removeWidget(DockWidget); auto TabWidget = DockWidget->tabWidget(); TabWidget->hide(); - d->TabsLayout->removeWidget(TabWidget); - disconnect(TabWidget, SIGNAL(clicked()), this, SLOT(onDockWidgetTitleClicked())); + d->TabBar->removeTab(TabWidget); if (NextOpenDockWidget) { setCurrentDockWidget(NextOpenDockWidget); @@ -426,20 +606,6 @@ void CDockAreaWidget::hideAreaIfNoVisibleContent() } -//============================================================================ -void CDockAreaWidget::onDockWidgetTitleClicked() -{ - CDockWidgetTab* TitleWidget = qobject_cast(sender()); - if (!TitleWidget) - { - return; - } - - int index = d->TabsLayout->indexOf(TitleWidget); - setCurrentIndex(index); -} - - //============================================================================ void CDockAreaWidget::onCloseButtonClicked() { @@ -469,45 +635,22 @@ void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget) //============================================================================ void CDockAreaWidget::setCurrentIndex(int index) { - if (index < 0 || index > (d->TabsLayout->count() - 1)) + if (index < 0 || index > (d->TabBar->count() - 1)) { qWarning() << Q_FUNC_INFO << "Invalid index" << index; return; } emit currentChanging(index); + d->TabBar->setCurrentIndex(index); + auto Features = d->TabBar->currentTab()->dockWidget()->features(); + d->CloseButton->setVisible(Features.testFlag(CDockWidget::DockWidgetClosable)); - // Set active TAB and update all other tabs to be inactive - for (int i = 0; i < d->TabsLayout->count(); ++i) + if (!dockManager()->isRestoringState()) { - 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->TabBar->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(); } - - d->ContentsLayout->setCurrentIndex(index); - d->ContentsLayout->currentWidget()->show(); emit currentChanged(index); } @@ -618,7 +761,7 @@ void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex) { qDebug() << "Invalid index for tab movement" << fromIndex << toIndex; - d->TabsLayout->update(); + //d->TabsLayout->update(); return; } @@ -639,11 +782,14 @@ void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) // 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; + /*liFrom = d->TabsLayout->takeAt(fromIndex); + d->TabsLayout->insertItem(toIndex, liFrom);*/ + //liFrom = d->ContentsLayout->takeAt(fromIndex); + //d->ContentsLayout->insertWidget(toIndex, liFrom->widget()); + auto Widget = d->ContentsLayout->widget(fromIndex); + d->ContentsLayout->removeWidget(Widget); + d->ContentsLayout->insertWidget(toIndex, Widget); + //delete liFrom; } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 2234365..0c41caf 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -63,7 +63,6 @@ private: friend class CDockWidget; private slots: - void onDockWidgetTitleClicked(); void onTabsMenuActionTriggered(QAction* Action); void onCloseButtonClicked(); void onTabsMenuAboutToShow(); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index fbb31ef..7071464 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -47,6 +47,9 @@ #include "ads_globals.h" #include "DockSplitter.h" +#include +#include + namespace ads { @@ -936,6 +939,9 @@ int CDockContainerWidget::visibleDockAreaCount() const void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWidget, const QPoint& TargetPos) { + QElapsedTimer Timer; + Timer.start(); + qDebug() << "CDockContainerWidget::dropFloatingWidget"; CDockAreaWidget* DockArea = dockAreaAt(TargetPos); auto dropArea = InvalidDockWidgetArea; @@ -977,6 +983,9 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi { TopLevelDockWidget->emitTopLevelChanged(false); } + + std::cout << "CDockContainerWidget::dropFloatingWidget " << + Timer.restart() << std::endl; } diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 2796bbf..9b964ba 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -33,7 +33,6 @@ #include - #include #include #include @@ -53,6 +52,8 @@ #include "DockStateSerialization.h" #include "DockAreaWidget.h" +#include +#include namespace ads { @@ -448,6 +449,9 @@ QByteArray CDockManager::saveState(eXmlMode XmlMode, int version) const //============================================================================ bool CDockManager::restoreState(const QByteArray &state, int version) { + QElapsedTimer Timer; + Timer.start(); + // Prevent multiple calls as long as state is not restore. This may // happen, if QApplication::processEvents() is called somewhere if (d->RestoringState) @@ -478,6 +482,7 @@ bool CDockManager::restoreState(const QByteArray &state, int version) show(); } + std::cout << "CDockManager::restoreState " << Timer.restart() << std::endl; return Result; } @@ -635,6 +640,13 @@ void CDockManager::setViewMenuInsertionOrder(eViewMenuInsertionOrder Order) d->MenuInsertionOrder = Order; } + +//=========================================================================== +bool CDockManager::isRestoringState() const +{ + return d->RestoringState; +} + } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockManager.h b/src/DockManager.h index e3e5fb3..22a26f0 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -264,6 +264,12 @@ public: */ void setViewMenuInsertionOrder(eViewMenuInsertionOrder Order); + /** + * This function returns true between the restoringState() and + * stateRestored() signals. + */ + bool isRestoringState() const; + public slots: /** * Opens the perspective with the given name. diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 2c8b880..50d61c1 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -327,7 +327,7 @@ void CDockWidget::setDockManager(CDockManager* DockManager) //============================================================================ CDockContainerWidget* CDockWidget::dockContainer() const { - return internal::findParent(this); + return d->DockArea->dockContainer(); } diff --git a/src/ads_globals.h b/src/ads_globals.h index 127a469..128fdb7 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -104,7 +104,7 @@ T findParent(const QWidget* w) QWidget* parentWidget = w->parentWidget(); while (parentWidget) { - T ParentImpl = dynamic_cast(parentWidget); + T ParentImpl = qobject_cast(parentWidget); if (ParentImpl) { return ParentImpl;