/******************************************************************************* ** Qt Advanced Docking System ** Copyright (C) 2017 Uwe Kindler ** ** This library is free software; you can redistribute it and/or ** modify it under the terms of the GNU Lesser General Public ** License as published by the Free Software Foundation; either ** version 2.1 of the License, or (at your option) any later version. ** ** This library 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 ** Lesser General Public License for more details. ** ** You should have received a copy of the GNU Lesser General Public ** License along with this library; If not, see . ******************************************************************************/ //============================================================================ /// \file DockAreaWidget.cpp /// \author Uwe Kindler /// \date 24.02.2017 /// \brief Implementation of CDockAreaWidget class //============================================================================ //============================================================================ // INCLUDES //============================================================================ #include #include "DockAreaWidget.h" #include #include #include #include #include #include #include #include #include #include "ElidingLabel.h" #include "DockContainerWidget.h" #include "DockWidget.h" #include "FloatingDockContainer.h" #include "DockManager.h" #include "DockOverlay.h" #include "DockAreaTabBar.h" #include "DockSplitter.h" #include "DockAreaTitleBar.h" #include "DockComponentsFactory.h" #include "DockWidgetTab.h" #include "DockWidgetSideTab.h" namespace ads { static const char* const INDEX_PROPERTY = "index"; static const char* const ACTION_PROPERTY = "action"; /** * Internal dock area layout mimics stack layout but only inserts the current * widget into the internal QLayout object. * \warning Only the current widget has a parent. All other widgets * do not have a parent. That means, a widget that is in this layout may * return nullptr for its parent() function if it is not the current widget. */ class CDockAreaLayout { private: QBoxLayout* m_ParentLayout; QList m_Widgets; int m_CurrentIndex = -1; QWidget* m_CurrentWidget = nullptr; public: /** * Creates an instance with the given parent layout */ CDockAreaLayout(QBoxLayout* ParentLayout) : m_ParentLayout(ParentLayout) { } /** * Returns the number of widgets in this layout */ int count() const { return m_Widgets.count(); } /** * Inserts the widget at the given index position into the internal widget * list */ void insertWidget(int index, QWidget* Widget) { Widget->setParent(nullptr); 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; } } } /** * Removes the given widget from the layout */ void removeWidget(QWidget* Widget) { if (currentWidget() == Widget) { auto LayoutItem = m_ParentLayout->takeAt(1); if (LayoutItem) { LayoutItem->widget()->setParent(nullptr); } m_CurrentWidget = nullptr; m_CurrentIndex = -1; } else if (indexOf(Widget) < m_CurrentIndex) { --m_CurrentIndex; } m_Widgets.removeOne(Widget); } /** * Returns the current selected widget */ QWidget* currentWidget() const { return m_CurrentWidget; } /** * Activates the widget with the give index. */ void setCurrentIndex(int index) { 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); } auto LayoutItem = m_ParentLayout->takeAt(1); if (LayoutItem) { LayoutItem->widget()->setParent(nullptr); } delete LayoutItem; m_ParentLayout->addWidget(next); if (prev) { prev->hide(); } m_CurrentIndex = index; m_CurrentWidget = next; if (reenableUpdates) { parent->setUpdatesEnabled(true); } } /** * Returns the index of the current active widget */ int currentIndex() const { return m_CurrentIndex; } /** * Returns true if there are no widgets in the layout */ bool isEmpty() const { return m_Widgets.empty(); } /** * Returns the index of the given widget */ int indexOf(QWidget* w) const { return m_Widgets.indexOf(w); } /** * Returns the widget for the given index */ QWidget* widget(int index) const { return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr; } /** * Returns the geometry of the current active widget */ QRect geometry() const { return m_Widgets.empty() ? QRect() : currentWidget()->geometry(); } }; using DockAreaLayout = CDockAreaLayout; static const DockWidgetAreas DefaultAllowedAreas = AllDockAreas; /** * Private data class of CDockAreaWidget class (pimpl) */ struct DockAreaWidgetPrivate { CDockAreaWidget* _this = nullptr; QBoxLayout* Layout = nullptr; DockAreaLayout* ContentsLayout = nullptr; CDockAreaTitleBar* TitleBar = nullptr; CDockManager* DockManager = nullptr; CAutoHideDockContainer* AutoHideDockContainer = nullptr; bool UpdateTitleBarButtons = false; DockWidgetAreas AllowedAreas = DefaultAllowedAreas; QSize MinSizeHint; CDockAreaWidget::DockAreaFlags Flags{CDockAreaWidget::DefaultFlags}; /** * Private data constructor */ DockAreaWidgetPrivate(CDockAreaWidget* _public); /** * Creates the layout for top area with tabs and close button */ void createTitleBar(); /** * Returns the dock widget with the given index */ CDockWidget* dockWidgetAt(int index) { return qobject_cast(ContentsLayout->widget(index)); } /** * Convenience function to ease title widget access by index */ CDockWidgetTab* tabWidgetAt(int index) { return dockWidgetAt(index)->tabWidget(); } /** * 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(); } /** * Convenience function for tabbar access */ CDockAreaTabBar* tabBar() const { return TitleBar->tabBar(); } /** * Udpates the enable state of the close and detach button */ void updateTitleBarButtonStates(); /** * Udpates the enable state of the close and detach button */ void updateTitleBarButtonVisibility(bool isTopLevel); /** * Convenience function to know if all dock widgets are focusable */ bool allDockWidgetsFocusable() const; /** * Scans all contained dock widgets for the max. minimum size hint */ void updateMinimumSizeHint() { MinSizeHint = QSize(); for (int i = 0; i < ContentsLayout->count(); ++i) { auto Widget = ContentsLayout->widget(i); MinSizeHint.setHeight(qMax(MinSizeHint.height(), Widget->minimumSizeHint().height())); MinSizeHint.setWidth(qMax(MinSizeHint.width(), Widget->minimumSizeHint().width())); } } }; //============================================================================ DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) : _this(_public) { } //============================================================================ void DockAreaWidgetPrivate::createTitleBar() { TitleBar = componentsFactory()->createDockAreaTitleBar(_this); Layout->addWidget(TitleBar); QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested); QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex); QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget); } //============================================================================ void DockAreaWidgetPrivate::updateTitleBarButtonStates() { if (_this->isHidden()) { UpdateTitleBarButtons = true; return; } TitleBar->button(TitleBarButtonClose)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetClosable)); TitleBar->button(TitleBarButtonUndock)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetFloatable)); TitleBar->button(TitleBarButtonAutoHide)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetPinnable)); TitleBar->updateDockWidgetActionsButtons(); UpdateTitleBarButtons = false; } //============================================================================ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) { auto *const container = _this->dockContainer(); if (!container) { return; } if (IsTopLevel) { TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating() && allDockWidgetsFocusable()); // Undock and tabs should never show when auto hidden TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isAutoHide()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide()); } else { TitleBar->button(TitleBarButtonClose)->setVisible(true); TitleBar->button(TitleBarButtonAutoHide)->setVisible(allDockWidgetsFocusable()); TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isAutoHide()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide()); } } bool DockAreaWidgetPrivate::allDockWidgetsFocusable() const { for (const auto &dockWidget : _this->dockWidgets()) { if (!dockWidget->features().testFlag(CDockWidget::DockWidgetFocusable)) { return false; } } return true; } //============================================================================ 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->createTitleBar(); d->ContentsLayout = new DockAreaLayout(d->Layout); if (d->DockManager) { Q_EMIT d->DockManager->dockAreaCreated(this); } } //============================================================================ CDockAreaWidget::~CDockAreaWidget() { ADS_PRINT("~CDockAreaWidget()"); delete d->ContentsLayout; delete d; } //============================================================================ CDockManager* CDockAreaWidget::dockManager() const { return d->DockManager; } //============================================================================ CDockContainerWidget* CDockAreaWidget::dockContainer() const { return internal::findParent(this); } //============================================================================ CAutoHideDockContainer* CDockAreaWidget::autoHideDockContainer() const { return d->AutoHideDockContainer; } //============================================================================ bool CDockAreaWidget::isAutoHide() const { return d->AutoHideDockContainer != nullptr; } //============================================================================ void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer) { d->AutoHideDockContainer = AutoHideDockContainer; } //============================================================================ 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->setDockArea(this); DockWidget->tabWidget()->setDockAreaWidget(this); auto TabWidget = DockWidget->tabWidget(); // Inserting the tab will change the current index which in turn will // make the tab widget visible in the slot d->tabBar()->blockSignals(true); d->tabBar()->insertTab(index, TabWidget); d->tabBar()->blockSignals(false); TabWidget->setVisible(!DockWidget->isClosed()); d->TitleBar->autoHideTitleLabel()->setText(DockWidget->windowTitle()); DockWidget->setProperty(INDEX_PROPERTY, index); d->MinSizeHint.setHeight(qMax(d->MinSizeHint.height(), DockWidget->minimumSizeHint().height())); d->MinSizeHint.setWidth(qMax(d->MinSizeHint.width(), DockWidget->minimumSizeHint().width())); if (Activate) { setCurrentIndex(index); DockWidget->setClosedState(false); // Set current index can show the widget without changing the close state, added to keep the close state consistent } // If this dock area is hidden, then we need to make it visible again // by calling DockWidget->toggleViewInternal(true); if (!this->isVisible() && d->ContentsLayout->count() > 1 && !dockManager()->isRestoringState()) { DockWidget->toggleViewInternal(true); } d->updateTitleBarButtonStates(); updateTitleBarVisibility(); } //============================================================================ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { ADS_PRINT("CDockAreaWidget::removeDockWidget"); auto CurrentDockWidget = currentDockWidget(); auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr; d->ContentsLayout->removeWidget(DockWidget); auto TabWidget = DockWidget->tabWidget(); TabWidget->hide(); d->tabBar()->removeTab(TabWidget); TabWidget->setParent(DockWidget); DockWidget->setDockArea(nullptr); CDockContainerWidget* DockContainer = dockContainer(); if (NextOpenDockWidget) { setCurrentDockWidget(NextOpenDockWidget); } else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1 && !isAutoHide()) // Don't remove empty dock areas that are auto hidden, they'll be deleted by the auto hide dock { ADS_PRINT("Dock Area empty"); DockContainer->removeDockArea(this); this->deleteLater(); if(DockContainer->dockAreaCount() == 0) { if(CFloatingDockContainer* FloatingDockContainer = DockContainer->floatingWidget()) { FloatingDockContainer->hide(); FloatingDockContainer->deleteLater(); } } } else if (DockWidget == CurrentDockWidget) { // if contents layout is not empty but there are no more open dock // widgets, then we need to hide the dock area because it does not // contain any visible content hideAreaWithNoVisibleContent(); } d->updateTitleBarButtonStates(); updateTitleBarVisibility(); d->updateMinimumSizeHint(); auto TopLevelDockWidget = DockContainer->topLevelDockWidget(); if (TopLevelDockWidget) { TopLevelDockWidget->emitTopLevelChanged(true); } #if (ADS_DEBUG_LEVEL > 0) DockContainer->dumpLayout(); #endif } //============================================================================ void CDockAreaWidget::hideAreaWithNoVisibleContent() { this->toggleView(false); // Hide empty parent splitters auto Splitter = internal::findParent(this); internal::hideEmptyParentSplitters(Splitter); //Hide empty floating widget CDockContainerWidget* Container = this->dockContainer(); if (!Container->isFloating() && !CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)) { return; } updateTitleBarVisibility(); auto TopLevelWidget = Container->topLevelDockWidget(); auto FloatingWidget = Container->floatingWidget(); if (TopLevelWidget) { if (FloatingWidget) { FloatingWidget->updateWindowTitle(); } CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); } else if (Container->openedDockAreas().isEmpty() && FloatingWidget) { FloatingWidget->hide(); } if (isAutoHide()) { autoHideDockContainer()->hide(); } } //============================================================================ void CDockAreaWidget::onTabCloseRequested(int Index) { ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index); auto* DockWidget = dockWidget(Index); if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) || DockWidget->features().testFlag(CDockWidget::CustomCloseHandling)) { DockWidget->closeDockWidgetInternal(); } else { DockWidget->toggleView(false); } } //============================================================================ CDockWidget* CDockAreaWidget::currentDockWidget() const { int CurrentIndex = currentIndex(); if (CurrentIndex < 0) { return nullptr; } return dockWidget(CurrentIndex); } //============================================================================ void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget) { if (dockManager()->isRestoringState()) { return; } internalSetCurrentDockWidget(DockWidget); } //============================================================================ void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget) { int Index = index(DockWidget); if (Index < 0) { return; } setCurrentIndex(Index); DockWidget->setClosedState(false); // Set current index can show the widget without changing the close state, added to keep the close state consistent } //============================================================================ void CDockAreaWidget::setCurrentIndex(int index) { auto TabBar = d->tabBar(); if (index < 0 || index > (TabBar->count() - 1)) { qWarning() << Q_FUNC_INFO << "Invalid index" << index; return; } auto cw = d->ContentsLayout->currentWidget(); auto nw = d->ContentsLayout->widget(index); if (cw == nw && !nw->isHidden()) { return; } Q_EMIT currentChanging(index); TabBar->setCurrentIndex(index); d->ContentsLayout->setCurrentIndex(index); d->ContentsLayout->currentWidget()->show(); Q_EMIT currentChanged(index); } //============================================================================ int CDockAreaWidget::currentIndex() const { return d->ContentsLayout->currentIndex(); } //============================================================================ QRect CDockAreaWidget::titleBarGeometry() const { return d->TitleBar->geometry(); } //============================================================================ QRect CDockAreaWidget::contentAreaGeometry() const { return d->ContentsLayout->geometry(); } //============================================================================ int CDockAreaWidget::index(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; } //============================================================================ int CDockAreaWidget::openDockWidgetsCount() const { int Count = 0; for (int i = 0; i < d->ContentsLayout->count(); ++i) { if (!dockWidget(i)->isClosed()) { ++Count; } } return Count; } //============================================================================ 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::indexOfFirstOpenDockWidget() const { for (int i = 0; i < d->ContentsLayout->count(); ++i) { if (!dockWidget(i)->isClosed()) { return i; } } return -1; } //============================================================================ int CDockAreaWidget::dockWidgetsCount() const { return d->ContentsLayout->count(); } //============================================================================ CDockWidget* CDockAreaWidget::dockWidget(int Index) const { return qobject_cast(d->ContentsLayout->widget(Index)); } //============================================================================ void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex) { ADS_PRINT("CDockAreaWidget::reorderDockWidget"); if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0 || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex) { ADS_PRINT("Invalid index for tab movement" << fromIndex << toIndex); return; } auto Widget = d->ContentsLayout->widget(fromIndex); d->ContentsLayout->removeWidget(Widget); d->ContentsLayout->insertWidget(toIndex, Widget); setCurrentIndex(toIndex); } //============================================================================ void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open) { Q_UNUSED(DockWidget); Q_UNUSED(Open); updateTitleBarVisibility(); } //============================================================================ void CDockAreaWidget::updateTitleBarVisibility() { CDockContainerWidget* Container = dockContainer(); if (!Container) { return; } if (CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs)) { return; } if (d->TitleBar) { bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); d->TitleBar->setVisible(isAutoHide() ? true : !Hidden); // Titlebar must always be visible when auto hidden so it can be dragged auto tabBar = d->TitleBar->tabBar(); tabBar->setVisible(isAutoHide() ? false : !Hidden); // Never show tab bar when auto hidden d->TitleBar->autoHideTitleLabel()->setVisible(CDockManager::testConfigFlag(CDockManager::AutoHideDockAreaHasTitle) && isAutoHide()); // Always show when auto hidden, never otherwise updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); } } //============================================================================ void CDockAreaWidget::markTitleBarMenuOutdated() { if (d->TitleBar) { d->TitleBar->markTabsMenuOutdated(); } } //============================================================================ void CDockAreaWidget::updateAutoHideButtonCheckState() { auto autoHideButton = titleBarButton(TitleBarButtonAutoHide); autoHideButton->blockSignals(true); autoHideButton->setChecked(isAutoHide()); autoHideButton->blockSignals(false); } //============================================================================ void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const { d->updateTitleBarButtonVisibility(IsTopLevel); } //============================================================================ void CDockAreaWidget::updateTitleBarButtonToolTip() { internal::setToolTip(titleBarButton(TitleBarButtonClose), titleBar()->closeGroupToolTip()); } //============================================================================ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const { s.writeStartElement("Area"); s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count())); auto CurrentDockWidget = currentDockWidget(); QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : ""; s.writeAttribute("Current", Name); // To keep the saved XML data small, we only save the allowed areas and the // dock area flags if the values are different from the default values if (isAutoHide()) { autoHideDockContainer()->saveState(s); } if (d->AllowedAreas != DefaultAllowedAreas) { s.writeAttribute("AllowedAreas", QString::number(d->AllowedAreas, 16)); } if (d->Flags != DefaultFlags) { s.writeAttribute("Flags", QString::number(d->Flags, 16)); } ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count() << " Current: " << Name); for (int i = 0; i < d->ContentsLayout->count(); ++i) { dockWidget(i)->saveState(s); } s.writeEndElement(); } //============================================================================ CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const { auto OpenDockWidgets = openedDockWidgets(); if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget)) { if (OpenDockWidgets.last() == DockWidget) { CDockWidget* NextDockWidget = OpenDockWidgets[OpenDockWidgets.count() - 2]; // search backwards for widget with tab for (int i = OpenDockWidgets.count() - 2; i >= 0; --i) { auto dw = OpenDockWidgets[i]; if (!dw->features().testFlag(CDockWidget::NoTab)) { return dw; } } // return widget without tab return NextDockWidget; } else { int IndexOfDockWidget = OpenDockWidgets.indexOf(DockWidget); CDockWidget* NextDockWidget = OpenDockWidgets[IndexOfDockWidget + 1]; // search forwards for widget with tab for (int i = IndexOfDockWidget + 1; i < OpenDockWidgets.count(); ++i) { auto dw = OpenDockWidgets[i]; if (!dw->features().testFlag(CDockWidget::NoTab)) { return dw; } } // search backwards for widget with tab for (int i = IndexOfDockWidget - 1; i >= 0; --i) { auto dw = OpenDockWidgets[i]; if (!dw->features().testFlag(CDockWidget::NoTab)) { return dw; } } // return widget without tab return NextDockWidget; } } else { return nullptr; } } //============================================================================ CDockWidget::DockWidgetFeatures CDockAreaWidget::features(eBitwiseOperator Mode) const { if (BitwiseAnd == Mode) { CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures); for (const auto DockWidget : dockWidgets()) { Features &= DockWidget->features(); } return Features; } else { CDockWidget::DockWidgetFeatures Features(CDockWidget::NoDockWidgetFeatures); for (const auto DockWidget : dockWidgets()) { Features |= DockWidget->features(); } return Features; } } //============================================================================ void CDockAreaWidget::toggleView(bool Open) { setVisible(Open); Q_EMIT viewToggled(Open); } //============================================================================ void CDockAreaWidget::setVisible(bool Visible) { Super::setVisible(Visible); if (d->UpdateTitleBarButtons) { d->updateTitleBarButtonStates(); } } //============================================================================ void CDockAreaWidget::setAllowedAreas(DockWidgetAreas areas) { d->AllowedAreas = areas; } //============================================================================ DockWidgetAreas CDockAreaWidget::allowedAreas() const { return d->AllowedAreas; } //============================================================================ CDockAreaWidget::DockAreaFlags CDockAreaWidget::dockAreaFlags() const { return d->Flags; } //============================================================================ void CDockAreaWidget::setDockAreaFlags(DockAreaFlags Flags) { auto ChangedFlags = d->Flags ^ Flags; d->Flags = Flags; if (ChangedFlags.testFlag(HideSingleWidgetTitleBar)) { updateTitleBarVisibility(); } } //============================================================================ void CDockAreaWidget::setDockAreaFlag(eDockAreaFlag Flag, bool On) { auto flags = dockAreaFlags(); internal::setFlag(flags, Flag, On); setDockAreaFlags(flags); } //============================================================================ QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const { return d->TitleBar->button(which); } //============================================================================ void CDockAreaWidget::closeArea() { // If there is only one single dock widget and this widget has the // DeleteOnClose feature or CustomCloseHandling, then we delete the dock widget now; // in the case of CustomCloseHandling, the CDockWidget class will emit its // closeRequested signal and not actually delete unless the signal is handled in a way that deletes it auto OpenDockWidgets = openedDockWidgets(); if (OpenDockWidgets.count() == 1 && (OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) || OpenDockWidgets[0]->features().testFlag(CDockWidget::CustomCloseHandling)) && !isAutoHide()) { OpenDockWidgets[0]->closeDockWidgetInternal(); } else { for (auto DockWidget : openedDockWidgets()) { if ((DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea)) || DockWidget->features().testFlag(CDockWidget::CustomCloseHandling)) { DockWidget->closeDockWidgetInternal(); } else if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && isAutoHide()) { DockWidget->closeDockWidgetInternal(); } else { DockWidget->toggleView(false); } } } } //============================================================================ void CDockAreaWidget::toggleAutoHideArea(bool Enable) { const auto area = dockContainer()->calculateSideTabBarArea(this); if (dockManager()->testConfigFlag(CDockManager::AutoHideButtonTogglesArea)) { for (const auto DockWidget : openedDockWidgets()) { if (Enable == isAutoHide()) { continue; } onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); } } else { const auto DockWidget = currentDockWidget(); if (Enable == isAutoHide()) { return; } onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); } } //============================================================================ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, CDockWidgetSideTab::SideTabBarArea area) { if (Enable) { dockContainer()->createAndInitializeAutoHideDockWidgetContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); } else { autoHideDockContainer()->moveContentsToParent(); } } //============================================================================ void CDockAreaWidget::closeOtherAreas() { dockContainer()->closeOtherAreas(this); } //============================================================================ CDockAreaTitleBar* CDockAreaWidget::titleBar() const { return d->TitleBar; } //============================================================================ bool CDockAreaWidget::isCentralWidgetArea() const { if (dockWidgetsCount()!= 1) { return false; } return dockManager()->centralWidget() == dockWidgets()[0]; } //============================================================================ bool CDockAreaWidget::containsCentralWidget() const { auto centralWidget = dockManager()->centralWidget(); for (const auto &dockWidget : dockWidgets()) { if (dockWidget == centralWidget) { return true; } } return false; } //============================================================================ QSize CDockAreaWidget::minimumSizeHint() const { if (!d->MinSizeHint.isValid()) { return Super::minimumSizeHint(); } if (d->TitleBar->isVisible()) { return d->MinSizeHint + QSize(0, d->TitleBar->minimumSizeHint().height()); } else { return d->MinSizeHint; } } //============================================================================ void CDockAreaWidget::onDockWidgetFeaturesChanged() { if (d->TitleBar) { d->updateTitleBarButtonStates(); } } #ifdef Q_OS_WIN //============================================================================ bool CDockAreaWidget::event(QEvent *e) { switch (e->type()) { case QEvent::PlatformSurface: return true; default: break; } return Super::event(e); } #endif } // namespace ads //--------------------------------------------------------------------------- // EOF DockAreaWidget.cpp