diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dea76a0..a68b2db 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,6 +27,9 @@ set(ads_SRCS FloatingDragPreview.cpp IconProvider.cpp DockComponentsFactory.cpp + SideTabBar.cpp + DockWidgetSideTab.cpp + OverlayDockContainer.cpp ads.qrc ) set(ads_HEADERS @@ -48,6 +51,9 @@ set(ads_HEADERS FloatingDragPreview.h IconProvider.h DockComponentsFactory.h + SideTabBar.h + DockWidgetSideTab.h + OverlayDockContainer.h ) add_compile_options("$<$:/utf-8>") if (UNIX AND NOT APPLE) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 8651d29..13021e3 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -52,6 +52,7 @@ #include "IconProvider.h" #include "DockComponentsFactory.h" #include "DockFocusController.h" +#include "OverlayDockContainer.h" #include @@ -65,6 +66,7 @@ struct DockAreaTitleBarPrivate { CDockAreaTitleBar* _this; QPointer TabsMenuButton; + QPointer AutoHideButton; QPointer UndockButton; QPointer CloseButton; QBoxLayout* Layout; @@ -162,6 +164,19 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), SLOT(onTabsMenuActionTriggered(QAction*))); + // AutoHide Button + const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar); + AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); + AutoHideButton->setObjectName("autoHideButton"); + AutoHideButton->setAutoRaise(true); + AutoHideButton->setCheckable(true); + AutoHideButton->setChecked(false); + internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide Group")); + internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::DockAreaUndockIcon); + AutoHideButton->setSizePolicy(ButtonSizePolicy); + Layout->addWidget(AutoHideButton, 0); + _this->connect(AutoHideButton, SIGNAL(toggled(bool)), SLOT(onAutoHideButtonClicked(bool))); + // Undock button UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton)); UndockButton->setObjectName("detachGroupButton"); @@ -249,6 +264,10 @@ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, //============================================================================ void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset) { + if (DockArea->overlayDockContainer() != nullptr) + { + DockArea->overlayDockContainer()->hide(); + } FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget); } @@ -438,6 +457,14 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) updateDockWidgetActionsButtons(); } +void CDockAreaTitleBar::onAutoHideButtonClicked(bool Checked) +{ + if (Checked != d->DockArea->isOverlayed()) + { + d->DockArea->toggleAutoHideArea(); + } +} + //============================================================================ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const @@ -447,6 +474,7 @@ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const case TitleBarButtonTabsMenu: return d->TabsMenuButton; case TitleBarButtonUndock: return d->UndockButton; case TitleBarButtonClose: return d->CloseButton; + case TitleBarButtonAutoHide: return d->AutoHideButton; default: return nullptr; } @@ -523,7 +551,8 @@ void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev) // sense to move it to a new floating widget and leave this one // empty if (d->DockArea->dockContainer()->isFloating() - && d->DockArea->dockContainer()->visibleDockAreaCount() == 1) + && d->DockArea->dockContainer()->visibleDockAreaCount() == 1 + && !d->DockArea->isOverlayed()) { return; } diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 37f3a91..70010a4 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -60,9 +60,10 @@ private Q_SLOTS: void onUndockButtonClicked(); void onTabsMenuActionTriggered(QAction* Action); void onCurrentTabChanged(int Index); + void onAutoHideButtonClicked(bool Checked); protected: - /** + /** * Stores mouse position to detect dragging */ virtual void mousePressEvent(QMouseEvent* ev) override; diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 09fd8fd..508fb7c 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -54,6 +54,9 @@ #include "DockAreaTitleBar.h" #include "DockComponentsFactory.h" #include "DockWidgetTab.h" +#include "SideTabBar.h" +#include "DockWidgetSideTab.h" +#include "OverlayDockContainer.h" namespace ads @@ -249,6 +252,7 @@ struct DockAreaWidgetPrivate DockAreaLayout* ContentsLayout = nullptr; CDockAreaTitleBar* TitleBar = nullptr; CDockManager* DockManager = nullptr; + COverlayDockContainer* OverlayDockContainer = nullptr; bool UpdateTitleBarButtons = false; DockWidgetAreas AllowedAreas = DefaultAllowedAreas; QSize MinSizeHint; @@ -358,6 +362,7 @@ void DockAreaWidgetPrivate::updateTitleBarButtonStates() _this->features().testFlag(CDockWidget::DockWidgetClosable)); TitleBar->button(TitleBarButtonUndock)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetFloatable)); + TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); TitleBar->updateDockWidgetActionsButtons(); UpdateTitleBarButtons = false; } @@ -404,6 +409,24 @@ CDockContainerWidget* CDockAreaWidget::dockContainer() const return internal::findParent(this); } +//============================================================================ +COverlayDockContainer* CDockAreaWidget::overlayDockContainer() const +{ + return d->OverlayDockContainer; +} + +//============================================================================ +bool CDockAreaWidget::isOverlayed() const +{ + return d->OverlayDockContainer != nullptr; +} + +//============================================================================ +void CDockAreaWidget::setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer) +{ + d->OverlayDockContainer = OverlayDockContainer; +} + //============================================================================ void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget) @@ -530,6 +553,10 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent() { FloatingWidget->hide(); } + if (isOverlayed()) + { + overlayDockContainer()->hide(); + } } @@ -757,7 +784,8 @@ void CDockAreaWidget::updateTitleBarVisibility() bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); - d->TitleBar->setVisible(!Hidden); + d->TitleBar->setVisible(isOverlayed() ? true : !Hidden); // Titlebar must always be visible when overlayed so it can be dragged + d->TitleBar->tabBar()->setVisible(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed } } @@ -783,6 +811,11 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const 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 (isOverlayed()) + { + overlayDockContainer()->saveState(s); + } + if (d->AllowedAreas != DefaultAllowedAreas) { s.writeAttribute("AllowedAreas", QString::number(d->AllowedAreas, 16)); @@ -957,8 +990,9 @@ void CDockAreaWidget::closeArea() { // If there is only one single dock widget and this widget has the // DeleteOnClose feature, then we delete the dock widget now + // Note: Auto hide and overlays do not support dock widget delete on close auto OpenDockWidgets = openedDockWidgets(); - if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose)) + if (OpenDockWidgets.count() == 1 && OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && !isOverlayed()) { OpenDockWidgets[0]->closeDockWidgetInternal(); } @@ -966,7 +1000,7 @@ void CDockAreaWidget::closeArea() { for (auto DockWidget : openedDockWidgets()) { - if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea)) + if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea) && !isOverlayed()) DockWidget->closeDockWidgetInternal(); else DockWidget->toggleView(false); @@ -974,6 +1008,31 @@ void CDockAreaWidget::closeArea() } } +//============================================================================ +void CDockAreaWidget::toggleAutoHideArea() +{ + const auto area = dockContainer()->getDockAreaPosition(this); + for (const auto DockWidget : openedDockWidgets()) + { + onAutoHideToggleRequested(DockWidget, !isOverlayed(), area); + } +} + +//============================================================================ +void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area) +{ + if (Enable) + { + dockContainer()->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); + DockWidget->sideTabWidget()->show(); + dockContainer()->createDockWidgetOverlayContainer(area, DockWidget); + toggleView(false); + } + else + { + overlayDockContainer()->moveContentsToParent(); + } +} //============================================================================ void CDockAreaWidget::closeOtherAreas() diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index eaf290c..d34c352 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -65,6 +65,7 @@ private: friend class CDockWidget; friend struct DockManagerPrivate; friend class CDockManager; + friend class COverlayDockContainer; void onDockWidgetFeaturesChanged(); private Q_SLOTS: @@ -186,6 +187,23 @@ public: */ CDockContainerWidget* dockContainer() const; + /** + * Returns the overlay dock container widget this dock area widget belongs to or 0 + * if there is no + */ + COverlayDockContainer* overlayDockContainer() const; + + /** + * Returns true if the dock area exists in an overlay dock container + */ + bool isOverlayed() const; + + + /** + * Sets the current overlay dock container + */ + void setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer); + /** * Returns the largest minimumSizeHint() of the dock widgets in this * area. @@ -337,6 +355,16 @@ public Q_SLOTS: void closeArea(); /** + * Toggles the Auto hides behaviour of the dock area and all dock widgets in this area + */ + void toggleAutoHideArea(); + + /** + * Auto hides the dock area and all dock widgets in this area + */ + void onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area); + + /** * This function closes all other areas except of this area */ void closeOtherAreas(); diff --git a/src/DockComponentsFactory.cpp b/src/DockComponentsFactory.cpp index 1f8be65..3e7ebc1 100644 --- a/src/DockComponentsFactory.cpp +++ b/src/DockComponentsFactory.cpp @@ -17,6 +17,7 @@ #include "DockAreaTitleBar.h" #include "DockWidget.h" #include "DockAreaWidget.h" +#include "DockWidgetSideTab.h" namespace ads { @@ -29,6 +30,12 @@ CDockWidgetTab* CDockComponentsFactory::createDockWidgetTab(CDockWidget* DockWid return new CDockWidgetTab(DockWidget); } +//============================================================================ +CDockWidgetSideTab* CDockComponentsFactory::createDockWidgetSideTab(CDockWidget *DockWidget) const +{ + return new CDockWidgetSideTab(DockWidget); +} + //============================================================================ CDockAreaTabBar* CDockComponentsFactory::createDockAreaTabBar(CDockAreaWidget* DockArea) const diff --git a/src/DockComponentsFactory.h b/src/DockComponentsFactory.h index f0598e9..3e726ae 100644 --- a/src/DockComponentsFactory.h +++ b/src/DockComponentsFactory.h @@ -19,6 +19,7 @@ class CDockAreaTitleBar; class CDockAreaTabBar; class CDockAreaWidget; class CDockWidget; +class CDockWidgetSideTab; @@ -46,6 +47,12 @@ public: */ virtual CDockWidgetTab* createDockWidgetTab(CDockWidget* DockWidget) const; + /** + * This default implementation just creates a dock widget side tab with + * new CDockWidgetTab(DockWidget). + */ + virtual CDockWidgetSideTab* createDockWidgetSideTab(CDockWidget* DockWidget) const; + /** * This default implementation just creates a dock area tab bar with * new CDockAreaTabBar(DockArea). diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 5451eb3..eaca38d 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "DockManager.h" #include "DockAreaWidget.h" @@ -47,6 +48,11 @@ #include "DockOverlay.h" #include "ads_globals.h" #include "DockSplitter.h" +#include "SideTabBar.h" +#include "OverlayDockContainer.h" +#include "DockWidgetTab.h" +#include "DockWidgetSideTab.h" +#include "DockAreaTitleBar.h" #include #include @@ -131,6 +137,7 @@ public: QPointer DockManager; unsigned int zOrderIndex = 0; QList DockAreas; + QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; bool isFloating = false; @@ -212,6 +219,11 @@ public: void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget); /** + * Save state of overlay widgets + */ + void saveOverlayWidgetsState(QXmlStreamWriter& Stream); + + /** * Restore state of child nodes. * \param[in] Stream The data stream that contains the serialized state * \param[out] CreatedWidget The widget created from parsed data or 0 if @@ -236,6 +248,19 @@ public: bool restoreDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, bool Testing); + /** + * Restores the overlay dock area. + * Assumes that there are no overlay dock areas, and then restores all the dock areas that + * exist in the XML + */ + bool restoreOverlayDockArea(CDockingStateReader& s, SideTabBarArea area, bool Testing); + + /** + * Restores either a dock area or an overlay dock area depending on the value in the XML + */ + bool restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, + bool Testing); + /** * Helper function for recursive dumping of layout */ @@ -404,11 +429,13 @@ void DockContainerWidgetPrivate::onVisibleDockAreaCountChanged() this->TopLevelDockArea = TopLevelDockArea; TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(false || !_this->isFloating()); TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(false || !_this->isFloating()); + TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(false || !_this->isFloating()); } else if (this->TopLevelDockArea) { this->TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true); this->TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(true); + this->TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true); this->TopLevelDockArea = nullptr; } } @@ -807,6 +834,7 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QListtitleBarButton(TitleBarButtonUndock)->setVisible(true); DockArea->titleBarButton(TitleBarButtonClose)->setVisible(true); + DockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true); } // We need to ensure, that the dock area title bar is visible. The title bar @@ -873,6 +901,19 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge } } +void DockContainerWidgetPrivate::saveOverlayWidgetsState(QXmlStreamWriter& Stream) +{ + for (const auto dockAreaWidget : _this->findChildren()) + { + if (!dockAreaWidget->isOverlayed()) + { + continue; + } + + dockAreaWidget->saveState(Stream); + } +} + //============================================================================ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, @@ -989,6 +1030,126 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, return true; } +//============================================================================ +bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, SideTabBarArea area, bool Testing) +{ + bool Ok; +#ifdef ADS_DEBUG_PRINT + int Tabs = s.attributes().value("Tabs").toInt(&Ok); + if (!Ok) + { + return false; + } +#endif + + QString CurrentDockWidget = s.attributes().value("Current").toString(); + ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " + << CurrentDockWidget); + + if (area == Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + { + return false; + } + + if (area == Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + { + return false; + } + + CDockAreaWidget* DockArea = nullptr; + if (!Testing) + { + const auto dockContainer = new COverlayDockContainer(DockManager, area, _this); + if (!dockContainer->restoreState(s, Testing)) + { + return false; + } + + dockContainer->hide(); + DockArea = dockContainer->dockAreaWidget(); + const auto titleBar = DockArea->titleBar(); + QSignalBlocker blocker(titleBar); + titleBar->button(TitleBarButtonAutoHide)->setChecked(true); + } + + while (s.readNextStartElement()) + { + if (s.name() != QLatin1String("Widget")) + { + continue; + } + + auto ObjectName = s.attributes().value("Name"); + if (ObjectName.isEmpty()) + { + return false; + } + + s.skipCurrentElement(); + CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString()); + if (!DockWidget || Testing) + { + continue; + } + + ADS_PRINT("Dock Widget found - parent " << DockWidget->parent()); + // We hide the DockArea here to prevent the short display (the flashing) + // of the dock areas during application startup + DockArea->hide(); + DockWidget->setToggleViewActionChecked(false); + DockWidget->setClosedState(true); + DockWidget->setProperty(internal::ClosedProperty, true); + DockWidget->setProperty(internal::DirtyProperty, false); + _this->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); + DockWidget->sideTabWidget()->show(); + DockWidget->toggleView(false); + DockArea->overlayDockContainer()->addDockWidget(DockWidget); + } + + if (Testing) + { + return true; + } + + if (!DockArea->dockWidgetsCount()) + { + delete DockArea; + DockArea = nullptr; + } + else + { + DockArea->setProperty("currentDockWidget", CurrentDockWidget); + appendDockAreas({DockArea}); + } + + return true; +} + + +//============================================================================ +bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, + bool Testing) +{ + bool Ok; + const auto sideTabAreaValue = Stream.attributes().value("SideTabBarArea"); + if (!sideTabAreaValue.isNull()) + { + auto sideTabBarArea = static_cast(sideTabAreaValue.toInt(&Ok)); + if (!Ok) + { + return false; + } + if (sideTabBarArea != SideTabBarArea::None) + { + return restoreOverlayDockArea(Stream, sideTabBarArea, Testing); + } + } + + // If there's no SideTabBarArea value in the XML, or the value of SideTabBarArea is none, restore the dock area + return restoreDockArea(Stream, CreatedWidget, Testing); + +} + //============================================================================ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, @@ -1054,7 +1215,7 @@ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, // We hide the DockArea here to prevent the short display (the flashing) // of the dock areas during application startup DockArea->hide(); - DockArea->addDockWidget(DockWidget); + DockArea->addDockWidget(DockWidget); DockWidget->setToggleViewActionChecked(!Closed); DockWidget->setClosedState(Closed); DockWidget->setProperty(internal::ClosedProperty, Closed); @@ -1096,7 +1257,7 @@ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s, } else if (s.name() == QLatin1String("Area")) { - Result = restoreDockArea(s, CreatedWidget, Testing); + Result = restoreDockOrOverlayDockArea(s, CreatedWidget, Testing); ADS_PRINT("DockAreaWidget"); } else @@ -1288,6 +1449,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p d->Layout = new QGridLayout(); d->Layout->setContentsMargins(0, 0, 0, 0); d->Layout->setSpacing(0); + d->Layout->setColumnStretch(1, 1); setLayout(d->Layout); // The function d->newSplitter() accesses the config flags from dock @@ -1299,6 +1461,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p { d->DockManager->registerDockContainer(this); createRootSplitter(); + createSideTabBarWidgets(); } } @@ -1334,6 +1497,45 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW } } +void CDockContainerWidget::createDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget) +{ + if (d->DockManager != DockWidget->dockManager()) + { + DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager + } + const auto dockContainer = new COverlayDockContainer(DockWidget, area); + dockContainer->hide(); +} + +//============================================================================ +SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget) +{ + const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(DockAreaWidget->frameGeometry().center()); + const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); + const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? Left : Right; + if (calculatedPosition == Right) + { + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + { + return Right; + } + + return Left; + } + + if (calculatedPosition == Left) + { + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + { + return Left; + } + return Right; + } + + return Left; + +} + //============================================================================ void CDockContainerWidget::removeDockWidget(CDockWidget* Dockwidget) { @@ -1408,6 +1610,22 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) *p = nullptr; } + if (area->isOverlayed()) + { + // Removing an area from an overlay widget implies deleting the whole overlay widget + // So cleanup will be done when the overlay widget is deleted + // Note: there is no parent splitter + CDockWidget* TopLevelWidget = topLevelDockWidget(); + + // Updated the title bar visibility of the dock widget if there is only + // one single visible dock widget + CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); + dumpLayout(); + d->emitDockAreasRemoved(); + area->setOverlayDockContainer(nullptr); + return; + } + // If splitter has more than 1 widgets, we are finished and can leave if (Splitter->count() > 1) { @@ -1675,6 +1893,7 @@ void CDockContainerWidget::saveState(QXmlStreamWriter& s) const #endif } d->saveChildNodesState(s, d->RootSplitter); + d->saveOverlayWidgetsState(s); s.writeEndElement(); } @@ -1759,7 +1978,24 @@ void CDockContainerWidget::createRootSplitter() return; } d->RootSplitter = d->newSplitter(Qt::Horizontal); - d->Layout->addWidget(d->RootSplitter); + d->Layout->addWidget(d->RootSplitter, 0, 1); // Add it to the center - the 0 and 2 indexes are used for the SideTabBar widgets +} + + +//============================================================================ +void CDockContainerWidget::createSideTabBarWidgets() +{ + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + { + d->SideTabBarWidgets[SideTabBarArea::Left] = new CSideTabBar(this); + d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Left], 0, 0); + } + + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + { + d->SideTabBarWidgets[SideTabBarArea::Right] = new CSideTabBar(this); + d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Right], 0, 2); + } } @@ -1894,7 +2130,11 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea) } } - +//============================================================================ +CSideTabBar* CDockContainerWidget::sideTabBar(SideTabBarArea area) const +{ + return d->SideTabBarWidgets[area]; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index a9ebea4..e895fd5 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -50,6 +50,7 @@ struct FloatingDockContainerPrivate; class CFloatingDragPreview; struct FloatingDragPreviewPrivate; class CDockingStateReader; +class CSideTabBar; /** @@ -74,6 +75,7 @@ private: friend class CDockWidget; friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; + friend class COverlayDockContainer; protected: /** @@ -91,6 +93,11 @@ protected: */ void createRootSplitter(); + /** + * Helper function for creation of the side tab bar widgets + */ + void createSideTabBarWidgets(); + /** * Drop floating widget into the container */ @@ -163,6 +170,7 @@ protected: void updateSplitterHandles(QSplitter* splitter); public: + /** * Default Constructor */ @@ -183,6 +191,16 @@ public: CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget = nullptr); + /** + * Creates and adds a dockwidget overlay container into the given area. + */ + void createDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget); + + /** + * Get's the overlay dock side tab bar area based on the dock area widget position + */ + SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget); + /** * Removes dockwidget */ @@ -278,6 +296,11 @@ public: */ void closeOtherAreas(CDockAreaWidget* KeepOpenArea); + /** + * Returns the side tab widget for the given area + */ + CSideTabBar* sideTabBar(SideTabBarArea area) const; + Q_SIGNALS: /** * This signal is emitted if one or multiple dock areas has been added to diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index 595c9fa..89d9499 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -25,6 +25,8 @@ #include "FloatingDockContainer.h" #include "DockManager.h" #include "DockAreaTitleBar.h" +#include "DockWidgetSideTab.h" +#include "OverlayDockContainer.h" #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" @@ -69,6 +71,8 @@ static void updateDockWidgetFocusStyle(CDockWidget* DockWidget, bool Focused) DockWidget->setProperty("focused", Focused); DockWidget->tabWidget()->setProperty("focused", Focused); DockWidget->tabWidget()->updateStyle(); + DockWidget->sideTabWidget()->setProperty("focused", Focused); + DockWidget->sideTabWidget()->updateStyle(); internal::repolishStyle(DockWidget); } @@ -185,6 +189,11 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget) } #endif + if (old && old->overlayDockContainer() && old != DockWidget) + { + old->overlayDockContainer()->hide(); + } + if (old == DockWidget && !ForceFocusChangedSignal) { return; diff --git a/src/DockManager.cpp b/src/DockManager.cpp index ecb558c..33c402e 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -56,6 +56,7 @@ #include "DockAreaTitleBar.h" #include "DockFocusController.h" #include "DockSplitter.h" +#include "OverlayDockContainer.h" #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" @@ -99,6 +100,7 @@ struct DockManagerPrivate CDockManager* _this; QList FloatingWidgets; QList HiddenFloatingWidgets; + QList OverlayWidgets; QList Containers; CDockOverlay* ContainerOverlay; CDockOverlay* DockAreaOverlay; @@ -146,6 +148,15 @@ struct DockManagerPrivate } } + void deleteOverlayWidgets() + { + for (auto OverlayWidget : OverlayWidgets) + { + OverlayWidget->cleanupAndDelete(); + } + OverlayWidgets.clear(); + } + void markDockWidgetsDirty() { for (auto DockWidget : DockWidgetsMap) @@ -430,6 +441,7 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version) // Hide updates of floating widgets from use hideFloatingWidgets(); + deleteOverlayWidgets(); markDockWidgetsDirty(); if (!restoreStateFromXml(state, version)) @@ -481,6 +493,7 @@ CDockManager::CDockManager(QWidget *parent) : d(new DockManagerPrivate(this)) { createRootSplitter(); + createSideTabBarWidgets(); QMainWindow* MainWindow = qobject_cast(parent); if (MainWindow) { @@ -525,6 +538,13 @@ CDockManager::~CDockManager() { delete FloatingWidget; } + + auto OverlayWidgets = d->OverlayWidgets; + for (auto OverlayWidget : OverlayWidgets) + { + delete OverlayWidget; + } + delete d; } @@ -616,6 +636,14 @@ void CDockManager::registerFloatingWidget(CFloatingDockContainer* FloatingWidget ADS_PRINT("d->FloatingWidgets.count() " << d->FloatingWidgets.count()); } +//============================================================================ +void CDockManager::registerOverlayWidget(COverlayDockContainer* OverlayWidget) +{ + d->OverlayWidgets.append(OverlayWidget); + Q_EMIT overlayWidgetCreated(OverlayWidget); + ADS_PRINT("d->OverlayWidgets.count() " << d->OverlayWidgets.count()); +} + //============================================================================ void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget) @@ -623,6 +651,11 @@ void CDockManager::removeFloatingWidget(CFloatingDockContainer* FloatingWidget) d->FloatingWidgets.removeAll(FloatingWidget); } +//============================================================================ +void CDockManager::removeOverlayWidget(COverlayDockContainer* OverlayWidget) +{ + d->OverlayWidgets.removeAll(OverlayWidget); +} //============================================================================ void CDockManager::registerDockContainer(CDockContainerWidget* DockContainer) diff --git a/src/DockManager.h b/src/DockManager.h index 7747d23..17b8bc2 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -84,6 +84,7 @@ private: friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; friend class CDockAreaTitleBar; + friend class COverlayDockContainer; protected: @@ -93,12 +94,24 @@ protected: */ void registerFloatingWidget(CFloatingDockContainer* FloatingWidget); + /** + * Registers the given floating widget in the internal list of + * overlay widgets + */ + void registerOverlayWidget(COverlayDockContainer* OverlayWidget); + /** * Remove the given floating widget from the list of registered floating * widgets */ void removeFloatingWidget(CFloatingDockContainer* FloatingWidget); + /** + * Remove the given overlay widget from the list of registered overlay + * widgets + */ + void removeOverlayWidget(COverlayDockContainer* OverlayWidget); + /** * Registers the given dock container widget */ @@ -202,14 +215,24 @@ public: //! Users can overwrite this by setting the environment variable ADS_UseNativeTitle to "1" or "0". MiddleMouseButtonClosesTab = 0x2000000, //! If the flag is set, the user can use the mouse middle button to close the tab under the mouse + DockAreaHasAutoHideButton = 0x4000000, //!< If the flag is set each dock area has a auto hide menu button + DockContainerHasLeftSideBar = 0x8000000, //!< If the flag is set each container will have a left side bar + DockContainerHasRightSideBar = 0x10000000, //!< If the flag is set each container will have a right side bar + + DefaultDockAreaButtons = DockAreaHasCloseButton | DockAreaHasUndockButton - | DockAreaHasTabsMenuButton,///< default configuration of dock area title bar buttons + | DockAreaHasTabsMenuButton + | DockAreaHasAutoHideButton,///< default configuration of dock area title bar buttons + + DefaultDockContainerSideBars = DockContainerHasLeftSideBar + | DockContainerHasRightSideBar, ///< the default configuration for left and right side bars DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton | XmlCompressionEnabled - | FloatingContainerHasWidgetTitle,///< default base configuration settings + | FloatingContainerHasWidgetTitle + | DefaultDockContainerSideBars, ///< default base configuration settings DefaultOpaqueConfig = DefaultBaseConfig | OpaqueSplitterResize @@ -602,6 +625,11 @@ Q_SIGNALS: */ void floatingWidgetCreated(ads::CFloatingDockContainer* FloatingWidget); + /** + * This signal is emitted, if a new overlay widget has been created. + */ + void overlayWidgetCreated(ads::COverlayDockContainer* OverlayWidget); + /** * This signal is emitted, if a new DockArea has been created. * An application can use this signal to set custom icons or custom diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index e4b94d8..f8b1cf1 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -50,6 +50,8 @@ #include #include +#include "SideTabBar.h" +#include "DockWidgetSideTab.h" #include "DockContainerWidget.h" #include "DockAreaWidget.h" #include "DockManager.h" @@ -57,6 +59,7 @@ #include "DockSplitter.h" #include "DockComponentsFactory.h" #include "ads_globals.h" +#include "OverlayDockContainer.h" namespace ads @@ -76,6 +79,7 @@ struct DockWidgetPrivate QBoxLayout* Layout = nullptr; QWidget* Widget = nullptr; CDockWidgetTab* TabWidget = nullptr; + CDockWidgetSideTab* SideTabWidget = nullptr; CDockWidget::DockWidgetFeatures Features = CDockWidget::DefaultDockWidgetFeatures; CDockManager* DockManager = nullptr; CDockAreaWidget* DockArea = nullptr; @@ -182,6 +186,11 @@ void DockWidgetPrivate::showDockWidget() CFloatingDockContainer*>(Container); FloatingWidget->show(); } + + if (DockArea->isOverlayed()) + { + DockArea->overlayDockContainer()->show(); + } } } @@ -197,6 +206,11 @@ void DockWidgetPrivate::hideDockWidget() Widget->deleteLater(); Widget = nullptr; } + + if (DockArea->isOverlayed()) + { + DockArea->overlayDockContainer()->hide(); + } } @@ -287,7 +301,11 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : setObjectName(title); d->TabWidget = componentsFactory()->createDockWidgetTab(this); - d->ToggleViewAction = new QAction(title, this); + d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(this); + + connect(d->SideTabWidget, &CDockWidgetSideTab::clicked, this, &CDockWidget::onDockWidgetSideTabClicked); + + d->ToggleViewAction = new QAction(title, this); d->ToggleViewAction->setCheckable(true); connect(d->ToggleViewAction, SIGNAL(triggered(bool)), this, SLOT(toggleView(bool))); @@ -302,7 +320,7 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : //============================================================================ CDockWidget::~CDockWidget() { - ADS_PRINT("~CDockWidget()"); + ADS_PRINT("~CDockWidget()"); delete d; } @@ -379,7 +397,7 @@ QWidget* CDockWidget::takeWidget() { w->setParent(nullptr); } - return w; + return w; } @@ -396,6 +414,16 @@ CDockWidgetTab* CDockWidget::tabWidget() const return d->TabWidget; } +COverlayDockContainer* CDockWidget::overlayDockContainer() const +{ + if (!d->DockArea) + { + return nullptr; + } + + return d->DockArea->overlayDockContainer(); +} + //============================================================================ void CDockWidget::setFeatures(DockWidgetFeatures features) @@ -416,8 +444,8 @@ void CDockWidget::setFeatures(DockWidgetFeatures features) void CDockWidget::setFeature(DockWidgetFeature flag, bool on) { auto Features = features(); - internal::setFlag(Features, flag, on); - setFeatures(Features); + internal::setFlag(Features, flag, on); + setFeatures(Features); } @@ -470,6 +498,12 @@ CDockAreaWidget* CDockWidget::dockAreaWidget() const return d->DockArea; } +//============================================================================ +CDockWidgetSideTab* CDockWidget::sideTabWidget() const +{ + return d->SideTabWidget; +} + //============================================================================ bool CDockWidget::isFloating() const @@ -541,7 +575,7 @@ void CDockWidget::setMinimumSizeHintMode(eMinimumSizeHintMode Mode) //============================================================================ bool CDockWidget::isCentralWidget() const { - return dockManager()->centralWidget() == this; + return dockManager()->centralWidget() == this; } @@ -662,7 +696,7 @@ bool CDockWidget::event(QEvent *e) case QEvent::Show: Q_EMIT visibilityChanged(geometry().right() >= 0 && geometry().bottom() >= 0); - break; + break; case QEvent::WindowTitleChange : { @@ -938,7 +972,7 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose) } if (features().testFlag(CDockWidget::DockWidgetDeleteOnClose)) - { + { // If the dock widget is floating, then we check if we also need to // delete the floating widget if (isFloating()) @@ -956,11 +990,11 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose) } deleteDockWidget(); Q_EMIT closed(); - } - else - { - toggleView(false); - } + } + else + { + toggleView(false); + } return true; } @@ -1007,6 +1041,27 @@ void CDockWidget::showNormal() } } +//============================================================================ +void CDockWidget::onDockWidgetSideTabClicked() +{ + const auto overlayContainer = overlayDockContainer(); + if (!overlayContainer) + { + return; + } + + overlayContainer->raise(); + const auto show = !overlayContainer->isVisible(); + overlayContainer->setVisible(show); + toggleView(show); + if (overlayContainer->isVisible()) + { + // d->DockManager->setDockWidgetFocused(this) does not + // de focus the old widget, leading to the overlay still being visible + // even after clicking outside the overlay. + setFocus(Qt::ActiveWindowFocusReason); + } +} //============================================================================ bool CDockWidget::isFullScreen() const diff --git a/src/DockWidget.h b/src/DockWidget.h index abf8766..1bcd03b 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -46,6 +46,8 @@ class CDockContainerWidget; class CDockAreaWidget; class DockContainerWidgetPrivate; class CFloatingDockContainer; +class CDockWidgetSideTab; +class COverlayDockContainer; /** * The QDockWidget class provides a widget that can be docked inside a @@ -75,6 +77,7 @@ protected: friend class CDockWidgetTab; friend struct DockWidgetTabPrivate; friend struct DockAreaTitleBarPrivate; + friend class COverlayDockContainer; /** * Assigns the dock manager that manages this dock widget @@ -300,6 +303,12 @@ public: */ CDockWidgetTab* tabWidget() const; + /** + * Returns the overlay dock container of this dock widget + * or 0 if there is none + */ + COverlayDockContainer* overlayDockContainer() const; + /** * Sets, whether the dock widget is movable, closable, and floatable. */ @@ -343,6 +352,11 @@ public: */ CDockAreaWidget* dockAreaWidget() const; + /** + * Returns the side tab widget for this dock + */ + CDockWidgetSideTab* sideTabWidget() const; + /** * This property holds whether the dock widget is floating. * A dock widget is only floating, if it is the one and only widget inside @@ -563,6 +577,10 @@ public Q_SLOTS: */ void showNormal(); + /** + * Shows the dock overlay container when the side tab is clicked + */ + void onDockWidgetSideTabClicked(); Q_SIGNALS: /** diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp new file mode 100644 index 0000000..a3d2b23 --- /dev/null +++ b/src/DockWidgetSideTab.cpp @@ -0,0 +1,151 @@ +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Implementation of CDockWidgetSideTab class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "DockWidgetSideTab.h" +#include "SideTabBar.h" + +#include + +#include "ElidingLabel.h" + +#include "DockWidget.h" + +namespace ads +{ + +using tTabLabel = CVerticalElidingLabel; + +/** + * Private data class of CDockWidgetTab class (pimpl) + */ +struct DockWidgetSideTabPrivate +{ + CDockWidgetSideTab* _this; + CDockWidget* DockWidget; + tTabLabel* TitleLabel; + QBoxLayout* Layout; + CSideTabBar* SideTabBar; + + /** + * Private data constructor + */ + DockWidgetSideTabPrivate(CDockWidgetSideTab* _public); + + /** + * Creates the complete layout + */ + void createLayout(); +}; +// struct DockWidgetTabPrivate + + +//============================================================================ +DockWidgetSideTabPrivate::DockWidgetSideTabPrivate(CDockWidgetSideTab* _public) : + _this(_public) +{ + +} + +//============================================================================ +void DockWidgetSideTabPrivate::createLayout() +{ + TitleLabel = new tTabLabel(); + TitleLabel->setElideMode(Qt::ElideRight); + TitleLabel->setText(DockWidget->windowTitle()); + TitleLabel->setObjectName("dockWidgetTabLabel"); + TitleLabel->setAlignment(Qt::AlignCenter); + _this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool))); + + QFontMetrics fm(TitleLabel->font()); + int Spacing = qRound(fm.height() / 2.0); + + // Fill the layout + Layout = new QBoxLayout(QBoxLayout::LeftToRight); + Layout->setContentsMargins(Spacing,Spacing,0,Spacing); + Layout->setSpacing(0); + _this->setLayout(Layout); + Layout->addWidget(TitleLabel, 1); + Layout->setAlignment(Qt::AlignCenter); + + TitleLabel->setVisible(true); +} + +//============================================================================ +void CDockWidgetSideTab::mousePressEvent(QMouseEvent* event) +{ + if (event->button() == Qt::LeftButton) + { + emit clicked(); + } + + QFrame::mousePressEvent(event); +} + + +//============================================================================ +void CDockWidgetSideTab::setSideTabBar(CSideTabBar* SideTabBar) +{ + d->SideTabBar = SideTabBar; +} + + +//============================================================================ +void CDockWidgetSideTab::removeFromSideTabBar() +{ + if (d->SideTabBar == nullptr) + { + return; + } + d->SideTabBar->removeSideTab(this); + setSideTabBar(nullptr); +} + +//============================================================================ +CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) : + QFrame(parent), + d(new DockWidgetSideTabPrivate(this)) +{ + setAttribute(Qt::WA_NoMousePropagation); + d->DockWidget = DockWidget; + d->createLayout(); + setFocusPolicy(Qt::NoFocus); +} + +//============================================================================ +CDockWidgetSideTab::~CDockWidgetSideTab() +{ + delete d; +} + +//============================================================================ +void CDockWidgetSideTab::updateStyle() +{ + internal::repolishStyle(this, internal::RepolishDirectChildren); +} +} diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h new file mode 100644 index 0000000..e99ada0 --- /dev/null +++ b/src/DockWidgetSideTab.h @@ -0,0 +1,96 @@ +#ifndef DockWidgetSideTabH +#define DockWidgetSideTabH +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Declaration of CDockWidgetSideTab class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +#include "ads_globals.h" + +namespace ads +{ +struct DockWidgetSideTabPrivate; +class CDockWidget; +class CSideTabBar; +class CDockWidgetTab; + +/** + * A dock widget Side tab that shows a title or an icon. + * The dock widget tab is shown in the side tab bar to switch between + * pinned dock widgets + */ +class ADS_EXPORT CDockWidgetSideTab : public QFrame +{ + Q_OBJECT + +private: + DockWidgetSideTabPrivate* d; ///< private data (pimpl) + friend struct DockWidgetSideTabPrivate; + friend class CDockWidget; + friend class COverlayDockContainer; + +protected: + friend class CSideTabBar; + friend class CDockAreaWidget; + friend class CDockContainerWidget; + + void mousePressEvent(QMouseEvent* event) override; + + void setSideTabBar(CSideTabBar *SideTabBar); + void removeFromSideTabBar(); + +public: + using Super = QFrame; + /** + * Default Constructor + * param[in] DockWidget The dock widget this title bar belongs to + * param[in] Orientation Horizontal or vertical orientation + * param[in] parent The parent widget of this title bar + */ + CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent = nullptr); + + /** + * Virtual Destructor + */ + virtual ~CDockWidgetSideTab(); + + /** + * Update stylesheet style if a property changes + */ + void updateStyle(); + +Q_SIGNALS: + void elidedChanged(bool elided); + void clicked(); +}; // class DockWidgetSideTab +} + // namespace ads +//----------------------------------------------------------------------------- + +#endif diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index 512e6b5..f8b4e72 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -51,6 +51,7 @@ #include "DockManager.h" #include "IconProvider.h" #include "DockFocusController.h" +#include "OverlayDockContainer.h" namespace ads @@ -752,7 +753,6 @@ QSize CDockWidgetTab::iconSize() const return d->IconSize; } - //============================================================================ void CDockWidgetTab::setIconSize(const QSize& Size) { diff --git a/src/DockWidgetTab.h b/src/DockWidgetTab.h index 7ee45e3..b46ac85 100644 --- a/src/DockWidgetTab.h +++ b/src/DockWidgetTab.h @@ -58,6 +58,7 @@ private: friend struct DockWidgetTabPrivate; friend class CDockWidget; friend class CDockManager; + friend class COverlayDockContainer; void onDockWidgetFeaturesChanged(); private Q_SLOTS: diff --git a/src/ElidingLabel.cpp b/src/ElidingLabel.cpp index ac52122..ee75313 100644 --- a/src/ElidingLabel.cpp +++ b/src/ElidingLabel.cpp @@ -29,6 +29,7 @@ //============================================================================ #include "ElidingLabel.h" #include +#include namespace ads @@ -225,6 +226,34 @@ QString CElidingLabel::text() const { return d->Text; } + +//============================================================================ +CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) : + CElidingLabel(parent, f) +{ +} + +//============================================================================ +void CVerticalElidingLabel::paintEvent(QPaintEvent* event) +{ + QPainter painter(this); + painter.rotate(90); + painter.drawText(0,0, text()); +} + +//============================================================================ +QSize CVerticalElidingLabel::sizeHint() const +{ + QSize s = CElidingLabel::minimumSizeHint(); + return QSize(s.height(), s.width()); +} + +//============================================================================ +QSize CVerticalElidingLabel::minimumSizeHint() const +{ + QSize s = CElidingLabel::sizeHint(); + return QSize(s.height(), s.width()); +} } // namespace QtLabb //--------------------------------------------------------------------------- diff --git a/src/ElidingLabel.h b/src/ElidingLabel.h index 894dcb0..8dbf051 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -102,6 +102,18 @@ Q_SIGNALS: void elidedChanged(bool elided); }; //class CElidingLabel + +class CVerticalElidingLabel : public CElidingLabel +{ +protected: + void paintEvent(QPaintEvent* event) override; + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + +public: + CVerticalElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags ()); +}; // class CVerticalElidingLabel + } // namespace QtLabb //--------------------------------------------------------------------------- diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index c6ceb1a..4fcbb51 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -21,6 +21,7 @@ #include "DockManager.h" #include "DockContainerWidget.h" #include "DockOverlay.h" +#include "OverlayDockContainer.h" namespace ads { @@ -319,6 +320,9 @@ void CFloatingDragPreview::startFloating(const QPoint &DragStartMousePos, void CFloatingDragPreview::finishDragging() { ADS_PRINT("CFloatingDragPreview::finishDragging"); + + cleanupOverlayContainerWidget(); + auto DockDropArea = d->DockManager->dockAreaOverlay()->visibleDropAreaUnderCursor(); auto ContainerDropArea = d->DockManager->containerOverlay()->visibleDropAreaUnderCursor(); if (!d->DropContainer) @@ -353,6 +357,22 @@ void CFloatingDragPreview::finishDragging() } +//============================================================================ +void CFloatingDragPreview::cleanupOverlayContainerWidget() +{ + auto DroppedDockWidget = qobject_cast(d->Content); + auto DroppedArea = qobject_cast(d->Content); + if (DroppedDockWidget && DroppedDockWidget->overlayDockContainer()) + { + DroppedDockWidget->overlayDockContainer()->cleanupAndDelete(); + } + if (DroppedArea && DroppedArea->overlayDockContainer()) + { + DroppedArea->overlayDockContainer()->cleanupAndDelete(); + } +} + + //============================================================================ void CFloatingDragPreview::paintEvent(QPaintEvent* event) { diff --git a/src/FloatingDragPreview.h b/src/FloatingDragPreview.h index 3822480..2920a9e 100644 --- a/src/FloatingDragPreview.h +++ b/src/FloatingDragPreview.h @@ -92,6 +92,11 @@ public: // implements IFloatingWidget ----------------------------------------- */ virtual void finishDragging() override; + /** + * Cleanup overlay container if the dragged widget has one + */ + void cleanupOverlayContainerWidget(); + Q_SIGNALS: /** * This signal is emitted, if dragging has been canceled by escape key diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp new file mode 100644 index 0000000..75b6a14 --- /dev/null +++ b/src/OverlayDockContainer.cpp @@ -0,0 +1,309 @@ +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Implementation of COverlayDockContainer class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "OverlayDockContainer.h" +#include "DockManager.h" +#include "DockWidgetSideTab.h" +#include "DockWidgetTab.h" +#include "SideTabBar.h" +#include "DockAreaTitleBar.h" +#include "DockAreaWidget.h" +#include "DockingStateReader.h" + +#include +#include +#include +#include +#include + +namespace ads +{ +struct OverlayDockContainerPrivate +{ + COverlayDockContainer* _this; + CDockAreaWidget* DockArea{nullptr}; + CDockWidget* DockWidget{nullptr}; + QPointer DockManager{nullptr}; + QSplitter* Splitter; + SideTabBarArea Area; + + /** + * Private data constructor + */ + OverlayDockContainerPrivate(COverlayDockContainer *_public); +}; // struct OverlayDockContainerPrivate + +//============================================================================ +OverlayDockContainerPrivate::OverlayDockContainerPrivate( + COverlayDockContainer *_public) : + _this(_public) +{ + +} + +CDockContainerWidget* COverlayDockContainer::parentContainer() const +{ + return qobject_cast(parent()); +} + +//============================================================================ +COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent) : + QFrame(parent), + d(new OverlayDockContainerPrivate(this)) +{ + d->DockManager = DockManager; + d->Area = area; + d->DockArea = new CDockAreaWidget(DockManager, parent); + d->DockArea->setObjectName("OverlayDockArea"); + d->DockArea->setOverlayDockContainer(this); + auto autoHideButton = d->DockArea->titleBar()->button(TitleBarButtonAutoHide); + autoHideButton->blockSignals(true); + autoHideButton->setChecked(true); + autoHideButton->blockSignals(false); + + QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); + d->Splitter = new QSplitter(Qt::Orientation::Horizontal); + d->Splitter->setChildrenCollapsible(false); + + const auto emptyWidget = new QWidget(); + emptyWidget->setMinimumWidth(50); + + if (area == SideTabBarArea::Left) + { + d->Splitter->addWidget(d->DockArea); + d->Splitter->addWidget(emptyWidget); + } + else + { + d->Splitter->addWidget(emptyWidget); + d->Splitter->addWidget(d->DockArea); + } + + // Allows an equal distribution between the empty widget and the splitter + const auto frameGeometry = d->DockManager->frameGeometry(); + const auto leftSize = area == SideTabBarArea::Left ? frameGeometry.width() / 3 : frameGeometry.width(); + const auto rightSize = area == SideTabBarArea::Left ? frameGeometry.width() : frameGeometry.width() / 3; + d->Splitter->setSizes(QList({ leftSize, rightSize })); + l->setContentsMargins(QMargins()); + l->setSpacing(0); + l->addWidget(d->Splitter); + setLayout(l); + + updateMask(); + updateSize(); + + DockManager->registerOverlayWidget(this); + + d->DockArea->installEventFilter(this); + parent->installEventFilter(this); +} + +//============================================================================ +void COverlayDockContainer::updateMask() +{ + const auto rect = d->DockArea->frameGeometry(); + const auto topLeft = rect.topLeft(); + const auto handleSize = d->Splitter->handleWidth(); + const auto offset = d->Area == SideTabBarArea::Left ? 0 : handleSize; + setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); +} + +//============================================================================ +void COverlayDockContainer::updateSize() +{ + const auto dockContainerParent = parentContainer(); + const auto rootSplitter = dockContainerParent->rootSplitter(); + const auto rect = rootSplitter->frameGeometry(); + move(rect.topLeft()); + resize(rect.width(), rect.height()); +} + +//============================================================================ +COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area) : + COverlayDockContainer(DockWidget->dockManager(), area, DockWidget->dockContainer() != nullptr ? DockWidget->dockContainer() : DockWidget->dockManager()) +{ + addDockWidget(DockWidget); +} + +//============================================================================ +COverlayDockContainer::~COverlayDockContainer() +{ + ADS_PRINT("~COverlayDockContainer"); + + // Remove event filter in case there are any queued messages + parent()->removeEventFilter(this); + + if (d->DockManager) + { + d->DockManager->removeOverlayWidget(this); + } + + delete d; +} + +//============================================================================ +CSideTabBar* COverlayDockContainer::sideTabBar() const +{ + return parentContainer()->sideTabBar(d->Area); +} + +//============================================================================ +CDockWidget* COverlayDockContainer::dockWidget() const +{ + return d->DockWidget; +} + +//============================================================================ +void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) +{ + if (d->DockWidget) + { + // Remove the old dock widget at this area + d->DockArea->removeDockWidget(d->DockWidget); + } + + d->DockWidget = DockWidget; + CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); + if (OldDockArea) + { + OldDockArea->removeDockWidget(DockWidget); + } + d->DockArea->addDockWidget(DockWidget); + + updateSize(); + updateMask(); +} + + +//============================================================================ +SideTabBarArea COverlayDockContainer::sideTabBarArea() const +{ + return d->Area; +} + +//============================================================================ +CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const +{ + return d->DockArea; +} + +//============================================================================ +void COverlayDockContainer::moveContentsToParent() +{ + const auto position = mapToGlobal(d->Area == Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2)); + + const auto dockAreaWidget = parentContainer()->dockAreaAt(position); + if (dockAreaWidget != nullptr && !dockAreaWidget->isCentralWidgetArea()) + { + parentContainer()->addDockWidget(CenterDockWidgetArea, d->DockWidget, dockAreaWidget); + } + else + { + parentContainer()->addDockWidget(d->Area == Left ? LeftDockWidgetArea : RightDockWidgetArea, d->DockWidget); + } + cleanupAndDelete(); +} + +//============================================================================ +void COverlayDockContainer::cleanupAndDelete() +{ + const auto dockWidget = d->DockWidget; + if (dockWidget) + { + dockWidget->sideTabWidget()->removeFromSideTabBar(); + dockWidget->sideTabWidget()->setParent(dockWidget); + dockWidget->sideTabWidget()->hide(); + } + hide(); + deleteLater(); +} + +void COverlayDockContainer::saveState(QXmlStreamWriter& s) +{ + s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); + QStringList Sizes; + for (auto Size : d->Splitter->sizes()) + { + Sizes << QString::number(Size); + } + + s.writeAttribute("Sizes", Sizes.join(" ")); +} + +bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) +{ + auto sSizes = s.attributes().value("Sizes").trimmed().toString(); + ADS_PRINT("Sizes: " << sSizes); + QTextStream TextStream(&sSizes); + QList Sizes; + while (!TextStream.atEnd()) + { + int value; + TextStream >> value; + Sizes.append(value); + } + + if (Sizes.count() != d->Splitter->count()) + { + return false; + } + + if (!Testing) + { + d->Splitter->setSizes(Sizes); + } + + return true; +} + +//============================================================================ +bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) +{ + if (event->type() == QEvent::Resize) + { + updateSize(); + updateMask(); + } + return QWidget::eventFilter(watched, event); +} + +//============================================================================ +void COverlayDockContainer::mousePressEvent(QMouseEvent* event) +{ + QWidget::mousePressEvent(event); +} + +//============================================================================ +void COverlayDockContainer::resizeEvent(QResizeEvent* event) +{ + updateMask(); + QWidget::resizeEvent(event); +} +} + diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h new file mode 100644 index 0000000..1fe7e15 --- /dev/null +++ b/src/OverlayDockContainer.h @@ -0,0 +1,129 @@ +#ifndef OverlayDockContainerH +#define OverlayDockContainerH +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Declaration of COverlayDockContainer class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "ads_globals.h" + +#include + +class QXmlStreamWriter; + +namespace ads +{ +struct OverlayDockContainerPrivate; +class CDockManager; +class CDockWidget; +class CDockContainerWidget; +class CSideTabBar; +class CDockAreaWidget; +class CDockingStateReader; + +class ADS_EXPORT COverlayDockContainer : public QFrame +{ + Q_OBJECT +private: + OverlayDockContainerPrivate* d; ///< private data (pimpl) + friend struct OverlayDockContainerPrivate; + + CDockContainerWidget* parentContainer() const; + +protected: + bool eventFilter(QObject* watched, QEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + void resizeEvent(QResizeEvent* event) override; + void updateMask(); + void updateSize(); + +public: + /** + * Create overlay widget with a dock manager + */ + COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent); + + /** + * Create overlay widget with the given dock widget + */ + COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area); + + /** + * Virtual Destructor + */ + virtual ~COverlayDockContainer(); + + /** + * Get's the side tab bar + */ + CSideTabBar* sideTabBar() const; + + /** + * Get's the dock widget in this dock container + */ + CDockWidget* dockWidget() const; + + /** + * Adds a dock widget and removes the previous dock widget + */ + void addDockWidget(CDockWidget* DockWidget); + + /** + * Returns the side tab bar area of this overlay dock container + */ + SideTabBarArea sideTabBarArea() const; + + /** + * Returns the dock area widget of this overlay dock container + */ + CDockAreaWidget* dockAreaWidget() const; + + /** + * Moves the contents to the parent container widget + * Used before removing this overlay dock container + */ + void moveContentsToParent(); + + /** + * Cleanups up the side tab widget and then deletes itself + */ + void cleanupAndDelete(); + + /* + * Saves the state and size + */ + void saveState(QXmlStreamWriter& Stream); + + /* + * Restores the size of the splitter + */ + bool restoreState(CDockingStateReader& Stream, bool Testing); +}; +} + + +#endif diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp new file mode 100644 index 0000000..64129c4 --- /dev/null +++ b/src/SideTabBar.cpp @@ -0,0 +1,101 @@ +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Implementation of CSideTabBar class +//============================================================================ + + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "SideTabBar.h" +#include "DockContainerWidget.h" +#include "DockWidgetSideTab.h" +#include "DockWidgetTab.h" + +#include + +namespace ads +{ +/** + * Private data class of CSideTabBar class (pimpl) + */ +struct SideTabBarPrivate +{ + /** + * Private data constructor + */ + SideTabBarPrivate(CSideTabBar* _public); + + CSideTabBar* _this; + CDockContainerWidget* ContainerWidget; + QBoxLayout* TabsLayout; +}; // struct SideTabBarPrivate + +//============================================================================ +SideTabBarPrivate::SideTabBarPrivate(CSideTabBar* _public) : + _this(_public) +{ +} + + +//============================================================================ +CSideTabBar::CSideTabBar(CDockContainerWidget* parent) : + QWidget(parent), + d(new SideTabBarPrivate(this)) +{ + d->ContainerWidget = parent; + + d->TabsLayout = new QBoxLayout(QBoxLayout::TopToBottom); + d->TabsLayout->setContentsMargins(0, 0, 0, 0); + d->TabsLayout->setSpacing(0); + d->TabsLayout->addStretch(1); + setLayout(d->TabsLayout); + + setFocusPolicy(Qt::NoFocus); +} + + +//============================================================================ +CSideTabBar::~CSideTabBar() +{ + delete d; +} + + +//============================================================================ +void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) +{ + d->TabsLayout->insertWidget(Index, SideTab); + SideTab->setSideTabBar(this); +} + + +//============================================================================ +void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) +{ + const auto index = d->TabsLayout->indexOf(SideTab); + d->TabsLayout->removeWidget(SideTab); +} +} diff --git a/src/SideTabBar.h b/src/SideTabBar.h new file mode 100644 index 0000000..5259203 --- /dev/null +++ b/src/SideTabBar.h @@ -0,0 +1,81 @@ +#ifndef SideTabBarH +#define SideTabBarH +/******************************************************************************* +** 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 DockWidgetTab.h +/// \author Syarif Fakhri +/// \date 05.09.2022 +/// \brief Declaration of CSideTabBar class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include +#include "ads_globals.h" + +namespace ads +{ +struct SideTabBarPrivate; +class CDockContainerWidget; +class CDockWidgetSideTab; +class CDockWidgetTab; + +/** + * Side tab widget that is shown at the edges of a dock container. + */ +class ADS_EXPORT CSideTabBar : public QWidget +{ + Q_OBJECT +private: + SideTabBarPrivate* d; ///< private data (pimpl) + friend struct SideTabBarPrivate; + friend class DockWidgetSideTab; + +public: + using Super = QWidget; + + /** + * Default Constructor + */ + CSideTabBar(CDockContainerWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CSideTabBar(); + + /** + * Inserts the given dock widget tab at the given position. + */ + void insertSideTab(int Index, CDockWidgetSideTab* SideTab); + + /** + * Removes the given DockWidgetSideTab from the tabbar + */ + void removeSideTab(CDockWidgetSideTab* SideTab); + + Q_SIGNALS: + void sideTabAutoHideToggleRequested(); +}; +} + +#endif diff --git a/src/ads_globals.h b/src/ads_globals.h index 777bd82..2df6459 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -91,7 +91,8 @@ enum TitleBarButton { TitleBarButtonTabsMenu, TitleBarButtonUndock, - TitleBarButtonClose + TitleBarButtonClose, + TitleBarButtonAutoHide }; /** @@ -105,12 +106,24 @@ enum eDragState DraggingFloatingWidget//!< DraggingFloatingWidget }; +/** + * Dock widget side tab bar locations + */ +enum SideTabBarArea +{ + None, + Left, + Right, + Bottom +}; + /** * The different icons used in the UI */ enum eIcon { TabCloseIcon, //!< TabCloseIcon + AutoHideIcon, //!< AutoHideIcon DockAreaMenuIcon, //!< DockAreaMenuIcon DockAreaUndockIcon,//!< DockAreaUndockIcon DockAreaCloseIcon, //!< DockAreaCloseIcon diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 5551721..2844d6e 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -2,7 +2,7 @@ * Default style sheet on Windows Platforms with focus highlighting flag enabled */ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; @@ -22,6 +22,14 @@ ads--CDockWidgetTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } +ads--CDockWidgetSideTab { + background: palette(window); + border-color: palette(light); + border-style: solid; + border-width: 1px 1px 1px 1px; + padding: 0 0px; +} + ads--CDockWidgetTab[activeTab="true"] { background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0 palette(window), stop:1 palette(light)); @@ -100,6 +108,10 @@ ads--CDockWidgetTab[focused="true"] { border-color: palette(highlight); } +ads--CDockWidgetSideTab[focused="true"] { + border-color: palette(highlight); +} + ads--CDockWidgetTab[focused="true"]>#tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } @@ -126,4 +138,4 @@ ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { background: transparent; border-bottom: 2px solid palette(highlight); padding-bottom: 0px; -} +} \ No newline at end of file