From da8f17cce252a900150c81d4e2a5f2f87e8f3dc9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 5 Sep 2022 17:04:41 +0800 Subject: [PATCH 001/236] Fix perspective for central widget demo --- examples/centralwidget/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/centralwidget/mainwindow.cpp b/examples/centralwidget/mainwindow.cpp index fe1b34714..3ad0056df 100644 --- a/examples/centralwidget/mainwindow.cpp +++ b/examples/centralwidget/mainwindow.cpp @@ -96,7 +96,7 @@ void CMainWindow::createPerspectiveUi() PerspectiveComboBox = new QComboBox(this); PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); - connect(PerspectiveComboBox, SIGNAL(activated(const QString&)), + connect(PerspectiveComboBox, SIGNAL(currentTextChanged(const QString&)), DockManager, SLOT(openPerspective(const QString&))); PerspectiveListAction->setDefaultWidget(PerspectiveComboBox); ui->toolBar->addSeparator(); From 3e9dc7f4d61a3ad170e305c853f44aa12826057f Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 5 Sep 2022 17:29:42 +0800 Subject: [PATCH 002/236] Add initial functionality for Auto hide - Add left and right side tab widgets - Add overlay dock and overlay dock widget behavior --- src/CMakeLists.txt | 6 + src/DockAreaTitleBar.cpp | 31 ++- src/DockAreaTitleBar.h | 3 +- src/DockAreaWidget.cpp | 65 +++++- src/DockAreaWidget.h | 28 +++ src/DockComponentsFactory.cpp | 7 + src/DockComponentsFactory.h | 7 + src/DockContainerWidget.cpp | 248 +++++++++++++++++++- src/DockContainerWidget.h | 23 ++ src/DockFocusController.cpp | 9 + src/DockManager.cpp | 33 +++ src/DockManager.h | 32 ++- src/DockWidget.cpp | 81 +++++-- src/DockWidget.h | 18 ++ src/DockWidgetSideTab.cpp | 151 ++++++++++++ src/DockWidgetSideTab.h | 96 ++++++++ src/DockWidgetTab.cpp | 2 +- src/DockWidgetTab.h | 1 + src/ElidingLabel.cpp | 29 +++ src/ElidingLabel.h | 12 + src/FloatingDragPreview.cpp | 20 ++ src/FloatingDragPreview.h | 5 + src/OverlayDockContainer.cpp | 309 +++++++++++++++++++++++++ src/OverlayDockContainer.h | 129 +++++++++++ src/SideTabBar.cpp | 101 ++++++++ src/SideTabBar.h | 81 +++++++ src/ads_globals.h | 15 +- src/stylesheets/focus_highlighting.css | 16 +- 28 files changed, 1530 insertions(+), 28 deletions(-) create mode 100644 src/DockWidgetSideTab.cpp create mode 100644 src/DockWidgetSideTab.h create mode 100644 src/OverlayDockContainer.cpp create mode 100644 src/OverlayDockContainer.h create mode 100644 src/SideTabBar.cpp create mode 100644 src/SideTabBar.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dea76a0d5..a68b2db44 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 8651d2994..13021e3e2 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 37f3a9182..70010a48c 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 09fd8fd22..508fb7cd2 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 eaf290cce..d34c3521a 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -65,6 +65,7 @@ class ADS_EXPORT CDockAreaWidget : public QFrame friend class CDockWidget; friend struct DockManagerPrivate; friend class CDockManager; + friend class COverlayDockContainer; void onDockWidgetFeaturesChanged(); private Q_SLOTS: @@ -186,6 +187,23 @@ protected Q_SLOTS: */ 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 1f8be65d6..3e7ebc1ff 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 f0598e989..3e726aef0 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 @@ class ADS_EXPORT CDockComponentsFactory */ 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 5451eb32e..eaca38d9b 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 @@ class DockContainerWidgetPrivate QPointer DockManager; unsigned int zOrderIndex = 0; QList DockAreas; + QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; bool isFloating = false; @@ -212,6 +219,11 @@ class DockContainerWidgetPrivate 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 @@ class DockContainerWidgetPrivate 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 a9ebea430..e895fd503 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 @@ class ADS_EXPORT CDockContainerWidget : public QFrame friend class CDockWidget; friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; + friend class COverlayDockContainer; protected: /** @@ -91,6 +93,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ void createRootSplitter(); + /** + * Helper function for creation of the side tab bar widgets + */ + void createSideTabBarWidgets(); + /** * Drop floating widget into the container */ @@ -163,6 +170,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame void updateSplitterHandles(QSplitter* splitter); public: + /** * Default Constructor */ @@ -183,6 +191,16 @@ class ADS_EXPORT CDockContainerWidget : public QFrame 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 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ 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 595c9fa67..89d94995d 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 ecb558cb0..33c402e39 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 7747d23bb..17b8bc2f1 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -84,6 +84,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; friend class CDockAreaTitleBar; + friend class COverlayDockContainer; protected: @@ -93,12 +94,24 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget */ 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 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget //! 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 @@ public Q_SLOTS: */ 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 e4b94d8a0..f8b1cf1db 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 abf876618..1bcd03b38 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 @@ private Q_SLOTS: 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 @@ private Q_SLOTS: */ 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 @@ private Q_SLOTS: */ 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 000000000..a3d2b2310 --- /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 000000000..e99ada0de --- /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 512e6b521..f8b4e7252 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 7ee45e387..b46ac8559 100644 --- a/src/DockWidgetTab.h +++ b/src/DockWidgetTab.h @@ -58,6 +58,7 @@ class ADS_EXPORT CDockWidgetTab : public QFrame 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 ac521228f..ee7531378 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 894dcb069..8dbf051af 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -102,6 +102,18 @@ class ADS_EXPORT CElidingLabel : public QLabel 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 c6ceb1a95..4fcbb5197 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 38224808c..2920a9e55 100644 --- a/src/FloatingDragPreview.h +++ b/src/FloatingDragPreview.h @@ -92,6 +92,11 @@ private Q_SLOTS: */ 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 000000000..75b6a14da --- /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 000000000..1fe7e1508 --- /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 000000000..64129c412 --- /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 000000000..5259203ae --- /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 777bd824c..2df6459ab 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 555172184..2844d6e5b 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 From bfab7e495a67a68d2383d89713ed8d6d9a6855b9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 6 Sep 2022 13:49:11 +0800 Subject: [PATCH 003/236] Move logic for enabling auto hide into the public toggle method --- src/DockAreaTitleBar.cpp | 7 +++---- src/DockAreaWidget.cpp | 7 ++++++- src/DockAreaWidget.h | 12 ++++++------ 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 13021e3e2..8795e0b4c 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -457,12 +457,11 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) updateDockWidgetActionsButtons(); } + +//============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked(bool Checked) { - if (Checked != d->DockArea->isOverlayed()) - { - d->DockArea->toggleAutoHideArea(); - } + d->DockArea->toggleAutoHideArea(Checked); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 508fb7cd2..dba256807 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1009,11 +1009,16 @@ void CDockAreaWidget::closeArea() } //============================================================================ -void CDockAreaWidget::toggleAutoHideArea() +void CDockAreaWidget::toggleAutoHideArea(bool Enable) { const auto area = dockContainer()->getDockAreaPosition(this); for (const auto DockWidget : openedDockWidgets()) { + if (Enable == isOverlayed()) + { + continue; + } + onAutoHideToggleRequested(DockWidget, !isOverlayed(), area); } } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index d34c3521a..b92e34de2 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -153,6 +153,11 @@ private Q_SLOTS: protected Q_SLOTS: void toggleView(bool Open); + /** + * Auto hides the dock area and all dock widgets in this area + */ + void onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area); + public: using Super = QFrame; @@ -357,12 +362,7 @@ public Q_SLOTS: /** * 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); + void toggleAutoHideArea(bool Enable); /** * This function closes all other areas except of this area From 6e35a9e7a79367eba5daec70a93a9c3634d57a89 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 6 Sep 2022 15:35:18 +0800 Subject: [PATCH 004/236] - Add an example folder for auto hide functionality Note: this does not include the py file, To be added in a different commit - Added a better API to programatically add the overlay areas in the CDockManager --- examples/autohide/CMakeLists.txt | 28 ++++ examples/autohide/main.cpp | 10 ++ examples/autohide/main.py | 106 ++++++++++++++ examples/autohide/mainwindow.cpp | 133 ++++++++++++++++++ examples/autohide/mainwindow.h | 43 ++++++ examples/autohide/mainwindow.ui | 47 +++++++ examples/centralwidget/CMakeLists.txt | 14 +- .../{centralwidget.pro => autohide.pro} | 5 +- examples/centralwidget/mainwindow.cpp | 4 +- src/DockAreaWidget.cpp | 2 +- src/DockContainerWidget.cpp | 21 ++- src/DockContainerWidget.h | 13 +- src/DockManager.cpp | 20 ++- src/DockManager.h | 14 ++ src/OverlayDockContainer.cpp | 19 ++- src/OverlayDockContainer.h | 5 + 16 files changed, 452 insertions(+), 32 deletions(-) create mode 100644 examples/autohide/CMakeLists.txt create mode 100644 examples/autohide/main.cpp create mode 100644 examples/autohide/main.py create mode 100644 examples/autohide/mainwindow.cpp create mode 100644 examples/autohide/mainwindow.h create mode 100644 examples/autohide/mainwindow.ui rename examples/centralwidget/{centralwidget.pro => autohide.pro} (92%) diff --git a/examples/autohide/CMakeLists.txt b/examples/autohide/CMakeLists.txt new file mode 100644 index 000000000..7f57821e8 --- /dev/null +++ b/examples/autohide/CMakeLists.txt @@ -0,0 +1,28 @@ +cmake_minimum_required(VERSION 3.5) +project(ads_example_centralwidget VERSION ${VERSION_SHORT}) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) +find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +add_executable(CentralWidgetExample WIN32 + main.cpp + mainwindow.cpp + mainwindow.ui +) +target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") +target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking) +target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Gui + Qt${QT_VERSION_MAJOR}::Widgets) +set_target_properties(CentralWidgetExample PROPERTIES + AUTOMOC ON + AUTORCC ON + AUTOUIC ON + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED ON + CXX_EXTENSIONS OFF + VERSION ${VERSION_SHORT} + EXPORT_NAME "Qt Advanced Docking System Central Widget Example" + ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" +) diff --git a/examples/autohide/main.cpp b/examples/autohide/main.cpp new file mode 100644 index 000000000..fa4c4fdea --- /dev/null +++ b/examples/autohide/main.cpp @@ -0,0 +1,10 @@ +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + CMainWindow w; + w.show(); + return a.exec(); +} diff --git a/examples/autohide/main.py b/examples/autohide/main.py new file mode 100644 index 000000000..5fe6a492d --- /dev/null +++ b/examples/autohide/main.py @@ -0,0 +1,106 @@ +import os +import sys + +from PyQt5 import uic +from PyQt5.QtCore import Qt, QTimer, QDir, QSignalBlocker +from PyQt5.QtGui import QCloseEvent, QIcon +from PyQt5.QtWidgets import (QApplication, QLabel, QCalendarWidget, QFrame, QTreeView, + QTableWidget, QFileSystemModel, QPlainTextEdit, QToolBar, + QWidgetAction, QComboBox, QAction, QSizePolicy, QInputDialog) + +from PyQtAds import QtAds + +UI_FILE = os.path.join(os.path.dirname(__file__), 'mainwindow.ui') +MainWindowUI, MainWindowBase = uic.loadUiType(UI_FILE) + +class MainWindow(MainWindowUI, MainWindowBase): + + def __init__(self, parent=None): + super().__init__(parent) + + self.setupUi(self) + + QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.OpaqueSplitterResize, True) + QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.XmlCompressionEnabled, False) + QtAds.CDockManager.setConfigFlag(QtAds.CDockManager.FocusHighlighting, True) + self.dock_manager = QtAds.CDockManager(self) + + # Set central widget + text_edit = QPlainTextEdit() + text_edit.setPlaceholderText("This is the central editor. Enter your text here.") + central_dock_widget = QtAds.CDockWidget("CentralWidget") + central_dock_widget.setWidget(text_edit) + central_dock_area = self.dock_manager.setCentralWidget(central_dock_widget) + central_dock_area.setAllowedAreas(QtAds.DockWidgetArea.OuterDockAreas) + + # create other dock widgets + table = QTableWidget() + table.setColumnCount(3) + table.setRowCount(10) + table_dock_widget = QtAds.CDockWidget("Table 1") + table_dock_widget.setWidget(table) + table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget) + table_dock_widget.resize(250, 150) + table_dock_widget.setMinimumSize(200, 150) + table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.LeftDockWidgetArea, table_dock_widget) + self.menuView.addAction(table_dock_widget.toggleViewAction()) + + table = QTableWidget() + table.setColumnCount(5) + table.setRowCount(1020) + table_dock_widget = QtAds.CDockWidget("Table 2") + table_dock_widget.setWidget(table) + table_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget) + table_dock_widget.resize(250, 150) + table_dock_widget.setMinimumSize(200, 150) + table_area = self.dock_manager.addDockWidget(QtAds.DockWidgetArea.BottomDockWidgetArea, table_dock_widget, table_area) + self.menuView.addAction(table_dock_widget.toggleViewAction()) + + properties_table = QTableWidget() + properties_table.setColumnCount(3) + properties_table.setRowCount(10) + properties_dock_widget = QtAds.CDockWidget("Properties") + properties_dock_widget.setWidget(properties_table) + properties_dock_widget.setMinimumSizeHintMode(QtAds.CDockWidget.MinimumSizeHintFromDockWidget) + properties_dock_widget.resize(250, 150) + properties_dock_widget.setMinimumSize(200, 150) + self.dock_manager.addDockWidget(QtAds.DockWidgetArea.RightDockWidgetArea, properties_dock_widget, central_dock_area) + self.menuView.addAction(properties_dock_widget.toggleViewAction()) + + self.create_perspective_ui() + + def create_perspective_ui(self): + save_perspective_action = QAction("Create Perspective", self) + save_perspective_action.triggered.connect(self.save_perspective) + perspective_list_action = QWidgetAction(self) + self.perspective_combobox = QComboBox(self) + self.perspective_combobox.setSizeAdjustPolicy(QComboBox.AdjustToContents) + self.perspective_combobox.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Preferred) + self.perspective_combobox.activated[str].connect(self.dock_manager.openPerspective) + perspective_list_action.setDefaultWidget(self.perspective_combobox) + self.toolBar.addSeparator() + self.toolBar.addAction(perspective_list_action) + self.toolBar.addAction(save_perspective_action) + + def save_perspective(self): + perspective_name, ok = QInputDialog.getText(self, "Save Perspective", "Enter Unique name:") + if not ok or not perspective_name: + return + + self.dock_manager.addPerspective(perspective_name) + blocker = QSignalBlocker(self.perspective_combobox) + self.perspective_combobox.clear() + self.perspective_combobox.addItems(self.dock_manager.perspectiveNames()) + self.perspective_combobox.setCurrentText(perspective_name) + + def closeEvent(self, event: QCloseEvent): + self.dock_manager.deleteLater() + super().closeEvent(event) + + +if __name__ == '__main__': + app = QApplication(sys.argv) + + w = MainWindow() + w.show() + app.exec_() diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp new file mode 100644 index 000000000..3ad0056df --- /dev/null +++ b/examples/autohide/mainwindow.cpp @@ -0,0 +1,133 @@ +#include "mainwindow.h" + +#include "ui_mainwindow.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "DockAreaWidget.h" +#include "DockAreaTitleBar.h" +#include "DockAreaTabBar.h" +#include "FloatingDockContainer.h" +#include "DockComponentsFactory.h" + +using namespace ads; + + +CMainWindow::CMainWindow(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::CMainWindow) +{ + ui->setupUi(this); + CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true); + CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false); + CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + DockManager = new CDockManager(this); + + // Set central widget + QPlainTextEdit* w = new QPlainTextEdit(); + w->setPlaceholderText("This is the central editor. Enter your text here."); + CDockWidget* CentralDockWidget = new CDockWidget("CentralWidget"); + CentralDockWidget->setWidget(w); + auto* CentralDockArea = DockManager->setCentralWidget(CentralDockWidget); + CentralDockArea->setAllowedAreas(DockWidgetArea::OuterDockAreas); + + // create other dock widgets + QTableWidget* table = new QTableWidget(); + table->setColumnCount(3); + table->setRowCount(10); + CDockWidget* TableDockWidget = new CDockWidget("Table 1"); + TableDockWidget->setWidget(table); + TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); + TableDockWidget->resize(250, 150); + TableDockWidget->setMinimumSize(200,150); + auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); + ui->menuView->addAction(TableDockWidget->toggleViewAction()); + + table = new QTableWidget(); + table->setColumnCount(5); + table->setRowCount(1020); + TableDockWidget = new CDockWidget("Table 2"); + TableDockWidget->setWidget(table); + TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); + TableDockWidget->resize(250, 150); + TableDockWidget->setMinimumSize(200,150); + DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); + ui->menuView->addAction(TableDockWidget->toggleViewAction()); + + QTableWidget* propertiesTable = new QTableWidget(); + propertiesTable->setColumnCount(3); + propertiesTable->setRowCount(10); + CDockWidget* PropertiesDockWidget = new CDockWidget("Properties"); + PropertiesDockWidget->setWidget(propertiesTable); + PropertiesDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); + PropertiesDockWidget->resize(250, 150); + PropertiesDockWidget->setMinimumSize(200,150); + DockManager->addDockWidget(DockWidgetArea::RightDockWidgetArea, PropertiesDockWidget, CentralDockArea); + ui->menuView->addAction(PropertiesDockWidget->toggleViewAction()); + + createPerspectiveUi(); +} + +CMainWindow::~CMainWindow() +{ + delete ui; +} + + +void CMainWindow::createPerspectiveUi() +{ + SavePerspectiveAction = new QAction("Create Perspective", this); + connect(SavePerspectiveAction, SIGNAL(triggered()), SLOT(savePerspective())); + PerspectiveListAction = new QWidgetAction(this); + PerspectiveComboBox = new QComboBox(this); + PerspectiveComboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); + PerspectiveComboBox->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + connect(PerspectiveComboBox, SIGNAL(currentTextChanged(const QString&)), + DockManager, SLOT(openPerspective(const QString&))); + PerspectiveListAction->setDefaultWidget(PerspectiveComboBox); + ui->toolBar->addSeparator(); + ui->toolBar->addAction(PerspectiveListAction); + ui->toolBar->addAction(SavePerspectiveAction); +} + + +void CMainWindow::savePerspective() +{ + QString PerspectiveName = QInputDialog::getText(this, "Save Perspective", "Enter unique name:"); + if (PerspectiveName.isEmpty()) + { + return; + } + + DockManager->addPerspective(PerspectiveName); + QSignalBlocker Blocker(PerspectiveComboBox); + PerspectiveComboBox->clear(); + PerspectiveComboBox->addItems(DockManager->perspectiveNames()); + PerspectiveComboBox->setCurrentText(PerspectiveName); +} + + +//============================================================================ +void CMainWindow::closeEvent(QCloseEvent* event) +{ + // Delete dock manager here to delete all floating widgets. This ensures + // that all top level windows of the dock manager are properly closed + DockManager->deleteLater(); + QMainWindow::closeEvent(event); +} + + diff --git a/examples/autohide/mainwindow.h b/examples/autohide/mainwindow.h new file mode 100644 index 000000000..75869da84 --- /dev/null +++ b/examples/autohide/mainwindow.h @@ -0,0 +1,43 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include +#include +#include + +#include "DockManager.h" +#include "DockAreaWidget.h" +#include "DockWidget.h" + +QT_BEGIN_NAMESPACE +namespace Ui { class CMainWindow; } +QT_END_NAMESPACE + +class CMainWindow : public QMainWindow +{ + Q_OBJECT + +public: + CMainWindow(QWidget *parent = nullptr); + ~CMainWindow(); + +protected: + virtual void closeEvent(QCloseEvent* event) override; + +private: + QAction* SavePerspectiveAction = nullptr; + QWidgetAction* PerspectiveListAction = nullptr; + QComboBox* PerspectiveComboBox = nullptr; + + Ui::CMainWindow *ui; + + ads::CDockManager* DockManager; + ads::CDockAreaWidget* StatusDockArea; + ads::CDockWidget* TimelineDockWidget; + + void createPerspectiveUi(); + +private slots: + void savePerspective(); +}; +#endif // MAINWINDOW_H diff --git a/examples/autohide/mainwindow.ui b/examples/autohide/mainwindow.ui new file mode 100644 index 000000000..f7d3b09e8 --- /dev/null +++ b/examples/autohide/mainwindow.ui @@ -0,0 +1,47 @@ + + + CMainWindow + + + + 0 + 0 + 1284 + 757 + + + + MainWindow + + + + + + 0 + 0 + 1284 + 21 + + + + + View + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + diff --git a/examples/centralwidget/CMakeLists.txt b/examples/centralwidget/CMakeLists.txt index 7f57821e8..cec3910e2 100644 --- a/examples/centralwidget/CMakeLists.txt +++ b/examples/centralwidget/CMakeLists.txt @@ -1,19 +1,19 @@ cmake_minimum_required(VERSION 3.5) -project(ads_example_centralwidget VERSION ${VERSION_SHORT}) +project(ads_example_autohide VERSION ${VERSION_SHORT}) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(CentralWidgetExample WIN32 +add_executable(AutoHideExample WIN32 main.cpp mainwindow.cpp mainwindow.ui ) -target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") -target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking) -target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core +target_include_directories(AutoHideExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") +target_link_libraries(AutoHideExample PRIVATE qtadvanceddocking) +target_link_libraries(AutoHideExample PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets) -set_target_properties(CentralWidgetExample PROPERTIES +set_target_properties(AutoHideExample PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON @@ -21,7 +21,7 @@ set_target_properties(CentralWidgetExample PROPERTIES CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF VERSION ${VERSION_SHORT} - EXPORT_NAME "Qt Advanced Docking System Central Widget Example" + EXPORT_NAME "Qt Advanced Docking System Auto Hide Example" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" diff --git a/examples/centralwidget/centralwidget.pro b/examples/centralwidget/autohide.pro similarity index 92% rename from examples/centralwidget/centralwidget.pro rename to examples/centralwidget/autohide.pro index 738ae781f..824b451bf 100644 --- a/examples/centralwidget/centralwidget.pro +++ b/examples/centralwidget/autohide.pro @@ -2,7 +2,7 @@ ADS_OUT_ROOT = $${OUT_PWD}/../.. QT += core gui widgets -TARGET = CentralWidgetExample +TARGET = AutoHideExample DESTDIR = $${ADS_OUT_ROOT}/lib TEMPLATE = app CONFIG += c++14 @@ -24,9 +24,6 @@ SOURCES += \ HEADERS += \ mainwindow.h -FORMS += \ - mainwindow.ui - LIBS += -L$${ADS_OUT_ROOT}/lib include(../../ads.pri) INCLUDEPATH += ../../src diff --git a/examples/centralwidget/mainwindow.cpp b/examples/centralwidget/mainwindow.cpp index 3ad0056df..eca2e946d 100644 --- a/examples/centralwidget/mainwindow.cpp +++ b/examples/centralwidget/mainwindow.cpp @@ -54,7 +54,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); + DockManager->addOverlayDockWidget(SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -65,7 +65,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); + DockManager->addOverlayDockWidget(SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index dba256807..602648637 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1030,7 +1030,7 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En { dockContainer()->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); - dockContainer()->createDockWidgetOverlayContainer(area, DockWidget); + dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget); toggleView(false); } else diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index eaca38d9b..bd261af5b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1046,12 +1046,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " << CurrentDockWidget); - if (area == Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) - { - return false; - } - - if (area == Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + if (!COverlayDockContainer::areaExistsInConfig(area)) { return false; } @@ -1497,14 +1492,26 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW } } -void CDockContainerWidget::createDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget) + +//============================================================================ +COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget) { if (d->DockManager != DockWidget->dockManager()) { DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager } + if (!COverlayDockContainer::areaExistsInConfig(area)) + { + assert(false, "Requested area does not exist in config"); + return nullptr; + } + + sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); + DockWidget->sideTabWidget()->show(); + const auto dockContainer = new COverlayDockContainer(DockWidget, area); dockContainer->hide(); + return dockContainer; } //============================================================================ diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index e895fd503..9d93b6f0b 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -88,6 +88,14 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ QSplitter* rootSplitter() const; + + /** + * Creates and initializes a dockwidget overlay container into the given area. + * Initializing inserts the tabs into the side tab widget and hides it + * Returns nullptr if you try and insert into an area where the configuration is not enabled + */ + COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget); + /** * Helper function for creation of the root splitter */ @@ -191,11 +199,6 @@ class ADS_EXPORT CDockContainerWidget : public QFrame 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 */ diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 33c402e39..4f4787de2 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -865,7 +865,7 @@ CDockAreaWidget* CDockManager::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); - auto Container = DockAreaWidget ? DockAreaWidget->dockContainer(): this; + auto Container = DockAreaWidget ? DockAreaWidget->dockContainer() : this; auto AreaOfAddedDockWidget = Container->addDockWidget(area, Dockwidget, DockAreaWidget); Q_EMIT dockWidgetAdded(Dockwidget); return AreaOfAddedDockWidget; @@ -881,6 +881,24 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, return AreaOfAddedDockWidget; } +//============================================================================ +COverlayDockContainer* CDockManager::addOverlayDockWidget(SideTabBarArea area, CDockWidget* Dockwidget) +{ + return addOverlayDockWidgetToContainer(area, Dockwidget, this); +} + +//============================================================================ +COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget) +{ + d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); + auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget); + container->dockAreaWidget()->toggleView(false); + Dockwidget->toggleView(false); + + Q_EMIT dockWidgetAdded(Dockwidget); + return container; +} + //============================================================================ CDockAreaWidget* CDockManager::addDockWidgetTab(DockWidgetArea area, diff --git a/src/DockManager.h b/src/DockManager.h index 17b8bc2f1..272aa1982 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -315,6 +315,20 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget CDockAreaWidget* addDockWidgetToContainer(DockWidgetArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); + /** + * Adds a dock widget overlayed into the dock manager container based on the side tab bar area. + * An overlay widget is used for auto hide functionality + * \return Returns the COverlayDockContainer that contains the new DockWidget + */ + COverlayDockContainer* addOverlayDockWidget(SideTabBarArea area, CDockWidget* Dockwidget); + + /** + * Adds dock widget overlayed into the given container based on the SideTabBarArea. + * An overlay widget is used for auto hide functionality + * \return Returns the COverlayDockContainer that contains the new DockWidget + */ + COverlayDockContainer* addOverlayDockWidgetToContainer(SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); + /** * This function will add the given Dockwidget to the given dock area as * a new tab. diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 75b6a14da..0eaf84dc1 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -105,11 +105,6 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabB 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); @@ -282,6 +277,20 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } +bool COverlayDockContainer::areaExistsInConfig(SideTabBarArea area) +{ + if (area == Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + { + return false; + } + if (area == Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + { + return false; + } + + return true; +} + //============================================================================ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) { diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index 1fe7e1508..e826e9cc9 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -122,6 +122,11 @@ class ADS_EXPORT COverlayDockContainer : public QFrame * Restores the size of the splitter */ bool restoreState(CDockingStateReader& Stream, bool Testing); + + /* + * Convenience function fr determining if area exists in config + */ + static bool areaExistsInConfig(SideTabBarArea area); }; } From fde133c25e14dfed257dd2eca4fdaf86fe372e79 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 6 Sep 2022 17:42:26 +0800 Subject: [PATCH 005/236] Fix a bug where overlay widgets from another container widget would not be correctly transferred into the container widget that it's dragged into. --- src/DockAreaWidget.cpp | 2 -- src/DockContainerWidget.cpp | 49 ++++++++++++++++++++++++++++++++++-- src/DockContainerWidget.h | 29 +++++++++++++++++++++ src/DockManager.cpp | 32 +---------------------- src/DockManager.h | 17 ------------- src/OverlayDockContainer.cpp | 8 +++--- src/OverlayDockContainer.h | 2 +- 7 files changed, 82 insertions(+), 57 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 602648637..245efc0b4 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1028,8 +1028,6 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En { if (Enable) { - dockContainer()->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); - DockWidget->sideTabWidget()->show(); dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget); toggleView(false); } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index bd261af5b..7f970b2f1 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -137,6 +137,7 @@ class DockContainerWidgetPrivate QPointer DockManager; unsigned int zOrderIndex = 0; QList DockAreas; + QList OverlayWidgets; QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; @@ -1467,6 +1468,13 @@ CDockContainerWidget::~CDockContainerWidget() { d->DockManager->removeDockContainer(this); } + + auto OverlayWidgets = d->OverlayWidgets; + for (auto OverlayWidget : OverlayWidgets) + { + delete OverlayWidget; + } + delete d; } @@ -1509,7 +1517,7 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); - const auto dockContainer = new COverlayDockContainer(DockWidget, area); + const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); dockContainer->hide(); return dockContainer; } @@ -1584,6 +1592,23 @@ bool CDockContainerWidget::event(QEvent *e) } +//============================================================================ +void CDockContainerWidget::deleteOverlayWidgets() +{ + for (auto OverlayWidget : d->OverlayWidgets) + { + OverlayWidget->cleanupAndDelete(); + } + d->OverlayWidgets.clear(); +} + +//============================================================================ +QList CDockContainerWidget::overlayWidgets() const +{ + return d->OverlayWidgets; +} + + //============================================================================ void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget, DockWidgetArea area) @@ -1758,6 +1783,14 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); bool Dropped = false; + // Handle any overlay widgets + // todo: cleanup - move into own func? + auto overlayWidgets = FloatingWidget->dockContainer()->overlayWidgets(); + for (const auto overlayWidget : overlayWidgets) + { + createAndInitializeDockWidgetOverlayContainer(overlayWidget->sideTabBarArea(), overlayWidget->dockWidget()); + } + if (DockArea) { auto dropOverlay = d->DockManager->dockAreaOverlay(); @@ -2084,13 +2117,25 @@ QList CDockContainerWidget::dockWidgets() const return Result; } - //============================================================================ void CDockContainerWidget::updateSplitterHandles(QSplitter* splitter) { d->updateSplitterHandles(splitter); } +//============================================================================ +void CDockContainerWidget::registerOverlayWidget(COverlayDockContainer* OverlayWidget) +{ + d->OverlayWidgets.append(OverlayWidget); + Q_EMIT overlayWidgetCreated(OverlayWidget); + ADS_PRINT("d->OverlayWidgets.count() " << d->OverlayWidgets.count()); +} + +//============================================================================ +void CDockContainerWidget::removeOverlayWidget(COverlayDockContainer* OverlayWidget) +{ + d->OverlayWidgets.removeAll(OverlayWidget); +} //============================================================================ CDockWidget::DockWidgetFeatures CDockContainerWidget::features() const diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 9d93b6f0b..281602d6b 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -83,6 +83,17 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ virtual bool event(QEvent *e) override; + /* + * Delete function for resetting the overlay widget list + * Used during restore + */ + void deleteOverlayWidgets(); + + /** + * Access function for overlay widgets + */ + QList overlayWidgets() const; + /** * Access function for the internal root splitter */ @@ -177,6 +188,19 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ void updateSplitterHandles(QSplitter* splitter); + /** + * Registers the given floating widget in the internal list of + * overlay widgets + */ + void registerOverlayWidget(COverlayDockContainer* OverlayWidget); + + /** + * Remove the given overlay widget from the list of registered overlay + * widgets + */ + void removeOverlayWidget(COverlayDockContainer* OverlayWidget); + + public: /** @@ -312,6 +336,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ void dockAreasAdded(); + /** + * This signal is emitted, if a new overlay widget has been created. + */ + void overlayWidgetCreated(ads::COverlayDockContainer* OverlayWidget); + /** * This signal is emitted if one or multiple dock areas has been removed */ diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 4f4787de2..22130160b 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -100,7 +100,6 @@ struct DockManagerPrivate CDockManager* _this; QList FloatingWidgets; QList HiddenFloatingWidgets; - QList OverlayWidgets; QList Containers; CDockOverlay* ContainerOverlay; CDockOverlay* DockAreaOverlay; @@ -148,15 +147,6 @@ struct DockManagerPrivate } } - void deleteOverlayWidgets() - { - for (auto OverlayWidget : OverlayWidgets) - { - OverlayWidget->cleanupAndDelete(); - } - OverlayWidgets.clear(); - } - void markDockWidgetsDirty() { for (auto DockWidget : DockWidgetsMap) @@ -441,7 +431,7 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version) // Hide updates of floating widgets from use hideFloatingWidgets(); - deleteOverlayWidgets(); + _this->deleteOverlayWidgets(); markDockWidgetsDirty(); if (!restoreStateFromXml(state, version)) @@ -539,12 +529,6 @@ CDockManager::~CDockManager() delete FloatingWidget; } - auto OverlayWidgets = d->OverlayWidgets; - for (auto OverlayWidget : OverlayWidgets) - { - delete OverlayWidget; - } - delete d; } @@ -636,14 +620,6 @@ 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) @@ -651,12 +627,6 @@ 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 272aa1982..88dcdf9f9 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -94,24 +94,12 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget */ 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 */ @@ -639,11 +627,6 @@ public Q_SLOTS: */ 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/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 0eaf84dc1..812c96959 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -113,7 +113,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabB updateMask(); updateSize(); - DockManager->registerOverlayWidget(this); + parent->registerOverlayWidget(this); d->DockArea->installEventFilter(this); parent->installEventFilter(this); @@ -140,8 +140,8 @@ void COverlayDockContainer::updateSize() } //============================================================================ -COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area) : - COverlayDockContainer(DockWidget->dockManager(), area, DockWidget->dockContainer() != nullptr ? DockWidget->dockContainer() : DockWidget->dockManager()) +COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area, CDockContainerWidget* parent) : + COverlayDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); } @@ -156,7 +156,7 @@ COverlayDockContainer::~COverlayDockContainer() if (d->DockManager) { - d->DockManager->removeOverlayWidget(this); + parentContainer()->removeOverlayWidget(this); } delete d; diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index e826e9cc9..ad42e4daa 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -70,7 +70,7 @@ class ADS_EXPORT COverlayDockContainer : public QFrame /** * Create overlay widget with the given dock widget */ - COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area); + COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area, CDockContainerWidget* parent); /** * Virtual Destructor From 052d3cecb9cc5bb16ed528e7634dd6aa0385490e Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 6 Sep 2022 17:59:56 +0800 Subject: [PATCH 006/236] Fix check state of the auto hide button when dragging the container into a floating window --- src/DockAreaWidget.cpp | 9 +++++++++ src/DockAreaWidget.h | 5 +++++ src/DockContainerWidget.cpp | 7 ++----- src/OverlayDockContainer.cpp | 5 +---- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 245efc0b4..c6c3f7976 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -800,6 +800,15 @@ void CDockAreaWidget::markTitleBarMenuOutdated() } +//============================================================================ +void CDockAreaWidget::updateAutoHidebuttonCheckState() +{ + auto autoHideButton = titleBarButton(TitleBarButtonAutoHide); + autoHideButton->blockSignals(true); + autoHideButton->setChecked(isOverlayed()); + autoHideButton->blockSignals(false); +} + //============================================================================ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index b92e34de2..9c39c2a14 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -150,6 +150,11 @@ private Q_SLOTS: */ void markTitleBarMenuOutdated(); + /* + * Update the auto hide button checked state based on if it's overlayed or not + */ + void updateAutoHidebuttonCheckState(); + protected Q_SLOTS: void toggleView(bool Open); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 7f970b2f1..2e4c25c23 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1063,9 +1063,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, dockContainer->hide(); DockArea = dockContainer->dockAreaWidget(); - const auto titleBar = DockArea->titleBar(); - QSignalBlocker blocker(titleBar); - titleBar->button(TitleBarButtonAutoHide)->setChecked(true); + DockArea->updateAutoHidebuttonCheckState(); } while (s.readNextStartElement()) @@ -1655,6 +1653,7 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) dumpLayout(); d->emitDockAreasRemoved(); area->setOverlayDockContainer(nullptr); + area->updateAutoHidebuttonCheckState(); return; } @@ -1783,8 +1782,6 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); bool Dropped = false; - // Handle any overlay widgets - // todo: cleanup - move into own func? auto overlayWidgets = FloatingWidget->dockContainer()->overlayWidgets(); for (const auto overlayWidget : overlayWidgets) { diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 812c96959..ecf394585 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -82,10 +82,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabB 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); + d->DockArea->updateAutoHidebuttonCheckState(); QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); d->Splitter = new QSplitter(Qt::Orientation::Horizontal); From 1a903e74f2feeb3e282b1517caba20dcf8f3c086 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 7 Sep 2022 11:54:03 +0800 Subject: [PATCH 007/236] add pin icon --- src/DockAreaTitleBar.cpp | 4 +- src/ads.qrc | 1 + src/images/pin-button.svg | 53 ++++++++++++++++++++ src/stylesheets/default.css | 5 ++ src/stylesheets/default_linux.css | 5 ++ src/stylesheets/focus_highlighting.css | 5 ++ src/stylesheets/focus_highlighting_linux.css | 5 ++ 7 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/images/pin-button.svg diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 8795e0b4c..621e2d22e 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -167,12 +167,12 @@ void DockAreaTitleBarPrivate::createButtons() // AutoHide Button const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar); AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); - AutoHideButton->setObjectName("autoHideButton"); + AutoHideButton->setObjectName("dockAreaAutoHideButton"); 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); + internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); Layout->addWidget(AutoHideButton, 0); _this->connect(AutoHideButton, SIGNAL(toggled(bool)), SLOT(onAutoHideButtonClicked(bool))); diff --git a/src/ads.qrc b/src/ads.qrc index a29a54210..4068d7ba2 100644 --- a/src/ads.qrc +++ b/src/ads.qrc @@ -2,6 +2,7 @@ stylesheets/default.css images/close-button.svg + images/pin-button.svg images/close-button-disabled.svg stylesheets/default_linux.css images/close-button-focused.svg diff --git a/src/images/pin-button.svg b/src/images/pin-button.svg new file mode 100644 index 000000000..12ff7cb7a --- /dev/null +++ b/src/images/pin-button.svg @@ -0,0 +1,53 @@ + +image/svg+xml diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 7952bd11a..3562115bf 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -55,6 +55,11 @@ QScrollArea#dockWidgetScrollArea { border: none; } +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-iconSize: 16px; +} + #tabCloseButton { margin-top: 2px; background: none; diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index ac41491eb..f9161f818 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -59,6 +59,11 @@ QScrollArea#dockWidgetScrollArea { border: none; } +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-iconSize: 16px; +} + #tabCloseButton { margin-top: 2px; background: none; diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 2844d6e5b..912166a66 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -83,6 +83,11 @@ QScrollArea#dockWidgetScrollArea { background: rgba(0, 0, 0, 48); } +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-iconSize: 16px; +} + #dockAreaCloseButton { qproperty-icon: url(:/ads/images/close-button.svg), url(:/ads/images/close-button-disabled.svg) disabled; diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index f16ab5e82..6f5b42a5b 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -72,6 +72,11 @@ QScrollArea#dockWidgetScrollArea { qproperty-iconSize: 16px; } +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-iconSize: 16px; +} + #tabCloseButton { margin-top: 2px; background: none; From 4a77580b075cd361ac4261f14d2fb56643d0f2bd Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 7 Sep 2022 11:54:32 +0800 Subject: [PATCH 008/236] swap position of auto hide button and detach group button --- src/DockAreaTitleBar.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 621e2d22e..8b67a5d5b 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -164,6 +164,16 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(TabsMenuButton->menu(), SIGNAL(triggered(QAction*)), SLOT(onTabsMenuActionTriggered(QAction*))); + // Undock button + UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton)); + UndockButton->setObjectName("detachGroupButton"); + UndockButton->setAutoRaise(true); + internal::setToolTip(UndockButton, QObject::tr("Detach Group")); + internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon); + UndockButton->setSizePolicy(ButtonSizePolicy); + Layout->addWidget(UndockButton, 0); + _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); + // AutoHide Button const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar); AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); @@ -177,16 +187,6 @@ void DockAreaTitleBarPrivate::createButtons() Layout->addWidget(AutoHideButton, 0); _this->connect(AutoHideButton, SIGNAL(toggled(bool)), SLOT(onAutoHideButtonClicked(bool))); - // Undock button - UndockButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasUndockButton)); - UndockButton->setObjectName("detachGroupButton"); - UndockButton->setAutoRaise(true); - internal::setToolTip(UndockButton, QObject::tr("Detach Group")); - internal::setButtonIcon(UndockButton, QStyle::SP_TitleBarNormalButton, ads::DockAreaUndockIcon); - UndockButton->setSizePolicy(ButtonSizePolicy); - Layout->addWidget(UndockButton, 0); - _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); - // Close button CloseButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasCloseButton)); CloseButton->setObjectName("dockAreaCloseButton"); From 9735f41b1a8661948e2eb9c1d4fee2e138a74c45 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 7 Sep 2022 12:13:46 +0800 Subject: [PATCH 009/236] Fix toggle view through the actions menu not working correctly --- src/DockFocusController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index d606d5fda..180219e47 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -191,7 +191,7 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget) if (old && old->overlayDockContainer() && old != DockWidget) { - old->overlayDockContainer()->hide(); + old->toggleView(false); } if (old == DockWidget && !ForceFocusChangedSignal) From 1d9902b6908257b8b2861c4c7dbe7eb9dd547a59 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 7 Sep 2022 13:31:44 +0800 Subject: [PATCH 010/236] Make tabs menu hidden when overlayed --- src/DockAreaWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 70f73893c..a247a63b3 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -362,7 +362,9 @@ void DockAreaWidgetPrivate::updateTitleBarButtonStates() _this->features().testFlag(CDockWidget::DockWidgetClosable)); TitleBar->button(TitleBarButtonUndock)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetFloatable)); + // Undock and tabs should never show when overlayed TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); + TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); TitleBar->updateDockWidgetActionsButtons(); UpdateTitleBarButtons = false; } From 302fcd14350ea29f08231789cdba905599c8fbee Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 7 Sep 2022 15:50:53 +0800 Subject: [PATCH 011/236] Fix bug where dragging an overlayed widget would cause it to be empty Fix bug where pin and unpin doesn't work --- src/DockAreaWidget.cpp | 3 ++- src/DockFocusController.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index a247a63b3..4c51b9144 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1045,11 +1045,12 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En if (Enable) { dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget); - toggleView(false); + DockWidget->toggleView(false); } else { overlayDockContainer()->moveContentsToParent(); + DockWidget->toggleView(true); } } diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index 180219e47..f1226b2a8 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -189,7 +189,7 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget) } #endif - if (old && old->overlayDockContainer() && old != DockWidget) + if (old && old->overlayDockContainer() && old->overlayDockContainer()->isVisible() && old != FocusedDockWidget) { old->toggleView(false); } From 068797dbb04417f5e9cd25a09d2cb5e9609cb03c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 7 Sep 2022 10:56:17 +0200 Subject: [PATCH 012/236] Fixed build issues of original pull request --- .../{centralwidget => autohide}/autohide.pro | 3 ++ examples/centralwidget/centralwidget.pro | 34 +++++++++++++++++++ examples/examples.pro | 1 + persist/perspectives.ini | 2 ++ src/DockContainerWidget.cpp | 3 +- src/OverlayDockContainer.cpp | 1 + src/src.pro | 10 ++++-- 7 files changed, 51 insertions(+), 3 deletions(-) rename examples/{centralwidget => autohide}/autohide.pro (95%) create mode 100644 examples/centralwidget/centralwidget.pro create mode 100644 persist/perspectives.ini diff --git a/examples/centralwidget/autohide.pro b/examples/autohide/autohide.pro similarity index 95% rename from examples/centralwidget/autohide.pro rename to examples/autohide/autohide.pro index 824b451bf..8a00c6253 100644 --- a/examples/centralwidget/autohide.pro +++ b/examples/autohide/autohide.pro @@ -23,6 +23,9 @@ SOURCES += \ HEADERS += \ mainwindow.h + +FORMS += \ + mainwindow.ui LIBS += -L$${ADS_OUT_ROOT}/lib include(../../ads.pri) diff --git a/examples/centralwidget/centralwidget.pro b/examples/centralwidget/centralwidget.pro new file mode 100644 index 000000000..738ae781f --- /dev/null +++ b/examples/centralwidget/centralwidget.pro @@ -0,0 +1,34 @@ +ADS_OUT_ROOT = $${OUT_PWD}/../.. + +QT += core gui widgets + +TARGET = CentralWidgetExample +DESTDIR = $${ADS_OUT_ROOT}/lib +TEMPLATE = app +CONFIG += c++14 +CONFIG += debug_and_release +adsBuildStatic { + DEFINES += ADS_STATIC +} + +# The following define makes your compiler emit warnings if you use +# any Qt feature that has been marked deprecated (the exact warnings +# depend on your compiler). Please consult the documentation of the +# deprecated API in order to know how to port your code away from it. +DEFINES += QT_DEPRECATED_WARNINGS + +SOURCES += \ + main.cpp \ + mainwindow.cpp + +HEADERS += \ + mainwindow.h + +FORMS += \ + mainwindow.ui + +LIBS += -L$${ADS_OUT_ROOT}/lib +include(../../ads.pri) +INCLUDEPATH += ../../src +DEPENDPATH += ../../src + diff --git a/examples/examples.pro b/examples/examples.pro index 3569f372e..4e4547a0f 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS = \ + autohide \ centralwidget \ simple \ hideshow \ diff --git a/persist/perspectives.ini b/persist/perspectives.ini new file mode 100644 index 000000000..e342ad72f --- /dev/null +++ b/persist/perspectives.ini @@ -0,0 +1,2 @@ +[Perspectives] +size=0 diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 2e4c25c23..ff64c2553 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1508,7 +1508,8 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla } if (!COverlayDockContainer::areaExistsInConfig(area)) { - assert(false, "Requested area does not exist in config"); + Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", + "Requested area does not exist in config"); return nullptr; } diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index ecf394585..489e96feb 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -41,6 +41,7 @@ #include #include #include +#include namespace ads { diff --git a/src/src.pro b/src/src.pro index 9f6d2654a..b400b5e1f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -47,7 +47,10 @@ HEADERS += \ ElidingLabel.h \ IconProvider.h \ DockComponentsFactory.h \ - DockFocusController.h + DockFocusController.h \ + OverlayDockContainer.h \ + SideTabBar.h \ + DockWidgetSideTab.h SOURCES += \ @@ -67,7 +70,10 @@ SOURCES += \ ElidingLabel.cpp \ IconProvider.cpp \ DockComponentsFactory.cpp \ - DockFocusController.cpp + DockFocusController.cpp \ + OverlayDockContainer.cpp \ + SideTabBar.cpp \ + DockWidgetSideTab.cpp unix:!macx { From de4a59d45a277bd45e7ac35b6b0c5af649765041 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 11:18:38 +0800 Subject: [PATCH 013/236] Re added back in CentralWidgetExample after mistakenly removing it --- examples/CMakeLists.txt | 1 + examples/autohide/CMakeLists.txt | 14 +++++++------- examples/autohide/mainwindow.cpp | 4 ++-- examples/centralwidget/CMakeLists.txt | 14 +++++++------- examples/centralwidget/mainwindow.cpp | 4 ++-- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 5ae02d6e2..ba2a064e6 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory(hideshow) add_subdirectory(sidebar) add_subdirectory(deleteonclose) add_subdirectory(centralwidget) +add_subdirectory(autohide) add_subdirectory(emptydockarea) add_subdirectory(dockindock) \ No newline at end of file diff --git a/examples/autohide/CMakeLists.txt b/examples/autohide/CMakeLists.txt index 7f57821e8..cec3910e2 100644 --- a/examples/autohide/CMakeLists.txt +++ b/examples/autohide/CMakeLists.txt @@ -1,19 +1,19 @@ cmake_minimum_required(VERSION 3.5) -project(ads_example_centralwidget VERSION ${VERSION_SHORT}) +project(ads_example_autohide VERSION ${VERSION_SHORT}) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(CentralWidgetExample WIN32 +add_executable(AutoHideExample WIN32 main.cpp mainwindow.cpp mainwindow.ui ) -target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") -target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking) -target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core +target_include_directories(AutoHideExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") +target_link_libraries(AutoHideExample PRIVATE qtadvanceddocking) +target_link_libraries(AutoHideExample PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets) -set_target_properties(CentralWidgetExample PROPERTIES +set_target_properties(AutoHideExample PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON @@ -21,7 +21,7 @@ set_target_properties(CentralWidgetExample PROPERTIES CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF VERSION ${VERSION_SHORT} - EXPORT_NAME "Qt Advanced Docking System Central Widget Example" + EXPORT_NAME "Qt Advanced Docking System Auto Hide Example" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 3ad0056df..32fc754cf 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -54,7 +54,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); + DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -65,7 +65,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); + DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/examples/centralwidget/CMakeLists.txt b/examples/centralwidget/CMakeLists.txt index cec3910e2..7f57821e8 100644 --- a/examples/centralwidget/CMakeLists.txt +++ b/examples/centralwidget/CMakeLists.txt @@ -1,19 +1,19 @@ cmake_minimum_required(VERSION 3.5) -project(ads_example_autohide VERSION ${VERSION_SHORT}) +project(ads_example_centralwidget VERSION ${VERSION_SHORT}) find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED) find_package(Qt${QT_VERSION_MAJOR} 5.5 COMPONENTS Core Gui Widgets REQUIRED) set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(AutoHideExample WIN32 +add_executable(CentralWidgetExample WIN32 main.cpp mainwindow.cpp mainwindow.ui ) -target_include_directories(AutoHideExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") -target_link_libraries(AutoHideExample PRIVATE qtadvanceddocking) -target_link_libraries(AutoHideExample PUBLIC Qt${QT_VERSION_MAJOR}::Core +target_include_directories(CentralWidgetExample PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../../src") +target_link_libraries(CentralWidgetExample PRIVATE qtadvanceddocking) +target_link_libraries(CentralWidgetExample PUBLIC Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets) -set_target_properties(AutoHideExample PROPERTIES +set_target_properties(CentralWidgetExample PROPERTIES AUTOMOC ON AUTORCC ON AUTOUIC ON @@ -21,7 +21,7 @@ set_target_properties(AutoHideExample PROPERTIES CXX_STANDARD_REQUIRED ON CXX_EXTENSIONS OFF VERSION ${VERSION_SHORT} - EXPORT_NAME "Qt Advanced Docking System Auto Hide Example" + EXPORT_NAME "Qt Advanced Docking System Central Widget Example" ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/lib" RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${ads_PlatformDir}/bin" diff --git a/examples/centralwidget/mainwindow.cpp b/examples/centralwidget/mainwindow.cpp index eca2e946d..3ad0056df 100644 --- a/examples/centralwidget/mainwindow.cpp +++ b/examples/centralwidget/mainwindow.cpp @@ -54,7 +54,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addOverlayDockWidget(SideTabBarArea::Left, TableDockWidget); + auto TableArea = DockManager->addDockWidget(DockWidgetArea::LeftDockWidgetArea, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -65,7 +65,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addOverlayDockWidget(SideTabBarArea::Left, TableDockWidget); + DockManager->addDockWidget(DockWidgetArea::BottomDockWidgetArea, TableDockWidget, TableArea); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); From 8bfb98ea2004f58cc0e1a289a2fb16fb95b2197a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 11:23:45 +0800 Subject: [PATCH 014/236] Remove auto hide feature being set by default. Add config for the default auto hide feature. --- examples/autohide/mainwindow.cpp | 10 +--------- src/DockManager.h | 3 +-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 32fc754cf..7d14a6f71 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -3,26 +3,17 @@ #include "ui_mainwindow.h" #include -#include -#include -#include #include #include #include -#include -#include #include #include #include -#include #include #include #include "DockAreaWidget.h" #include "DockAreaTitleBar.h" -#include "DockAreaTabBar.h" -#include "FloatingDockContainer.h" -#include "DockComponentsFactory.h" using namespace ads; @@ -35,6 +26,7 @@ CMainWindow::CMainWindow(QWidget *parent) CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true); CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false); CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + CDockManager::setConfigFlag(CDockManager::DefaultDockContainerConfig, true); DockManager = new CDockManager(this); // Set central widget diff --git a/src/DockManager.h b/src/DockManager.h index 88dcdf9f9..d7930b4c1 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -210,8 +210,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget DefaultDockAreaButtons = DockAreaHasCloseButton | DockAreaHasUndockButton - | DockAreaHasTabsMenuButton - | DockAreaHasAutoHideButton,///< default configuration of dock area title bar buttons + | DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons DefaultDockContainerSideBars = DockContainerHasLeftSideBar | DockContainerHasRightSideBar, ///< the default configuration for left and right side bars From 0087a1b3602fd865cb09603e849725e65e562bd1 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 11:30:56 +0800 Subject: [PATCH 015/236] Add left right styling to the dock widget side tab --- src/DockAreaWidget.cpp | 2 +- src/DockAreaWidget.h | 3 +- src/DockContainerWidget.cpp | 40 +++++++++++++------------- src/DockContainerWidget.h | 7 +++-- src/DockManager.cpp | 4 +-- src/DockManager.h | 14 ++++----- src/DockWidgetSideTab.cpp | 13 +++++++++ src/DockWidgetSideTab.h | 21 ++++++++++++++ src/OverlayDockContainer.cpp | 24 ++++++++-------- src/OverlayDockContainer.h | 15 ++++++---- src/ads_globals.h | 11 ------- src/stylesheets/focus_highlighting.css | 9 +++++- 12 files changed, 99 insertions(+), 64 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 4c51b9144..502c8b3f0 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1040,7 +1040,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) } //============================================================================ -void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area) +void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, CDockWidgetSideTab::SideTabBarArea area) { if (Enable) { diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 9c39c2a14..67063b6d2 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -34,6 +34,7 @@ #include "ads_globals.h" #include "DockWidget.h" +#include "DockWidgetSideTab.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) QT_FORWARD_DECLARE_CLASS(QAbstractButton) @@ -161,7 +162,7 @@ protected Q_SLOTS: /** * Auto hides the dock area and all dock widgets in this area */ - void onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, SideTabBarArea area); + void onAutoHideToggleRequested(CDockWidget* DockWidget, bool Enable, CDockWidgetSideTab::SideTabBarArea area); public: using Super = QFrame; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index ff64c2553..dd5e396cd 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -138,7 +138,7 @@ class DockContainerWidgetPrivate unsigned int zOrderIndex = 0; QList DockAreas; QList OverlayWidgets; - QMap SideTabBarWidgets; + QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; bool isFloating = false; @@ -254,7 +254,7 @@ class DockContainerWidgetPrivate * 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); + bool restoreOverlayDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing); /** * Restores either a dock area or an overlay dock area depending on the value in the XML @@ -1032,7 +1032,7 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, } //============================================================================ -bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, SideTabBarArea area, bool Testing) +bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing) { bool Ok; #ifdef ADS_DEBUG_PRINT @@ -1128,12 +1128,12 @@ bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReade const auto sideTabAreaValue = Stream.attributes().value("SideTabBarArea"); if (!sideTabAreaValue.isNull()) { - auto sideTabBarArea = static_cast(sideTabAreaValue.toInt(&Ok)); + auto sideTabBarArea = static_cast(sideTabAreaValue.toInt(&Ok)); if (!Ok) { return false; } - if (sideTabBarArea != SideTabBarArea::None) + if (sideTabBarArea != CDockWidgetSideTab::None) { return restoreOverlayDockArea(Stream, sideTabBarArea, Testing); } @@ -1500,7 +1500,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget) +COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget) { if (d->DockManager != DockWidget->dockManager()) { @@ -1522,31 +1522,31 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla } //============================================================================ -SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget) +CDockWidgetSideTab::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) + const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::Left : CDockWidgetSideTab::Right; + if (calculatedPosition == CDockWidgetSideTab::Right) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - return Right; + return CDockWidgetSideTab::Right; } - return Left; + return CDockWidgetSideTab::Left; } - if (calculatedPosition == Left) + if (calculatedPosition == CDockWidgetSideTab::Left) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return Left; + return CDockWidgetSideTab::Left; } - return Right; + return CDockWidgetSideTab::Right; } - return Left; + return CDockWidgetSideTab::Left; } @@ -2025,14 +2025,14 @@ void CDockContainerWidget::createSideTabBarWidgets() { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - d->SideTabBarWidgets[SideTabBarArea::Left] = new CSideTabBar(this); - d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Left], 0, 0); + d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left], 0, 0); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - d->SideTabBarWidgets[SideTabBarArea::Right] = new CSideTabBar(this); - d->Layout->addWidget(d->SideTabBarWidgets[SideTabBarArea::Right], 0, 2); + d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right], 0, 2); } } @@ -2181,7 +2181,7 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea) } //============================================================================ -CSideTabBar* CDockContainerWidget::sideTabBar(SideTabBarArea area) const +CSideTabBar* CDockContainerWidget::sideTabBar(CDockWidgetSideTab::SideTabBarArea area) const { return d->SideTabBarWidgets[area]; } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 281602d6b..5588f65ed 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -34,6 +34,7 @@ #include "ads_globals.h" #include "DockWidget.h" +#include "DockWidgetSideTab.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) @@ -105,7 +106,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(SideTabBarArea area, CDockWidget* DockWidget); + COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget); /** * Helper function for creation of the root splitter @@ -226,7 +227,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Get's the overlay dock side tab bar area based on the dock area widget position */ - SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget); + CDockWidgetSideTab::SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget); /** * Removes dockwidget @@ -326,7 +327,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Returns the side tab widget for the given area */ - CSideTabBar* sideTabBar(SideTabBarArea area) const; + CSideTabBar* sideTabBar(CDockWidgetSideTab::SideTabBarArea area) const; Q_SIGNALS: /** diff --git a/src/DockManager.cpp b/src/DockManager.cpp index e3e2a87b8..6708552c4 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -863,13 +863,13 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidget(SideTabBarArea area, CDockWidget* Dockwidget) +COverlayDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget) { return addOverlayDockWidgetToContainer(area, Dockwidget, this); } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget) +COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget); diff --git a/src/DockManager.h b/src/DockManager.h index d7930b4c1..14b3331be 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -212,14 +212,14 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget | DockAreaHasUndockButton | DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons - DefaultDockContainerSideBars = DockContainerHasLeftSideBar - | DockContainerHasRightSideBar, ///< the default configuration for left and right side bars + DefaultDockContainerConfig = DockContainerHasLeftSideBar + | DockContainerHasRightSideBar + | DockAreaHasAutoHideButton, ///< the default configuration for left and right side bars DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton | XmlCompressionEnabled - | FloatingContainerHasWidgetTitle - | DefaultDockContainerSideBars, ///< default base configuration settings + | FloatingContainerHasWidgetTitle, ///< default base configuration settings DefaultOpaqueConfig = DefaultBaseConfig | OpaqueSplitterResize @@ -307,14 +307,14 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidget(SideTabBarArea area, CDockWidget* Dockwidget); + COverlayDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget); /** - * Adds dock widget overlayed into the given container based on the SideTabBarArea. + * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidgetToContainer(SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); + COverlayDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index a3d2b2310..1913d8dbf 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -32,9 +32,11 @@ #include +#include "DockAreaWidget.h" #include "ElidingLabel.h" #include "DockWidget.h" +#include "OverlayDockContainer.h" namespace ads { @@ -148,4 +150,15 @@ void CDockWidgetSideTab::updateStyle() { internal::repolishStyle(this, internal::RepolishDirectChildren); } + +CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const +{ + auto dockAreaWidget = d->DockWidget->dockAreaWidget(); + if (dockAreaWidget && dockAreaWidget->isOverlayed()) + { + return dockAreaWidget->overlayDockContainer()->sideTabBarArea(); + } + + return Left; +} } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index e99ada0de..73f1adb43 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -49,6 +49,8 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame { Q_OBJECT + Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) + private: DockWidgetSideTabPrivate* d; ///< private data (pimpl) friend struct DockWidgetSideTabPrivate; @@ -67,6 +69,20 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame public: using Super = QFrame; + + /** + * Dock widget side tab bar locations + */ + enum SideTabBarArea + { + None, + Left, + Right, + Bottom + }; + + Q_ENUM(SideTabBarArea) + /** * Default Constructor * param[in] DockWidget The dock widget this title bar belongs to @@ -85,6 +101,11 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ void updateStyle(); + /** + * Getter for side tab bar area property + */ + SideTabBarArea sideTabBarArea() const; + Q_SIGNALS: void elidedChanged(bool elided); void clicked(); diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 489e96feb..9ff8e3b1a 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -52,7 +52,7 @@ struct OverlayDockContainerPrivate CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; QSplitter* Splitter; - SideTabBarArea Area; + CDockWidgetSideTab::SideTabBarArea Area; /** * Private data constructor @@ -74,7 +74,7 @@ CDockContainerWidget* COverlayDockContainer::parentContainer() const } //============================================================================ -COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent) : +COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : QFrame(parent), d(new OverlayDockContainerPrivate(this)) { @@ -92,7 +92,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, SideTabB const auto emptyWidget = new QWidget(); emptyWidget->setMinimumWidth(50); - if (area == SideTabBarArea::Left) + if (area == CDockWidgetSideTab::SideTabBarArea::Left) { d->Splitter->addWidget(d->DockArea); d->Splitter->addWidget(emptyWidget); @@ -123,7 +123,7 @@ 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; + const auto offset = d->Area == CDockWidgetSideTab::SideTabBarArea::Left ? 0 : handleSize; setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); } @@ -138,7 +138,7 @@ void COverlayDockContainer::updateSize() } //============================================================================ -COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area, CDockContainerWidget* parent) : +COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : COverlayDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); @@ -195,7 +195,7 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -SideTabBarArea COverlayDockContainer::sideTabBarArea() const +CDockWidgetSideTab::SideTabBarArea COverlayDockContainer::sideTabBarArea() const { return d->Area; } @@ -209,7 +209,7 @@ CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const //============================================================================ void COverlayDockContainer::moveContentsToParent() { - const auto position = mapToGlobal(d->Area == Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2)); + const auto position = mapToGlobal(d->Area == CDockWidgetSideTab::Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2)); const auto dockAreaWidget = parentContainer()->dockAreaAt(position); if (dockAreaWidget != nullptr && !dockAreaWidget->isCentralWidgetArea()) @@ -218,7 +218,7 @@ void COverlayDockContainer::moveContentsToParent() } else { - parentContainer()->addDockWidget(d->Area == Left ? LeftDockWidgetArea : RightDockWidgetArea, d->DockWidget); + parentContainer()->addDockWidget(d->Area == CDockWidgetSideTab::Left ? LeftDockWidgetArea : RightDockWidgetArea, d->DockWidget); } cleanupAndDelete(); } @@ -239,7 +239,7 @@ void COverlayDockContainer::cleanupAndDelete() void COverlayDockContainer::saveState(QXmlStreamWriter& s) { - s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); + s.writeAttribute("CDockWidgetSideTab::SideTabBarArea", QString::number(sideTabBarArea())); QStringList Sizes; for (auto Size : d->Splitter->sizes()) { @@ -275,13 +275,13 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } -bool COverlayDockContainer::areaExistsInConfig(SideTabBarArea area) +bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) { - if (area == Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + if (area == CDockWidgetSideTab::Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { return false; } - if (area == Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + if (area == CDockWidgetSideTab::Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { return false; } diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index ad42e4daa..4a531720f 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -31,6 +31,8 @@ //============================================================================ #include "ads_globals.h" +#include "DockWidgetSideTab.h" + #include class QXmlStreamWriter; @@ -48,12 +50,11 @@ 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; @@ -61,16 +62,18 @@ class ADS_EXPORT COverlayDockContainer : public QFrame void updateMask(); void updateSize(); + CDockContainerWidget* parentContainer() const; + public: /** * Create overlay widget with a dock manager */ - COverlayDockContainer(CDockManager* DockManager, SideTabBarArea area, CDockContainerWidget* parent); + COverlayDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); /** * Create overlay widget with the given dock widget */ - COverlayDockContainer(CDockWidget* DockWidget, SideTabBarArea area, CDockContainerWidget* parent); + COverlayDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); /** * Virtual Destructor @@ -95,7 +98,7 @@ class ADS_EXPORT COverlayDockContainer : public QFrame /** * Returns the side tab bar area of this overlay dock container */ - SideTabBarArea sideTabBarArea() const; + CDockWidgetSideTab::SideTabBarArea sideTabBarArea() const; /** * Returns the dock area widget of this overlay dock container @@ -126,7 +129,7 @@ class ADS_EXPORT COverlayDockContainer : public QFrame /* * Convenience function fr determining if area exists in config */ - static bool areaExistsInConfig(SideTabBarArea area); + static bool areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area); }; } diff --git a/src/ads_globals.h b/src/ads_globals.h index 2df6459ab..4748c277f 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -106,17 +106,6 @@ enum eDragState DraggingFloatingWidget//!< DraggingFloatingWidget }; -/** - * Dock widget side tab bar locations - */ -enum SideTabBarArea -{ - None, - Left, - Right, - Bottom -}; - /** * The different icons used in the UI */ diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 912166a66..3a2563b28 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -26,10 +26,17 @@ ads--CDockWidgetSideTab { background: palette(window); border-color: palette(light); border-style: solid; - border-width: 1px 1px 1px 1px; padding: 0 0px; } +ads--CDockWidgetSideTab[sideTabBarArea="Left"] { + border-width: 0px 0px 0px 3px; +} + +ads--CDockWidgetSideTab[sideTabBarArea="Right"] { + border-width: 0px 3px 0px 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)); From ecccba4536ba130d5a78d9a46ce2092258690a58 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 11:31:54 +0800 Subject: [PATCH 016/236] Add overlay splitter object name --- src/OverlayDockContainer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 9ff8e3b1a..abadc2976 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -87,6 +87,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); d->Splitter = new QSplitter(Qt::Orientation::Horizontal); + d->Splitter->setObjectName("overlaySplitter"); d->Splitter->setChildrenCollapsible(false); const auto emptyWidget = new QWidget(); From 5ddb02cc8eaf4143042bbdcf44662c7ad25523be Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 11:45:30 +0800 Subject: [PATCH 017/236] fix the border styling of the dock widget side tab when not focused --- src/stylesheets/focus_highlighting.css | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 3a2563b28..73f187605 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -24,19 +24,12 @@ ads--CDockWidgetTab { ads--CDockWidgetSideTab { background: palette(window); - border-color: palette(light); + border-color: white; border-style: solid; + border-width: 1px 0px 1px 0px; padding: 0 0px; } -ads--CDockWidgetSideTab[sideTabBarArea="Left"] { - border-width: 0px 0px 0px 3px; -} - -ads--CDockWidgetSideTab[sideTabBarArea="Right"] { - border-width: 0px 3px 0px 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)); @@ -120,6 +113,14 @@ ads--CDockWidgetTab[focused="true"] { border-color: palette(highlight); } +ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { + border-width: 0px 0px 0px 3px; +} + +ads--CDockWidgetSideTab[sideTabBarArea="Right"][focused="true"] { + border-width: 0px 3px 0px 0px; +} + ads--CDockWidgetSideTab[focused="true"] { border-color: palette(highlight); } From a279e7153508b49f7dd0d37484cc25f3ac4da311 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 13:10:46 +0800 Subject: [PATCH 018/236] Fix side tab bar area name being saved wrong in the XML --- src/OverlayDockContainer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index abadc2976..9b6486b83 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -240,7 +240,7 @@ void COverlayDockContainer::cleanupAndDelete() void COverlayDockContainer::saveState(QXmlStreamWriter& s) { - s.writeAttribute("CDockWidgetSideTab::SideTabBarArea", QString::number(sideTabBarArea())); + s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); QStringList Sizes; for (auto Size : d->Splitter->sizes()) { From be4e5a88a65008e97d5fd3e567f87fce6c5f5e0f Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 13:52:30 +0800 Subject: [PATCH 019/236] Change the styling - Now the dock widget side tab has a gray left/right edge border when not selected --- src/stylesheets/focus_highlighting.css | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 73f187605..23596641a 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -10,7 +10,7 @@ ads--CDockContainerWidget > QSplitter{ ads--CDockAreaWidget { background: palette(window); - border: 1px solid white; + border: 1px solid white } ads--CDockWidgetTab { @@ -24,10 +24,16 @@ ads--CDockWidgetTab { ads--CDockWidgetSideTab { background: palette(window); - border-color: white; - border-style: solid; - border-width: 1px 0px 1px 0px; - padding: 0 0px; +} + +ads--CDockWidgetSideTab[sideTabBarArea="Left"] { + border-left: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="Right"] { + border-right: 3px solid grey; + border-bottom: 1px solid white; } ads--CDockWidgetTab[activeTab="true"] { @@ -113,16 +119,12 @@ ads--CDockWidgetTab[focused="true"] { border-color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { - border-width: 0px 0px 0px 3px; -} - ads--CDockWidgetSideTab[sideTabBarArea="Right"][focused="true"] { - border-width: 0px 3px 0px 0px; + border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[focused="true"] { - border-color: palette(highlight); +ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { + border-left: 3px solid palette(highlight); } ads--CDockWidgetTab[focused="true"]>#tabCloseButton { From 37edf47c4baf05e496f1df49109cc51bd0822ea1 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 14:04:18 +0800 Subject: [PATCH 020/236] Fix the side tab widget not updating style when its restored from XML --- src/DockContainerWidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index dd5e396cd..57751836b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1095,9 +1095,10 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, 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); + DockWidget->sideTabWidget()->show(); + DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added } if (Testing) From 9bfd77a206ac396c76ee107b733bdf8c4618def9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 14:13:45 +0800 Subject: [PATCH 021/236] Remove None and Bottom from the SideTabBarArea enum --- src/DockContainerWidget.cpp | 6 ++---- src/DockWidgetSideTab.h | 4 +--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 57751836b..3e6d014f2 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1134,10 +1134,8 @@ bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReade { return false; } - if (sideTabBarArea != CDockWidgetSideTab::None) - { - return restoreOverlayDockArea(Stream, sideTabBarArea, Testing); - } + + 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 diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 73f1adb43..51078283d 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -75,10 +75,8 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ enum SideTabBarArea { - None, Left, - Right, - Bottom + Right }; Q_ENUM(SideTabBarArea) From af549d8ca9fcc589adfa598a6699107c0a45ae9b Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 14:43:18 +0800 Subject: [PATCH 022/236] Add title label to the overlayed dock area --- src/DockAreaTitleBar.cpp | 27 ++++++++++++++++++++++++++- src/DockAreaTitleBar.h | 6 ++++++ src/DockAreaWidget.cpp | 11 +++++------ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 8b67a5d5b..9c994a774 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -49,10 +49,10 @@ #include "DockWidget.h" #include "DockWidgetTab.h" #include "DockAreaTabBar.h" -#include "IconProvider.h" #include "DockComponentsFactory.h" #include "DockFocusController.h" #include "OverlayDockContainer.h" +#include "ElidingLabel.h" #include @@ -72,6 +72,7 @@ struct DockAreaTitleBarPrivate QBoxLayout* Layout; CDockAreaWidget* DockArea; CDockAreaTabBar* TabBar; + CElidingLabel* OverlayTitleLabel; bool MenuOutdated = true; QMenu* TabsMenu; QList DockWidgetActionsButtons; @@ -91,7 +92,13 @@ struct DockAreaTitleBarPrivate */ void createButtons(); + /** + * Creates the overlay title label, only displayed when the dock area is overlayed + */ + void createOverlayTitleLabel(); + + /** * Creates the internal TabBar */ void createTabBar(); @@ -207,6 +214,15 @@ void DockAreaTitleBarPrivate::createButtons() } +//============================================================================ +void DockAreaTitleBarPrivate::createOverlayTitleLabel() +{ + OverlayTitleLabel = new CElidingLabel(""); + OverlayTitleLabel->setObjectName("overlayTitleLabel"); + Layout->addWidget(OverlayTitleLabel); +} + + //============================================================================ void DockAreaTitleBarPrivate::createTabBar() { @@ -287,6 +303,8 @@ CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) : setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->createTabBar(); + d->createOverlayTitleLabel(); + d->OverlayTitleLabel->setVisible(false); // Default hidden d->Layout->addWidget(new CSpacerWidget(this)); d->createButtons(); @@ -480,6 +498,13 @@ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const } +//============================================================================ +CElidingLabel* CDockAreaTitleBar::overlayTitleLabel() const +{ + return d->OverlayTitleLabel; +} + + //============================================================================ void CDockAreaTitleBar::setVisible(bool Visible) { diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 70010a48c..b3af047a7 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -41,6 +41,7 @@ namespace ads class CDockAreaTabBar; class CDockAreaWidget; struct DockAreaTitleBarPrivate; +class CElidingLabel; /** * Title bar of a dock area. @@ -120,6 +121,11 @@ public Q_SLOTS: */ QAbstractButton* button(TitleBarButton which) const; + /** + * Returns the overlay title label, used when the dock area is overlayed + */ + CElidingLabel* overlayTitleLabel() const; + /** * Updates the visibility of the dock widget actions in the title bar */ diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 502c8b3f0..be27e6dfb 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -32,18 +32,15 @@ #include #include -#include #include #include #include #include #include -#include #include -#include #include - +#include "ElidingLabel.h" #include "DockContainerWidget.h" #include "DockWidget.h" #include "FloatingDockContainer.h" @@ -54,7 +51,6 @@ #include "DockAreaTitleBar.h" #include "DockComponentsFactory.h" #include "DockWidgetTab.h" -#include "SideTabBar.h" #include "DockWidgetSideTab.h" #include "OverlayDockContainer.h" @@ -451,6 +447,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, d->tabBar()->insertTab(index, TabWidget); d->tabBar()->blockSignals(false); TabWidget->setVisible(!DockWidget->isClosed()); + d->TitleBar->overlayTitleLabel()->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())); @@ -787,7 +784,9 @@ void CDockAreaWidget::updateTitleBarVisibility() || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); 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 + auto tabBar = d->TitleBar->tabBar(); + tabBar->setVisible(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed + d->TitleBar->overlayTitleLabel()->setVisible(isOverlayed()); // Always show when overlayed, never otherwise } } From c1df05b55d1032432c9c9ee5b774da0fe3883ba5 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 16:08:20 +0800 Subject: [PATCH 023/236] Fix bug where undock button would be show incorrectly in floating dock widgets when toggling overlay Also centralized and simplified the logic for the title bar button visibility --- src/DockAreaWidget.cpp | 41 ++++++++++++++++++++++++++++++++++--- src/DockAreaWidget.h | 5 +++++ src/DockContainerWidget.cpp | 9 ++------ 3 files changed, 45 insertions(+), 10 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index be27e6dfb..60261ccf6 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -310,6 +310,11 @@ struct DockAreaWidgetPrivate */ void updateTitleBarButtonStates(); + /** + * Udpates the enable state of the close and detach button + */ + void updateTitleBarButtonVisibility(bool isTopLevel); + /** * Scans all contained dock widgets for the max. minimum size hint */ @@ -358,14 +363,38 @@ void DockAreaWidgetPrivate::updateTitleBarButtonStates() _this->features().testFlag(CDockWidget::DockWidgetClosable)); TitleBar->button(TitleBarButtonUndock)->setEnabled( _this->features().testFlag(CDockWidget::DockWidgetFloatable)); - // Undock and tabs should never show when overlayed - TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); - TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); 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()); + // Undock and tabs should never show when overlayed + TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isOverlayed()); + TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); + } + else + { + TitleBar->button(TitleBarButtonClose)->setVisible(true); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(true); + TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); + TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); + } +} + + //============================================================================ CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) : QFrame(parent), @@ -787,6 +816,7 @@ void CDockAreaWidget::updateTitleBarVisibility() auto tabBar = d->TitleBar->tabBar(); tabBar->setVisible(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed d->TitleBar->overlayTitleLabel()->setVisible(isOverlayed()); // Always show when overlayed, never otherwise + updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); } } @@ -810,6 +840,11 @@ void CDockAreaWidget::updateAutoHidebuttonCheckState() autoHideButton->blockSignals(false); } +void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const +{ + d->updateTitleBarButtonVisibility(IsTopLevel); +} + //============================================================================ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 67063b6d2..503df45ca 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -156,6 +156,11 @@ private Q_SLOTS: */ void updateAutoHidebuttonCheckState(); + /* + * Update the title bar button visibility based on if it's top level or not + */ + void updateTitleBarButtonVisibility(bool IsTopLevel) const; + protected Q_SLOTS: void toggleView(bool Open); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 3e6d014f2..a6287dd13 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -428,15 +428,11 @@ void DockContainerWidgetPrivate::onVisibleDockAreaCountChanged() if (TopLevelDockArea) { this->TopLevelDockArea = TopLevelDockArea; - TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(false || !_this->isFloating()); - TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(false || !_this->isFloating()); - TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(false || !_this->isFloating()); + TopLevelDockArea->updateTitleBarButtonVisibility(true); } else if (this->TopLevelDockArea) { - this->TopLevelDockArea->titleBarButton(TitleBarButtonUndock)->setVisible(true); - this->TopLevelDockArea->titleBarButton(TitleBarButtonClose)->setVisible(true); - this->TopLevelDockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true); + this->TopLevelDockArea->updateTitleBarButtonVisibility(false); this->TopLevelDockArea = nullptr; } } @@ -833,7 +829,6 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QListtitleBarButton(TitleBarButtonUndock)->setVisible(true); DockArea->titleBarButton(TitleBarButtonClose)->setVisible(true); DockArea->titleBarButton(TitleBarButtonAutoHide)->setVisible(true); } From fac81265bf84b1739bd202ae296db4ac813d3626 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 16:30:07 +0800 Subject: [PATCH 024/236] Whitespace changes only --- src/OverlayDockContainer.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 9b6486b83..22ea6338c 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -224,6 +224,7 @@ void COverlayDockContainer::moveContentsToParent() cleanupAndDelete(); } + //============================================================================ void COverlayDockContainer::cleanupAndDelete() { @@ -238,6 +239,8 @@ void COverlayDockContainer::cleanupAndDelete() deleteLater(); } + +//============================================================================ void COverlayDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); @@ -250,6 +253,8 @@ void COverlayDockContainer::saveState(QXmlStreamWriter& s) s.writeAttribute("Sizes", Sizes.join(" ")); } + +//============================================================================ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) { auto sSizes = s.attributes().value("Sizes").trimmed().toString(); @@ -276,6 +281,8 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } + +//============================================================================ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) { if (area == CDockWidgetSideTab::Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) @@ -290,6 +297,7 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre return true; } + //============================================================================ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) { @@ -301,12 +309,14 @@ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) return QWidget::eventFilter(watched, event); } + //============================================================================ void COverlayDockContainer::mousePressEvent(QMouseEvent* event) { QWidget::mousePressEvent(event); } + //============================================================================ void COverlayDockContainer::resizeEvent(QResizeEvent* event) { From 3ec395fe799ae896ff83132862f8ef52e2b84d25 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 16:41:00 +0800 Subject: [PATCH 025/236] update default stylesheet --- src/stylesheets/default.css | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 3562115bf..7f8d50237 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -2,7 +2,7 @@ * Default style sheet on Windows Platforms */ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; @@ -39,6 +39,20 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +ads--CDockWidgetSideTab { + background: palette(window); +} + +ads--CDockWidgetSideTab[sideTabBarArea="Left"] { + border-left: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="Right"] { + border-right: 3px solid grey; + border-bottom: 1px solid white; +} + ads--CDockWidget { background: palette(light); border-color: palette(light); From 60c22000a8384e35645f45f41cd63b278640319d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 16:49:32 +0800 Subject: [PATCH 026/236] Add hover styling --- src/stylesheets/focus_highlighting.css | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 23596641a..3d70856c8 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -114,9 +114,12 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetTab[focused="true"] { - background: palette(highlight); - border-color: palette(highlight); +ads--CDockWidgetSideTab:hover[sideTabBarArea="Right"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="Left"] { + border-left: 3px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="Right"][focused="true"] { @@ -127,6 +130,11 @@ ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { border-left: 3px solid palette(highlight); } +ads--CDockWidgetTab[focused="true"] { + background: palette(highlight); + border-color: palette(highlight); +} + ads--CDockWidgetTab[focused="true"]>#tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } From a2e9c1aa9c1721766b070f8e252cc4281317166e Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 16:58:40 +0800 Subject: [PATCH 027/236] Add config flag for enabling the overlay dock area title Changed the config name from DefaultDockContainerConfig->DefaultAutoHideConfig --- examples/autohide/mainwindow.cpp | 2 +- src/DockAreaWidget.cpp | 2 +- src/DockManager.h | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 7d14a6f71..ff9259af9 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -26,7 +26,7 @@ CMainWindow::CMainWindow(QWidget *parent) CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true); CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false); CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); - CDockManager::setConfigFlag(CDockManager::DefaultDockContainerConfig, true); + CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); DockManager = new CDockManager(this); // Set central widget diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 60261ccf6..2112192c7 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -815,7 +815,7 @@ void CDockAreaWidget::updateTitleBarVisibility() d->TitleBar->setVisible(isOverlayed() ? true : !Hidden); // Titlebar must always be visible when overlayed so it can be dragged auto tabBar = d->TitleBar->tabBar(); tabBar->setVisible(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed - d->TitleBar->overlayTitleLabel()->setVisible(isOverlayed()); // Always show when overlayed, never otherwise + d->TitleBar->overlayTitleLabel()->setVisible(CDockManager::testConfigFlag(CDockManager::DockAreaOverlayHasTitle) && isOverlayed()); // Always show when overlayed, never otherwise updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); } } diff --git a/src/DockManager.h b/src/DockManager.h index 14b3331be..04c8283a1 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -206,15 +206,16 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget 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 - + DockAreaOverlayHasTitle = 0x20000000, //!< If the flag is set overlay dock area title bar will show the window title DefaultDockAreaButtons = DockAreaHasCloseButton | DockAreaHasUndockButton | DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons - DefaultDockContainerConfig = DockContainerHasLeftSideBar - | DockContainerHasRightSideBar - | DockAreaHasAutoHideButton, ///< the default configuration for left and right side bars + DefaultAutoHideConfig = DockContainerHasLeftSideBar + | DockContainerHasRightSideBar + | DockAreaHasAutoHideButton + | DockAreaOverlayHasTitle, ///< the default configuration for left and right side bars DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton From 6ae14fada39a9ab4df569f2d413237c295ebf5c0 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 8 Sep 2022 17:42:24 +0800 Subject: [PATCH 028/236] add comment regarding empty widget in overlay dock container --- src/OverlayDockContainer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 22ea6338c..d50b01073 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -91,7 +91,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid d->Splitter->setChildrenCollapsible(false); const auto emptyWidget = new QWidget(); - emptyWidget->setMinimumWidth(50); + emptyWidget->setMinimumWidth(50); // Prevents you from dragging the splitter too far if (area == CDockWidgetSideTab::SideTabBarArea::Left) { From 1097d65959e0ac65c2548cdba90faa0314c2b26a Mon Sep 17 00:00:00 2001 From: Nick D'Ademo Date: Fri, 9 Sep 2022 09:34:45 +0800 Subject: [PATCH 029/236] fix elision for vertical eliding label. --- src/ElidingLabel.cpp | 34 ++++++++++++++++++++++++++++++---- src/ElidingLabel.h | 5 +++++ 2 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/ElidingLabel.cpp b/src/ElidingLabel.cpp index ee7531378..403e24dcf 100644 --- a/src/ElidingLabel.cpp +++ b/src/ElidingLabel.cpp @@ -118,7 +118,7 @@ Qt::TextElideMode CElidingLabel::elideMode() const void CElidingLabel::setElideMode(Qt::TextElideMode mode) { d->ElideMode = mode; - d->elideText(size().width()); + d->elideText(availableWidthForText()); } //============================================================================ @@ -155,12 +155,26 @@ void CElidingLabel::resizeEvent(QResizeEvent *event) { if (!d->isModeElideNone()) { - d->elideText(event->size().width()); + d->elideText(availableWidthForText(event)); } Super::resizeEvent(event); } +//============================================================================ +int CElidingLabel::availableWidthForText() const +{ + return size().width(); +} + + +//============================================================================ +int CElidingLabel::availableWidthForText(QResizeEvent* event) const +{ + return event->size().width(); +} + + //============================================================================ QSize CElidingLabel::minimumSizeHint() const { @@ -216,7 +230,7 @@ void CElidingLabel::setText(const QString &text) else { internal::setToolTip(this, text); - d->elideText(this->size().width()); + d->elideText(availableWidthForText()); } } @@ -238,7 +252,7 @@ void CVerticalElidingLabel::paintEvent(QPaintEvent* event) { QPainter painter(this); painter.rotate(90); - painter.drawText(0,0, text()); + painter.drawText(0,0, QLabel::text()); } //============================================================================ @@ -254,6 +268,18 @@ QSize CVerticalElidingLabel::minimumSizeHint() const QSize s = CElidingLabel::sizeHint(); return QSize(s.height(), s.width()); } + +//============================================================================ +int CVerticalElidingLabel::availableWidthForText() const +{ + return size().height(); +} + +//============================================================================ +int CVerticalElidingLabel::availableWidthForText(QResizeEvent* event) const +{ + return event->size().height(); +} } // namespace QtLabb //--------------------------------------------------------------------------- diff --git a/src/ElidingLabel.h b/src/ElidingLabel.h index 8dbf051af..dcb116395 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -55,6 +55,9 @@ class ADS_EXPORT CElidingLabel : public QLabel virtual void resizeEvent( QResizeEvent *event ) override; virtual void mouseDoubleClickEvent( QMouseEvent *ev ) override; + virtual int availableWidthForText() const; + virtual int availableWidthForText(QResizeEvent* event) const; + public: using Super = QLabel; @@ -109,6 +112,8 @@ class CVerticalElidingLabel : public CElidingLabel void paintEvent(QPaintEvent* event) override; QSize sizeHint() const override; QSize minimumSizeHint() const override; + int availableWidthForText() const override; + int availableWidthForText(QResizeEvent* event) const override; public: CVerticalElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags ()); From 84c6afa4286c5156a0c8513700f3766894331704 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 12:18:41 +0800 Subject: [PATCH 030/236] Reworked toggle view Previous: - It would just hide the overlay dock widget and leave the side tabs still visible - Close button, toggle view action would simply collapse the dock widget intsead of completely hiding it Current: - Now toggle view and collapse functionality are separated. - Toggle view will now hide the side tab bars completely - Close button and toggle view action will completely hide it - Collapse view will simply hide the overlay dock container without hiding the side tabs - Handled logic for floating widgets and toggling view --- src/DockAreaWidget.cpp | 2 -- src/DockContainerWidget.cpp | 15 +++++++---- src/DockContainerWidget.h | 11 ++++---- src/DockFocusController.cpp | 2 +- src/DockManager.cpp | 3 +-- src/DockWidget.cpp | 50 +++++++++++++++++++++++++++--------- src/OverlayDockContainer.cpp | 37 ++++++++++++++++++++++++++ src/OverlayDockContainer.h | 12 +++++++++ 8 files changed, 105 insertions(+), 27 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 2112192c7..fc4770649 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1079,12 +1079,10 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En if (Enable) { dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget); - DockWidget->toggleView(false); } else { overlayDockContainer()->moveContentsToParent(); - DockWidget->toggleView(true); } } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index a6287dd13..fb72c926c 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1074,6 +1074,12 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, return false; } + bool Closed = s.attributes().value("Closed").toInt(&Ok); + if (!Ok) + { + return false; + } + s.skipCurrentElement(); CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString()); if (!DockWidget || Testing) @@ -1085,15 +1091,14 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, // 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->setToggleViewActionChecked(!Closed); + DockWidget->setClosedState(Closed); + DockWidget->setProperty(internal::ClosedProperty, Closed); DockWidget->setProperty(internal::DirtyProperty, false); _this->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); - DockWidget->toggleView(false); DockArea->overlayDockContainer()->addDockWidget(DockWidget); - DockWidget->sideTabWidget()->show(); DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added + DockWidget->toggleView(Closed); } if (Testing) diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 5588f65ed..ea3d55ab6 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -90,11 +90,6 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ void deleteOverlayWidgets(); - /** - * Access function for overlay widgets - */ - QList overlayWidgets() const; - /** * Access function for the internal root splitter */ @@ -329,6 +324,12 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ CSideTabBar* sideTabBar(CDockWidgetSideTab::SideTabBarArea area) const; + + /** + * Access function for overlay widgets + */ + QList overlayWidgets() 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 f1226b2a8..d467bdb13 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -191,7 +191,7 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget) if (old && old->overlayDockContainer() && old->overlayDockContainer()->isVisible() && old != FocusedDockWidget) { - old->toggleView(false); + old->overlayDockContainer()->collapseView(true); } if (old == DockWidget && !ForceFocusChangedSignal) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 6708552c4..0a3442e1f 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -873,8 +873,7 @@ COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidget { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget); - container->dockAreaWidget()->toggleView(false); - Dockwidget->toggleView(false); + container->collapseView(true); Q_EMIT dockWidgetAdded(Dockwidget); return container; diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index f8b1cf1db..ecc26620d 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -118,6 +118,12 @@ struct DockWidgetPrivate */ void updateParentDockArea(); + /** + * Closes all overlayed dock widgets if there are no more opened dock areas + * This prevents the overlayed dock widgets from being pinned to an empty dock area + */ + void closeOverlayDockWidgetsIfNeeded(); + /** * Setup the top tool bar */ @@ -187,9 +193,10 @@ void DockWidgetPrivate::showDockWidget() FloatingWidget->show(); } - if (DockArea->isOverlayed()) + // If this widget is pinned and there are no opened dock widgets, unpin the overlay widget by moving it's contents to parent container + if (Container->openedDockWidgets().count() == 0 && DockArea->isOverlayed()) { - DockArea->overlayDockContainer()->show(); + DockArea->overlayDockContainer()->moveContentsToParent(); } } } @@ -200,17 +207,14 @@ void DockWidgetPrivate::hideDockWidget() { TabWidget->hide(); updateParentDockArea(); - + + closeOverlayDockWidgetsIfNeeded(); + if (Features.testFlag(CDockWidget::DeleteContentOnClose)) { Widget->deleteLater(); Widget = nullptr; } - - if (DockArea->isOverlayed()) - { - DockArea->overlayDockContainer()->hide(); - } } @@ -239,6 +243,22 @@ void DockWidgetPrivate::updateParentDockArea() } } +void DockWidgetPrivate::closeOverlayDockWidgetsIfNeeded() +{ + if (_this->dockContainer() && _this->dockContainer()->openedDockWidgets().isEmpty()) + { + for (auto overlayWidget : _this->dockContainer()->overlayWidgets()) + { + if (overlayWidget->dockWidget() == _this) + { + continue; + } + + overlayWidget->dockWidget()->toggleView(false); + } + } +} + //============================================================================ void DockWidgetPrivate::setupToolBar() @@ -611,6 +631,8 @@ void CDockWidget::toggleViewInternal(bool Open) CDockWidget* TopLevelDockWidgetBefore = DockContainer ? DockContainer->topLevelDockWidget() : nullptr; + d->Closed = !Open; + if (Open) { d->showDockWidget(); @@ -619,7 +641,7 @@ void CDockWidget::toggleViewInternal(bool Open) { d->hideDockWidget(); } - d->Closed = !Open; + d->ToggleViewAction->blockSignals(true); d->ToggleViewAction->setChecked(Open); d->ToggleViewAction->blockSignals(false); @@ -628,6 +650,11 @@ void CDockWidget::toggleViewInternal(bool Open) d->DockArea->toggleDockWidgetView(this, Open); } + if (d->DockArea->isOverlayed()) + { + d->DockArea->overlayDockContainer()->toggleView(Open); + } + if (Open && TopLevelDockWidgetBefore) { CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetBefore, false); @@ -1051,9 +1078,8 @@ void CDockWidget::onDockWidgetSideTabClicked() } overlayContainer->raise(); - const auto show = !overlayContainer->isVisible(); - overlayContainer->setVisible(show); - toggleView(show); + const auto shouldCollapse = overlayContainer->isVisible(); + overlayContainer->collapseView(shouldCollapse); if (overlayContainer->isVisible()) { // d->DockManager->setDockWidgetFocused(this) does not diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index d50b01073..28be35249 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -281,6 +281,43 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } +void COverlayDockContainer::toggleView(bool Enable) +{ + if (Enable) + { + const auto dockWidget = d->DockWidget; + if (dockWidget) + { + dockWidget->sideTabWidget()->show(); + } + } + else + { + const auto dockWidget = d->DockWidget; + if (dockWidget) + { + dockWidget->sideTabWidget()->hide(); + } + hide(); + } +} + +void COverlayDockContainer::collapseView(bool Enable) +{ + if (Enable) + { + hide(); + d->DockArea->hide(); + d->DockWidget->hide(); + } + else + { + show(); + d->DockArea->show(); + d->DockWidget->show(); + } +} + //============================================================================ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index 4a531720f..a0c8ab3b3 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -126,6 +126,18 @@ class ADS_EXPORT COverlayDockContainer : public QFrame */ bool restoreState(CDockingStateReader& Stream, bool Testing); + /* + * Toggles the overlay dock container widget + * This will also hide the side tab widget + */ + void toggleView(bool Enable); + + /* + * Collapses the overlay dock container widget + * Does not hide the side tab widget + */ + void collapseView(bool Enable); + /* * Convenience function fr determining if area exists in config */ From dc05ec3acf08e3ac59b5939822f3b6a1a0cc9a1a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 13:33:42 +0800 Subject: [PATCH 031/236] Add nullptr check when restoring state with overlayed widgets --- src/DockAreaTitleBar.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 9c994a774..e86b12e2a 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -427,7 +427,14 @@ void CDockAreaTitleBar::onTabsMenuActionTriggered(QAction* Action) //============================================================================ void CDockAreaTitleBar::updateDockWidgetActionsButtons() { - CDockWidget* DockWidget = d->TabBar->currentTab()->dockWidget(); + auto* const currentTab = d->TabBar->currentTab(); + if (currentTab == nullptr) + { + // It's possible for this to be nullptr when restoring state + return; + } + + CDockWidget* DockWidget = currentTab->dockWidget(); if (!d->DockWidgetActionsButtons.isEmpty()) { for (auto Button : d->DockWidgetActionsButtons) From 22402e79f5bea18b5098cd51b1bdfac30d3f4ab7 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 13:57:43 +0800 Subject: [PATCH 032/236] Added support for delete on close to overlayed widgets --- examples/autohide/mainwindow.cpp | 1 + src/DockAreaWidget.cpp | 12 ++++++++++-- src/DockWidget.cpp | 4 ++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index ff9259af9..1e9a448dd 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,6 +46,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); + TableDockWidget->setFeature(CDockWidget::DockWidgetDeleteOnClose, true); DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index fc4770649..e471eb077 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1049,11 +1049,19 @@ void CDockAreaWidget::closeArea() { for (auto DockWidget : openedDockWidgets()) { - if ((DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea)) || - DockWidget->features().testFlag(CDockWidget::CustomCloseHandling) && !isOverlayed()) + 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) && isOverlayed()) + { DockWidget->closeDockWidgetInternal(); + } else + { DockWidget->toggleView(false); + } } } } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index ecc26620d..9f7f9bffd 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1015,6 +1015,10 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose) FloatingWidget->hide(); } } + if (d->DockArea && d->DockArea->isOverlayed()) + { + d->DockArea->overlayDockContainer()->cleanupAndDelete(); + } deleteDockWidget(); Q_EMIT closed(); } From 621e5e778911400d97252f3150eebff16f316025 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 14:43:59 +0800 Subject: [PATCH 033/236] fix tooltips for auto hide button and close button --- src/DockAreaTitleBar.cpp | 27 ++++++++++++++++++--------- src/DockAreaTitleBar.h | 6 ++++++ src/DockAreaWidget.cpp | 11 ++++++++++- src/DockAreaWidget.h | 7 ++++++- src/DockContainerWidget.cpp | 6 ++++-- src/OverlayDockContainer.cpp | 3 ++- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index e86b12e2a..16c690d65 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -188,7 +188,7 @@ void DockAreaTitleBarPrivate::createButtons() AutoHideButton->setAutoRaise(true); AutoHideButton->setCheckable(true); AutoHideButton->setChecked(false); - internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide Group")); + internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); Layout->addWidget(AutoHideButton, 0); @@ -199,14 +199,7 @@ void DockAreaTitleBarPrivate::createButtons() CloseButton->setObjectName("dockAreaCloseButton"); CloseButton->setAutoRaise(true); internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon); - if (testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) - { - internal::setToolTip(CloseButton, QObject::tr("Close Active Tab")); - } - else - { - internal::setToolTip(CloseButton, QObject::tr("Close Group")); - } + internal::setToolTip(CloseButton, _this->closeGroupToolTip()); CloseButton->setSizePolicy(ButtonSizePolicy); CloseButton->setIconSize(QSize(16, 16)); Layout->addWidget(CloseButton, 0); @@ -664,6 +657,22 @@ int CDockAreaTitleBar::indexOf(QWidget *widget) const return d->Layout->indexOf(widget); } +//============================================================================ +QString CDockAreaTitleBar::closeGroupToolTip() const +{ + if (d->DockArea->isOverlayed()) + { + return QObject::tr("Close Overlay"); + + } + if (CDockManager::testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) + { + return QObject::tr("Close Active Tab"); + } + + return QObject::tr("Close Group") ; +} + //============================================================================ CTitleBarButton::CTitleBarButton(bool visible, QWidget* parent) : tTitleBarButton(parent), diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index b3af047a7..63d6749e5 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -155,6 +155,12 @@ public Q_SLOTS: */ int indexOf(QWidget *widget) const; + /** + * Close group tool tip based on the current state + * Overlayed widgets can only have one dock widget so it does not make sense for the tooltip to show close group + */ + QString closeGroupToolTip() const; + Q_SIGNALS: /** * This signal is emitted if a tab in the tab bar is clicked by the user diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index e471eb077..598ac78d0 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -832,7 +832,7 @@ void CDockAreaWidget::markTitleBarMenuOutdated() //============================================================================ -void CDockAreaWidget::updateAutoHidebuttonCheckState() +void CDockAreaWidget::updateAutoHideButtonCheckState() { auto autoHideButton = titleBarButton(TitleBarButtonAutoHide); autoHideButton->blockSignals(true); @@ -840,12 +840,21 @@ void CDockAreaWidget::updateAutoHidebuttonCheckState() 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 { diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 503df45ca..f94fc3417 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -154,13 +154,18 @@ private Q_SLOTS: /* * Update the auto hide button checked state based on if it's overlayed or not */ - void updateAutoHidebuttonCheckState(); + void updateAutoHideButtonCheckState(); /* * Update the title bar button visibility based on if it's top level or not */ void updateTitleBarButtonVisibility(bool IsTopLevel) const; + /* + * Update the title bar button tooltips + */ + void updateTitleBarButtonToolTip(); + protected Q_SLOTS: void toggleView(bool Open); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index fb72c926c..312d726a2 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1058,7 +1058,8 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, dockContainer->hide(); DockArea = dockContainer->dockAreaWidget(); - DockArea->updateAutoHidebuttonCheckState(); + DockArea->updateAutoHideButtonCheckState(); + DockArea->updateTitleBarButtonToolTip(); } while (s.readNextStartElement()) @@ -1653,7 +1654,8 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) dumpLayout(); d->emitDockAreasRemoved(); area->setOverlayDockContainer(nullptr); - area->updateAutoHidebuttonCheckState(); + area->updateAutoHideButtonCheckState(); + area->updateTitleBarButtonToolTip(); return; } diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 28be35249..d908dcdc0 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -83,7 +83,8 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("OverlayDockArea"); d->DockArea->setOverlayDockContainer(this); - d->DockArea->updateAutoHidebuttonCheckState(); + d->DockArea->updateAutoHideButtonCheckState(); + d->DockArea->updateTitleBarButtonToolTip(); QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); d->Splitter = new QSplitter(Qt::Orientation::Horizontal); From 3ef1ac97c21205450570e08893489129416d67f9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 15:24:33 +0800 Subject: [PATCH 034/236] Fix splitter size being saved incorrectly if the overlay widget is never opened --- src/OverlayDockContainer.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index d908dcdc0..0d14d5157 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -191,6 +191,19 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockArea->addDockWidget(DockWidget); + const auto dockContainerParent = parentContainer(); + const auto rootSplitter = dockContainerParent->rootSplitter(); + const auto rect = rootSplitter->frameGeometry(); + const auto dockWidth = DockWidget->size().width(); + if (d->Area == CDockWidgetSideTab::SideTabBarArea::Left) + { + d->Splitter->setSizes({ dockWidth, rect.width() - dockWidth }); + } + else + { + d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); + } + updateSize(); updateMask(); } From 883d5b51985306f8519d3a93136637d8f29d726d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 9 Sep 2022 15:38:31 +0800 Subject: [PATCH 035/236] fix crash when sometimes restoring state --- src/DockManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 0a3442e1f..66f61300c 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -432,8 +432,8 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version) // Hide updates of floating widgets from use hideFloatingWidgets(); - _this->deleteOverlayWidgets(); markDockWidgetsDirty(); + _this->deleteOverlayWidgets(); if (!restoreStateFromXml(state, version)) { From 489f72aa0c21e4bc8240c387d855aaa544f38241 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 12 Sep 2022 15:55:45 +0800 Subject: [PATCH 036/236] Add side tab widget icons - Add config to prioritize icon only if it has one --- src/DockAreaTitleBar.cpp | 9 ++ src/DockManager.cpp | 27 ++++ src/DockManager.h | 50 ++++++-- src/DockWidget.cpp | 1 + src/DockWidgetSideTab.cpp | 170 ++++++++++++++++++++++++- src/DockWidgetSideTab.h | 39 ++++++ src/DockWidgetTab.cpp | 4 - src/OverlayDockContainer.cpp | 2 + src/stylesheets/focus_highlighting.css | 1 + 9 files changed, 282 insertions(+), 21 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 16c690d65..df2c66a43 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -120,6 +120,15 @@ struct DockAreaTitleBarPrivate return CDockManager::testConfigFlag(Flag); } + /** + * Returns true if the given config flag is set + * Convenience function to ease config flag testing + */ + static bool testConfigFlag(CDockManager::eOverlayFlag Flag) + { + return CDockManager::testConfigFlag(Flag); + } + /** * Test function for current drag state */ diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 66f61300c..1b0c5da17 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -92,6 +92,7 @@ enum eStateFileVersion }; static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig; +static CDockManager::OverlayFlags StaticOverlayConfigFlags = CDockManager::DefaultAutoHideConfig; /** * Private data class of CDockManager class (pimpl) @@ -1135,6 +1136,11 @@ CDockManager::ConfigFlags CDockManager::configFlags() return StaticConfigFlags; } +CDockManager::OverlayFlags CDockManager::overlayConfigFlags() +{ + return StaticOverlayConfigFlags; +} + //=========================================================================== void CDockManager::setConfigFlags(const ConfigFlags Flags) @@ -1143,12 +1149,26 @@ void CDockManager::setConfigFlags(const ConfigFlags Flags) } +//=========================================================================== +void CDockManager::setConfigFlags(const OverlayFlags Flags) +{ + StaticOverlayConfigFlags = Flags; +} + + //=========================================================================== void CDockManager::setConfigFlag(eConfigFlag Flag, bool On) { internal::setFlag(StaticConfigFlags, Flag, On); } + +//=========================================================================== +void CDockManager::setConfigFlag(eOverlayFlag Flag, bool On) +{ + internal::setFlag(StaticOverlayConfigFlags, Flag, On); +} + //=========================================================================== bool CDockManager::testConfigFlag(eConfigFlag Flag) { @@ -1156,6 +1176,13 @@ bool CDockManager::testConfigFlag(eConfigFlag Flag) } +//=========================================================================== +bool CDockManager::testConfigFlag(eOverlayFlag Flag) +{ + return overlayConfigFlags().testFlag(Flag); +} + + //=========================================================================== CIconProvider& CDockManager::iconProvider() { diff --git a/src/DockManager.h b/src/DockManager.h index 04c8283a1..9cbd5ac7f 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -203,20 +203,10 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget //! 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 - DockAreaOverlayHasTitle = 0x20000000, //!< If the flag is set overlay dock area title bar will show the window title - DefaultDockAreaButtons = DockAreaHasCloseButton | DockAreaHasUndockButton | DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons - DefaultAutoHideConfig = DockContainerHasLeftSideBar - | DockContainerHasRightSideBar - | DockAreaHasAutoHideButton - | DockAreaOverlayHasTitle, ///< the default configuration for left and right side bars - DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton | XmlCompressionEnabled @@ -234,6 +224,23 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget }; Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag) + enum eOverlayFlag + { + DockContainerHasLeftSideBar = 0x01, //!< If the flag is set left side bar will prioritize showing icons only over text + DockContainerHasRightSideBar = 0x02, //!< If the flag is set right side bar will prioritize showing icons only over text + DockAreaHasAutoHideButton = 0x04, //!< If the flag is set each dock area has a auto hide menu button + LeftSideBarPrioritizeIconOnly = 0x08, //!< If the flag is set each container will have a left side bar + RightSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a right side bar + DockAreaOverlayHasTitle = 0x20, //!< If the flag is set overlay dock area title bar will show the window title + + DefaultAutoHideConfig = DockContainerHasLeftSideBar + | DockContainerHasRightSideBar + | DockAreaHasAutoHideButton + | DockAreaOverlayHasTitle, ///< the default configuration for left and right side bars + }; + Q_DECLARE_FLAGS(OverlayFlags, eOverlayFlag) + + /** * Default Constructor. * If the given parent is a QMainWindow, the dock manager sets itself as the @@ -253,6 +260,11 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget */ static ConfigFlags configFlags(); + /** + * This function returns the overlay configuration flags + */ + static OverlayFlags overlayConfigFlags(); + /** * Sets the global configuration flags for the whole docking system. * Call this function before you create the dock manager and before @@ -260,17 +272,35 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget */ static void setConfigFlags(const ConfigFlags Flags); + /** + * Sets the global configuration flags for the whole docking system. + * Call this function before you create the dock manager and before + * your create the first dock widget. + */ + static void setConfigFlags(const OverlayFlags Flags); + /** * Set a certain config flag. * \see setConfigFlags() */ static void setConfigFlag(eConfigFlag Flag, bool On = true); + /** + * Set a certain overlay config flag. + * \see setConfigFlags() + */ + static void setConfigFlag(eOverlayFlag Flag, bool On = true); + /** * Returns true if the given config flag is set */ static bool testConfigFlag(eConfigFlag Flag); + /** + * Returns true if the given overlay config flag is set + */ + static bool testConfigFlag(eOverlayFlag Flag); + /** * Returns the global icon provider. * The icon provider enables the use of custom icons in case using diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 9f7f9bffd..a87ac04cc 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -782,6 +782,7 @@ void CDockWidget::setTabToolTip(const QString &text) void CDockWidget::setIcon(const QIcon& Icon) { d->TabWidget->setIcon(Icon); + d->SideTabWidget->setIcon(Icon); if (!d->ToggleViewAction->isCheckable()) { d->ToggleViewAction->setIcon(Icon); diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 1913d8dbf..a3376bef7 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -33,6 +33,7 @@ #include #include "DockAreaWidget.h" +#include "DockManager.h" #include "ElidingLabel.h" #include "DockWidget.h" @@ -52,7 +53,11 @@ struct DockWidgetSideTabPrivate CDockWidget* DockWidget; tTabLabel* TitleLabel; QBoxLayout* Layout; + QBoxLayout* TitleLayout; // To have independent spacing from the icon CSideTabBar* SideTabBar; + QSize IconSize; + SideTabIconLabel* IconLabel = nullptr; + QIcon Icon; /** * Private data constructor @@ -63,8 +68,28 @@ struct DockWidgetSideTabPrivate * Creates the complete layout */ void createLayout(); -}; -// struct DockWidgetTabPrivate + + /** + * Update the icon in case the icon size changed + */ + void updateIcon() + { + if (!IconLabel || Icon.isNull()) + { + return; + } + + if (IconSize.isValid()) + { + IconLabel->setPixmap(Icon.pixmap(IconSize)); + } + else + { + IconLabel->setPixmap(Icon.pixmap(_this->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, _this))); + } + IconLabel->setVisible(true); + } +}; // struct DockWidgetTabPrivate //============================================================================ @@ -81,19 +106,24 @@ void DockWidgetSideTabPrivate::createLayout() TitleLabel->setElideMode(Qt::ElideRight); TitleLabel->setText(DockWidget->windowTitle()); TitleLabel->setObjectName("dockWidgetTabLabel"); - TitleLabel->setAlignment(Qt::AlignCenter); + //TitleLabel->setAlignment(Qt::AlignLeft); _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); + // Purely for spacing on the text without messing up spacing on the icon + TitleLayout = new QBoxLayout(QBoxLayout::TopToBottom); + TitleLayout->setContentsMargins(Spacing,Spacing,0,Spacing); + TitleLayout->addWidget(TitleLabel); + TitleLayout->setSpacing(0); + + Layout = new QBoxLayout(QBoxLayout::TopToBottom); + Layout->setContentsMargins(0,0,0,0); Layout->setSpacing(0); _this->setLayout(Layout); - Layout->addWidget(TitleLabel, 1); - Layout->setAlignment(Qt::AlignCenter); + Layout->addLayout(TitleLayout, 1); TitleLabel->setVisible(true); } @@ -139,18 +169,22 @@ CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) setFocusPolicy(Qt::NoFocus); } + //============================================================================ CDockWidgetSideTab::~CDockWidgetSideTab() { delete d; } + //============================================================================ void CDockWidgetSideTab::updateStyle() { internal::repolishStyle(this, internal::RepolishDirectChildren); } + +//============================================================================ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const { auto dockAreaWidget = d->DockWidget->dockAreaWidget(); @@ -161,4 +195,126 @@ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const return Left; } + + +//============================================================================ +void CDockWidgetSideTab::setIcon(const QIcon& Icon) +{ + QBoxLayout* Layout = qobject_cast(layout()); + if (!d->IconLabel && Icon.isNull()) + { + return; + } + + if (!d->IconLabel) + { + d->IconLabel = new SideTabIconLabel(); + internal::setToolTip(d->IconLabel, d->TitleLabel->toolTip()); + Layout->insertWidget(0, d->IconLabel, Qt::AlignHCenter); + } + else if (Icon.isNull()) + { + // Remove icon label + Layout->removeWidget(d->IconLabel); + delete d->IconLabel; + d->IconLabel = nullptr; + } + + d->Icon = Icon; + d->updateIcon(); +} + + +//============================================================================ +QSize CDockWidgetSideTab::iconSize() const +{ + return d->IconSize; +} + + +//============================================================================ +void CDockWidgetSideTab::setIconSize(const QSize& Size) +{ + d->IconSize = Size; + d->updateIcon(); +} + + +//============================================================================ +void CDockWidgetSideTab::updateTitleAndIconVisibility(SideTabBarArea area) +{ + if (d->Icon.isNull()) + { + return; + } + + QFontMetrics fm(d->TitleLabel->font()); + int Spacing = qRound(fm.height() / 2.0); + + if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left + || CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) + { + d->TitleLabel->hide(); + d->TitleLayout->setContentsMargins(0, 0, 0, 0); + d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); + return; + } + + d->TitleLayout->setContentsMargins(Spacing, Spacing, 0, Spacing); + d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); + + d->TitleLabel->show(); +} + +/** + * Private data class of SideTabIcon class (pimpl) + */ +struct SideTabIconLabelPrivate +{ + SideTabIconLabel* _this; + QLabel* IconLabel; + QBoxLayout* Layout; + + SideTabIconLabelPrivate(SideTabIconLabel* _public); +}; // struct SideTabIconLabelPrivate + + +//============================================================================ +SideTabIconLabelPrivate::SideTabIconLabelPrivate(SideTabIconLabel* _public) : + _this(_public) +{ +} + + +//============================================================================ +SideTabIconLabel::SideTabIconLabel(QWidget* parent) : QWidget(parent), + d(new SideTabIconLabelPrivate(this)) +{ + d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); + d->Layout->addWidget(d->IconLabel = new QLabel()); + d->IconLabel->setAlignment(Qt::AlignHCenter); + d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + setLayout(d->Layout); +} + + +//============================================================================ +SideTabIconLabel::~SideTabIconLabel() +{ + delete d; +} + + +//============================================================================ +void SideTabIconLabel::setPixmap(const QPixmap& pixmap) +{ + d->IconLabel->setPixmap(pixmap); +} + + +//============================================================================ +void SideTabIconLabel::setContentsMargins(int left, int top, int right, int bottom) +{ + d->Layout->setContentsMargins(left, top, right, bottom); +} } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 51078283d..0112308c8 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -39,6 +39,7 @@ struct DockWidgetSideTabPrivate; class CDockWidget; class CSideTabBar; class CDockWidgetTab; +struct SideTabIconLabelPrivate; /** * A dock widget Side tab that shows a title or an icon. @@ -50,6 +51,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame Q_OBJECT Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) private: DockWidgetSideTabPrivate* d; ///< private data (pimpl) @@ -104,10 +106,47 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ SideTabBarArea sideTabBarArea() const; + /** + * Sets the icon to show in title bar + */ + void setIcon(const QIcon& Icon); + + /** + * Returns the icon size. + * If no explicit icon size has been set, the function returns an invalid + * QSize + */ + QSize iconSize() const; + + /** + * Set an explicit icon size. + * If no icon size has been set explicitely, than the tab sets the icon size + * depending on the style + */ + void setIconSize(const QSize& Size); + + /** + * Update the title and icon visibility based on the area and the config + */ + void updateTitleAndIconVisibility(SideTabBarArea area); + Q_SIGNALS: void elidedChanged(bool elided); void clicked(); }; // class DockWidgetSideTab + +class SideTabIconLabel : public QWidget +{ +private: + SideTabIconLabelPrivate *d; ///< private data (pimpl) + +public: + SideTabIconLabel(QWidget* parent = nullptr); + virtual ~SideTabIconLabel(); + + void setPixmap(const QPixmap &pixmap); + void setContentsMargins(int left, int top, int right, int bottom); +}; // class SideTabIconLabel } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index f8b4e7252..eed6fff53 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -759,10 +759,6 @@ void CDockWidgetTab::setIconSize(const QSize& Size) d->IconSize = Size; d->updateIcon(); } - - - - } // namespace ads //--------------------------------------------------------------------------- // EOF DockWidgetTab.cpp diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 0d14d5157..49bfb7828 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -204,6 +204,8 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); } + d->DockWidget->sideTabWidget()->updateTitleAndIconVisibility(d->Area); + updateSize(); updateMask(); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 3d70856c8..f115a9cd8 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -24,6 +24,7 @@ ads--CDockWidgetTab { ads--CDockWidgetSideTab { background: palette(window); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } ads--CDockWidgetSideTab[sideTabBarArea="Left"] { From 214c415fa2d9134d0a7552f23a0bc8a100503832 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 10:42:58 +0800 Subject: [PATCH 037/236] Add Bottom side bar --- src/DockContainerWidget.cpp | 45 ++++++++- src/DockManager.h | 11 +- src/DockWidgetSideTab.cpp | 56 +++++++++-- src/DockWidgetSideTab.h | 14 ++- src/ElidingLabel.cpp | 71 +++++++++++-- src/ElidingLabel.h | 7 +- src/OverlayDockContainer.cpp | 133 ++++++++++++++++++------- src/SideTabBar.cpp | 7 +- src/SideTabBar.h | 2 +- src/stylesheets/focus_highlighting.css | 14 +++ 10 files changed, 289 insertions(+), 71 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 312d726a2..18c05124f 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1444,6 +1444,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p d->Layout->setContentsMargins(0, 0, 0, 0); d->Layout->setSpacing(0); d->Layout->setColumnStretch(1, 1); + d->Layout->setRowStretch(0, 1); setLayout(d->Layout); // The function d->newSplitter() accesses the config flags from dock @@ -1524,8 +1525,24 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla //============================================================================ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget) { - const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(DockAreaWidget->frameGeometry().center()); + // Handle bottom case + // It's bottom if the width is wider than the height, and if it's below 50% of the window + const auto dockWidgetFrameGeometry = DockAreaWidget->frameGeometry(); const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); + const auto a = dockWidgetFrameGeometry.width(); + const auto b = dockWidgetFrameGeometry.height(); + const auto c = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y(); + const auto d = splitterCenter.y(); + const auto e = CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); + if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height() + && DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() + && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) + { + return CDockWidgetSideTab::Bottom; + } + + // Then handle left and right + const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.center()); const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::Left : CDockWidgetSideTab::Right; if (calculatedPosition == CDockWidgetSideTab::Right) { @@ -1534,7 +1551,12 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo return CDockWidgetSideTab::Right; } - return CDockWidgetSideTab::Left; + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) + { + return CDockWidgetSideTab::Left; + } + + return CDockWidgetSideTab::Bottom; } if (calculatedPosition == CDockWidgetSideTab::Left) @@ -1543,9 +1565,16 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo { return CDockWidgetSideTab::Left; } - return CDockWidgetSideTab::Right; + + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) + { + return CDockWidgetSideTab::Right; + } + + return CDockWidgetSideTab::Bottom; } + Q_ASSERT_X(false, "CDockContainerWidget::getDockAreaPosition", "Unhandled branch. All positions should be accounted for."); return CDockWidgetSideTab::Left; } @@ -2026,15 +2055,21 @@ void CDockContainerWidget::createSideTabBarWidgets() { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this); + d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left], 0, 0); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this); + d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right], 0, 2); } + + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) + { + d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 1, 1); + } } diff --git a/src/DockManager.h b/src/DockManager.h index 9cbd5ac7f..198cdb554 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -228,13 +228,16 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget { DockContainerHasLeftSideBar = 0x01, //!< If the flag is set left side bar will prioritize showing icons only over text DockContainerHasRightSideBar = 0x02, //!< If the flag is set right side bar will prioritize showing icons only over text - DockAreaHasAutoHideButton = 0x04, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x08, //!< If the flag is set each container will have a left side bar - RightSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a right side bar - DockAreaOverlayHasTitle = 0x20, //!< If the flag is set overlay dock area title bar will show the window title + DockContainerHasBottomSideBar = 0x04, //!< If the flag is set right side bar will prioritize showing icons only over text + DockAreaHasAutoHideButton = 0x08, //!< If the flag is set each dock area has a auto hide menu button + LeftSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a left side bar + RightSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a right side bar + BottomSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set right side bar will prioritize showing icons only over text + DockAreaOverlayHasTitle = 0x80, //!< If the flag is set overlay dock area title bar will show the window title DefaultAutoHideConfig = DockContainerHasLeftSideBar | DockContainerHasRightSideBar + | DockContainerHasBottomSideBar | DockAreaHasAutoHideButton | DockAreaOverlayHasTitle, ///< the default configuration for left and right side bars }; diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index a3376bef7..eae6717bf 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -56,6 +56,7 @@ struct DockWidgetSideTabPrivate QBoxLayout* TitleLayout; // To have independent spacing from the icon CSideTabBar* SideTabBar; QSize IconSize; + Qt::Orientation Orientation{Qt::Vertical}; SideTabIconLabel* IconLabel = nullptr; QIcon Icon; @@ -89,6 +90,29 @@ struct DockWidgetSideTabPrivate } IconLabel->setVisible(true); } + + void updateContentsMargins() + { + QFontMetrics fm(TitleLabel->font()); + int Spacing = qRound(fm.height() / 2.0); + + if (Orientation == Qt::Vertical) + { + TitleLayout->setContentsMargins(Spacing, Spacing, 0, Spacing); + if (IconLabel) + { + IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); + } + } + else if (Orientation == Qt::Horizontal) + { + TitleLayout->setContentsMargins(Spacing,Spacing / 2,Spacing,Spacing); + if (IconLabel) + { + IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); + } + } + } }; // struct DockWidgetTabPrivate @@ -115,7 +139,6 @@ void DockWidgetSideTabPrivate::createLayout() // Fill the layout // Purely for spacing on the text without messing up spacing on the icon TitleLayout = new QBoxLayout(QBoxLayout::TopToBottom); - TitleLayout->setContentsMargins(Spacing,Spacing,0,Spacing); TitleLayout->addWidget(TitleLabel); TitleLayout->setSpacing(0); @@ -125,6 +148,8 @@ void DockWidgetSideTabPrivate::createLayout() _this->setLayout(Layout); Layout->addLayout(TitleLayout, 1); + updateContentsMargins(); + TitleLabel->setVisible(true); } @@ -241,8 +266,22 @@ void CDockWidgetSideTab::setIconSize(const QSize& Size) //============================================================================ -void CDockWidgetSideTab::updateTitleAndIconVisibility(SideTabBarArea area) +void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) +{ + d->Orientation = Orientation; + d->Layout->setDirection(Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); + d->TitleLabel->setOrientation(Orientation); +} + + +//============================================================================ +void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) { + setOrientation(area == Bottom ? Qt::Horizontal : Qt::Vertical); + + d->updateContentsMargins(); + + // Handle Icon changes if (d->Icon.isNull()) { return; @@ -251,17 +290,20 @@ void CDockWidgetSideTab::updateTitleAndIconVisibility(SideTabBarArea area) QFontMetrics fm(d->TitleLabel->font()); int Spacing = qRound(fm.height() / 2.0); - if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left - || CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) + if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); return; } - - d->TitleLayout->setContentsMargins(Spacing, Spacing, 0, Spacing); - d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); + if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) + { + d->TitleLabel->hide(); + d->TitleLayout->setContentsMargins(0, 0, 0, 0); + d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing / 2); + return; + } d->TitleLabel->show(); } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 0112308c8..edda9be23 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -78,7 +78,8 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame enum SideTabBarArea { Left, - Right + Right, + Bottom }; Q_ENUM(SideTabBarArea) @@ -120,15 +121,20 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame /** * Set an explicit icon size. - * If no icon size has been set explicitely, than the tab sets the icon size + * If no icon size has been set explicitly, than the tab sets the icon size * depending on the style */ void setIconSize(const QSize& Size); /** - * Update the title and icon visibility based on the area and the config + * Set orientation vertical or horizontal */ - void updateTitleAndIconVisibility(SideTabBarArea area); + void setOrientation(Qt::Orientation Orientation); + + /** + * Update the orientation, visibility and spacing based on the area and the config + */ + void updateOrientationAndSpacing(SideTabBarArea area); Q_SIGNALS: void elidedChanged(bool elided); diff --git a/src/ElidingLabel.cpp b/src/ElidingLabel.cpp index 403e24dcf..86cc60afb 100644 --- a/src/ElidingLabel.cpp +++ b/src/ElidingLabel.cpp @@ -241,44 +241,95 @@ QString CElidingLabel::text() const return d->Text; } +/** + * Private data of public CVerticalElidingLabel + */ +struct VerticalElidingLabelPrivate +{ + CVerticalElidingLabel* _this; + Qt::Orientation Orientation {Qt::Horizontal}; + + VerticalElidingLabelPrivate(CVerticalElidingLabel* _public); +}; + + +//============================================================================ +VerticalElidingLabelPrivate::VerticalElidingLabelPrivate(CVerticalElidingLabel* _public) +{ +} + //============================================================================ CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) : - CElidingLabel(parent, f) + CElidingLabel(parent, f), + d(new VerticalElidingLabelPrivate(this)) +{ +} + +//============================================================================ +void CVerticalElidingLabel::setOrientation(Qt::Orientation orientation) { + d->Orientation = orientation; + updateGeometry(); } //============================================================================ void CVerticalElidingLabel::paintEvent(QPaintEvent* event) { - QPainter painter(this); - painter.rotate(90); - painter.drawText(0,0, QLabel::text()); + if (d->Orientation == Qt::Vertical) + { + QPainter painter(this); + painter.rotate(90); + painter.drawText(0,0, QLabel::text()); + return; + } + + CElidingLabel::paintEvent(event); } //============================================================================ QSize CVerticalElidingLabel::sizeHint() const { - QSize s = CElidingLabel::minimumSizeHint(); - return QSize(s.height(), s.width()); + if (d->Orientation == Qt::Vertical) + { + QSize s = CElidingLabel::minimumSizeHint(); + return QSize(s.height(), s.width()); + } + + return CElidingLabel::sizeHint(); } //============================================================================ QSize CVerticalElidingLabel::minimumSizeHint() const { - QSize s = CElidingLabel::sizeHint(); - return QSize(s.height(), s.width()); + if (d->Orientation == Qt::Vertical) + { + QSize s = CElidingLabel::sizeHint(); + return QSize(s.height(), s.width()); + } + + return CElidingLabel::minimumSizeHint(); } //============================================================================ int CVerticalElidingLabel::availableWidthForText() const { - return size().height(); + if (d->Orientation == Qt::Vertical) + { + return size().height(); + } + + return CElidingLabel::availableWidthForText(); } //============================================================================ int CVerticalElidingLabel::availableWidthForText(QResizeEvent* event) const { - return event->size().height(); + if (d->Orientation == Qt::Vertical) + { + return event->size().height(); + } + + return CElidingLabel::availableWidthForText(event); } } // namespace QtLabb diff --git a/src/ElidingLabel.h b/src/ElidingLabel.h index dcb116395..f1525e255 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -36,7 +36,7 @@ namespace ads { struct ElidingLabelPrivate; - +struct VerticalElidingLabelPrivate; /** * A QLabel that supports eliding text. * Because the functions setText() and text() are no virtual functions setting @@ -108,6 +108,9 @@ class ADS_EXPORT CElidingLabel : public QLabel class CVerticalElidingLabel : public CElidingLabel { +private: + VerticalElidingLabelPrivate* d; + protected: void paintEvent(QPaintEvent* event) override; QSize sizeHint() const override; @@ -117,6 +120,8 @@ class CVerticalElidingLabel : public CElidingLabel public: CVerticalElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags ()); + + void setOrientation(Qt::Orientation orientation); }; // class CVerticalElidingLabel } // namespace QtLabb diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 49bfb7828..6007e5b82 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -58,6 +58,30 @@ struct OverlayDockContainerPrivate * Private data constructor */ OverlayDockContainerPrivate(COverlayDockContainer *_public); + + /** + * Convenience function to get a dock widget area + */ + DockWidgetArea getArea(CDockWidgetSideTab::SideTabBarArea area) + { + switch (area) + { + case CDockWidgetSideTab::Left: + { + return LeftDockWidgetArea; + } + case CDockWidgetSideTab::Right: + { + return RightDockWidgetArea; + } + case CDockWidgetSideTab::Bottom: + { + return BottomDockWidgetArea; + } + } + + return LeftDockWidgetArea; + } }; // struct OverlayDockContainerPrivate //============================================================================ @@ -87,23 +111,35 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid d->DockArea->updateTitleBarButtonToolTip(); QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); - d->Splitter = new QSplitter(Qt::Orientation::Horizontal); + d->Splitter = new QSplitter(area == CDockWidgetSideTab::Bottom ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal); d->Splitter->setObjectName("overlaySplitter"); d->Splitter->setChildrenCollapsible(false); const auto emptyWidget = new QWidget(); - emptyWidget->setMinimumWidth(50); // Prevents you from dragging the splitter too far + emptyWidget->setMinimumWidth(50); + emptyWidget->setMinimumHeight(50); // Prevents you from dragging the splitter too far - if (area == CDockWidgetSideTab::SideTabBarArea::Left) - { - d->Splitter->addWidget(d->DockArea); - d->Splitter->addWidget(emptyWidget); - } - else - { - d->Splitter->addWidget(emptyWidget); - d->Splitter->addWidget(d->DockArea); - } + switch (area) + { + case CDockWidgetSideTab::Left: + { + d->Splitter->addWidget(d->DockArea); + d->Splitter->addWidget(emptyWidget); + break; + } + case CDockWidgetSideTab::Right: + { + d->Splitter->addWidget(emptyWidget); + d->Splitter->addWidget(d->DockArea); + break; + } + case CDockWidgetSideTab::Bottom: + { + d->Splitter->addWidget(emptyWidget); + d->Splitter->addWidget(d->DockArea); + break; + } + } l->setContentsMargins(QMargins()); l->setSpacing(0); @@ -122,11 +158,19 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid //============================================================================ 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 == CDockWidgetSideTab::SideTabBarArea::Left ? 0 : handleSize; - setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); + const auto rect = d->DockArea->frameGeometry(); + const auto topLeft = rect.topLeft(); + const auto handleSize = d->Splitter->handleWidth(); + + if (d->Area == CDockWidgetSideTab::Bottom) + { + setMask(QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize))); + } + else + { + const auto offset = d->Area == CDockWidgetSideTab::SideTabBarArea::Left ? 0 : handleSize; + setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); + } } //============================================================================ @@ -194,17 +238,27 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) const auto dockContainerParent = parentContainer(); const auto rootSplitter = dockContainerParent->rootSplitter(); const auto rect = rootSplitter->frameGeometry(); - const auto dockWidth = DockWidget->size().width(); - if (d->Area == CDockWidgetSideTab::SideTabBarArea::Left) - { - d->Splitter->setSizes({ dockWidth, rect.width() - dockWidth }); - } - else - { - d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); - } + const auto dockWidth = DockWidget->sizeHint().width(); + switch (d->Area) + { + case CDockWidgetSideTab::Left: + { + d->Splitter->setSizes({ dockWidth, rect.width() - dockWidth }); + break; + } + case CDockWidgetSideTab::Right: + { + d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); + break; + } + case CDockWidgetSideTab::Bottom: + { + d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); + break; + } + } - d->DockWidget->sideTabWidget()->updateTitleAndIconVisibility(d->Area); + d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->Area); updateSize(); updateMask(); @@ -235,7 +289,7 @@ void COverlayDockContainer::moveContentsToParent() } else { - parentContainer()->addDockWidget(d->Area == CDockWidgetSideTab::Left ? LeftDockWidgetArea : RightDockWidgetArea, d->DockWidget); + parentContainer()->addDockWidget(d->getArea(d->Area), d->DockWidget); } cleanupAndDelete(); } @@ -338,14 +392,21 @@ void COverlayDockContainer::collapseView(bool Enable) //============================================================================ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) { - if (area == CDockWidgetSideTab::Left && !CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) - { - return false; - } - if (area == CDockWidgetSideTab::Right && !CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) - { - return false; - } + switch (area) + { + case CDockWidgetSideTab::Left: + { + return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); + } + case CDockWidgetSideTab::Right: + { + return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); + } + case CDockWidgetSideTab::Bottom: + { + return CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); + } + } return true; } diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 64129c412..6f743f66c 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -51,6 +51,7 @@ struct SideTabBarPrivate CSideTabBar* _this; CDockContainerWidget* ContainerWidget; QBoxLayout* TabsLayout; + Qt::Orientation Orientation; }; // struct SideTabBarPrivate //============================================================================ @@ -61,13 +62,14 @@ SideTabBarPrivate::SideTabBarPrivate(CSideTabBar* _public) : //============================================================================ -CSideTabBar::CSideTabBar(CDockContainerWidget* parent) : +CSideTabBar::CSideTabBar(CDockContainerWidget* parent, Qt::Orientation orientation) : QWidget(parent), d(new SideTabBarPrivate(this)) { d->ContainerWidget = parent; + d->Orientation = orientation; - d->TabsLayout = new QBoxLayout(QBoxLayout::TopToBottom); + d->TabsLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); d->TabsLayout->setContentsMargins(0, 0, 0, 0); d->TabsLayout->setSpacing(0); d->TabsLayout->addStretch(1); @@ -95,7 +97,6 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) //============================================================================ 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 index 5259203ae..ba22f49a9 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -56,7 +56,7 @@ class ADS_EXPORT CSideTabBar : public QWidget /** * Default Constructor */ - CSideTabBar(CDockContainerWidget* parent); + CSideTabBar(CDockContainerWidget* parent, Qt::Orientation orientation); /** * Virtual Destructor diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index f115a9cd8..661097e42 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -37,6 +37,11 @@ ads--CDockWidgetSideTab[sideTabBarArea="Right"] { border-bottom: 1px solid white; } +ads--CDockWidgetSideTab[sideTabBarArea="Bottom"] { + border-bottom: 3px solid grey; + border-right: 1px solid white; +} + 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)); @@ -123,6 +128,11 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="Left"] { border-left: 3px solid palette(highlight); } +ads--CDockWidgetSideTab:hover[sideTabBarArea="Bottom"] { + border-bottom: 3px solid palette(highlight); +} + + ads--CDockWidgetSideTab[sideTabBarArea="Right"][focused="true"] { border-right: 3px solid palette(highlight); } @@ -131,6 +141,10 @@ ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { border-left: 3px solid palette(highlight); } +ads--CDockWidgetSideTab[sideTabBarArea="Bottom"][focused="true"] { + border-bottom: 3px solid palette(highlight); +} + ads--CDockWidgetTab[focused="true"] { background: palette(highlight); border-color: palette(highlight); From 4841d9b89675f59cd553271b51115a6d61e5067e Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 11:20:46 +0800 Subject: [PATCH 038/236] Set splitter sizes based on proportion settable in the dock widget --- examples/autohide/mainwindow.cpp | 2 +- src/DockWidget.cpp | 13 +++++++++++++ src/DockWidget.h | 12 ++++++++++++ src/OverlayDockContainer.cpp | 27 +++++++++++++-------------- src/OverlayDockContainer.h | 16 ++++++++++++---- 5 files changed, 51 insertions(+), 19 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 1e9a448dd..ef5da7d7f 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,7 +46,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - TableDockWidget->setFeature(CDockWidget::DockWidgetDeleteOnClose, true); + TableDockWidget->setDefaultOverlayDockProportion(2); DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index a87ac04cc..1a97b03ac 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -95,6 +95,7 @@ struct DockWidgetPrivate QList TitleBarActions; CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; + int DefaultOverlayDockProportion = 4; /** * Private data constructor @@ -1133,6 +1134,18 @@ bool CDockWidget::isCurrentTab() const } +//============================================================================ +void CDockWidget::setDefaultOverlayDockProportion(int Proportion) +{ + d->DefaultOverlayDockProportion = Proportion; +} + +int CDockWidget::DefaultOverlayDockProportion() const +{ + return d->DefaultOverlayDockProportion; +} + + //============================================================================ void CDockWidget::raise() { diff --git a/src/DockWidget.h b/src/DockWidget.h index 1bcd03b38..5fa176fc2 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -511,6 +511,18 @@ private Q_SLOTS: */ bool isCurrentTab() const; + /* + * Set default dock proportion when overlayed + * 4 is a quarter of the size, 2 is half the size, 1 is the entire size + */ + void setDefaultOverlayDockProportion(int Proportion); + + /* + * Set default dock proportion when overlayed + * 4 is a quarter of the size, 2 is half the size, 1 is the entire size + */ + int DefaultOverlayDockProportion() const; + public: // reimplements QFrame ----------------------------------------------- /** * Emits titleChanged signal if title change event occurs diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 6007e5b82..b4069fa5a 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -188,6 +188,7 @@ COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, CDockWidge COverlayDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); + setDockSizeProportion(DockWidget->DefaultOverlayDockProportion()); } //============================================================================ @@ -234,34 +235,32 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) OldDockArea->removeDockWidget(DockWidget); } d->DockArea->addDockWidget(DockWidget); + d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->Area); + + updateSize(); + updateMask(); +} + - const auto dockContainerParent = parentContainer(); - const auto rootSplitter = dockContainerParent->rootSplitter(); - const auto rect = rootSplitter->frameGeometry(); - const auto dockWidth = DockWidget->sizeHint().width(); +//============================================================================ +void COverlayDockContainer::setDockSizeProportion(int SplitterProportion) +{ switch (d->Area) { case CDockWidgetSideTab::Left: { - d->Splitter->setSizes({ dockWidth, rect.width() - dockWidth }); + d->Splitter->setSizes({ INT_MAX / SplitterProportion, INT_MAX - INT_MAX / SplitterProportion }); break; } case CDockWidgetSideTab::Right: - { - d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); - break; - } + [[fallthrough]]; case CDockWidgetSideTab::Bottom: { - d->Splitter->setSizes({ rect.width() - dockWidth, dockWidth }); + d->Splitter->setSizes({ INT_MAX - INT_MAX / SplitterProportion, INT_MAX / SplitterProportion }); break; } } - d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->Area); - - updateSize(); - updateMask(); } diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index a0c8ab3b3..b723ca76e 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -49,17 +49,17 @@ class CDockingStateReader; class ADS_EXPORT COverlayDockContainer : public QFrame { - Q_OBJECT + Q_OBJECT private: - OverlayDockContainerPrivate* d; ///< private data (pimpl) - friend struct OverlayDockContainerPrivate; + OverlayDockContainerPrivate* d; ///< private data (pimpl) + friend struct OverlayDockContainerPrivate; protected: bool eventFilter(QObject* watched, QEvent* event) override; void mousePressEvent(QMouseEvent* event) override; void resizeEvent(QResizeEvent* event) override; - void updateMask(); + void updateMask(); void updateSize(); CDockContainerWidget* parentContainer() const; @@ -95,6 +95,14 @@ class ADS_EXPORT COverlayDockContainer : public QFrame */ void addDockWidget(CDockWidget* DockWidget); + /* + * Set default splitter sizes. Don't use when restoring state + * As we want the size from the XML + * Takes an int which determines the size proportion of the child dock + * E.g. 4 is a quarter of the size, 2 is half the size and 1 is the entire size of the container + */ + void setDockSizeProportion(int SplitterProportion = 4); + /** * Returns the side tab bar area of this overlay dock container */ From dfc2714d3bb5227efdc78a310f5e3327b859176d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 12:44:48 +0800 Subject: [PATCH 039/236] Fix invalid state on restore - Overlayed dock areas should not be added to the d->DockArea list - As they are not treated like normal dock areas --- src/DockContainerWidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 18c05124f..f6db6de78 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1115,7 +1115,6 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, else { DockArea->setProperty("currentDockWidget", CurrentDockWidget); - appendDockAreas({DockArea}); } return true; From b950b8a20972e7cef7066e22f2ef63344d534657 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 12:45:26 +0800 Subject: [PATCH 040/236] Fix overlayed containers able to drag into the center of the central widget --- src/FloatingDragPreview.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 4fcbb5197..616e6e250 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -121,14 +121,21 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos) } int VisibleDockAreas = TopContainer->visibleDockAreaCount(); - ContainerOverlay->setAllowedAreas( - VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas); + + // Include the overlay widget we're dragging as a visible widget + auto dockAreaWidget = qobject_cast(Content); + if (dockAreaWidget && dockAreaWidget->isOverlayed()) + { + VisibleDockAreas++; + } + + ContainerOverlay->setAllowedAreas( VisibleDockAreas > 1 ? OuterDockAreas : AllDockAreas); auto DockArea = TopContainer->dockAreaAt(GlobalPos); if (DockArea && DockArea->isVisible() && VisibleDockAreas >= 0 && DockArea != ContentSourceArea) { DockAreaOverlay->enableDropPreview(true); - DockAreaOverlay->setAllowedAreas( - (VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas()); + DockAreaOverlay->setAllowedAreas( (VisibleDockAreas == 1) ? NoDockWidgetArea : DockArea->allowedAreas()); + DockWidgetArea Area = DockAreaOverlay->showOverlay(DockArea); // A CenterDockWidgetArea for the dockAreaOverlay() indicates that From 9a69955124a7e2fe409bf19ca5510fba1e8ada48 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 13:10:29 +0800 Subject: [PATCH 041/236] Simplify logic when restoring state --- src/DockContainerWidget.cpp | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index f6db6de78..9f518285a 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1099,22 +1099,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, _this->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); DockArea->overlayDockContainer()->addDockWidget(DockWidget); DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added - DockWidget->toggleView(Closed); - } - - if (Testing) - { - return true; - } - - if (!DockArea->dockWidgetsCount()) - { - delete DockArea; - DockArea = nullptr; - } - else - { - DockArea->setProperty("currentDockWidget", CurrentDockWidget); + DockArea->overlayDockContainer()->toggleView(!Closed); } return true; @@ -1913,6 +1898,8 @@ QList CDockContainerWidget::openedDockAreas() const //============================================================================ QList CDockContainerWidget::openedDockWidgets() const { + // todo: cleanup + qInfo() << "Opened Dock Widgets: "; QList DockWidgetList; for (auto DockArea : d->DockAreas) { @@ -1922,6 +1909,12 @@ QList CDockContainerWidget::openedDockWidgets() const } } + // todo: cleanup + for (auto dockWidget : DockWidgetList) + { + qInfo() << "Opened dock widgets: " << dockWidget->objectName(); + } + return DockWidgetList; } From 263c73188a99df870c98a10db1c1a3d125cb89a8 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 14:16:12 +0800 Subject: [PATCH 042/236] Add bottom side icon config --- src/DockManager.h | 2 +- src/DockWidgetSideTab.cpp | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/DockManager.h b/src/DockManager.h index 198cdb554..3a8d740bd 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -232,7 +232,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget DockAreaHasAutoHideButton = 0x08, //!< If the flag is set each dock area has a auto hide menu button LeftSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a left side bar RightSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a right side bar - BottomSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set right side bar will prioritize showing icons only over text + BottomSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set bottom side bar will prioritize showing icons only over text DockAreaOverlayHasTitle = 0x80, //!< If the flag is set overlay dock area title bar will show the window title DefaultAutoHideConfig = DockContainerHasLeftSideBar diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index eae6717bf..c4868d785 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -304,6 +304,13 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing / 2); return; } + if (CDockManager::testConfigFlag(CDockManager::BottomSideBarPrioritizeIconOnly) && area == Bottom) + { + d->TitleLabel->hide(); + d->TitleLayout->setContentsMargins(0, 0, 0, 0); + d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); + return; + } d->TitleLabel->show(); } From daa52e109e6129416cc39eee9d7dcf363302eed7 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 14:21:01 +0800 Subject: [PATCH 043/236] Add missing update style to dock widget side tab --- src/DockWidgetSideTab.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index c4868d785..5eff15bfb 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -271,6 +271,7 @@ void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) d->Orientation = Orientation; d->Layout->setDirection(Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); d->TitleLabel->setOrientation(Orientation); + updateStyle(); } From 42498b2021a7d85bb6b250a7d19a26c6625f1432 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 14:57:24 +0800 Subject: [PATCH 044/236] Fixed some more spacing in DockWidgetSideTab --- src/DockWidgetSideTab.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 5eff15bfb..5f873839a 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -106,10 +106,10 @@ struct DockWidgetSideTabPrivate } else if (Orientation == Qt::Horizontal) { - TitleLayout->setContentsMargins(Spacing,Spacing / 2,Spacing,Spacing); + TitleLayout->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing); if (IconLabel) { - IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); + IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, 0); } } } @@ -130,23 +130,21 @@ void DockWidgetSideTabPrivate::createLayout() TitleLabel->setElideMode(Qt::ElideRight); TitleLabel->setText(DockWidget->windowTitle()); TitleLabel->setObjectName("dockWidgetTabLabel"); - //TitleLabel->setAlignment(Qt::AlignLeft); _this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool))); - QFontMetrics fm(TitleLabel->font()); - int Spacing = qRound(fm.height() / 2.0); - // Fill the layout // Purely for spacing on the text without messing up spacing on the icon TitleLayout = new QBoxLayout(QBoxLayout::TopToBottom); + TitleLayout->setAlignment(Qt::AlignCenter); TitleLayout->addWidget(TitleLabel); TitleLayout->setSpacing(0); Layout = new QBoxLayout(QBoxLayout::TopToBottom); + Layout->setAlignment(Qt::AlignCenter); Layout->setContentsMargins(0,0,0,0); Layout->setSpacing(0); _this->setLayout(Layout); - Layout->addLayout(TitleLayout, 1); + Layout->addLayout(TitleLayout); updateContentsMargins(); @@ -342,7 +340,7 @@ SideTabIconLabel::SideTabIconLabel(QWidget* parent) : QWidget(parent), { d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); d->Layout->addWidget(d->IconLabel = new QLabel()); - d->IconLabel->setAlignment(Qt::AlignHCenter); + d->Layout->setAlignment(Qt::AlignCenter); d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); setLayout(d->Layout); } From 8ddabc4cc83a11d4e29b97c3755834cd2c15ed24 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 16:02:14 +0800 Subject: [PATCH 045/236] Fix docking behavior when there is a central widget --- src/DockAreaWidget.cpp | 16 ++++++++++++++++ src/DockAreaWidget.h | 7 ++++++- src/DockContainerWidget.cpp | 8 -------- src/OverlayDockContainer.cpp | 2 +- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 598ac78d0..526e7ee74 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1129,6 +1129,22 @@ bool CDockAreaWidget::isCentralWidgetArea() const } +//============================================================================ +bool CDockAreaWidget::containsCentralWidget() const +{ + auto centralWidget = dockManager()->centralWidget(); + for (const auto &dockWidget : dockWidgets()) + { + if (dockWidget == centralWidget) + { + return true; + } + } + + return false; +} + + //============================================================================ QSize CDockAreaWidget::minimumSizeHint() const { diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index f94fc3417..9e265545d 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -358,10 +358,15 @@ protected Q_SLOTS: void setDockAreaFlag(eDockAreaFlag Flag, bool On); /** - * Returns true if the area contains the central widget of it's manager. + * Returns true if the area has a single dock widget and contains the central widget of it's manager. */ bool isCentralWidgetArea() const; + /** + * Returns true if the area contains the central widget of it's manager. + */ + bool containsCentralWidget() const; + public Q_SLOTS: /** * This activates the tab for the given tab index. diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 9f518285a..bcf53bd83 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1898,8 +1898,6 @@ QList CDockContainerWidget::openedDockAreas() const //============================================================================ QList CDockContainerWidget::openedDockWidgets() const { - // todo: cleanup - qInfo() << "Opened Dock Widgets: "; QList DockWidgetList; for (auto DockArea : d->DockAreas) { @@ -1909,12 +1907,6 @@ QList CDockContainerWidget::openedDockWidgets() const } } - // todo: cleanup - for (auto dockWidget : DockWidgetList) - { - qInfo() << "Opened dock widgets: " << dockWidget->objectName(); - } - return DockWidgetList; } diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index b4069fa5a..ebb72d9ef 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -282,7 +282,7 @@ void COverlayDockContainer::moveContentsToParent() const auto position = mapToGlobal(d->Area == CDockWidgetSideTab::Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2)); const auto dockAreaWidget = parentContainer()->dockAreaAt(position); - if (dockAreaWidget != nullptr && !dockAreaWidget->isCentralWidgetArea()) + if (dockAreaWidget != nullptr && !dockAreaWidget->containsCentralWidget()) { parentContainer()->addDockWidget(CenterDockWidgetArea, d->DockWidget, dockAreaWidget); } From 19192541f9cecd0deefe583958c741783a526723 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 16:19:11 +0800 Subject: [PATCH 046/236] Fix central dock widget being pinnable - Add config for dock widget being pinnable --- src/DockAreaTitleBar.cpp | 5 ++++- src/DockAreaWidget.cpp | 2 ++ src/DockManager.cpp | 1 + src/DockWidget.h | 3 ++- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index df2c66a43..34ef197c5 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -488,7 +488,10 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked(bool Checked) { - d->DockArea->toggleAutoHideArea(Checked); + if (d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)) + { + d->DockArea->toggleAutoHideArea(Checked); + } } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 526e7ee74..d8e95add3 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -363,6 +363,8 @@ void DockAreaWidgetPrivate::updateTitleBarButtonStates() _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; } diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 1b0c5da17..843402b3e 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -1065,6 +1065,7 @@ CDockAreaWidget* CDockManager::setCentralWidget(CDockWidget* widget) widget->setFeature(CDockWidget::DockWidgetClosable, false); widget->setFeature(CDockWidget::DockWidgetMovable, false); widget->setFeature(CDockWidget::DockWidgetFloatable, false); + widget->setFeature(CDockWidget::DockWidgetPinnable, false); d->CentralWidget = widget; CDockAreaWidget* CentralArea = addDockWidget(CenterDockWidgetArea, widget); CentralArea->setDockAreaFlag(CDockAreaWidget::eDockAreaFlag::HideSingleWidgetTitleBar, true); diff --git a/src/DockWidget.h b/src/DockWidget.h index 5fa176fc2..373f06894 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -159,7 +159,8 @@ private Q_SLOTS: DockWidgetForceCloseWithArea = 0x040, ///< dock widget will be closed when the dock area hosting it is closed NoTab = 0x080, ///< dock widget tab will never be shown if this flag is set DeleteContentOnClose = 0x100, ///< deletes only the contained widget on close, keeping the dock widget intact and in place. Attempts to rebuild the contents widget on show if there is a widget factory set. - DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable, + DockWidgetPinnable = 0x200, ///< dock widget can be pinned and added to an overlay widget + DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable | DockWidgetPinnable, AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling, DockWidgetAlwaysCloseAndDelete = DockWidgetForceCloseWithArea | DockWidgetDeleteOnClose, NoDockWidgetFeatures = 0x000 From d394930d742306253706402469b9e2956b9e86fc Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 16:29:39 +0800 Subject: [PATCH 047/236] Change splitter proportion from int to double - Allows for fine grain control (can now set 0.75 or 0.6) - Makes more sense --- src/DockWidget.cpp | 8 +++++--- src/DockWidget.h | 8 ++++---- src/OverlayDockContainer.cpp | 14 +++++++++++--- src/OverlayDockContainer.h | 6 +++--- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 1a97b03ac..f633e27ed 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -95,7 +95,7 @@ struct DockWidgetPrivate QList TitleBarActions; CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; - int DefaultOverlayDockProportion = 4; + double DefaultOverlayDockProportion = 0.25; /** * Private data constructor @@ -1135,12 +1135,14 @@ bool CDockWidget::isCurrentTab() const //============================================================================ -void CDockWidget::setDefaultOverlayDockProportion(int Proportion) +void CDockWidget::setDefaultOverlayDockProportion(double Proportion) { d->DefaultOverlayDockProportion = Proportion; } -int CDockWidget::DefaultOverlayDockProportion() const + +//============================================================================ +double CDockWidget::DefaultOverlayDockProportion() const { return d->DefaultOverlayDockProportion; } diff --git a/src/DockWidget.h b/src/DockWidget.h index 373f06894..da0000c90 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -514,15 +514,15 @@ private Q_SLOTS: /* * Set default dock proportion when overlayed - * 4 is a quarter of the size, 2 is half the size, 1 is the entire size + * see *DefaultOverlayDockProportion() */ - void setDefaultOverlayDockProportion(int Proportion); + void setDefaultOverlayDockProportion(double Proportion); /* * Set default dock proportion when overlayed - * 4 is a quarter of the size, 2 is half the size, 1 is the entire size + * 0.25 is a quarter of the size, 0.5 is half the size, 1 is the entire size */ - int DefaultOverlayDockProportion() const; + double DefaultOverlayDockProportion() const; public: // reimplements QFrame ----------------------------------------------- /** diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index ebb72d9ef..1aca25e10 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -243,20 +243,28 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -void COverlayDockContainer::setDockSizeProportion(int SplitterProportion) +void COverlayDockContainer::setDockSizeProportion(double SplitterProportion) { + if (SplitterProportion < 0 || SplitterProportion > 1) + { + ADS_PRINT("SplitterProportion must be set between 0 and 1."); + return; + } + + const auto dockSize = static_cast(static_cast(INT_MAX) * SplitterProportion); + const auto remainingSize = INT_MAX - dockSize; switch (d->Area) { case CDockWidgetSideTab::Left: { - d->Splitter->setSizes({ INT_MAX / SplitterProportion, INT_MAX - INT_MAX / SplitterProportion }); + d->Splitter->setSizes({ dockSize, remainingSize }); break; } case CDockWidgetSideTab::Right: [[fallthrough]]; case CDockWidgetSideTab::Bottom: { - d->Splitter->setSizes({ INT_MAX - INT_MAX / SplitterProportion, INT_MAX / SplitterProportion }); + d->Splitter->setSizes({ remainingSize, dockSize }); break; } } diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index b723ca76e..175a1b891 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -98,10 +98,10 @@ class ADS_EXPORT COverlayDockContainer : public QFrame /* * Set default splitter sizes. Don't use when restoring state * As we want the size from the XML - * Takes an int which determines the size proportion of the child dock - * E.g. 4 is a quarter of the size, 2 is half the size and 1 is the entire size of the container + * Takes a float between 0 and 1 + * E.g. 0.25 is a quarter of the size, 0.5 is half the size and 1 is the entire size of the container */ - void setDockSizeProportion(int SplitterProportion = 4); + void setDockSizeProportion(double SplitterProportion = 0.25); /** * Returns the side tab bar area of this overlay dock container From f0f3caeb326f1598b6347422230b6ff2f502d5a6 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 16:51:15 +0800 Subject: [PATCH 048/236] tweak spacing --- src/DockWidgetSideTab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 5f873839a..4c07dea92 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -109,7 +109,7 @@ struct DockWidgetSideTabPrivate TitleLayout->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing); if (IconLabel) { - IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, 0); + IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, Spacing / 2); } } } From ac311d6d450dab89499bc87cca9b2dc2efa11f2a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 17:26:00 +0800 Subject: [PATCH 049/236] Fix moving content to parent on toggle view --- src/DockWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index f633e27ed..a828dc8de 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -195,7 +195,7 @@ void DockWidgetPrivate::showDockWidget() } // If this widget is pinned and there are no opened dock widgets, unpin the overlay widget by moving it's contents to parent container - if (Container->openedDockWidgets().count() == 0 && DockArea->isOverlayed()) + if (Container->openedDockWidgets().count() == 0 && DockArea->isOverlayed() && !DockManager->isRestoringState()) { DockArea->overlayDockContainer()->moveContentsToParent(); } From 0e5329fd3e37d4087a06ee37499b685f3dfa402d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 13 Sep 2022 17:27:13 +0800 Subject: [PATCH 050/236] add comment --- src/DockWidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index a828dc8de..c990209eb 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -195,6 +195,7 @@ void DockWidgetPrivate::showDockWidget() } // If this widget is pinned and there are no opened dock widgets, unpin the overlay widget by moving it's contents to parent container + // While restoring state, opened dock widgets are not valid if (Container->openedDockWidgets().count() == 0 && DockArea->isOverlayed() && !DockManager->isRestoringState()) { DockArea->overlayDockContainer()->moveContentsToParent(); From ee97b03e5336a085f6c868800a79b124f606fc76 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 12:16:36 +0800 Subject: [PATCH 051/236] Fix crash when restoring state - when restoring state, the old dock widgets would remove themselves from their old dock areas and add themselves to the new dock areas. The old dock areas that are empty would then delete themselves. - That is a problem when the old overlay dock container would still try to access the old dock areas, not knowing their deleted, causing a crash. --- src/DockContainerWidget.cpp | 1 + src/OverlayDockContainer.cpp | 34 ++++++++++++++++++++++++++++++---- src/OverlayDockContainer.h | 6 ++++++ 3 files changed, 37 insertions(+), 4 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index bcf53bd83..77f2d090b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1666,6 +1666,7 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); dumpLayout(); d->emitDockAreasRemoved(); + area->overlayDockContainer()->clearDockArea(); area->setOverlayDockContainer(nullptr); area->updateAutoHideButtonCheckState(); area->updateTitleBarButtonToolTip(); diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 1aca25e10..cec961d3d 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -158,6 +158,11 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid //============================================================================ void COverlayDockContainer::updateMask() { + if (d->DockArea == nullptr) + { + return; + } + const auto rect = d->DockArea->frameGeometry(); const auto topLeft = rect.topLeft(); const auto handleSize = d->Splitter->handleWidth(); @@ -222,6 +227,8 @@ CDockWidget* COverlayDockContainer::dockWidget() const //============================================================================ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) { + Q_ASSERT_X(d->DockArea != nullptr, "COverlayDockContainer::addDockWidget", "You should not be using the overlay dock container after the dock area is set to nullptr."); + if (d->DockWidget) { // Remove the old dock widget at this area @@ -384,14 +391,26 @@ void COverlayDockContainer::collapseView(bool Enable) if (Enable) { hide(); - d->DockArea->hide(); - d->DockWidget->hide(); + if (d->DockArea) + { + d->DockArea->hide(); + } + if (d->DockWidget) + { + d->DockWidget->hide(); + } } else { show(); - d->DockArea->show(); - d->DockWidget->show(); + if (d->DockArea) + { + d->DockArea->show(); + } + if (d->DockWidget) + { + d->DockWidget->show(); + } } } @@ -419,6 +438,13 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre } +//============================================================================ +void COverlayDockContainer::clearDockArea() +{ + d->DockArea = nullptr; +} + + //============================================================================ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) { diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index 175a1b891..e9d9fa950 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -150,6 +150,12 @@ class ADS_EXPORT COverlayDockContainer : public QFrame * Convenience function fr determining if area exists in config */ static bool areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area); + + /** + * Sets internal DockArea to nullptr + * Called when removing the dock area from this overlay widget + */ + void clearDockArea(); }; } From 6b85b2b505839688d0ecb49b272913cb800f5fbc Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 12:32:32 +0800 Subject: [PATCH 052/236] Revert "Fix crash when restoring state" This reverts commit ee97b03e5336a085f6c868800a79b124f606fc76. --- src/DockContainerWidget.cpp | 1 - src/OverlayDockContainer.cpp | 34 ++++------------------------------ src/OverlayDockContainer.h | 6 ------ 3 files changed, 4 insertions(+), 37 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 77f2d090b..bcf53bd83 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1666,7 +1666,6 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); dumpLayout(); d->emitDockAreasRemoved(); - area->overlayDockContainer()->clearDockArea(); area->setOverlayDockContainer(nullptr); area->updateAutoHideButtonCheckState(); area->updateTitleBarButtonToolTip(); diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index cec961d3d..1aca25e10 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -158,11 +158,6 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid //============================================================================ void COverlayDockContainer::updateMask() { - if (d->DockArea == nullptr) - { - return; - } - const auto rect = d->DockArea->frameGeometry(); const auto topLeft = rect.topLeft(); const auto handleSize = d->Splitter->handleWidth(); @@ -227,8 +222,6 @@ CDockWidget* COverlayDockContainer::dockWidget() const //============================================================================ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) { - Q_ASSERT_X(d->DockArea != nullptr, "COverlayDockContainer::addDockWidget", "You should not be using the overlay dock container after the dock area is set to nullptr."); - if (d->DockWidget) { // Remove the old dock widget at this area @@ -391,26 +384,14 @@ void COverlayDockContainer::collapseView(bool Enable) if (Enable) { hide(); - if (d->DockArea) - { - d->DockArea->hide(); - } - if (d->DockWidget) - { - d->DockWidget->hide(); - } + d->DockArea->hide(); + d->DockWidget->hide(); } else { show(); - if (d->DockArea) - { - d->DockArea->show(); - } - if (d->DockWidget) - { - d->DockWidget->show(); - } + d->DockArea->show(); + d->DockWidget->show(); } } @@ -438,13 +419,6 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre } -//============================================================================ -void COverlayDockContainer::clearDockArea() -{ - d->DockArea = nullptr; -} - - //============================================================================ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) { diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index e9d9fa950..175a1b891 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -150,12 +150,6 @@ class ADS_EXPORT COverlayDockContainer : public QFrame * Convenience function fr determining if area exists in config */ static bool areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area); - - /** - * Sets internal DockArea to nullptr - * Called when removing the dock area from this overlay widget - */ - void clearDockArea(); }; } From 773f186a7fde4c6a4db67e9ca7f691461d2bf763 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 12:34:13 +0800 Subject: [PATCH 053/236] Fix crash when restoring state but better - Rather than having to check for nullptr, just make sure the slot isn't called --- src/OverlayDockContainer.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 1aca25e10..c46dc61fd 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -196,9 +196,6 @@ COverlayDockContainer::~COverlayDockContainer() { ADS_PRINT("~COverlayDockContainer"); - // Remove event filter in case there are any queued messages - parent()->removeEventFilter(this); - if (d->DockManager) { parentContainer()->removeOverlayWidget(this); @@ -312,6 +309,10 @@ void COverlayDockContainer::cleanupAndDelete() dockWidget->sideTabWidget()->setParent(dockWidget); dockWidget->sideTabWidget()->hide(); } + + // Remove event filter in case there are any queued messages + parent()->removeEventFilter(this); + hide(); deleteLater(); } From 8e5e97466997ec9e48cf8b2216a9ee9ae0d2f20a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 12:39:18 +0800 Subject: [PATCH 054/236] Remove event filter from dock area as well --- src/OverlayDockContainer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index c46dc61fd..6f38b7df7 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -311,6 +311,7 @@ void COverlayDockContainer::cleanupAndDelete() } // Remove event filter in case there are any queued messages + d->DockArea->removeEventFilter(this); parent()->removeEventFilter(this); hide(); From f3305b95d236499a0adb83604c9ff4cf7afe31d2 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 13:10:06 +0800 Subject: [PATCH 055/236] Remove old crash fix --- src/DockAreaWidget.cpp | 2 +- src/OverlayDockContainer.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index d8e95add3..127d9ca21 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -515,7 +515,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { setCurrentDockWidget(NextOpenDockWidget); } - else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1) + else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1 && !isOverlayed()) // Don't remove empty dock areas that are overlayed, they'll be deleted by the overlay dock { ADS_PRINT("Dock Area empty"); DockContainer->removeDockArea(this); diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 6f38b7df7..e78e2b000 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -196,6 +196,10 @@ COverlayDockContainer::~COverlayDockContainer() { ADS_PRINT("~COverlayDockContainer"); + // Remove event filter in case there are any queued messages + d->DockArea->removeEventFilter(this); + parent()->removeEventFilter(this); + if (d->DockManager) { parentContainer()->removeOverlayWidget(this); @@ -310,10 +314,6 @@ void COverlayDockContainer::cleanupAndDelete() dockWidget->sideTabWidget()->hide(); } - // Remove event filter in case there are any queued messages - d->DockArea->removeEventFilter(this); - parent()->removeEventFilter(this); - hide(); deleteLater(); } From 48163d2679344624223a99fa2fb41424466e342d Mon Sep 17 00:00:00 2001 From: Nick D'Ademo Date: Wed, 14 Sep 2022 14:17:28 +0800 Subject: [PATCH 056/236] add paintEvent override for styling purposes. --- src/SideTabBar.cpp | 11 +++++++++++ src/SideTabBar.h | 3 +++ 2 files changed, 14 insertions(+) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 6f743f66c..da18456ed 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -35,6 +35,8 @@ #include "DockWidgetTab.h" #include +#include +#include namespace ads { @@ -99,4 +101,13 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { d->TabsLayout->removeWidget(SideTab); } + +//============================================================================ +void CSideTabBar::paintEvent(QPaintEvent* event) +{ + QStyleOption option; + option.initFrom(this); + QPainter painter(this); + style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this); +} } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index ba22f49a9..5e442b908 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -50,6 +50,9 @@ class ADS_EXPORT CSideTabBar : public QWidget friend struct SideTabBarPrivate; friend class DockWidgetSideTab; +protected: + void paintEvent(QPaintEvent* event) override; + public: using Super = QWidget; From 5df24675921923ef0b0bd224caf6559298637f43 Mon Sep 17 00:00:00 2001 From: Nick D'Ademo Date: Wed, 14 Sep 2022 14:25:11 +0800 Subject: [PATCH 057/236] add orientation prop to SideTabBar. --- src/SideTabBar.cpp | 8 ++++++++ src/SideTabBar.h | 10 +++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index da18456ed..08cb111ba 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -102,6 +102,7 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) d->TabsLayout->removeWidget(SideTab); } + //============================================================================ void CSideTabBar::paintEvent(QPaintEvent* event) { @@ -110,4 +111,11 @@ void CSideTabBar::paintEvent(QPaintEvent* event) QPainter painter(this); style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this); } + + +//============================================================================ +Qt::Orientation CSideTabBar::orientation() const +{ + return d->Orientation; +} } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 5e442b908..9575d531c 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -45,6 +45,9 @@ class CDockWidgetTab; class ADS_EXPORT CSideTabBar : public QWidget { Q_OBJECT + + Q_PROPERTY(Qt::Orientation orientation READ orientation) + private: SideTabBarPrivate* d; ///< private data (pimpl) friend struct SideTabBarPrivate; @@ -52,7 +55,7 @@ class ADS_EXPORT CSideTabBar : public QWidget protected: void paintEvent(QPaintEvent* event) override; - + public: using Super = QWidget; @@ -76,6 +79,11 @@ class ADS_EXPORT CSideTabBar : public QWidget */ void removeSideTab(CDockWidgetSideTab* SideTab); + /** + * Returns orientation of side tab. + */ + Qt::Orientation orientation() const; + Q_SIGNALS: void sideTabAutoHideToggleRequested(); }; From 06bcf2cd48eb918ee2d04001c5b8659957438ffe Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 15:52:34 +0800 Subject: [PATCH 058/236] Add insert order for overlayed widget to the side tab bar - Set the default insert order to append --- src/DockAreaWidget.cpp | 2 +- src/DockContainerWidget.cpp | 6 +++--- src/DockContainerWidget.h | 4 +--- src/DockManager.cpp | 8 ++++---- src/DockManager.h | 4 ++-- src/DockWidget.cpp | 13 +++++++++++++ src/DockWidget.h | 21 +++++++++++++++++++++ src/SideTabBar.cpp | 9 +++++++-- 8 files changed, 52 insertions(+), 15 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 127d9ca21..e8243b635 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1097,7 +1097,7 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En { if (Enable) { - dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget); + dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget, DockWidget->overlayInsertOrder()); } else { diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index bcf53bd83..dbb9a66bb 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1485,7 +1485,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget) +COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder) { if (d->DockManager != DockWidget->dockManager()) { @@ -1498,7 +1498,7 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla return nullptr; } - sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); + sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); @@ -1800,7 +1800,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto overlayWidgets = FloatingWidget->dockContainer()->overlayWidgets(); for (const auto overlayWidget : overlayWidgets) { - createAndInitializeDockWidgetOverlayContainer(overlayWidget->sideTabBarArea(), overlayWidget->dockWidget()); + createAndInitializeDockWidgetOverlayContainer(overlayWidget->sideTabBarArea(), overlayWidget->dockWidget(), overlayWidget->dockWidget()->overlayInsertOrder()); } if (DockArea) diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index ea3d55ab6..269f784ea 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -95,13 +95,12 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ QSplitter* rootSplitter() const; - /** * Creates and initializes a dockwidget overlay container into the given area. * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget); + COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder); /** * Helper function for creation of the root splitter @@ -198,7 +197,6 @@ class ADS_EXPORT CDockContainerWidget : public QFrame public: - /** * Default Constructor */ diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 843402b3e..b29f1a658 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -864,16 +864,16 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget) +COverlayDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder) { - return addOverlayDockWidgetToContainer(area, Dockwidget, this); + return addOverlayDockWidgetToContainer(area, Dockwidget, this, insertOrder); } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget) +COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder insertOrder) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); - auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget); + auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget, insertOrder); container->collapseView(true); Q_EMIT dockWidgetAdded(Dockwidget); diff --git a/src/DockManager.h b/src/DockManager.h index 3a8d740bd..7f42d87cc 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -341,14 +341,14 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget); + COverlayDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder = CDockWidget::Last); /** * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); + COverlayDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder = CDockWidget::Last); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index c990209eb..05d0335b4 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -96,6 +96,7 @@ struct DockWidgetPrivate CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; double DefaultOverlayDockProportion = 0.25; + CDockWidget::eOverlayInsertOrder OverlayInsertOrder = CDockWidget::Last; /** * Private data constructor @@ -1149,6 +1150,18 @@ double CDockWidget::DefaultOverlayDockProportion() const } +//============================================================================ +void CDockWidget::setOverlayInsertOrder(eOverlayInsertOrder insertOrder) +{ + d->OverlayInsertOrder = insertOrder; +} + +CDockWidget::eOverlayInsertOrder CDockWidget::overlayInsertOrder() const +{ + return d->OverlayInsertOrder; +} + + //============================================================================ void CDockWidget::raise() { diff --git a/src/DockWidget.h b/src/DockWidget.h index da0000c90..f63cf3c62 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -229,6 +229,17 @@ private Q_SLOTS: ActionModeShow //!< ActionModeShow }; + /** + * This mode configures the order of pinning and unpinning overlayed widgets + * First will add it to the top of the SideTabBar, while last will append it to the end + */ + enum eOverlayInsertOrder + { + First, + Last + }; + + /** * This constructor creates a dock widget with the given title. @@ -524,6 +535,16 @@ private Q_SLOTS: */ double DefaultOverlayDockProportion() const; + /* + * Set overlay insertion mode + */ + void setOverlayInsertOrder(eOverlayInsertOrder insertOrder); + + /* + * Get overlay insertion mode + */ + eOverlayInsertOrder overlayInsertOrder() const; + public: // reimplements QFrame ----------------------------------------------- /** * Emits titleChanged signal if title change event occurs diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 08cb111ba..bbc1b5bb7 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -71,12 +71,17 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, Qt::Orientation orientati d->ContainerWidget = parent; d->Orientation = orientation; + auto mainLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); + d->TabsLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); d->TabsLayout->setContentsMargins(0, 0, 0, 0); d->TabsLayout->setSpacing(0); - d->TabsLayout->addStretch(1); - setLayout(d->TabsLayout); + mainLayout->addLayout(d->TabsLayout); + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + mainLayout->addStretch(1); + setLayout(mainLayout); setFocusPolicy(Qt::NoFocus); } From 4d3328e468edb25189aa0c8f7ada46ea29e2f059 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 14 Sep 2022 17:39:57 +0800 Subject: [PATCH 059/236] Fix side tab widget ordering Now is fixed based on the side tab widget --- src/DockContainerWidget.cpp | 19 ++++++++++++------- src/DockWidgetSideTab.cpp | 7 +++++++ src/DockWidgetSideTab.h | 6 ++++++ src/SideTabBar.cpp | 14 ++++++++++++++ src/SideTabBar.h | 10 ++++++++++ 5 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index dbb9a66bb..32de11518 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -899,14 +899,19 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge void DockContainerWidgetPrivate::saveOverlayWidgetsState(QXmlStreamWriter& Stream) { - for (const auto dockAreaWidget : _this->findChildren()) + for (const auto sideTabBar : SideTabBarWidgets.values()) { - if (!dockAreaWidget->isOverlayed()) - { - continue; - } + for (auto itemIndex = 0; itemIndex < sideTabBar->tabCount(); itemIndex++) + { + const auto sideTab = sideTabBar->tabAt(itemIndex); + if (sideTab == nullptr) + { + continue; + } - dockAreaWidget->saveState(Stream); + const auto dockArea = sideTab->dockWidget()->dockAreaWidget(); + dockArea->saveState(Stream); + } } } @@ -1096,7 +1101,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, DockWidget->setClosedState(Closed); DockWidget->setProperty(internal::ClosedProperty, Closed); DockWidget->setProperty(internal::DirtyProperty, false); - _this->sideTabBar(area)->insertSideTab(0, DockWidget->sideTabWidget()); + _this->sideTabBar(area)->insertSideTab(-1, DockWidget->sideTabWidget()); DockArea->overlayDockContainer()->addDockWidget(DockWidget); DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added DockArea->overlayDockContainer()->toggleView(!Closed); diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 4c07dea92..d65c1723c 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -314,6 +314,13 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) d->TitleLabel->show(); } + +//============================================================================ +CDockWidget* CDockWidgetSideTab::dockWidget() const +{ + return d->DockWidget; +} + /** * Private data class of SideTabIcon class (pimpl) */ diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index edda9be23..73fc4c12d 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -136,6 +136,12 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ void updateOrientationAndSpacing(SideTabBarArea area); + + /** + * returns the dock widget this belongs to + */ + CDockWidget* dockWidget() const; + Q_SIGNALS: void elidedChanged(bool elided); void clicked(); diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index bbc1b5bb7..a6fb4de07 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -123,4 +123,18 @@ Qt::Orientation CSideTabBar::orientation() const { return d->Orientation; } + + +//============================================================================ +CDockWidgetSideTab* CSideTabBar::tabAt(int index) const +{ + return qobject_cast(d->TabsLayout->itemAt(index)->widget()); +} + + +//============================================================================ +int CSideTabBar::tabCount() const +{ + return d->TabsLayout->count(); +} } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 9575d531c..47d0d490a 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -84,6 +84,16 @@ class ADS_EXPORT CSideTabBar : public QWidget */ Qt::Orientation orientation() const; + /* + * get the side tab widget at position, returns nullptr if it's out of bounds + */ + CDockWidgetSideTab* tabAt(int index) const; + + /* + * Gets the count of the tab widgets + */ + int tabCount() const; + Q_SIGNALS: void sideTabAutoHideToggleRequested(); }; From 6998c0e5852e57d016298d1d701a6a9a92123bc5 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 09:43:15 +0800 Subject: [PATCH 060/236] double -> float --- src/DockWidget.cpp | 4 ++-- src/DockWidget.h | 4 ++-- src/OverlayDockContainer.cpp | 4 ++-- src/OverlayDockContainer.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 05d0335b4..5e9e2e576 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1137,14 +1137,14 @@ bool CDockWidget::isCurrentTab() const //============================================================================ -void CDockWidget::setDefaultOverlayDockProportion(double Proportion) +void CDockWidget::setDefaultOverlayDockProportion(float Proportion) { d->DefaultOverlayDockProportion = Proportion; } //============================================================================ -double CDockWidget::DefaultOverlayDockProportion() const +float CDockWidget::DefaultOverlayDockProportion() const { return d->DefaultOverlayDockProportion; } diff --git a/src/DockWidget.h b/src/DockWidget.h index f63cf3c62..08454f3b9 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -527,13 +527,13 @@ private Q_SLOTS: * Set default dock proportion when overlayed * see *DefaultOverlayDockProportion() */ - void setDefaultOverlayDockProportion(double Proportion); + void setDefaultOverlayDockProportion(float Proportion); /* * Set default dock proportion when overlayed * 0.25 is a quarter of the size, 0.5 is half the size, 1 is the entire size */ - double DefaultOverlayDockProportion() const; + float DefaultOverlayDockProportion() const; /* * Set overlay insertion mode diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index e78e2b000..1bee55dd2 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -244,7 +244,7 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -void COverlayDockContainer::setDockSizeProportion(double SplitterProportion) +void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) { if (SplitterProportion < 0 || SplitterProportion > 1) { @@ -252,7 +252,7 @@ void COverlayDockContainer::setDockSizeProportion(double SplitterProportion) return; } - const auto dockSize = static_cast(static_cast(INT_MAX) * SplitterProportion); + const auto dockSize = static_cast(static_cast(INT_MAX) * SplitterProportion); const auto remainingSize = INT_MAX - dockSize; switch (d->Area) { diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index 175a1b891..a93f8abfc 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -101,7 +101,7 @@ class ADS_EXPORT COverlayDockContainer : public QFrame * Takes a float between 0 and 1 * E.g. 0.25 is a quarter of the size, 0.5 is half the size and 1 is the entire size of the container */ - void setDockSizeProportion(double SplitterProportion = 0.25); + void setDockSizeProportion(float SplitterProportion = 0.25); /** * Returns the side tab bar area of this overlay dock container From 68e5aec91253f1e6493982648189c633d6f0631f Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 11:51:56 +0800 Subject: [PATCH 061/236] add rais --- src/OverlayDockContainer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 1bee55dd2..a661af497 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -391,6 +391,7 @@ void COverlayDockContainer::collapseView(bool Enable) } else { + raise(); show(); d->DockArea->show(); d->DockWidget->show(); From 68a3bcde08d9316c740727d40c938a80f42a1a62 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 12:15:33 +0800 Subject: [PATCH 062/236] Add assert --- src/DockContainerWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 32de11518..20950f1e2 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1471,6 +1471,8 @@ CDockContainerWidget::~CDockContainerWidget() CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget) { + Q_ASSERT_X(!DockAreaWidget->isOverlayed(), "CDockContainerWidget::addDockWidget", "Adding a dock widget to an area that is already overlayed is not supported."); + CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget(); if (OldDockArea) { From 59108ed245bcc70ee1478db03a524e3adfcba48c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 12:51:59 +0800 Subject: [PATCH 063/236] Add right bottom and left bottom --- src/DockContainerWidget.cpp | 36 ++++++++----- src/DockWidgetSideTab.cpp | 6 +-- src/DockWidgetSideTab.h | 6 ++- src/OverlayDockContainer.cpp | 75 +++++++++++++++++++++----- src/stylesheets/focus_highlighting.css | 12 ++--- 5 files changed, 96 insertions(+), 39 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 20950f1e2..1f99d28a4 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1471,8 +1471,6 @@ CDockContainerWidget::~CDockContainerWidget() CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget) { - Q_ASSERT_X(!DockAreaWidget->isOverlayed(), "CDockContainerWidget::addDockWidget", "Adding a dock widget to an area that is already overlayed is not supported."); - CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget(); if (OldDockArea) { @@ -1534,39 +1532,39 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo // Then handle left and right const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.center()); - const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::Left : CDockWidgetSideTab::Right; - if (calculatedPosition == CDockWidgetSideTab::Right) + const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::LeftTop : CDockWidgetSideTab::RightTop; + if (calculatedPosition == CDockWidgetSideTab::RightTop) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - return CDockWidgetSideTab::Right; + return CDockWidgetSideTab::RightTop; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return CDockWidgetSideTab::Left; + return CDockWidgetSideTab::LeftTop; } return CDockWidgetSideTab::Bottom; } - if (calculatedPosition == CDockWidgetSideTab::Left) + if (calculatedPosition == CDockWidgetSideTab::LeftTop) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return CDockWidgetSideTab::Left; + return CDockWidgetSideTab::LeftTop; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - return CDockWidgetSideTab::Right; + return CDockWidgetSideTab::RightTop; } return CDockWidgetSideTab::Bottom; } Q_ASSERT_X(false, "CDockContainerWidget::getDockAreaPosition", "Unhandled branch. All positions should be accounted for."); - return CDockWidgetSideTab::Left; + return CDockWidgetSideTab::LeftTop; } @@ -2046,14 +2044,24 @@ void CDockContainerWidget::createSideTabBarWidgets() { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left], 0, 0); + auto leftLayout = new QVBoxLayout(); + d->SideTabBarWidgets[CDockWidgetSideTab::LeftTop] = new CSideTabBar(this, Qt::Vertical); + leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::LeftTop]); + leftLayout->addStretch(1); + d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom] = new CSideTabBar(this, Qt::Vertical); + leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom]); + d->Layout->addLayout(leftLayout, 0, 0); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right], 0, 2); + auto rightLayout = new QVBoxLayout(); + d->SideTabBarWidgets[CDockWidgetSideTab::RightTop] = new CSideTabBar(this, Qt::Vertical); + rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::RightTop]); + rightLayout->addStretch(1); + d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom] = new CSideTabBar(this, Qt::Vertical); + rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom]); + d->Layout->addLayout(rightLayout, 0, 2); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index d65c1723c..a782ef568 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -216,7 +216,7 @@ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const return dockAreaWidget->overlayDockContainer()->sideTabBarArea(); } - return Left; + return LeftTop; } @@ -289,14 +289,14 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) QFontMetrics fm(d->TitleLabel->font()); int Spacing = qRound(fm.height() / 2.0); - if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) + if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && (area == LeftTop || area == LeftBottom)) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); return; } - if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) + if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && (area == RightTop || area == RightBottom)) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 73fc4c12d..92c0d82f6 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -77,8 +77,10 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ enum SideTabBarArea { - Left, - Right, + LeftTop, + LeftBottom, + RightTop, + RightBottom, Bottom }; diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index a661af497..43f7ebe30 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -66,11 +66,15 @@ struct OverlayDockContainerPrivate { switch (area) { - case CDockWidgetSideTab::Left: + case CDockWidgetSideTab::LeftBottom: + [[fallthrough]]; + case CDockWidgetSideTab::LeftTop: { return LeftDockWidgetArea; } - case CDockWidgetSideTab::Right: + case CDockWidgetSideTab::RightBottom: + [[fallthrough]]; + case CDockWidgetSideTab::RightTop: { return RightDockWidgetArea; } @@ -82,6 +86,34 @@ struct OverlayDockContainerPrivate return LeftDockWidgetArea; } + + /* + * Convenience function to get dock position + */ + QPoint getSimplifiedDockAreaPosition() const + { + switch (Area) + { + case CDockWidgetSideTab::LeftTop: + [[fallthrough]]; + case CDockWidgetSideTab::LeftBottom: + { + return QPoint(1, _this->height() / 2); + } + case CDockWidgetSideTab::RightTop: + [[fallthrough]]; + case CDockWidgetSideTab::RightBottom: + { + return QPoint(_this->width() - 1, _this->height() / 2); + } + case CDockWidgetSideTab::Bottom: + { + return QPoint(_this->width() / 2, _this->height() - 1); + } + } + + return QPoint(); + } }; // struct OverlayDockContainerPrivate //============================================================================ @@ -121,13 +153,17 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid switch (area) { - case CDockWidgetSideTab::Left: + case CDockWidgetSideTab::LeftBottom: + [[fallthrough]]; + case CDockWidgetSideTab::LeftTop: { d->Splitter->addWidget(d->DockArea); d->Splitter->addWidget(emptyWidget); break; } - case CDockWidgetSideTab::Right: + case CDockWidgetSideTab::RightBottom: + [[fallthrough]]; + case CDockWidgetSideTab::RightTop: { d->Splitter->addWidget(emptyWidget); d->Splitter->addWidget(d->DockArea); @@ -165,12 +201,15 @@ void COverlayDockContainer::updateMask() if (d->Area == CDockWidgetSideTab::Bottom) { setMask(QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize))); + return; } - else - { - const auto offset = d->Area == CDockWidgetSideTab::SideTabBarArea::Left ? 0 : handleSize; - setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); - } + + auto offset = 0; + if (d->Area == CDockWidgetSideTab::SideTabBarArea::RightTop || d->Area == CDockWidgetSideTab::SideTabBarArea::RightBottom) + { + offset = handleSize; + } + setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); } //============================================================================ @@ -256,12 +295,16 @@ void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) const auto remainingSize = INT_MAX - dockSize; switch (d->Area) { - case CDockWidgetSideTab::Left: + case CDockWidgetSideTab::LeftBottom: + [[fallthrough]]; + case CDockWidgetSideTab::LeftTop: { d->Splitter->setSizes({ dockSize, remainingSize }); break; } - case CDockWidgetSideTab::Right: + case CDockWidgetSideTab::RightBottom: + [[fallthrough]]; + case CDockWidgetSideTab::RightTop: [[fallthrough]]; case CDockWidgetSideTab::Bottom: { @@ -288,7 +331,7 @@ CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const //============================================================================ void COverlayDockContainer::moveContentsToParent() { - const auto position = mapToGlobal(d->Area == CDockWidgetSideTab::Left ? QPoint(1,height() / 2) : QPoint(width() - 1, height() / 2)); + const auto position = mapToGlobal(d->getSimplifiedDockAreaPosition()); const auto dockAreaWidget = parentContainer()->dockAreaAt(position); if (dockAreaWidget != nullptr && !dockAreaWidget->containsCentralWidget()) @@ -404,11 +447,15 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre { switch (area) { - case CDockWidgetSideTab::Left: + case CDockWidgetSideTab::LeftBottom: + [[fallthrough]]; + case CDockWidgetSideTab::LeftTop: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); } - case CDockWidgetSideTab::Right: + case CDockWidgetSideTab::RightBottom: + [[fallthrough]]; + case CDockWidgetSideTab::RightTop: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 661097e42..6bbf601ba 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -27,12 +27,12 @@ ads--CDockWidgetSideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab[sideTabBarArea="Left"] { +ads--CDockWidgetSideTab[sideTabBarArea="LeftTop"],[sideTabBarArea="LeftBottom"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="Right"] { +ads--CDockWidgetSideTab[sideTabBarArea="RightTop"],[sideTabBarArea="RightBottom"] { border-right: 3px solid grey; border-bottom: 1px solid white; } @@ -120,11 +120,11 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetSideTab:hover[sideTabBarArea="Right"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="RightTop"],:hover[sideTabBarArea="RightBottom"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="Left"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="LeftTop"],:hover[sideTabBarArea="LeftBottom"] { border-left: 3px solid palette(highlight); } @@ -133,11 +133,11 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="Bottom"] { } -ads--CDockWidgetSideTab[sideTabBarArea="Right"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="RightTop"][focused="true"],[sideTabBarArea="RightBottom"][focused="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="Left"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="LeftTop"][focused="true"],[sideTabBarArea="LeftBottom"][focused="true"] { border-left: 3px solid palette(highlight); } From 060313c11f6841354c8247c4e6f493d4f90d3eca Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 13:04:49 +0800 Subject: [PATCH 064/236] clear dock widget focus on repin --- src/DockContainerWidget.cpp | 2 ++ src/DockFocusController.cpp | 8 ++++++++ src/DockFocusController.h | 5 +++++ 3 files changed, 15 insertions(+) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 1f99d28a4..d984834fc 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -53,6 +53,7 @@ #include "DockWidgetTab.h" #include "DockWidgetSideTab.h" #include "DockAreaTitleBar.h" +#include "DockFocusController.h" #include #include @@ -1508,6 +1509,7 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); dockContainer->hide(); + d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); return dockContainer; } diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index d467bdb13..4310f5118 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -320,6 +320,14 @@ void CDockFocusController::setDockWidgetTabFocused(CDockWidgetTab* Tab) } +//=========================================================================== +void CDockFocusController::clearDockWidgetFocus(CDockWidget* dockWidget) +{ + dockWidget->clearFocus(); + updateDockWidgetFocusStyle(dockWidget, false); +} + + //=========================================================================== void CDockFocusController::setDockWidgetFocused(CDockWidget* focusedNow) { diff --git a/src/DockFocusController.h b/src/DockFocusController.h index b080f3bad..06ec049fc 100644 --- a/src/DockFocusController.h +++ b/src/DockFocusController.h @@ -75,6 +75,11 @@ private Q_SLOTS: */ void setDockWidgetTabFocused(CDockWidgetTab* Tab); + /* + * Request clear focus for a dock widget + */ + void clearDockWidgetFocus(CDockWidget* dockWidget); + public Q_SLOTS: /** * Request a focus change to the given dock widget From 87324846cdae5a250696bb35e857ff67c9eb691c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 15 Sep 2022 16:02:55 +0800 Subject: [PATCH 065/236] Fix side tab widget resizing strangely on first add --- src/DockContainerWidget.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index d984834fc..329eeb6c0 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1505,6 +1505,7 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla } sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); + sideTabBar(area)->show(); DockWidget->sideTabWidget()->show(); const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); @@ -1554,7 +1555,8 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return CDockWidgetSideTab::LeftTop; + // todo: cleanup - revert + return CDockWidgetSideTab::LeftBottom; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) From f69b1e1ef8e3dd723825b4f0a75c95e393e6283d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 10:49:07 +0800 Subject: [PATCH 066/236] Fix active X widgets not being rendered correctly --- src/OverlayDockContainer.cpp | 45 +++++++++++++++--------------------- src/OverlayDockContainer.h | 6 +++-- 2 files changed, 22 insertions(+), 29 deletions(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 43f7ebe30..1771fcc04 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -32,12 +32,10 @@ #include "DockWidgetSideTab.h" #include "DockWidgetTab.h" #include "SideTabBar.h" -#include "DockAreaTitleBar.h" #include "DockAreaWidget.h" #include "DockingStateReader.h" #include -#include #include #include #include @@ -51,7 +49,6 @@ struct OverlayDockContainerPrivate CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; - QSplitter* Splitter; CDockWidgetSideTab::SideTabBarArea Area; /** @@ -126,26 +123,24 @@ OverlayDockContainerPrivate::OverlayDockContainerPrivate( CDockContainerWidget* COverlayDockContainer::parentContainer() const { - return qobject_cast(parent()); + return internal::findParent(this); } //============================================================================ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : - QFrame(parent), + QSplitter(area == CDockWidgetSideTab::Bottom ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal, parent), d(new OverlayDockContainerPrivate(this)) { d->DockManager = DockManager; d->Area = area; d->DockArea = new CDockAreaWidget(DockManager, parent); - d->DockArea->setObjectName("OverlayDockArea"); + d->DockArea->setObjectName("overlayDockArea"); d->DockArea->setOverlayDockContainer(this); d->DockArea->updateAutoHideButtonCheckState(); d->DockArea->updateTitleBarButtonToolTip(); - QBoxLayout* l = new QBoxLayout(QBoxLayout::LeftToRight); - d->Splitter = new QSplitter(area == CDockWidgetSideTab::Bottom ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal); - d->Splitter->setObjectName("overlaySplitter"); - d->Splitter->setChildrenCollapsible(false); + setObjectName("overlaySplitter"); + setChildrenCollapsible(false); const auto emptyWidget = new QWidget(); emptyWidget->setMinimumWidth(50); @@ -157,31 +152,26 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { - d->Splitter->addWidget(d->DockArea); - d->Splitter->addWidget(emptyWidget); + addWidget(d->DockArea); + addWidget(emptyWidget); break; } case CDockWidgetSideTab::RightBottom: [[fallthrough]]; case CDockWidgetSideTab::RightTop: { - d->Splitter->addWidget(emptyWidget); - d->Splitter->addWidget(d->DockArea); + addWidget(emptyWidget); + addWidget(d->DockArea); break; } case CDockWidgetSideTab::Bottom: { - d->Splitter->addWidget(emptyWidget); - d->Splitter->addWidget(d->DockArea); + addWidget(emptyWidget); + addWidget(d->DockArea); break; } } - l->setContentsMargins(QMargins()); - l->setSpacing(0); - l->addWidget(d->Splitter); - setLayout(l); - updateMask(); updateSize(); @@ -196,7 +186,7 @@ void COverlayDockContainer::updateMask() { const auto rect = d->DockArea->frameGeometry(); const auto topLeft = rect.topLeft(); - const auto handleSize = d->Splitter->handleWidth(); + const auto handleSize = handleWidth(); if (d->Area == CDockWidgetSideTab::Bottom) { @@ -220,6 +210,7 @@ void COverlayDockContainer::updateSize() const auto rect = rootSplitter->frameGeometry(); move(rect.topLeft()); resize(rect.width(), rect.height()); + d->DockArea->updateGeometry(); } //============================================================================ @@ -299,7 +290,7 @@ void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { - d->Splitter->setSizes({ dockSize, remainingSize }); + setSizes({ dockSize, remainingSize }); break; } case CDockWidgetSideTab::RightBottom: @@ -308,7 +299,7 @@ void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) [[fallthrough]]; case CDockWidgetSideTab::Bottom: { - d->Splitter->setSizes({ remainingSize, dockSize }); + setSizes({ remainingSize, dockSize }); break; } } @@ -367,7 +358,7 @@ void COverlayDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); QStringList Sizes; - for (auto Size : d->Splitter->sizes()) + for (auto Size : sizes()) { Sizes << QString::number(Size); } @@ -390,14 +381,14 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) Sizes.append(value); } - if (Sizes.count() != d->Splitter->count()) + if (Sizes.count() != count()) { return false; } if (!Testing) { - d->Splitter->setSizes(Sizes); + setSizes(Sizes); } return true; diff --git a/src/OverlayDockContainer.h b/src/OverlayDockContainer.h index a93f8abfc..04a1ff1fd 100644 --- a/src/OverlayDockContainer.h +++ b/src/OverlayDockContainer.h @@ -33,7 +33,7 @@ #include "DockWidgetSideTab.h" -#include +#include class QXmlStreamWriter; @@ -47,7 +47,9 @@ class CSideTabBar; class CDockAreaWidget; class CDockingStateReader; -class ADS_EXPORT COverlayDockContainer : public QFrame +// Note: This widget must be a QSplitter, inheriting from QWidget and keeping an internal splitter breaks ActiveX widgets +// likely due to layout issues between this widget and the internal splitter +class ADS_EXPORT COverlayDockContainer : public QSplitter { Q_OBJECT From ea0eac0e3817f111aed62cbc522d50c37f8d53ea Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 11:01:49 +0800 Subject: [PATCH 067/236] Fix autohide example --- examples/autohide/mainwindow.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index ef5da7d7f..179fd82f2 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,8 +46,8 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - TableDockWidget->setDefaultOverlayDockProportion(2); - DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); + TableDockWidget->setDefaultOverlayDockProportion(0.5); + DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget); + DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); From 6e143de09d752cc899dfafd0bbdd98ddf7f313ba Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 14:19:31 +0800 Subject: [PATCH 068/236] Fix side tab widgets being the wrong size when being added to a layout --- src/DockContainerWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 329eeb6c0..dcd3b7f2f 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1504,8 +1504,8 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla return nullptr; } + DockWidget->sideTabWidget()->updateOrientationAndSpacing(area); sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); - sideTabBar(area)->show(); DockWidget->sideTabWidget()->show(); const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); From 3d4d6774948793899030918086c078e68b64117b Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 14:30:07 +0800 Subject: [PATCH 069/236] Bump XML version --- src/DockManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index b29f1a658..cb32fbf1e 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -88,7 +88,8 @@ enum eStateFileVersion { InitialVersion = 0, //!< InitialVersion Version1 = 1, //!< Version1 - CurrentVersion = Version1//!< CurrentVersion + Version2 = 2, //!< Version2 - Version bump due to addition of Autohide functionality + CurrentVersion = Version2//!< CurrentVersion }; static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig; From 40dccdb5aeb55893268a7edada5c03b30008cb89 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 14:30:18 +0800 Subject: [PATCH 070/236] Remove testing code --- src/DockContainerWidget.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index dcd3b7f2f..87c13ca18 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1555,8 +1555,7 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - // todo: cleanup - revert - return CDockWidgetSideTab::LeftBottom; + return CDockWidgetSideTab::LeftTop; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) From 2bb1589ca2d9a1c0dcfa4a14e7f7bb10eab6002c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 16:02:32 +0800 Subject: [PATCH 071/236] Add missing check for bottom sidebar config --- src/DockAreaTitleBar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 34ef197c5..d50e0b64e 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -191,7 +191,7 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); // AutoHide Button - const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar); + const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar) || testConfigFlag(CDockManager::DockContainerHasBottomSideBar); AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); From c850e3602544e4b7d0baf99cbf686542f03c6f12 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 16:33:45 +0800 Subject: [PATCH 072/236] Update css for qt-5 --- src/stylesheets/focus_highlighting.css | 27 +++++++++++++------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 6bbf601ba..672783cc4 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -27,17 +27,17 @@ ads--CDockWidgetSideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab[sideTabBarArea="LeftTop"],[sideTabBarArea="LeftBottom"] { +ads--CDockWidgetSideTab[sideTabBarArea="0"],[sideTabBarArea="1"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="RightTop"],[sideTabBarArea="RightBottom"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"],[sideTabBarArea="3"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="Bottom"] { +ads--CDockWidgetSideTab[sideTabBarArea="4"] { border-bottom: 3px solid grey; border-right: 1px solid white; } @@ -120,28 +120,27 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetSideTab:hover[sideTabBarArea="RightTop"],:hover[sideTabBarArea="RightBottom"] { - border-right: 3px solid palette(highlight); +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"],:hover[sideTabBarArea="1"] { + border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="LeftTop"],:hover[sideTabBarArea="LeftBottom"] { - border-left: 3px solid palette(highlight); +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"],:hover[sideTabBarArea="3"] { + border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="Bottom"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="4"] { border-bottom: 3px solid palette(highlight); } - -ads--CDockWidgetSideTab[sideTabBarArea="RightTop"][focused="true"],[sideTabBarArea="RightBottom"][focused="true"] { - border-right: 3px solid palette(highlight); +ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"],[sideTabBarArea="1"][focused="true"] { + border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="LeftTop"][focused="true"],[sideTabBarArea="LeftBottom"][focused="true"] { - border-left: 3px solid palette(highlight); +ads--CDockWidgetSideTab[sideTabBarArea="2"][focused="true"],[sideTabBarArea="3"][focused="true"] { + border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="Bottom"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="4"][focused="true"] { border-bottom: 3px solid palette(highlight); } From b567f6c5d278b871236f777d3dd7395f18ed6876 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 16:34:21 +0800 Subject: [PATCH 073/236] Add documentation --- doc/autohide-feature-demo.png | Bin 0 -> 13222 bytes doc/user-guide.md | 51 ++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 doc/autohide-feature-demo.png diff --git a/doc/autohide-feature-demo.png b/doc/autohide-feature-demo.png new file mode 100644 index 0000000000000000000000000000000000000000..9e7eff7040efdfe3f113c36e39075b8815133b83 GIT binary patch literal 13222 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 V2vwZ0SOjDockManager = new CDockManager(this); +``` + +### Adding Overlay Widgets + +Adding an overlay widget is similar to adding a dock widget, simply call `dockManager->addOverlayDockWidget`. + +```c++ +d->DockManager = new CDockManager(this); +CDockWidget* TableDockWidget = new CDockWidget("Table 1"); +TableDockWidget->setDefaultOverlayDockProportion(0.5); // Default size in proportion to the window size when adding the overlay widget +DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); +``` + +See `autohide` example to learn how it works. + +### Configuration Flags For Overlay Widgets + +- `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar` -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable `DockContainerHasRightSideBar` and `DockContainerHasBottomSideBar` then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work. +- `DockAreaHasAutoHideButton` -> Adds the auto hide button to the title bar of the dock area +- `LeftSideBarPrioritizeIconOnly`, `RightSideBarPrioritizeIconOnly`, `BottomSideBarPrioritizeIconOnly` -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable `LeftSideBarPrioritizeIconOnly`, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual. +- `DockAreaOverlayHasTitle` -> Adds the title of the dock window where the title bar would be. +- `DefaultAutoHideConfig` -> Enables `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `DockAreaOverlayHasTitle` + +### Limitations + +- Currently the `LeftBottom` and `RightBottom` areas can only be added programatically, and not through the pin icon. These are used if you'd like to add a new dock widget separated from the normal dock areas. + +- Adding a `DockWidget` (e.g. via `addDockWidget`) to an overlayed `DockArea` that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be overlayed, check first if it's overlayed via `CDockArea::isOverlayed` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). + ## Styling The Advanced Docking System supports styling via [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet.html). All components like splitters, tabs, buttons, titlebar and From 32f9b4664bd3cc1889d5594145e4447b78e6087c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 19 Sep 2022 18:11:47 +0800 Subject: [PATCH 074/236] Fix weird behavior when widget is overlayed --- src/DockWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 5e9e2e576..f6e402907 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -181,7 +181,7 @@ void DockWidgetPrivate::showDockWidget() DockArea->toggleView(true); TabWidget->show(); QSplitter* Splitter = internal::findParent(DockArea); - while (Splitter && !Splitter->isVisible()) + while (Splitter && !Splitter->isVisible() && !DockArea->isOverlayed()) { Splitter->show(); Splitter = internal::findParent(Splitter); From 0e6971e2aef08fbc4e35f549d50518517ce764b2 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 20 Sep 2022 09:41:02 +0800 Subject: [PATCH 075/236] Remove [[fallthrough]] --- src/OverlayDockContainer.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 1771fcc04..26134e5ce 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -64,13 +64,11 @@ struct OverlayDockContainerPrivate switch (area) { case CDockWidgetSideTab::LeftBottom: - [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { return LeftDockWidgetArea; } case CDockWidgetSideTab::RightBottom: - [[fallthrough]]; case CDockWidgetSideTab::RightTop: { return RightDockWidgetArea; @@ -92,13 +90,11 @@ struct OverlayDockContainerPrivate switch (Area) { case CDockWidgetSideTab::LeftTop: - [[fallthrough]]; case CDockWidgetSideTab::LeftBottom: { return QPoint(1, _this->height() / 2); } case CDockWidgetSideTab::RightTop: - [[fallthrough]]; case CDockWidgetSideTab::RightBottom: { return QPoint(_this->width() - 1, _this->height() / 2); @@ -149,7 +145,6 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid switch (area) { case CDockWidgetSideTab::LeftBottom: - [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { addWidget(d->DockArea); @@ -157,7 +152,6 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid break; } case CDockWidgetSideTab::RightBottom: - [[fallthrough]]; case CDockWidgetSideTab::RightTop: { addWidget(emptyWidget); @@ -287,16 +281,13 @@ void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) switch (d->Area) { case CDockWidgetSideTab::LeftBottom: - [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { setSizes({ dockSize, remainingSize }); break; } case CDockWidgetSideTab::RightBottom: - [[fallthrough]]; case CDockWidgetSideTab::RightTop: - [[fallthrough]]; case CDockWidgetSideTab::Bottom: { setSizes({ remainingSize, dockSize }); @@ -439,13 +430,11 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre switch (area) { case CDockWidgetSideTab::LeftBottom: - [[fallthrough]]; case CDockWidgetSideTab::LeftTop: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); } case CDockWidgetSideTab::RightBottom: - [[fallthrough]]; case CDockWidgetSideTab::RightTop: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); From 8ac8d63b96966d9834b82031c23967f55c912579 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 20 Sep 2022 14:47:28 +0800 Subject: [PATCH 076/236] Ensure that the closed state is consistent --- src/DockAreaWidget.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index e8243b635..f0b036a93 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -485,6 +485,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, 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); @@ -641,6 +642,7 @@ void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget) } setCurrentIndex(Index); + DockWidget->setClosedState(false); // Set current index can show the widget without changing the close state, added to keep the close state consistent } From 7f6fa0c96c9008045f23d706393c499f0d91824d Mon Sep 17 00:00:00 2001 From: syarif fakhri Date: Thu, 22 Sep 2022 09:53:14 +0800 Subject: [PATCH 077/236] Fix linux styling --- src/stylesheets/focus_highlighting_linux.css | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 6f5b42a5b..594ce6b4b 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -44,6 +44,26 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +ads--CDockWidgetSideTab { + background: palette(window); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"],[sideTabBarArea="1"] { + border-left: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="2"],[sideTabBarArea="3"] { + border-right: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="4"] { + border-bottom: 3px solid grey; + border-right: 1px solid white; +} + ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -104,6 +124,30 @@ QScrollArea#dockWidgetScrollArea { /* Focus related styling */ +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"],:hover[sideTabBarArea="1"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"],:hover[sideTabBarArea="3"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="4"] { + border-bottom: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"],[sideTabBarArea="1"][focused="true"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="2"][focused="true"],[sideTabBarArea="3"][focused="true"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="4"][focused="true"] { + border-bottom: 3px solid palette(highlight); +} + ads--CDockWidgetTab[focused="true"] { background: palette(highlight); border-color: palette(highlight); From 880a7f13b57241efc317921be8f91b83d305df1a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 22 Sep 2022 10:40:11 +0800 Subject: [PATCH 078/236] add config flag in ads demo --- demo/MainWindow.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 6d8d0c950..496313d50 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -652,6 +652,9 @@ CMainWindow::CMainWindow(QWidget *parent) : // widget that has the focus CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + // uncomment if you would like to enable dock widget auto hiding + // CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); + // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets // CDockManager::setConfigFlag(CDockManager::EqualSplitOnInsertion, true); From 3cd0265df64b82c08faaf5c9e4a9b118206bb419 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 3 Oct 2022 17:29:56 +0800 Subject: [PATCH 079/236] - Fix crash caused by not removing dock area from parent container - Fix strange behavior caused by not calling QSplitter::resizeEvent base implementation --- src/OverlayDockContainer.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 26134e5ce..799cf9f64 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -204,7 +204,6 @@ void COverlayDockContainer::updateSize() const auto rect = rootSplitter->frameGeometry(); move(rect.topLeft()); resize(rect.width(), rect.height()); - d->DockArea->updateGeometry(); } //============================================================================ @@ -313,6 +312,8 @@ CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const //============================================================================ void COverlayDockContainer::moveContentsToParent() { + cleanupAndDelete(); + const auto position = mapToGlobal(d->getSimplifiedDockAreaPosition()); const auto dockAreaWidget = parentContainer()->dockAreaAt(position); @@ -324,7 +325,8 @@ void COverlayDockContainer::moveContentsToParent() { parentContainer()->addDockWidget(d->getArea(d->Area), d->DockWidget); } - cleanupAndDelete(); + + parentContainer()->removeDockArea(d->DockArea); } @@ -457,14 +459,15 @@ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) updateSize(); updateMask(); } - return QWidget::eventFilter(watched, event); + + return QSplitter::eventFilter(watched, event); } //============================================================================ void COverlayDockContainer::mousePressEvent(QMouseEvent* event) { - QWidget::mousePressEvent(event); + QSplitter::mousePressEvent(event); } @@ -472,7 +475,7 @@ void COverlayDockContainer::mousePressEvent(QMouseEvent* event) void COverlayDockContainer::resizeEvent(QResizeEvent* event) { updateMask(); - QWidget::resizeEvent(event); + QSplitter::resizeEvent(event); } } From a74e03451fef5ef5a2f93ed75c219438cb683e62 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 3 Oct 2022 17:46:07 +0800 Subject: [PATCH 080/236] remove unused vars --- src/DockContainerWidget.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 87c13ca18..f97c92ef0 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1521,11 +1521,7 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo // It's bottom if the width is wider than the height, and if it's below 50% of the window const auto dockWidgetFrameGeometry = DockAreaWidget->frameGeometry(); const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); - const auto a = dockWidgetFrameGeometry.width(); - const auto b = dockWidgetFrameGeometry.height(); - const auto c = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y(); - const auto d = splitterCenter.y(); - const auto e = CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); + if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height() && DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) From 412f24537bd1c7bbcfcbcb32c267c22279f4dac7 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 6 Oct 2022 17:00:29 +0800 Subject: [PATCH 081/236] Dissallow non focusable dock widgets from being pinned --- src/DockAreaWidget.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index f0b036a93..bf4a714f2 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -315,6 +315,11 @@ struct DockAreaWidgetPrivate */ 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 */ @@ -382,7 +387,7 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) if (IsTopLevel) { TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating()); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating() && allDockWidgetsFocusable()); // Undock and tabs should never show when overlayed TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isOverlayed()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); @@ -390,12 +395,25 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) else { TitleBar->button(TitleBarButtonClose)->setVisible(true); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(true); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(allDockWidgetsFocusable()); TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); } } +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) : From 8fc333806aed1a6aef62547e0e6db83bf598cca9 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 12 Oct 2022 10:58:47 +0200 Subject: [PATCH 082/236] Pulled latest changes from duer autohide branch --- src/DockAreaWidget.cpp | 22 ++++++++++++++++++++-- src/DockContainerWidget.cpp | 6 +----- src/OverlayDockContainer.cpp | 13 ++++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index f0b036a93..bf4a714f2 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -315,6 +315,11 @@ struct DockAreaWidgetPrivate */ 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 */ @@ -382,7 +387,7 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) if (IsTopLevel) { TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating()); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating() && allDockWidgetsFocusable()); // Undock and tabs should never show when overlayed TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isOverlayed()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); @@ -390,12 +395,25 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) else { TitleBar->button(TitleBarButtonClose)->setVisible(true); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(true); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(allDockWidgetsFocusable()); TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isOverlayed()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); } } +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) : diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 87c13ca18..f97c92ef0 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1521,11 +1521,7 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo // It's bottom if the width is wider than the height, and if it's below 50% of the window const auto dockWidgetFrameGeometry = DockAreaWidget->frameGeometry(); const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); - const auto a = dockWidgetFrameGeometry.width(); - const auto b = dockWidgetFrameGeometry.height(); - const auto c = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y(); - const auto d = splitterCenter.y(); - const auto e = CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); + if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height() && DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) diff --git a/src/OverlayDockContainer.cpp b/src/OverlayDockContainer.cpp index 26134e5ce..799cf9f64 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/OverlayDockContainer.cpp @@ -204,7 +204,6 @@ void COverlayDockContainer::updateSize() const auto rect = rootSplitter->frameGeometry(); move(rect.topLeft()); resize(rect.width(), rect.height()); - d->DockArea->updateGeometry(); } //============================================================================ @@ -313,6 +312,8 @@ CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const //============================================================================ void COverlayDockContainer::moveContentsToParent() { + cleanupAndDelete(); + const auto position = mapToGlobal(d->getSimplifiedDockAreaPosition()); const auto dockAreaWidget = parentContainer()->dockAreaAt(position); @@ -324,7 +325,8 @@ void COverlayDockContainer::moveContentsToParent() { parentContainer()->addDockWidget(d->getArea(d->Area), d->DockWidget); } - cleanupAndDelete(); + + parentContainer()->removeDockArea(d->DockArea); } @@ -457,14 +459,15 @@ bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) updateSize(); updateMask(); } - return QWidget::eventFilter(watched, event); + + return QSplitter::eventFilter(watched, event); } //============================================================================ void COverlayDockContainer::mousePressEvent(QMouseEvent* event) { - QWidget::mousePressEvent(event); + QSplitter::mousePressEvent(event); } @@ -472,7 +475,7 @@ void COverlayDockContainer::mousePressEvent(QMouseEvent* event) void COverlayDockContainer::resizeEvent(QResizeEvent* event) { updateMask(); - QWidget::resizeEvent(event); + QSplitter::resizeEvent(event); } } From 62d3d73651c12e78f816e5490dbd5ae861ad8bf1 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 12 Oct 2022 11:17:54 +0200 Subject: [PATCH 083/236] Made Auto Hide Feature independent from Focus Feature and renamed OverlayDockContainer to AutoHideDockContainer --- demo/MainWindow.cpp | 2 +- ...ontainer.cpp => AutoHideDockContainer.cpp} | 136 +++++++++++++----- ...ockContainer.h => AutoHideDockContainer.h} | 20 +-- src/CMakeLists.txt | 4 +- src/DockAreaTitleBar.cpp | 2 +- src/DockAreaWidget.cpp | 8 +- src/DockAreaWidget.h | 6 +- src/DockContainerWidget.cpp | 20 +-- src/DockContainerWidget.h | 12 +- src/DockFocusController.cpp | 8 +- src/DockManager.cpp | 6 +- src/DockManager.h | 6 +- src/DockWidget.cpp | 11 +- src/DockWidget.h | 6 +- src/DockWidgetSideTab.cpp | 2 +- src/DockWidgetSideTab.h | 2 +- src/DockWidgetTab.cpp | 2 +- src/DockWidgetTab.h | 2 +- src/ElidingLabel.cpp | 4 + src/FloatingDragPreview.cpp | 6 +- src/SideTabBar.cpp | 2 + src/src.pro | 4 +- 22 files changed, 170 insertions(+), 101 deletions(-) rename src/{OverlayDockContainer.cpp => AutoHideDockContainer.cpp} (75%) rename src/{OverlayDockContainer.h => AutoHideDockContainer.h} (87%) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 496313d50..8b43e2e6a 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -650,7 +650,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus - CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + //CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding // CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); diff --git a/src/OverlayDockContainer.cpp b/src/AutoHideDockContainer.cpp similarity index 75% rename from src/OverlayDockContainer.cpp rename to src/AutoHideDockContainer.cpp index 799cf9f64..08c3926b7 100644 --- a/src/OverlayDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -27,7 +27,7 @@ //============================================================================ // INCLUDES //============================================================================ -#include "OverlayDockContainer.h" +#include #include "DockManager.h" #include "DockWidgetSideTab.h" #include "DockWidgetTab.h" @@ -40,21 +40,26 @@ #include #include #include +#include + +#include namespace ads { -struct OverlayDockContainerPrivate +struct AutoHideDockContainerPrivate { - COverlayDockContainer* _this; + CAutoHideDockContainer* _this; CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; CDockWidgetSideTab::SideTabBarArea Area; + bool Collapsed = true; + bool Ignore = false; /** * Private data constructor */ - OverlayDockContainerPrivate(COverlayDockContainer *_public); + AutoHideDockContainerPrivate(CAutoHideDockContainer *_public); /** * Convenience function to get a dock widget area @@ -110,22 +115,22 @@ struct OverlayDockContainerPrivate }; // struct OverlayDockContainerPrivate //============================================================================ -OverlayDockContainerPrivate::OverlayDockContainerPrivate( - COverlayDockContainer *_public) : +AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( + CAutoHideDockContainer *_public) : _this(_public) { } -CDockContainerWidget* COverlayDockContainer::parentContainer() const +CDockContainerWidget* CAutoHideDockContainer::parentContainer() const { return internal::findParent(this); } //============================================================================ -COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : +CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : QSplitter(area == CDockWidgetSideTab::Bottom ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal, parent), - d(new OverlayDockContainerPrivate(this)) + d(new AutoHideDockContainerPrivate(this)) { d->DockManager = DockManager; d->Area = area; @@ -176,7 +181,7 @@ COverlayDockContainer::COverlayDockContainer(CDockManager* DockManager, CDockWid } //============================================================================ -void COverlayDockContainer::updateMask() +void CAutoHideDockContainer::updateMask() { const auto rect = d->DockArea->frameGeometry(); const auto topLeft = rect.topLeft(); @@ -197,7 +202,7 @@ void COverlayDockContainer::updateMask() } //============================================================================ -void COverlayDockContainer::updateSize() +void CAutoHideDockContainer::updateSize() { const auto dockContainerParent = parentContainer(); const auto rootSplitter = dockContainerParent->rootSplitter(); @@ -207,15 +212,15 @@ void COverlayDockContainer::updateSize() } //============================================================================ -COverlayDockContainer::COverlayDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : - COverlayDockContainer(DockWidget->dockManager(), area, parent) +CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : + CAutoHideDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); setDockSizeProportion(DockWidget->DefaultOverlayDockProportion()); } //============================================================================ -COverlayDockContainer::~COverlayDockContainer() +CAutoHideDockContainer::~CAutoHideDockContainer() { ADS_PRINT("~COverlayDockContainer"); @@ -232,19 +237,19 @@ COverlayDockContainer::~COverlayDockContainer() } //============================================================================ -CSideTabBar* COverlayDockContainer::sideTabBar() const +CSideTabBar* CAutoHideDockContainer::sideTabBar() const { return parentContainer()->sideTabBar(d->Area); } //============================================================================ -CDockWidget* COverlayDockContainer::dockWidget() const +CDockWidget* CAutoHideDockContainer::dockWidget() const { return d->DockWidget; } //============================================================================ -void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) +void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) { if (d->DockWidget) { @@ -267,7 +272,7 @@ void COverlayDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) +void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) { if (SplitterProportion < 0 || SplitterProportion > 1) { @@ -298,19 +303,19 @@ void COverlayDockContainer::setDockSizeProportion(float SplitterProportion) //============================================================================ -CDockWidgetSideTab::SideTabBarArea COverlayDockContainer::sideTabBarArea() const +CDockWidgetSideTab::SideTabBarArea CAutoHideDockContainer::sideTabBarArea() const { return d->Area; } //============================================================================ -CDockAreaWidget* COverlayDockContainer::dockAreaWidget() const +CDockAreaWidget* CAutoHideDockContainer::dockAreaWidget() const { return d->DockArea; } //============================================================================ -void COverlayDockContainer::moveContentsToParent() +void CAutoHideDockContainer::moveContentsToParent() { cleanupAndDelete(); @@ -331,7 +336,7 @@ void COverlayDockContainer::moveContentsToParent() //============================================================================ -void COverlayDockContainer::cleanupAndDelete() +void CAutoHideDockContainer::cleanupAndDelete() { const auto dockWidget = d->DockWidget; if (dockWidget) @@ -347,7 +352,7 @@ void COverlayDockContainer::cleanupAndDelete() //============================================================================ -void COverlayDockContainer::saveState(QXmlStreamWriter& s) +void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); QStringList Sizes; @@ -361,7 +366,7 @@ void COverlayDockContainer::saveState(QXmlStreamWriter& s) //============================================================================ -bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) +bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) { auto sSizes = s.attributes().value("Sizes").trimmed().toString(); ADS_PRINT("Sizes: " << sSizes); @@ -387,7 +392,7 @@ bool COverlayDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } -void COverlayDockContainer::toggleView(bool Enable) +void CAutoHideDockContainer::toggleView(bool Enable) { if (Enable) { @@ -405,11 +410,20 @@ void COverlayDockContainer::toggleView(bool Enable) dockWidget->sideTabWidget()->hide(); } hide(); + qApp->removeEventFilter(this); } } -void COverlayDockContainer::collapseView(bool Enable) +void CAutoHideDockContainer::collapseView(bool Enable) { + std::cout << "COverlayDockContainer::collapseView " << Enable << " " + << d->DockWidget->objectName().toStdString() << std::endl; + + if (d->Ignore) + { + return; + } + if (Enable) { hide(); @@ -422,12 +436,21 @@ void COverlayDockContainer::collapseView(bool Enable) show(); d->DockArea->show(); d->DockWidget->show(); + qApp->installEventFilter(this); } + d->Collapsed = Enable; +} + + +//============================================================================ +void CAutoHideDockContainer::toggleCollapseState() +{ + collapseView(isVisible()); } //============================================================================ -bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) +bool CAutoHideDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) { switch (area) { @@ -452,27 +475,68 @@ bool COverlayDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAre //============================================================================ -bool COverlayDockContainer::eventFilter(QObject* watched, QEvent* event) +bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Resize) { updateSize(); updateMask(); } + else if (event->type() == QEvent::MouseButtonPress) + { + // First we check, if the mouse button press is inside the dock manager + // widget. If it is not, i.e. if someone resizes the main window or + // clicks into the application menu or toolbar, then we ignore the + // event + auto widget = qobject_cast(watched); + bool IsDockManager = false; + while (widget) + { + if (widget == d->DockManager) + { + IsDockManager = true; + } + widget = widget->parentWidget(); + } + + if (!IsDockManager) + { + return QSplitter::eventFilter(watched, event); + } + + // Now we check, if the user clicked inside of this overlay. If the click + // is inside of the overlay, the we can also ignore the event, because + // the overlay should not get collapsed if user works in it + QMouseEvent* me = static_cast(event); + auto pos = d->DockArea->mapFromGlobal(me->globalPos()); + auto rect = d->DockArea->rect().adjusted(-handleWidth(), 0, 0, 0); + if (rect.contains(pos)) + { + return QSplitter::eventFilter(watched, event); + } + + // If the mouse button down event is in the dock manager but outside + // of the open overlay container, then the overlay dock widget + // should get collapsed + collapseView(true); + d->Ignore = true; + } + else if (event->type() == QEvent::MouseButtonRelease) + { + std::cout << "Mouse release: " << watched->metaObject()->className() << std::endl; + d->Ignore = false; + if (!isVisible()) + { + qApp->removeEventFilter(this); + } + } return QSplitter::eventFilter(watched, event); } //============================================================================ -void COverlayDockContainer::mousePressEvent(QMouseEvent* event) -{ - QSplitter::mousePressEvent(event); -} - - -//============================================================================ -void COverlayDockContainer::resizeEvent(QResizeEvent* event) +void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) { updateMask(); QSplitter::resizeEvent(event); diff --git a/src/OverlayDockContainer.h b/src/AutoHideDockContainer.h similarity index 87% rename from src/OverlayDockContainer.h rename to src/AutoHideDockContainer.h index 04a1ff1fd..efe694287 100644 --- a/src/OverlayDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -39,7 +39,7 @@ class QXmlStreamWriter; namespace ads { -struct OverlayDockContainerPrivate; +struct AutoHideDockContainerPrivate; class CDockManager; class CDockWidget; class CDockContainerWidget; @@ -49,17 +49,16 @@ class CDockingStateReader; // Note: This widget must be a QSplitter, inheriting from QWidget and keeping an internal splitter breaks ActiveX widgets // likely due to layout issues between this widget and the internal splitter -class ADS_EXPORT COverlayDockContainer : public QSplitter +class ADS_EXPORT CAutoHideDockContainer : public QSplitter { Q_OBJECT private: - OverlayDockContainerPrivate* d; ///< private data (pimpl) - friend struct OverlayDockContainerPrivate; + AutoHideDockContainerPrivate* d; ///< private data (pimpl) + friend struct AutoHideDockContainerPrivate; protected: bool eventFilter(QObject* watched, QEvent* event) override; - void mousePressEvent(QMouseEvent* event) override; void resizeEvent(QResizeEvent* event) override; void updateMask(); void updateSize(); @@ -70,17 +69,17 @@ class ADS_EXPORT COverlayDockContainer : public QSplitter /** * Create overlay widget with a dock manager */ - COverlayDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); /** * Create overlay widget with the given dock widget */ - COverlayDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); /** * Virtual Destructor */ - virtual ~COverlayDockContainer(); + virtual ~CAutoHideDockContainer(); /** * Get's the side tab bar @@ -148,6 +147,11 @@ class ADS_EXPORT COverlayDockContainer : public QSplitter */ void collapseView(bool Enable); + /** + * Toggles the current collapse state + */ + void toggleCollapseState(); + /* * Convenience function fr determining if area exists in config */ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9365db05b..f74775e5e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -29,7 +29,7 @@ set(ads_SRCS DockComponentsFactory.cpp SideTabBar.cpp DockWidgetSideTab.cpp - OverlayDockContainer.cpp + AutoHideDockContainer.cpp ads.qrc ) set(ads_HEADERS @@ -53,7 +53,7 @@ set(ads_HEADERS DockComponentsFactory.h SideTabBar.h DockWidgetSideTab.h - OverlayDockContainer.h + AutoHideDockContainer.h ) add_compile_options("$<$:/utf-8>") if (UNIX AND NOT APPLE) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index d50e0b64e..6584586a3 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -27,6 +27,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockAreaTitleBar.h" #include @@ -51,7 +52,6 @@ #include "DockAreaTabBar.h" #include "DockComponentsFactory.h" #include "DockFocusController.h" -#include "OverlayDockContainer.h" #include "ElidingLabel.h" #include diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index bf4a714f2..b3a5f8ebd 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -28,6 +28,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockAreaWidget.h" #include @@ -52,7 +53,6 @@ #include "DockComponentsFactory.h" #include "DockWidgetTab.h" #include "DockWidgetSideTab.h" -#include "OverlayDockContainer.h" namespace ads @@ -248,7 +248,7 @@ struct DockAreaWidgetPrivate DockAreaLayout* ContentsLayout = nullptr; CDockAreaTitleBar* TitleBar = nullptr; CDockManager* DockManager = nullptr; - COverlayDockContainer* OverlayDockContainer = nullptr; + CAutoHideDockContainer* OverlayDockContainer = nullptr; bool UpdateTitleBarButtons = false; DockWidgetAreas AllowedAreas = DefaultAllowedAreas; QSize MinSizeHint; @@ -457,7 +457,7 @@ CDockContainerWidget* CDockAreaWidget::dockContainer() const } //============================================================================ -COverlayDockContainer* CDockAreaWidget::overlayDockContainer() const +CAutoHideDockContainer* CDockAreaWidget::overlayDockContainer() const { return d->OverlayDockContainer; } @@ -469,7 +469,7 @@ bool CDockAreaWidget::isOverlayed() const } //============================================================================ -void CDockAreaWidget::setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer) +void CDockAreaWidget::setOverlayDockContainer(CAutoHideDockContainer* OverlayDockContainer) { d->OverlayDockContainer = OverlayDockContainer; } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 9e265545d..4a33a2be0 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -66,7 +66,7 @@ class ADS_EXPORT CDockAreaWidget : public QFrame friend class CDockWidget; friend struct DockManagerPrivate; friend class CDockManager; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; void onDockWidgetFeaturesChanged(); private Q_SLOTS: @@ -212,7 +212,7 @@ protected Q_SLOTS: * Returns the overlay dock container widget this dock area widget belongs to or 0 * if there is no */ - COverlayDockContainer* overlayDockContainer() const; + CAutoHideDockContainer* overlayDockContainer() const; /** * Returns true if the dock area exists in an overlay dock container @@ -223,7 +223,7 @@ protected Q_SLOTS: /** * Sets the current overlay dock container */ - void setOverlayDockContainer(COverlayDockContainer* OverlayDockContainer); + void setOverlayDockContainer(CAutoHideDockContainer* OverlayDockContainer); /** * Returns the largest minimumSizeHint() of the dock widgets in this diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index f97c92ef0..6761cc78b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -28,6 +28,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockContainerWidget.h" #include @@ -49,7 +50,6 @@ #include "ads_globals.h" #include "DockSplitter.h" #include "SideTabBar.h" -#include "OverlayDockContainer.h" #include "DockWidgetTab.h" #include "DockWidgetSideTab.h" #include "DockAreaTitleBar.h" @@ -138,7 +138,7 @@ class DockContainerWidgetPrivate QPointer DockManager; unsigned int zOrderIndex = 0; QList DockAreas; - QList OverlayWidgets; + QList OverlayWidgets; QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; @@ -1048,7 +1048,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " << CurrentDockWidget); - if (!COverlayDockContainer::areaExistsInConfig(area)) + if (!CAutoHideDockContainer::areaExistsInConfig(area)) { return false; } @@ -1056,7 +1056,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, CDockAreaWidget* DockArea = nullptr; if (!Testing) { - const auto dockContainer = new COverlayDockContainer(DockManager, area, _this); + const auto dockContainer = new CAutoHideDockContainer(DockManager, area, _this); if (!dockContainer->restoreState(s, Testing)) { return false; @@ -1491,13 +1491,13 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder) { if (d->DockManager != DockWidget->dockManager()) { DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager } - if (!COverlayDockContainer::areaExistsInConfig(area)) + if (!CAutoHideDockContainer::areaExistsInConfig(area)) { Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", "Requested area does not exist in config"); @@ -1508,7 +1508,7 @@ COverlayDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverla sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); - const auto dockContainer = new COverlayDockContainer(DockWidget, area, this); + const auto dockContainer = new CAutoHideDockContainer(DockWidget, area, this); dockContainer->hide(); d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); return dockContainer; @@ -1619,7 +1619,7 @@ void CDockContainerWidget::deleteOverlayWidgets() } //============================================================================ -QList CDockContainerWidget::overlayWidgets() const +QList CDockContainerWidget::overlayWidgets() const { return d->OverlayWidgets; } @@ -2156,7 +2156,7 @@ void CDockContainerWidget::updateSplitterHandles(QSplitter* splitter) } //============================================================================ -void CDockContainerWidget::registerOverlayWidget(COverlayDockContainer* OverlayWidget) +void CDockContainerWidget::registerOverlayWidget(CAutoHideDockContainer* OverlayWidget) { d->OverlayWidgets.append(OverlayWidget); Q_EMIT overlayWidgetCreated(OverlayWidget); @@ -2164,7 +2164,7 @@ void CDockContainerWidget::registerOverlayWidget(COverlayDockContainer* OverlayW } //============================================================================ -void CDockContainerWidget::removeOverlayWidget(COverlayDockContainer* OverlayWidget) +void CDockContainerWidget::removeOverlayWidget(CAutoHideDockContainer* OverlayWidget) { d->OverlayWidgets.removeAll(OverlayWidget); } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 269f784ea..6313481b0 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -76,7 +76,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame friend class CDockWidget; friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; protected: /** @@ -100,7 +100,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - COverlayDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder); + CAutoHideDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder); /** * Helper function for creation of the root splitter @@ -187,13 +187,13 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Registers the given floating widget in the internal list of * overlay widgets */ - void registerOverlayWidget(COverlayDockContainer* OverlayWidget); + void registerOverlayWidget(CAutoHideDockContainer* OverlayWidget); /** * Remove the given overlay widget from the list of registered overlay * widgets */ - void removeOverlayWidget(COverlayDockContainer* OverlayWidget); + void removeOverlayWidget(CAutoHideDockContainer* OverlayWidget); public: @@ -326,7 +326,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Access function for overlay widgets */ - QList overlayWidgets() const; + QList overlayWidgets() const; Q_SIGNALS: /** @@ -339,7 +339,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * This signal is emitted, if a new overlay widget has been created. */ - void overlayWidgetCreated(ads::COverlayDockContainer* OverlayWidget); + void overlayWidgetCreated(ads::CAutoHideDockContainer* OverlayWidget); /** * This signal is emitted if one or multiple dock areas has been removed diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index 4310f5118..c3076fc83 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -26,7 +26,6 @@ #include "DockManager.h" #include "DockAreaTitleBar.h" #include "DockWidgetSideTab.h" -#include "OverlayDockContainer.h" #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" @@ -189,12 +188,7 @@ void DockFocusControllerPrivate::updateDockWidgetFocus(CDockWidget* DockWidget) } #endif - if (old && old->overlayDockContainer() && old->overlayDockContainer()->isVisible() && old != FocusedDockWidget) - { - old->overlayDockContainer()->collapseView(true); - } - - if (old == DockWidget && !ForceFocusChangedSignal) + if (old == DockWidget && !ForceFocusChangedSignal) { return; } diff --git a/src/DockManager.cpp b/src/DockManager.cpp index cb32fbf1e..a1fe05853 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -28,6 +28,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockWidgetTab.h" #include "DockManager.h" @@ -57,7 +58,6 @@ #include "DockAreaTitleBar.h" #include "DockFocusController.h" #include "DockSplitter.h" -#include "OverlayDockContainer.h" #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" @@ -865,13 +865,13 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder) { return addOverlayDockWidgetToContainer(area, Dockwidget, this, insertOrder); } //============================================================================ -COverlayDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder insertOrder) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget, insertOrder); diff --git a/src/DockManager.h b/src/DockManager.h index 7f42d87cc..82dda8cbf 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -84,7 +84,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; friend class CDockAreaTitleBar; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; protected: @@ -341,14 +341,14 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder = CDockWidget::Last); + CAutoHideDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder = CDockWidget::Last); /** * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. * An overlay widget is used for auto hide functionality * \return Returns the COverlayDockContainer that contains the new DockWidget */ - COverlayDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder = CDockWidget::Last); + CAutoHideDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder = CDockWidget::Last); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index f6e402907..004973ebb 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -28,6 +28,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockWidgetTab.h" #include "DockWidget.h" @@ -59,7 +60,6 @@ #include "DockSplitter.h" #include "DockComponentsFactory.h" #include "ads_globals.h" -#include "OverlayDockContainer.h" namespace ads @@ -437,7 +437,7 @@ CDockWidgetTab* CDockWidget::tabWidget() const return d->TabWidget; } -COverlayDockContainer* CDockWidget::overlayDockContainer() const +CAutoHideDockContainer* CDockWidget::autoHideDockContainer() const { if (!d->DockArea) { @@ -1079,15 +1079,16 @@ void CDockWidget::showNormal() //============================================================================ void CDockWidget::onDockWidgetSideTabClicked() { - const auto overlayContainer = overlayDockContainer(); + const auto overlayContainer = autoHideDockContainer(); if (!overlayContainer) { return; } overlayContainer->raise(); - const auto shouldCollapse = overlayContainer->isVisible(); - overlayContainer->collapseView(shouldCollapse); + //const auto shouldCollapse = overlayContainer->isVisible(); + //overlayContainer->collapseView(shouldCollapse); + overlayContainer->toggleCollapseState(); if (overlayContainer->isVisible()) { // d->DockManager->setDockWidgetFocused(this) does not diff --git a/src/DockWidget.h b/src/DockWidget.h index 08454f3b9..871184772 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -47,7 +47,7 @@ class CDockAreaWidget; class DockContainerWidgetPrivate; class CFloatingDockContainer; class CDockWidgetSideTab; -class COverlayDockContainer; +class CAutoHideDockContainer; /** * The QDockWidget class provides a widget that can be docked inside a @@ -77,7 +77,7 @@ private Q_SLOTS: friend class CDockWidgetTab; friend struct DockWidgetTabPrivate; friend struct DockAreaTitleBarPrivate; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; /** * Assigns the dock manager that manages this dock widget @@ -319,7 +319,7 @@ private Q_SLOTS: * Returns the overlay dock container of this dock widget * or 0 if there is none */ - COverlayDockContainer* overlayDockContainer() const; + CAutoHideDockContainer* autoHideDockContainer() const; /** * Sets, whether the dock widget is movable, closable, and floatable. diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index a782ef568..9fbaf0e0a 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -27,6 +27,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockWidgetSideTab.h" #include "SideTabBar.h" @@ -37,7 +38,6 @@ #include "ElidingLabel.h" #include "DockWidget.h" -#include "OverlayDockContainer.h" namespace ads { diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 92c0d82f6..42ebdcada 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -57,7 +57,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame DockWidgetSideTabPrivate* d; ///< private data (pimpl) friend struct DockWidgetSideTabPrivate; friend class CDockWidget; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; protected: friend class CSideTabBar; diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index eed6fff53..e82ae77a4 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -28,6 +28,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "FloatingDragPreview.h" #include "ElidingLabel.h" #include "DockWidgetTab.h" @@ -51,7 +52,6 @@ #include "DockManager.h" #include "IconProvider.h" #include "DockFocusController.h" -#include "OverlayDockContainer.h" namespace ads diff --git a/src/DockWidgetTab.h b/src/DockWidgetTab.h index b46ac8559..d186c460c 100644 --- a/src/DockWidgetTab.h +++ b/src/DockWidgetTab.h @@ -58,7 +58,7 @@ class ADS_EXPORT CDockWidgetTab : public QFrame friend struct DockWidgetTabPrivate; friend class CDockWidget; friend class CDockManager; - friend class COverlayDockContainer; + friend class CAutoHideDockContainer; void onDockWidgetFeaturesChanged(); private Q_SLOTS: diff --git a/src/ElidingLabel.cpp b/src/ElidingLabel.cpp index 86cc60afb..f865941ec 100644 --- a/src/ElidingLabel.cpp +++ b/src/ElidingLabel.cpp @@ -241,6 +241,7 @@ QString CElidingLabel::text() const return d->Text; } + /** * Private data of public CVerticalElidingLabel */ @@ -255,9 +256,11 @@ struct VerticalElidingLabelPrivate //============================================================================ VerticalElidingLabelPrivate::VerticalElidingLabelPrivate(CVerticalElidingLabel* _public) + : _this(_public) { } + //============================================================================ CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) : CElidingLabel(parent, f), @@ -265,6 +268,7 @@ CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) { } + //============================================================================ void CVerticalElidingLabel::setOrientation(Qt::Orientation orientation) { diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 616e6e250..5a3bf847f 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -8,6 +8,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "FloatingDragPreview.h" #include @@ -21,7 +22,6 @@ #include "DockManager.h" #include "DockContainerWidget.h" #include "DockOverlay.h" -#include "OverlayDockContainer.h" namespace ads { @@ -369,9 +369,9 @@ void CFloatingDragPreview::cleanupOverlayContainerWidget() { auto DroppedDockWidget = qobject_cast(d->Content); auto DroppedArea = qobject_cast(d->Content); - if (DroppedDockWidget && DroppedDockWidget->overlayDockContainer()) + if (DroppedDockWidget && DroppedDockWidget->autoHideDockContainer()) { - DroppedDockWidget->overlayDockContainer()->cleanupAndDelete(); + DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(); } if (DroppedArea && DroppedArea->overlayDockContainer()) { diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index a6fb4de07..be3b40831 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -111,6 +111,8 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) //============================================================================ void CSideTabBar::paintEvent(QPaintEvent* event) { + Q_UNUSED(event) + QStyleOption option; option.initFrom(this); QPainter painter(this); diff --git a/src/src.pro b/src/src.pro index b400b5e1f..e86ebad1f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -48,7 +48,7 @@ HEADERS += \ IconProvider.h \ DockComponentsFactory.h \ DockFocusController.h \ - OverlayDockContainer.h \ + AutoHideDockContainer.h \ SideTabBar.h \ DockWidgetSideTab.h @@ -71,7 +71,7 @@ SOURCES += \ IconProvider.cpp \ DockComponentsFactory.cpp \ DockFocusController.cpp \ - OverlayDockContainer.cpp \ + AutoHideDockContainer.cpp \ SideTabBar.cpp \ DockWidgetSideTab.cpp From 6c27115de80e63639e015a87fd83ae254f8aadfc Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 12 Oct 2022 11:32:55 +0200 Subject: [PATCH 084/236] Ignore MouseButtonPress events of SideTabWidget in event filter --- src/AutoHideDockContainer.cpp | 40 ++++++++++++++++------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 08c3926b7..8e94d2fc2 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -53,8 +53,6 @@ struct AutoHideDockContainerPrivate CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; CDockWidgetSideTab::SideTabBarArea Area; - bool Collapsed = true; - bool Ignore = false; /** * Private data constructor @@ -392,6 +390,8 @@ bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) return true; } + +//============================================================================ void CAutoHideDockContainer::toggleView(bool Enable) { if (Enable) @@ -414,21 +414,16 @@ void CAutoHideDockContainer::toggleView(bool Enable) } } + +//============================================================================ void CAutoHideDockContainer::collapseView(bool Enable) { - std::cout << "COverlayDockContainer::collapseView " << Enable << " " - << d->DockWidget->objectName().toStdString() << std::endl; - - if (d->Ignore) - { - return; - } - if (Enable) { hide(); d->DockArea->hide(); d->DockWidget->hide(); + qApp->removeEventFilter(this); } else { @@ -438,7 +433,6 @@ void CAutoHideDockContainer::collapseView(bool Enable) d->DockWidget->show(); qApp->installEventFilter(this); } - d->Collapsed = Enable; } @@ -515,20 +509,22 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) return QSplitter::eventFilter(watched, event); } + // Now check, if the user clicked into the side tab and ignore this event, + // because the side tab click handler will call collapseView(). If we + // do not ignore this here, then we will collapse the container and the side tab + // click handler will uncollapse it + auto SideTab = d->DockWidget->sideTabWidget(); + pos = SideTab->mapFromGlobal(me->globalPos()); + if (SideTab->rect().contains(pos)) + { + return QSplitter::eventFilter(watched, event); + } + // If the mouse button down event is in the dock manager but outside - // of the open overlay container, then the overlay dock widget + // of the open overlay container, then the auto hide dock widget // should get collapsed + // If the user clicked into the side tab widget of this collapseView(true); - d->Ignore = true; - } - else if (event->type() == QEvent::MouseButtonRelease) - { - std::cout << "Mouse release: " << watched->metaObject()->className() << std::endl; - d->Ignore = false; - if (!isVisible()) - { - qApp->removeEventFilter(this); - } } return QSplitter::eventFilter(watched, event); From 60526f2293823c358d0e71dde96230d2dc2d3d5a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 12 Oct 2022 11:47:54 +0200 Subject: [PATCH 085/236] Fixed some typos --- src/AutoHideDockContainer.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 8e94d2fc2..45e127ecd 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -498,9 +498,10 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) return QSplitter::eventFilter(watched, event); } - // Now we check, if the user clicked inside of this overlay. If the click - // is inside of the overlay, the we can also ignore the event, because - // the overlay should not get collapsed if user works in it + // Now we check, if the user clicked inside of this auto hide container. + // If the click is inside of this auto hide container, then we can also + // ignore the event, because the overlay should not get collapsed if + // user works in it QMouseEvent* me = static_cast(event); auto pos = d->DockArea->mapFromGlobal(me->globalPos()); auto rect = d->DockArea->rect().adjusted(-handleWidth(), 0, 0, 0); @@ -521,9 +522,8 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) } // If the mouse button down event is in the dock manager but outside - // of the open overlay container, then the auto hide dock widget + // of the open auto hide container, then the auto hide dock widget // should get collapsed - // If the user clicked into the side tab widget of this collapseView(true); } From 8610a64b510a2d69c6a99dd49d2037af832d1f3d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 13 Oct 2022 14:26:54 +0800 Subject: [PATCH 086/236] Rename overlayDockContainer -> AutoHideDockContainer --- examples/autohide/mainwindow.cpp | 6 +-- src/AutoHideDockContainer.cpp | 20 ++++---- src/AutoHideDockContainer.h | 20 ++++---- src/DockAreaTitleBar.cpp | 34 +++++++------- src/DockAreaTitleBar.h | 6 +-- src/DockAreaWidget.cpp | 57 ++++++++++++----------- src/DockAreaWidget.h | 14 +++--- src/DockContainerWidget.cpp | 78 ++++++++++++++++---------------- src/DockContainerWidget.h | 26 +++++------ src/DockManager.cpp | 28 ++++++------ src/DockManager.h | 26 +++++------ src/DockWidget.cpp | 70 ++++++++++++++-------------- src/DockWidget.h | 30 ++++++------ src/DockWidgetSideTab.cpp | 4 +- src/FloatingDragPreview.cpp | 10 ++-- src/FloatingDragPreview.h | 4 +- 16 files changed, 215 insertions(+), 218 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 179fd82f2..2a8f06a4b 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,8 +46,8 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - TableDockWidget->setDefaultOverlayDockProportion(0.5); - DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); + TableDockWidget->setDefaultAutoHideDockProportion(0.5); + DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 45e127ecd..047b0e0a4 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -21,7 +21,7 @@ /// \file DockWidgetTab.h /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Implementation of COverlayDockContainer class +/// \brief Implementation of CAutoHideDockContainer class //============================================================================ //============================================================================ @@ -110,7 +110,7 @@ struct AutoHideDockContainerPrivate return QPoint(); } -}; // struct OverlayDockContainerPrivate +}; // struct AutoHideDockContainerPrivate //============================================================================ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( @@ -133,12 +133,12 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW d->DockManager = DockManager; d->Area = area; d->DockArea = new CDockAreaWidget(DockManager, parent); - d->DockArea->setObjectName("overlayDockArea"); - d->DockArea->setOverlayDockContainer(this); + d->DockArea->setObjectName("autoHideDockArea"); + d->DockArea->setAutoHideDockContainer(this); d->DockArea->updateAutoHideButtonCheckState(); d->DockArea->updateTitleBarButtonToolTip(); - setObjectName("overlaySplitter"); + setObjectName("autoHideSplitter"); setChildrenCollapsible(false); const auto emptyWidget = new QWidget(); @@ -172,7 +172,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW updateMask(); updateSize(); - parent->registerOverlayWidget(this); + parent->registerAutoHideWidget(this); d->DockArea->installEventFilter(this); parent->installEventFilter(this); @@ -214,13 +214,13 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWid CAutoHideDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); - setDockSizeProportion(DockWidget->DefaultOverlayDockProportion()); + setDockSizeProportion(DockWidget->DefaultAutoHideDockProportion()); } //============================================================================ CAutoHideDockContainer::~CAutoHideDockContainer() { - ADS_PRINT("~COverlayDockContainer"); + ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages d->DockArea->removeEventFilter(this); @@ -228,7 +228,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer() if (d->DockManager) { - parentContainer()->removeOverlayWidget(this); + parentContainer()->removeAutoHideWidget(this); } delete d; @@ -500,7 +500,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) // Now we check, if the user clicked inside of this auto hide container. // If the click is inside of this auto hide container, then we can also - // ignore the event, because the overlay should not get collapsed if + // ignore the event, because the auto hide overlay should not get collapsed if // user works in it QMouseEvent* me = static_cast(event); auto pos = d->DockArea->mapFromGlobal(me->globalPos()); diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index efe694287..fdac6539f 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -1,5 +1,5 @@ -#ifndef OverlayDockContainerH -#define OverlayDockContainerH +#ifndef AutoHideDockContainerH +#define AutoHideDockContainerH /******************************************************************************* ** Qt Advanced Docking System ** Copyright (C) 2017 Uwe Kindler @@ -23,7 +23,7 @@ /// \file DockWidgetTab.h /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Declaration of COverlayDockContainer class +/// \brief Declaration of CAutoHideDockContainer class //============================================================================ //============================================================================ @@ -67,12 +67,12 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter public: /** - * Create overlay widget with a dock manager + * Create Auto Hide widget with a dock manager */ CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); /** - * Create overlay widget with the given dock widget + * Create Auto Hide widget with the given dock widget */ CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); @@ -105,18 +105,18 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter void setDockSizeProportion(float SplitterProportion = 0.25); /** - * Returns the side tab bar area of this overlay dock container + * Returns the side tab bar area of this Auto Hide dock container */ CDockWidgetSideTab::SideTabBarArea sideTabBarArea() const; /** - * Returns the dock area widget of this overlay dock container + * Returns the dock area widget of this Auto Hide dock container */ CDockAreaWidget* dockAreaWidget() const; /** * Moves the contents to the parent container widget - * Used before removing this overlay dock container + * Used before removing this Auto Hide dock container */ void moveContentsToParent(); @@ -136,13 +136,13 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter bool restoreState(CDockingStateReader& Stream, bool Testing); /* - * Toggles the overlay dock container widget + * Toggles the auto Hide dock container widget * This will also hide the side tab widget */ void toggleView(bool Enable); /* - * Collapses the overlay dock container widget + * Collapses the auto hide dock container widget * Does not hide the side tab widget */ void collapseView(bool Enable); diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 6584586a3..a6bf3f80b 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -72,7 +72,7 @@ struct DockAreaTitleBarPrivate QBoxLayout* Layout; CDockAreaWidget* DockArea; CDockAreaTabBar* TabBar; - CElidingLabel* OverlayTitleLabel; + CElidingLabel* AutoHideTitleLabel; bool MenuOutdated = true; QMenu* TabsMenu; QList DockWidgetActionsButtons; @@ -94,9 +94,9 @@ struct DockAreaTitleBarPrivate /** - * Creates the overlay title label, only displayed when the dock area is overlayed + * Creates the auto hide title label, only displayed when the dock area is overlayed */ - void createOverlayTitleLabel(); + void createAutoHideTitleLabel(); /** * Creates the internal TabBar @@ -124,7 +124,7 @@ struct DockAreaTitleBarPrivate * Returns true if the given config flag is set * Convenience function to ease config flag testing */ - static bool testConfigFlag(CDockManager::eOverlayFlag Flag) + static bool testConfigFlag(CDockManager::eAutoHideFlag Flag) { return CDockManager::testConfigFlag(Flag); } @@ -217,11 +217,11 @@ void DockAreaTitleBarPrivate::createButtons() //============================================================================ -void DockAreaTitleBarPrivate::createOverlayTitleLabel() +void DockAreaTitleBarPrivate::createAutoHideTitleLabel() { - OverlayTitleLabel = new CElidingLabel(""); - OverlayTitleLabel->setObjectName("overlayTitleLabel"); - Layout->addWidget(OverlayTitleLabel); + AutoHideTitleLabel = new CElidingLabel(""); + AutoHideTitleLabel->setObjectName("autoHideTitleLabel"); + Layout->addWidget(AutoHideTitleLabel); } @@ -282,9 +282,9 @@ IFloatingWidget* DockAreaTitleBarPrivate::makeAreaFloating(const QPoint& Offset, //============================================================================ void DockAreaTitleBarPrivate::startFloating(const QPoint& Offset) { - if (DockArea->overlayDockContainer() != nullptr) + if (DockArea->autoHideDockContainer() != nullptr) { - DockArea->overlayDockContainer()->hide(); + DockArea->autoHideDockContainer()->hide(); } FloatingWidget = makeAreaFloating(Offset, DraggingFloatingWidget); } @@ -305,8 +305,8 @@ CDockAreaTitleBar::CDockAreaTitleBar(CDockAreaWidget* parent) : setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->createTabBar(); - d->createOverlayTitleLabel(); - d->OverlayTitleLabel->setVisible(false); // Default hidden + d->createAutoHideTitleLabel(); + d->AutoHideTitleLabel->setVisible(false); // Default hidden d->Layout->addWidget(new CSpacerWidget(this)); d->createButtons(); @@ -511,9 +511,9 @@ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const //============================================================================ -CElidingLabel* CDockAreaTitleBar::overlayTitleLabel() const +CElidingLabel* CDockAreaTitleBar::autoHideTitleLabel() const { - return d->OverlayTitleLabel; + return d->AutoHideTitleLabel; } @@ -588,7 +588,7 @@ void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev) // empty if (d->DockArea->dockContainer()->isFloating() && d->DockArea->dockContainer()->visibleDockAreaCount() == 1 - && !d->DockArea->isOverlayed()) + && !d->DockArea->isAutoHide()) { return; } @@ -607,7 +607,7 @@ void CDockAreaTitleBar::mouseMoveEvent(QMouseEvent* ev) int DragDistance = (d->DragStartMousePos - ev->pos()).manhattanLength(); if (DragDistance >= CDockManager::startDragDistance()) { - ADS_PRINT("CDockAreaTitlBar::startFloating"); + ADS_PRINT("CDockAreaTitleBar::startFloating"); d->startFloating(d->DragStartMousePos); auto Overlay = d->DockArea->dockManager()->containerOverlay(); Overlay->setAllowedAreas(OuterDockAreas); @@ -672,7 +672,7 @@ int CDockAreaTitleBar::indexOf(QWidget *widget) const //============================================================================ QString CDockAreaTitleBar::closeGroupToolTip() const { - if (d->DockArea->isOverlayed()) + if (d->DockArea->isAutoHide()) { return QObject::tr("Close Overlay"); diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 63d6749e5..0650ae817 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -122,9 +122,9 @@ public Q_SLOTS: QAbstractButton* button(TitleBarButton which) const; /** - * Returns the overlay title label, used when the dock area is overlayed + * Returns the auto hide title label, used when the dock area is expanded and auto hidden */ - CElidingLabel* overlayTitleLabel() const; + CElidingLabel* autoHideTitleLabel() const; /** * Updates the visibility of the dock widget actions in the title bar @@ -157,7 +157,7 @@ public Q_SLOTS: /** * Close group tool tip based on the current state - * Overlayed widgets can only have one dock widget so it does not make sense for the tooltip to show close group + * Auto hide widgets can only have one dock widget so it does not make sense for the tooltip to show close group */ QString closeGroupToolTip() const; diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index b3a5f8ebd..3e7934382 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -248,7 +248,7 @@ struct DockAreaWidgetPrivate DockAreaLayout* ContentsLayout = nullptr; CDockAreaTitleBar* TitleBar = nullptr; CDockManager* DockManager = nullptr; - CAutoHideDockContainer* OverlayDockContainer = nullptr; + CAutoHideDockContainer* AutoHideDockContainer = nullptr; bool UpdateTitleBarButtons = false; DockWidgetAreas AllowedAreas = DefaultAllowedAreas; QSize MinSizeHint; @@ -388,16 +388,16 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) { TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating() && allDockWidgetsFocusable()); - // Undock and tabs should never show when overlayed - TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isOverlayed()); - TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); + // 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->isOverlayed()); - TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isOverlayed()); + TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isAutoHide()); + TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide()); } } @@ -457,21 +457,21 @@ CDockContainerWidget* CDockAreaWidget::dockContainer() const } //============================================================================ -CAutoHideDockContainer* CDockAreaWidget::overlayDockContainer() const +CAutoHideDockContainer* CDockAreaWidget::autoHideDockContainer() const { - return d->OverlayDockContainer; + return d->AutoHideDockContainer; } //============================================================================ -bool CDockAreaWidget::isOverlayed() const +bool CDockAreaWidget::isAutoHide() const { - return d->OverlayDockContainer != nullptr; + return d->AutoHideDockContainer != nullptr; } //============================================================================ -void CDockAreaWidget::setOverlayDockContainer(CAutoHideDockContainer* OverlayDockContainer) +void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer) { - d->OverlayDockContainer = OverlayDockContainer; + d->AutoHideDockContainer = AutoHideDockContainer; } @@ -496,7 +496,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, d->tabBar()->insertTab(index, TabWidget); d->tabBar()->blockSignals(false); TabWidget->setVisible(!DockWidget->isClosed()); - d->TitleBar->overlayTitleLabel()->setText(DockWidget->windowTitle()); + 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())); @@ -534,7 +534,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { setCurrentDockWidget(NextOpenDockWidget); } - else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1 && !isOverlayed()) // Don't remove empty dock areas that are overlayed, they'll be deleted by the overlay dock + 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); @@ -602,9 +602,9 @@ void CDockAreaWidget::hideAreaWithNoVisibleContent() { FloatingWidget->hide(); } - if (isOverlayed()) + if (isAutoHide()) { - overlayDockContainer()->hide(); + autoHideDockContainer()->hide(); } } @@ -834,10 +834,10 @@ void CDockAreaWidget::updateTitleBarVisibility() bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); - d->TitleBar->setVisible(isOverlayed() ? true : !Hidden); // Titlebar must always be visible when overlayed so it can be dragged + 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(isOverlayed() ? false : !Hidden); // Never show tab bar when overlayed - d->TitleBar->overlayTitleLabel()->setVisible(CDockManager::testConfigFlag(CDockManager::DockAreaOverlayHasTitle) && isOverlayed()); // Always show when overlayed, never otherwise + 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); } } @@ -858,7 +858,7 @@ void CDockAreaWidget::updateAutoHideButtonCheckState() { auto autoHideButton = titleBarButton(TitleBarButtonAutoHide); autoHideButton->blockSignals(true); - autoHideButton->setChecked(isOverlayed()); + autoHideButton->setChecked(isAutoHide()); autoHideButton->blockSignals(false); } @@ -887,9 +887,9 @@ 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()) + if (isAutoHide()) { - overlayDockContainer()->saveState(s); + autoHideDockContainer()->saveState(s); } if (d->AllowedAreas != DefaultAllowedAreas) @@ -1068,11 +1068,10 @@ void CDockAreaWidget::closeArea() // 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 - // 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) || OpenDockWidgets[0]->features().testFlag(CDockWidget::CustomCloseHandling)) - && !isOverlayed()) + && !isAutoHide()) { OpenDockWidgets[0]->closeDockWidgetInternal(); } @@ -1085,7 +1084,7 @@ void CDockAreaWidget::closeArea() { DockWidget->closeDockWidgetInternal(); } - else if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && isOverlayed()) + else if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && isAutoHide()) { DockWidget->closeDockWidgetInternal(); } @@ -1103,12 +1102,12 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) const auto area = dockContainer()->getDockAreaPosition(this); for (const auto DockWidget : openedDockWidgets()) { - if (Enable == isOverlayed()) + if (Enable == isAutoHide()) { continue; } - onAutoHideToggleRequested(DockWidget, !isOverlayed(), area); + onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); } } @@ -1117,11 +1116,11 @@ void CDockAreaWidget::onAutoHideToggleRequested(CDockWidget* DockWidget, bool En { if (Enable) { - dockContainer()->createAndInitializeDockWidgetOverlayContainer(area, DockWidget, DockWidget->overlayInsertOrder()); + dockContainer()->createAndInitializeAutoHideDockWidgetContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); } else { - overlayDockContainer()->moveContentsToParent(); + autoHideDockContainer()->moveContentsToParent(); } } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 4a33a2be0..e9708120f 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -152,7 +152,7 @@ private Q_SLOTS: void markTitleBarMenuOutdated(); /* - * Update the auto hide button checked state based on if it's overlayed or not + * Update the auto hide button checked state based on if it's contained in an auto hide container or not */ void updateAutoHideButtonCheckState(); @@ -209,21 +209,21 @@ protected Q_SLOTS: CDockContainerWidget* dockContainer() const; /** - * Returns the overlay dock container widget this dock area widget belongs to or 0 + * Returns the auto hide dock container widget this dock area widget belongs to or 0 * if there is no */ - CAutoHideDockContainer* overlayDockContainer() const; + CAutoHideDockContainer* autoHideDockContainer() const; /** - * Returns true if the dock area exists in an overlay dock container + * Returns true if the dock area exists in an auto hide dock container */ - bool isOverlayed() const; + bool isAutoHide() const; /** - * Sets the current overlay dock container + * Sets the current auto hide dock container */ - void setOverlayDockContainer(CAutoHideDockContainer* OverlayDockContainer); + void setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer); /** * Returns the largest minimumSizeHint() of the dock widgets in this diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 6761cc78b..fa928e119 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -138,7 +138,7 @@ class DockContainerWidgetPrivate QPointer DockManager; unsigned int zOrderIndex = 0; QList DockAreas; - QList OverlayWidgets; + QList AutoHideWidgets; QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; @@ -221,9 +221,9 @@ class DockContainerWidgetPrivate void saveChildNodesState(QXmlStreamWriter& Stream, QWidget* Widget); /** - * Save state of overlay widgets + * Save state of auto hide widgets */ - void saveOverlayWidgetsState(QXmlStreamWriter& Stream); + void saveAutoHideWidgetsState(QXmlStreamWriter& Stream); /** * Restore state of child nodes. @@ -251,16 +251,16 @@ class DockContainerWidgetPrivate bool Testing); /** - * Restores the overlay dock area. - * Assumes that there are no overlay dock areas, and then restores all the dock areas that + * Restores the auto hide dock area. + * Assumes that there are no auto hidden dock areas, and then restores all the dock areas that * exist in the XML */ - bool restoreOverlayDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing); + bool restoreAutoHideDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing); /** - * Restores either a dock area or an overlay dock area depending on the value in the XML + * Restores either a dock area or an auto hide dock area depending on the value in the XML */ - bool restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, + bool restoreDockOrAutoHideDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, bool Testing); /** @@ -898,7 +898,7 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge } } -void DockContainerWidgetPrivate::saveOverlayWidgetsState(QXmlStreamWriter& Stream) +void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& Stream) { for (const auto sideTabBar : SideTabBarWidgets.values()) { @@ -1033,7 +1033,7 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, } //============================================================================ -bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing) +bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing) { bool Ok; #ifdef ADS_DEBUG_PRINT @@ -1103,9 +1103,9 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, DockWidget->setProperty(internal::ClosedProperty, Closed); DockWidget->setProperty(internal::DirtyProperty, false); _this->sideTabBar(area)->insertSideTab(-1, DockWidget->sideTabWidget()); - DockArea->overlayDockContainer()->addDockWidget(DockWidget); + DockArea->autoHideDockContainer()->addDockWidget(DockWidget); DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added - DockArea->overlayDockContainer()->toggleView(!Closed); + DockArea->autoHideDockContainer()->toggleView(!Closed); } return true; @@ -1113,7 +1113,7 @@ bool DockContainerWidgetPrivate::restoreOverlayDockArea(CDockingStateReader& s, //============================================================================ -bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, +bool DockContainerWidgetPrivate::restoreDockOrAutoHideDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, bool Testing) { bool Ok; @@ -1126,7 +1126,7 @@ bool DockContainerWidgetPrivate::restoreDockOrOverlayDockArea(CDockingStateReade return false; } - return restoreOverlayDockArea(Stream, sideTabBarArea, Testing); + return restoreAutoHideDockArea(Stream, sideTabBarArea, Testing); } // If there's no SideTabBarArea value in the XML, or the value of SideTabBarArea is none, restore the dock area @@ -1241,7 +1241,7 @@ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s, } else if (s.name() == QLatin1String("Area")) { - Result = restoreDockOrOverlayDockArea(s, CreatedWidget, Testing); + Result = restoreDockOrAutoHideDockArea(s, CreatedWidget, Testing); ADS_PRINT("DockAreaWidget"); } else @@ -1458,10 +1458,10 @@ CDockContainerWidget::~CDockContainerWidget() d->DockManager->removeDockContainer(this); } - auto OverlayWidgets = d->OverlayWidgets; - for (auto OverlayWidget : OverlayWidgets) + auto AutoHideWidgets = d->AutoHideWidgets; + for (auto AutohideWidget : AutoHideWidgets) { - delete OverlayWidget; + delete AutohideWidget; } delete d; @@ -1491,7 +1491,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -CAutoHideDockContainer* CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWidgetContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { if (d->DockManager != DockWidget->dockManager()) { @@ -1609,19 +1609,19 @@ bool CDockContainerWidget::event(QEvent *e) //============================================================================ -void CDockContainerWidget::deleteOverlayWidgets() +void CDockContainerWidget::deleteAutoHideWidgets() { - for (auto OverlayWidget : d->OverlayWidgets) + for (auto AutohideWidget : d->AutoHideWidgets) { - OverlayWidget->cleanupAndDelete(); + AutohideWidget->cleanupAndDelete(); } - d->OverlayWidgets.clear(); + d->AutoHideWidgets.clear(); } //============================================================================ -QList CDockContainerWidget::overlayWidgets() const +QList CDockContainerWidget::autoHideWidgets() const { - return d->OverlayWidgets; + return d->AutoHideWidgets; } @@ -1658,10 +1658,10 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) *p = nullptr; } - if (area->isOverlayed()) + if (area->isAutoHide()) { - // Removing an area from an overlay widget implies deleting the whole overlay widget - // So cleanup will be done when the overlay widget is deleted + // Removing an area from an auto hide container widget implies deleting the whole auto hide widget + // So cleanup will be done when the auto hide container widget is deleted // Note: there is no parent splitter CDockWidget* TopLevelWidget = topLevelDockWidget(); @@ -1670,7 +1670,7 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); dumpLayout(); d->emitDockAreasRemoved(); - area->setOverlayDockContainer(nullptr); + area->setAutoHideDockContainer(nullptr); area->updateAutoHideButtonCheckState(); area->updateTitleBarButtonToolTip(); return; @@ -1801,10 +1801,10 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); bool Dropped = false; - auto overlayWidgets = FloatingWidget->dockContainer()->overlayWidgets(); - for (const auto overlayWidget : overlayWidgets) + auto autoHideWidgets = FloatingWidget->dockContainer()->autoHideWidgets(); + for (const auto autohideWidget : autoHideWidgets) { - createAndInitializeDockWidgetOverlayContainer(overlayWidget->sideTabBarArea(), overlayWidget->dockWidget(), overlayWidget->dockWidget()->overlayInsertOrder()); + createAndInitializeAutoHideDockWidgetContainer(autohideWidget->sideTabBarArea(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); } if (DockArea) @@ -1949,7 +1949,7 @@ void CDockContainerWidget::saveState(QXmlStreamWriter& s) const #endif } d->saveChildNodesState(s, d->RootSplitter); - d->saveOverlayWidgetsState(s); + d->saveAutoHideWidgetsState(s); s.writeEndElement(); } @@ -2156,17 +2156,17 @@ void CDockContainerWidget::updateSplitterHandles(QSplitter* splitter) } //============================================================================ -void CDockContainerWidget::registerOverlayWidget(CAutoHideDockContainer* OverlayWidget) +void CDockContainerWidget::registerAutoHideWidget(CAutoHideDockContainer* AutohideWidget) { - d->OverlayWidgets.append(OverlayWidget); - Q_EMIT overlayWidgetCreated(OverlayWidget); - ADS_PRINT("d->OverlayWidgets.count() " << d->OverlayWidgets.count()); + d->AutoHideWidgets.append(AutohideWidget); + Q_EMIT autoHideWidgetCreated(AutohideWidget); + ADS_PRINT("d->AutoHideWidgets.count() " << d->AutoHideWidgets.count()); } //============================================================================ -void CDockContainerWidget::removeOverlayWidget(CAutoHideDockContainer* OverlayWidget) +void CDockContainerWidget::removeAutoHideWidget(CAutoHideDockContainer* AutohideWidget) { - d->OverlayWidgets.removeAll(OverlayWidget); + d->AutoHideWidgets.removeAll(AutohideWidget); } //============================================================================ diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 6313481b0..63e1d6de2 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -85,10 +85,10 @@ class ADS_EXPORT CDockContainerWidget : public QFrame virtual bool event(QEvent *e) override; /* - * Delete function for resetting the overlay widget list + * Delete function for resetting the auto hide widget list * Used during restore */ - void deleteOverlayWidgets(); + void deleteAutoHideWidgets(); /** * Access function for the internal root splitter @@ -96,11 +96,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame QSplitter* rootSplitter() const; /** - * Creates and initializes a dockwidget overlay container into the given area. + * Creates and initializes a dockwidget auto hide container into the given area. * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - CAutoHideDockContainer* createAndInitializeDockWidgetOverlayContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eOverlayInsertOrder insertOrder); + CAutoHideDockContainer* createAndInitializeAutoHideDockWidgetContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder); /** * Helper function for creation of the root splitter @@ -185,15 +185,15 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Registers the given floating widget in the internal list of - * overlay widgets + * auto hide widgets */ - void registerOverlayWidget(CAutoHideDockContainer* OverlayWidget); + void registerAutoHideWidget(CAutoHideDockContainer* AutoHideWidget); /** - * Remove the given overlay widget from the list of registered overlay + * Remove the given auto hide widget from the list of registered auto hide * widgets */ - void removeOverlayWidget(CAutoHideDockContainer* OverlayWidget); + void removeAutoHideWidget(CAutoHideDockContainer* AutoHideWidget); public: @@ -218,7 +218,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame CDockAreaWidget* DockAreaWidget = nullptr); /** - * Get's the overlay dock side tab bar area based on the dock area widget position + * Get's the auto hide dock side tab bar area based on the dock area widget position */ CDockWidgetSideTab::SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget); @@ -324,9 +324,9 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** - * Access function for overlay widgets + * Access function for auto hide widgets */ - QList overlayWidgets() const; + QList autoHideWidgets() const; Q_SIGNALS: /** @@ -337,9 +337,9 @@ class ADS_EXPORT CDockContainerWidget : public QFrame void dockAreasAdded(); /** - * This signal is emitted, if a new overlay widget has been created. + * This signal is emitted, if a new auto hide widget has been created. */ - void overlayWidgetCreated(ads::CAutoHideDockContainer* OverlayWidget); + void autoHideWidgetCreated(ads::CAutoHideDockContainer* AutoHideWidget); /** * This signal is emitted if one or multiple dock areas has been removed diff --git a/src/DockManager.cpp b/src/DockManager.cpp index a1fe05853..9b1a18179 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -93,7 +93,7 @@ enum eStateFileVersion }; static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig; -static CDockManager::OverlayFlags StaticOverlayConfigFlags = CDockManager::DefaultAutoHideConfig; +static CDockManager::AutoHideFlags StaticAutoHideConfigFlags = CDockManager::DefaultAutoHideConfig; /** * Private data class of CDockManager class (pimpl) @@ -435,7 +435,7 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version) // Hide updates of floating widgets from use hideFloatingWidgets(); markDockWidgetsDirty(); - _this->deleteOverlayWidgets(); + _this->deleteAutoHideWidgets(); if (!restoreStateFromXml(state, version)) { @@ -865,16 +865,16 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -CAutoHideDockContainer* CDockManager::addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eAutoHideInsertOrder insertOrder) { - return addOverlayDockWidgetToContainer(area, Dockwidget, this, insertOrder); + return addAutoHideDockWidgetToContainer(area, Dockwidget, this, insertOrder); } //============================================================================ -CAutoHideDockContainer* CDockManager::addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); - auto container = DockContainerWidget->createAndInitializeDockWidgetOverlayContainer(area, Dockwidget, insertOrder); + auto container = DockContainerWidget->createAndInitializeAutoHideDockWidgetContainer(area, Dockwidget, insertOrder); container->collapseView(true); Q_EMIT dockWidgetAdded(Dockwidget); @@ -1138,9 +1138,9 @@ CDockManager::ConfigFlags CDockManager::configFlags() return StaticConfigFlags; } -CDockManager::OverlayFlags CDockManager::overlayConfigFlags() +CDockManager::AutoHideFlags CDockManager::autoHideConfigFlags() { - return StaticOverlayConfigFlags; + return StaticAutoHideConfigFlags; } @@ -1152,9 +1152,9 @@ void CDockManager::setConfigFlags(const ConfigFlags Flags) //=========================================================================== -void CDockManager::setConfigFlags(const OverlayFlags Flags) +void CDockManager::setConfigFlags(const AutoHideFlags Flags) { - StaticOverlayConfigFlags = Flags; + StaticAutoHideConfigFlags = Flags; } @@ -1166,9 +1166,9 @@ void CDockManager::setConfigFlag(eConfigFlag Flag, bool On) //=========================================================================== -void CDockManager::setConfigFlag(eOverlayFlag Flag, bool On) +void CDockManager::setConfigFlag(eAutoHideFlag Flag, bool On) { - internal::setFlag(StaticOverlayConfigFlags, Flag, On); + internal::setFlag(StaticAutoHideConfigFlags, Flag, On); } //=========================================================================== @@ -1179,9 +1179,9 @@ bool CDockManager::testConfigFlag(eConfigFlag Flag) //=========================================================================== -bool CDockManager::testConfigFlag(eOverlayFlag Flag) +bool CDockManager::testConfigFlag(eAutoHideFlag Flag) { - return overlayConfigFlags().testFlag(Flag); + return autoHideConfigFlags().testFlag(Flag); } diff --git a/src/DockManager.h b/src/DockManager.h index 82dda8cbf..e1f23c019 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -224,7 +224,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget }; Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag) - enum eOverlayFlag + enum eAutoHideFlag { DockContainerHasLeftSideBar = 0x01, //!< If the flag is set left side bar will prioritize showing icons only over text DockContainerHasRightSideBar = 0x02, //!< If the flag is set right side bar will prioritize showing icons only over text @@ -233,15 +233,15 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget LeftSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a left side bar RightSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a right side bar BottomSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set bottom side bar will prioritize showing icons only over text - DockAreaOverlayHasTitle = 0x80, //!< If the flag is set overlay dock area title bar will show the window title + AutoHideDockAreaHasTitle = 0x80, //!< If the flag is set overlay dock area title bar will show the window title DefaultAutoHideConfig = DockContainerHasLeftSideBar | DockContainerHasRightSideBar | DockContainerHasBottomSideBar | DockAreaHasAutoHideButton - | DockAreaOverlayHasTitle, ///< the default configuration for left and right side bars + | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars }; - Q_DECLARE_FLAGS(OverlayFlags, eOverlayFlag) + Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) /** @@ -264,9 +264,9 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget static ConfigFlags configFlags(); /** - * This function returns the overlay configuration flags + * This function returns the auto hide configuration flags */ - static OverlayFlags overlayConfigFlags(); + static AutoHideFlags autoHideConfigFlags(); /** * Sets the global configuration flags for the whole docking system. @@ -280,7 +280,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * Call this function before you create the dock manager and before * your create the first dock widget. */ - static void setConfigFlags(const OverlayFlags Flags); + static void setConfigFlags(const AutoHideFlags Flags); /** * Set a certain config flag. @@ -292,7 +292,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * Set a certain overlay config flag. * \see setConfigFlags() */ - static void setConfigFlag(eOverlayFlag Flag, bool On = true); + static void setConfigFlag(eAutoHideFlag Flag, bool On = true); /** * Returns true if the given config flag is set @@ -302,7 +302,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget /** * Returns true if the given overlay config flag is set */ - static bool testConfigFlag(eOverlayFlag Flag); + static bool testConfigFlag(eAutoHideFlag Flag); /** * Returns the global icon provider. @@ -339,16 +339,16 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget /** * Adds a dock widget overlayed into the dock manager container based on the side tab bar area. * An overlay widget is used for auto hide functionality - * \return Returns the COverlayDockContainer that contains the new DockWidget + * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eOverlayInsertOrder insertOrder = CDockWidget::Last); + CAutoHideDockContainer* addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eAutoHideInsertOrder insertOrder = CDockWidget::Last); /** * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. * An overlay widget is used for auto hide functionality - * \return Returns the COverlayDockContainer that contains the new DockWidget + * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addOverlayDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eOverlayInsertOrder = CDockWidget::Last); + CAutoHideDockContainer* addAutoHideDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder = CDockWidget::Last); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 004973ebb..2a90d3d39 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -95,8 +95,8 @@ struct DockWidgetPrivate QList TitleBarActions; CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; - double DefaultOverlayDockProportion = 0.25; - CDockWidget::eOverlayInsertOrder OverlayInsertOrder = CDockWidget::Last; + double DefaultAutoHideDockProportion = 0.25; + CDockWidget::eAutoHideInsertOrder AutoHideInsertOrder = CDockWidget::Last; /** * Private data constructor @@ -121,10 +121,10 @@ struct DockWidgetPrivate void updateParentDockArea(); /** - * Closes all overlayed dock widgets if there are no more opened dock areas - * This prevents the overlayed dock widgets from being pinned to an empty dock area + * Closes all auto hide dock widgets if there are no more opened dock areas + * This prevents the auto hide dock widgets from being pinned to an empty dock area */ - void closeOverlayDockWidgetsIfNeeded(); + void closeAutoHideDockWidgetsIfNeeded(); /** * Setup the top tool bar @@ -181,7 +181,7 @@ void DockWidgetPrivate::showDockWidget() DockArea->toggleView(true); TabWidget->show(); QSplitter* Splitter = internal::findParent(DockArea); - while (Splitter && !Splitter->isVisible() && !DockArea->isOverlayed()) + while (Splitter && !Splitter->isVisible() && !DockArea->isAutoHide()) { Splitter->show(); Splitter = internal::findParent(Splitter); @@ -195,11 +195,11 @@ void DockWidgetPrivate::showDockWidget() FloatingWidget->show(); } - // If this widget is pinned and there are no opened dock widgets, unpin the overlay widget by moving it's contents to parent container + // If this widget is pinned and there are no opened dock widgets, unpin the auto hide widget by moving it's contents to parent container // While restoring state, opened dock widgets are not valid - if (Container->openedDockWidgets().count() == 0 && DockArea->isOverlayed() && !DockManager->isRestoringState()) + if (Container->openedDockWidgets().count() == 0 && DockArea->isAutoHide() && !DockManager->isRestoringState()) { - DockArea->overlayDockContainer()->moveContentsToParent(); + DockArea->autoHideDockContainer()->moveContentsToParent(); } } } @@ -211,7 +211,7 @@ void DockWidgetPrivate::hideDockWidget() TabWidget->hide(); updateParentDockArea(); - closeOverlayDockWidgetsIfNeeded(); + closeAutoHideDockWidgetsIfNeeded(); if (Features.testFlag(CDockWidget::DeleteContentOnClose)) { @@ -246,18 +246,18 @@ void DockWidgetPrivate::updateParentDockArea() } } -void DockWidgetPrivate::closeOverlayDockWidgetsIfNeeded() +void DockWidgetPrivate::closeAutoHideDockWidgetsIfNeeded() { if (_this->dockContainer() && _this->dockContainer()->openedDockWidgets().isEmpty()) { - for (auto overlayWidget : _this->dockContainer()->overlayWidgets()) + for (auto autoHideWidget : _this->dockContainer()->autoHideWidgets()) { - if (overlayWidget->dockWidget() == _this) + if (autoHideWidget->dockWidget() == _this) { continue; } - overlayWidget->dockWidget()->toggleView(false); + autoHideWidget->dockWidget()->toggleView(false); } } } @@ -444,7 +444,7 @@ CAutoHideDockContainer* CDockWidget::autoHideDockContainer() const return nullptr; } - return d->DockArea->overlayDockContainer(); + return d->DockArea->autoHideDockContainer(); } @@ -653,9 +653,9 @@ void CDockWidget::toggleViewInternal(bool Open) d->DockArea->toggleDockWidgetView(this, Open); } - if (d->DockArea->isOverlayed()) + if (d->DockArea->isAutoHide()) { - d->DockArea->overlayDockContainer()->toggleView(Open); + d->DockArea->autoHideDockContainer()->toggleView(Open); } if (Open && TopLevelDockWidgetBefore) @@ -1019,9 +1019,9 @@ bool CDockWidget::closeDockWidgetInternal(bool ForceClose) FloatingWidget->hide(); } } - if (d->DockArea && d->DockArea->isOverlayed()) + if (d->DockArea && d->DockArea->isAutoHide()) { - d->DockArea->overlayDockContainer()->cleanupAndDelete(); + d->DockArea->autoHideDockContainer()->cleanupAndDelete(); } deleteDockWidget(); Q_EMIT closed(); @@ -1079,21 +1079,19 @@ void CDockWidget::showNormal() //============================================================================ void CDockWidget::onDockWidgetSideTabClicked() { - const auto overlayContainer = autoHideDockContainer(); - if (!overlayContainer) + const auto autoHideContainer = autoHideDockContainer(); + if (!autoHideContainer) { return; } - overlayContainer->raise(); - //const auto shouldCollapse = overlayContainer->isVisible(); - //overlayContainer->collapseView(shouldCollapse); - overlayContainer->toggleCollapseState(); - if (overlayContainer->isVisible()) + autoHideContainer->raise(); + autoHideContainer->toggleCollapseState(); + if (autoHideContainer->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. + // de focus the old widget, leading to the auto hide still being visible + // even after clicking outside the auto hide. setFocus(Qt::ActiveWindowFocusReason); } } @@ -1138,28 +1136,28 @@ bool CDockWidget::isCurrentTab() const //============================================================================ -void CDockWidget::setDefaultOverlayDockProportion(float Proportion) +void CDockWidget::setDefaultAutoHideDockProportion(float Proportion) { - d->DefaultOverlayDockProportion = Proportion; + d->DefaultAutoHideDockProportion = Proportion; } //============================================================================ -float CDockWidget::DefaultOverlayDockProportion() const +float CDockWidget::DefaultAutoHideDockProportion() const { - return d->DefaultOverlayDockProportion; + return d->DefaultAutoHideDockProportion; } //============================================================================ -void CDockWidget::setOverlayInsertOrder(eOverlayInsertOrder insertOrder) +void CDockWidget::setAutoHideInsertOrder(eAutoHideInsertOrder insertOrder) { - d->OverlayInsertOrder = insertOrder; + d->AutoHideInsertOrder = insertOrder; } -CDockWidget::eOverlayInsertOrder CDockWidget::overlayInsertOrder() const +CDockWidget::eAutoHideInsertOrder CDockWidget::autoHideInsertOrder() const { - return d->OverlayInsertOrder; + return d->AutoHideInsertOrder; } diff --git a/src/DockWidget.h b/src/DockWidget.h index 871184772..60df0e38c 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -159,7 +159,7 @@ private Q_SLOTS: DockWidgetForceCloseWithArea = 0x040, ///< dock widget will be closed when the dock area hosting it is closed NoTab = 0x080, ///< dock widget tab will never be shown if this flag is set DeleteContentOnClose = 0x100, ///< deletes only the contained widget on close, keeping the dock widget intact and in place. Attempts to rebuild the contents widget on show if there is a widget factory set. - DockWidgetPinnable = 0x200, ///< dock widget can be pinned and added to an overlay widget + DockWidgetPinnable = 0x200, ///< dock widget can be pinned and added to an auto hide dock container DefaultDockWidgetFeatures = DockWidgetClosable | DockWidgetMovable | DockWidgetFloatable | DockWidgetFocusable | DockWidgetPinnable, AllDockWidgetFeatures = DefaultDockWidgetFeatures | DockWidgetDeleteOnClose | CustomCloseHandling, DockWidgetAlwaysCloseAndDelete = DockWidgetForceCloseWithArea | DockWidgetDeleteOnClose, @@ -230,10 +230,10 @@ private Q_SLOTS: }; /** - * This mode configures the order of pinning and unpinning overlayed widgets - * First will add it to the top of the SideTabBar, while last will append it to the end + * This mode configures the order of pinning and unpinning auto hide widgets + * First will add it to the top of the SideTabBar, while Last will append it to the end */ - enum eOverlayInsertOrder + enum eAutoHideInsertOrder { First, Last @@ -316,7 +316,7 @@ private Q_SLOTS: CDockWidgetTab* tabWidget() const; /** - * Returns the overlay dock container of this dock widget + * Returns the auto hide dock container of this dock widget * or 0 if there is none */ CAutoHideDockContainer* autoHideDockContainer() const; @@ -524,26 +524,26 @@ private Q_SLOTS: bool isCurrentTab() const; /* - * Set default dock proportion when overlayed - * see *DefaultOverlayDockProportion() + * Set default dock proportion when auto hiding + * see *DefaultAutoHideDockProportion() */ - void setDefaultOverlayDockProportion(float Proportion); + void setDefaultAutoHideDockProportion(float Proportion); /* - * Set default dock proportion when overlayed + * Set default dock proportion when auto hiding * 0.25 is a quarter of the size, 0.5 is half the size, 1 is the entire size */ - float DefaultOverlayDockProportion() const; + float DefaultAutoHideDockProportion() const; /* - * Set overlay insertion mode + * Set auto hide insertion mode */ - void setOverlayInsertOrder(eOverlayInsertOrder insertOrder); + void setAutoHideInsertOrder(eAutoHideInsertOrder insertOrder); /* - * Get overlay insertion mode + * Get auto hide insertion mode */ - eOverlayInsertOrder overlayInsertOrder() const; + eAutoHideInsertOrder autoHideInsertOrder() const; public: // reimplements QFrame ----------------------------------------------- /** @@ -612,7 +612,7 @@ public Q_SLOTS: void showNormal(); /** - * Shows the dock overlay container when the side tab is clicked + * Toggles the dock auto hide container when the side tab is clicked */ void onDockWidgetSideTabClicked(); diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 9fbaf0e0a..630770738 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -211,9 +211,9 @@ void CDockWidgetSideTab::updateStyle() CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const { auto dockAreaWidget = d->DockWidget->dockAreaWidget(); - if (dockAreaWidget && dockAreaWidget->isOverlayed()) + if (dockAreaWidget && dockAreaWidget->isAutoHide()) { - return dockAreaWidget->overlayDockContainer()->sideTabBarArea(); + return dockAreaWidget->autoHideDockContainer()->sideTabBarArea(); } return LeftTop; diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 5a3bf847f..a48611df6 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -124,7 +124,7 @@ void FloatingDragPreviewPrivate::updateDropOverlays(const QPoint &GlobalPos) // Include the overlay widget we're dragging as a visible widget auto dockAreaWidget = qobject_cast(Content); - if (dockAreaWidget && dockAreaWidget->isOverlayed()) + if (dockAreaWidget && dockAreaWidget->isAutoHide()) { VisibleDockAreas++; } @@ -328,7 +328,7 @@ void CFloatingDragPreview::finishDragging() { ADS_PRINT("CFloatingDragPreview::finishDragging"); - cleanupOverlayContainerWidget(); + cleanupAutoHideContainerWidget(); auto DockDropArea = d->DockManager->dockAreaOverlay()->visibleDropAreaUnderCursor(); auto ContainerDropArea = d->DockManager->containerOverlay()->visibleDropAreaUnderCursor(); @@ -365,7 +365,7 @@ void CFloatingDragPreview::finishDragging() //============================================================================ -void CFloatingDragPreview::cleanupOverlayContainerWidget() +void CFloatingDragPreview::cleanupAutoHideContainerWidget() { auto DroppedDockWidget = qobject_cast(d->Content); auto DroppedArea = qobject_cast(d->Content); @@ -373,9 +373,9 @@ void CFloatingDragPreview::cleanupOverlayContainerWidget() { DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(); } - if (DroppedArea && DroppedArea->overlayDockContainer()) + if (DroppedArea && DroppedArea->autoHideDockContainer()) { - DroppedArea->overlayDockContainer()->cleanupAndDelete(); + DroppedArea->autoHideDockContainer()->cleanupAndDelete(); } } diff --git a/src/FloatingDragPreview.h b/src/FloatingDragPreview.h index 2920a9e55..236f80eb5 100644 --- a/src/FloatingDragPreview.h +++ b/src/FloatingDragPreview.h @@ -93,9 +93,9 @@ private Q_SLOTS: virtual void finishDragging() override; /** - * Cleanup overlay container if the dragged widget has one + * Cleanup auto hide container if the dragged widget has one */ - void cleanupOverlayContainerWidget(); + void cleanupAutoHideContainerWidget(); Q_SIGNALS: /** From 84ca7b18a0351fe01e038b4074cbadc929466bbe Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 13 Oct 2022 14:37:39 +0800 Subject: [PATCH 087/236] fix side tab not hiding when double clicking dock title bar --- src/DockAreaTitleBar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index a6bf3f80b..a86e82dae 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -632,6 +632,11 @@ void CDockAreaTitleBar::mouseDoubleClickEvent(QMouseEvent *event) { return; } + if (d->DockArea->autoHideDockContainer()) + { + d->DockArea->autoHideDockContainer()->cleanupAndDelete(); + } + d->makeAreaFloating(event->pos(), DraggingInactive); } From b51c56e28669a091119b4486e69a46b809d08a65 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 13 Oct 2022 14:56:25 +0800 Subject: [PATCH 088/236] Fix bug where left and bottom overlay splitters cannot be clicked --- src/AutoHideDockContainer.cpp | 60 ++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 047b0e0a4..066921dfa 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -52,7 +52,7 @@ struct AutoHideDockContainerPrivate CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; - CDockWidgetSideTab::SideTabBarArea Area; + CDockWidgetSideTab::SideTabBarArea SideTabBarArea; /** * Private data constructor @@ -90,7 +90,7 @@ struct AutoHideDockContainerPrivate */ QPoint getSimplifiedDockAreaPosition() const { - switch (Area) + switch (SideTabBarArea) { case CDockWidgetSideTab::LeftTop: case CDockWidgetSideTab::LeftBottom: @@ -110,6 +110,29 @@ struct AutoHideDockContainerPrivate return QPoint(); } + + /* + * Convenience function to get dock area with splitter total size + */ + QRect getDockAreaWithSplitterRect() const + { + const auto rect = DockArea->frameGeometry(); + const auto topLeft = rect.topLeft(); + const auto handleSize = _this->handleWidth(); + + if (SideTabBarArea == CDockWidgetSideTab::Bottom) + { + return QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize)); + } + + auto offset = 0; + if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightTop || SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightBottom) + { + offset = handleSize; + } + + return QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height())); + } }; // struct AutoHideDockContainerPrivate //============================================================================ @@ -131,7 +154,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW d(new AutoHideDockContainerPrivate(this)) { d->DockManager = DockManager; - d->Area = area; + d->SideTabBarArea = area; d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); d->DockArea->setAutoHideDockContainer(this); @@ -181,22 +204,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW //============================================================================ void CAutoHideDockContainer::updateMask() { - const auto rect = d->DockArea->frameGeometry(); - const auto topLeft = rect.topLeft(); - const auto handleSize = handleWidth(); - - if (d->Area == CDockWidgetSideTab::Bottom) - { - setMask(QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize))); - return; - } - - auto offset = 0; - if (d->Area == CDockWidgetSideTab::SideTabBarArea::RightTop || d->Area == CDockWidgetSideTab::SideTabBarArea::RightBottom) - { - offset = handleSize; - } - setMask(QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height()))); + setMask(d->getDockAreaWithSplitterRect()); } //============================================================================ @@ -237,7 +245,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer() //============================================================================ CSideTabBar* CAutoHideDockContainer::sideTabBar() const { - return parentContainer()->sideTabBar(d->Area); + return parentContainer()->sideTabBar(d->SideTabBarArea); } //============================================================================ @@ -262,7 +270,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) OldDockArea->removeDockWidget(DockWidget); } d->DockArea->addDockWidget(DockWidget); - d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->Area); + d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); updateSize(); updateMask(); @@ -280,7 +288,7 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) const auto dockSize = static_cast(static_cast(INT_MAX) * SplitterProportion); const auto remainingSize = INT_MAX - dockSize; - switch (d->Area) + switch (d->SideTabBarArea) { case CDockWidgetSideTab::LeftBottom: case CDockWidgetSideTab::LeftTop: @@ -303,7 +311,7 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) //============================================================================ CDockWidgetSideTab::SideTabBarArea CAutoHideDockContainer::sideTabBarArea() const { - return d->Area; + return d->SideTabBarArea; } //============================================================================ @@ -326,7 +334,7 @@ void CAutoHideDockContainer::moveContentsToParent() } else { - parentContainer()->addDockWidget(d->getArea(d->Area), d->DockWidget); + parentContainer()->addDockWidget(d->getArea(d->SideTabBarArea), d->DockWidget); } parentContainer()->removeDockArea(d->DockArea); @@ -503,8 +511,8 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) // ignore the event, because the auto hide overlay should not get collapsed if // user works in it QMouseEvent* me = static_cast(event); - auto pos = d->DockArea->mapFromGlobal(me->globalPos()); - auto rect = d->DockArea->rect().adjusted(-handleWidth(), 0, 0, 0); + auto pos = mapFromGlobal(me->globalPos()); + auto rect = d->getDockAreaWithSplitterRect(); if (rect.contains(pos)) { return QSplitter::eventFilter(watched, event); From 589a62fe15b93216a126498c23b9f3d05b678371 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 13 Oct 2022 15:24:11 +0800 Subject: [PATCH 089/236] update user guide --- doc/user-guide.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/doc/user-guide.md b/doc/user-guide.md index 6f478c842..981826e2e 100644 --- a/doc/user-guide.md +++ b/doc/user-guide.md @@ -622,9 +622,7 @@ Note: Overlay, Pin, and Auto Hide here all refer to the same functionality. ### Setting Configuration Flags -Setting and enabling the overlay feature is similar to setting config flags, but do be aware that it uses a different eOverlayFlag enum and not the eConfigFlag enum. This is only relevant if you call `CDockManager::setConfigFlags` for the `ConfigFlags`, as it would mean you have to call `CDockManager::setConfigFlags` a second time for the `OverlayFlags`. - -Note: The dock areas collapse on losing focus, so the `FocusHighlighting` feature must be enabled for collapsing an overlay to work. Furthermore, widgets that don't have focus (e.g. by setting DockWidgetFocusable to false), will also prevent the dock widget from losing focus. The widgets are still collapsible on clicking the tab, so it's up to you if you would like collapsing the dock view based on losing focus. +Setting and enabling the overlay feature is similar to setting config flags, but do be aware that it uses a different eOverlayFlag enum and not the eConfigFlag enum. This is only relevant if you call `CDockManager::setConfigFlags` for the `ConfigFlags`, as it would mean you have to call `CDockManager::setConfigFlags` a second time for the `AutoHideFlags`. ```c++ CDockManager::setConfigFlags(CDockManager::DefaultAutoHideConfig); @@ -633,9 +631,9 @@ CDockManager::setConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly, true); d->DockManager = new CDockManager(this); ``` -### Adding Overlay Widgets +### Adding Auto Hide Widgets -Adding an overlay widget is similar to adding a dock widget, simply call `dockManager->addOverlayDockWidget`. +Adding an overlay widget is similar to adding a dock widget, simply call `dockManager->addAutoHideDockWidget`. ```c++ d->DockManager = new CDockManager(this); @@ -646,19 +644,19 @@ DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, T See `autohide` example to learn how it works. -### Configuration Flags For Overlay Widgets +### Configuration Flags For Auto Hide Widgets - `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar` -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable `DockContainerHasRightSideBar` and `DockContainerHasBottomSideBar` then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work. - `DockAreaHasAutoHideButton` -> Adds the auto hide button to the title bar of the dock area - `LeftSideBarPrioritizeIconOnly`, `RightSideBarPrioritizeIconOnly`, `BottomSideBarPrioritizeIconOnly` -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable `LeftSideBarPrioritizeIconOnly`, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual. -- `DockAreaOverlayHasTitle` -> Adds the title of the dock window where the title bar would be. -- `DefaultAutoHideConfig` -> Enables `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `DockAreaOverlayHasTitle` +- `AutoHideDockAreaHasTitle` -> Adds the title of the dock window where the title bar would be. +- `DefaultAutoHideConfig` -> Enables `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `AutoHideDockAreaHasTitle` ### Limitations - Currently the `LeftBottom` and `RightBottom` areas can only be added programatically, and not through the pin icon. These are used if you'd like to add a new dock widget separated from the normal dock areas. -- Adding a `DockWidget` (e.g. via `addDockWidget`) to an overlayed `DockArea` that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be overlayed, check first if it's overlayed via `CDockArea::isOverlayed` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). +- Adding a `DockWidget` (e.g. via `addDockWidget`) to an overlayed `DockArea` that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be overlayed, check first if it's overlayed via `CDockArea::isAutoHide` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). ## Styling From 5b3ad7e5db9cfaf5bb752afe9919d109d06c2360 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 13 Oct 2022 15:41:15 +0800 Subject: [PATCH 090/236] fix typo --- src/AutoHideDockContainer.cpp | 2 +- src/AutoHideDockContainer.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 066921dfa..65bb075d6 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -18,7 +18,7 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideDockContainer.h /// \author Syarif Fakhri /// \date 05.09.2022 /// \brief Implementation of CAutoHideDockContainer class diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index fdac6539f..4aea9c653 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -20,7 +20,7 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideDockContainer.h /// \author Syarif Fakhri /// \date 05.09.2022 /// \brief Declaration of CAutoHideDockContainer class From ad0c2103bf36a289a07aa9f9977f5f7b525ff70f Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 16:09:13 +0800 Subject: [PATCH 091/236] fix crash when using widgets that delete on close --- src/AutoHideDockContainer.cpp | 8 +++----- src/DockContainerWidget.cpp | 8 +++++++- src/DockWidget.cpp | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 65bb075d6..83a34feb9 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -196,9 +196,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW updateSize(); parent->registerAutoHideWidget(this); - - d->DockArea->installEventFilter(this); - parent->installEventFilter(this); } //============================================================================ @@ -231,8 +228,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer() ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages - d->DockArea->removeEventFilter(this); - parent()->removeEventFilter(this); + qApp->removeEventFilter(this); if (d->DockManager) { @@ -439,6 +435,8 @@ void CAutoHideDockContainer::collapseView(bool Enable) show(); d->DockArea->show(); d->DockWidget->show(); + updateMask(); + updateSize(); qApp->installEventFilter(this); } } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index fa928e119..eccfec8ed 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1054,9 +1054,10 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, } CDockAreaWidget* DockArea = nullptr; + CAutoHideDockContainer* dockContainer = nullptr; if (!Testing) { - const auto dockContainer = new CAutoHideDockContainer(DockManager, area, _this); + dockContainer = new CAutoHideDockContainer(DockManager, area, _this); if (!dockContainer->restoreState(s, Testing)) { return false; @@ -1108,6 +1109,11 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, DockArea->autoHideDockContainer()->toggleView(!Closed); } + if (dockContainer && !dockContainer->dockWidget()) + { + dockContainer->cleanupAndDelete(); + } + return true; } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 2a90d3d39..0d189a008 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -248,7 +248,7 @@ void DockWidgetPrivate::updateParentDockArea() void DockWidgetPrivate::closeAutoHideDockWidgetsIfNeeded() { - if (_this->dockContainer() && _this->dockContainer()->openedDockWidgets().isEmpty()) + if (_this->dockContainer() && _this->dockContainer()->openedDockWidgets().isEmpty() && !_this->dockManager()->isRestoringState()) { for (auto autoHideWidget : _this->dockContainer()->autoHideWidgets()) { From efb87c868b998305d50aa18e8ce7241eaf9c358c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 16:20:32 +0800 Subject: [PATCH 092/236] update size then mask --- src/AutoHideDockContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 83a34feb9..100e801b3 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -192,8 +192,8 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW } } - updateMask(); updateSize(); + updateMask(); parent->registerAutoHideWidget(this); } @@ -435,8 +435,8 @@ void CAutoHideDockContainer::collapseView(bool Enable) show(); d->DockArea->show(); d->DockWidget->show(); - updateMask(); updateSize(); + updateMask(); qApp->installEventFilter(this); } } From 91190e8744d65467a571339f1a64f36d1f85626b Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 17:47:41 +0800 Subject: [PATCH 093/236] cleaner dock widget side tab click handling --- src/AutoHideDockContainer.cpp | 1 + src/DockWidget.cpp | 8 -------- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 100e801b3..408d383fd 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -437,6 +437,7 @@ void CAutoHideDockContainer::collapseView(bool Enable) d->DockWidget->show(); updateSize(); updateMask(); + d->DockManager->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); } } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 0d189a008..50eaf15fc 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1085,15 +1085,7 @@ void CDockWidget::onDockWidgetSideTabClicked() return; } - autoHideContainer->raise(); autoHideContainer->toggleCollapseState(); - if (autoHideContainer->isVisible()) - { - // d->DockManager->setDockWidgetFocused(this) does not - // de focus the old widget, leading to the auto hide still being visible - // even after clicking outside the auto hide. - setFocus(Qt::ActiveWindowFocusReason); - } } //============================================================================ From ac8cf863a03234d1622ffe07ddd3e26d59e2c1e8 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 21:07:58 +0800 Subject: [PATCH 094/236] remove unused css --- src/stylesheets/default.css | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 7f8d50237..42cf1c14b 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -43,16 +43,6 @@ ads--CDockWidgetSideTab { background: palette(window); } -ads--CDockWidgetSideTab[sideTabBarArea="Left"] { - border-left: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="Right"] { - border-right: 3px solid grey; - border-bottom: 1px solid white; -} - ads--CDockWidget { background: palette(light); border-color: palette(light); From f9b62234b0615dc720953d167a12b9f1445d628b Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 21:13:32 +0800 Subject: [PATCH 095/236] Add top area --- src/AutoHideDockContainer.cpp | 25 +++++++++++++++++- src/DockContainerWidget.cpp | 31 +++++++++++++++-------- src/DockManager.h | 17 +++++++------ src/DockWidgetSideTab.cpp | 11 ++++++-- src/DockWidgetSideTab.h | 1 + src/stylesheets/focus_highlighting.css | 35 +++++++++++++++++++------- 6 files changed, 91 insertions(+), 29 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 408d383fd..0d6f70025 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -80,6 +80,10 @@ struct AutoHideDockContainerPrivate { return BottomDockWidgetArea; } + case CDockWidgetSideTab::Top: + { + return TopDockWidgetArea; + } } return LeftDockWidgetArea; @@ -106,6 +110,10 @@ struct AutoHideDockContainerPrivate { return QPoint(_this->width() / 2, _this->height() - 1); } + case CDockWidgetSideTab::Top: + { + return QPoint(_this->width() / 2, 1); + } } return QPoint(); @@ -125,6 +133,11 @@ struct AutoHideDockContainerPrivate return QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize)); } + if (SideTabBarArea == CDockWidgetSideTab::Top) + { + return QRect(QPoint(topLeft.x(), topLeft.y()), QSize(rect.size().width(), rect.size().height() + handleSize)); + } + auto offset = 0; if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightTop || SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightBottom) { @@ -150,7 +163,7 @@ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const //============================================================================ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : - QSplitter(area == CDockWidgetSideTab::Bottom ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal, parent), + QSplitter((area == CDockWidgetSideTab::Bottom || area == CDockWidgetSideTab::Top) ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal, parent), d(new AutoHideDockContainerPrivate(this)) { d->DockManager = DockManager; @@ -170,6 +183,12 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW switch (area) { + case CDockWidgetSideTab::Top: + { + addWidget(d->DockArea); + addWidget(emptyWidget); + break; + } case CDockWidgetSideTab::LeftBottom: case CDockWidgetSideTab::LeftTop: { @@ -469,6 +488,10 @@ bool CAutoHideDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAr { return CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); } + case CDockWidgetSideTab::Top: + { + return CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar); + } } return true; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index eccfec8ed..77b430430 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1440,7 +1440,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p d->Layout->setContentsMargins(0, 0, 0, 0); d->Layout->setSpacing(0); d->Layout->setColumnStretch(1, 1); - d->Layout->setRowStretch(0, 1); + d->Layout->setRowStretch(1, 1); setLayout(d->Layout); // The function d->newSplitter() accesses the config flags from dock @@ -1523,16 +1523,21 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid //============================================================================ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget) { - // Handle bottom case + // Handle bottom case and top case // It's bottom if the width is wider than the height, and if it's below 50% of the window const auto dockWidgetFrameGeometry = DockAreaWidget->frameGeometry(); const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); - if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height() - && DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() - && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) + if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height()) { - return CDockWidgetSideTab::Bottom; + if (DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) + { + return CDockWidgetSideTab::Bottom; + } + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar)) + { + return CDockWidgetSideTab::Top; + } } // Then handle left and right @@ -2040,7 +2045,7 @@ void CDockContainerWidget::createRootSplitter() return; } d->RootSplitter = d->newSplitter(Qt::Horizontal); - d->Layout->addWidget(d->RootSplitter, 0, 1); // Add it to the center - the 0 and 2 indexes are used for the SideTabBar widgets + d->Layout->addWidget(d->RootSplitter, 1, 1); // Add it to the center - the 0 and 2 indexes are used for the SideTabBar widgets } @@ -2055,7 +2060,7 @@ void CDockContainerWidget::createSideTabBarWidgets() leftLayout->addStretch(1); d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom] = new CSideTabBar(this, Qt::Vertical); leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom]); - d->Layout->addLayout(leftLayout, 0, 0); + d->Layout->addLayout(leftLayout, 1, 0); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) @@ -2066,13 +2071,19 @@ void CDockContainerWidget::createSideTabBarWidgets() rightLayout->addStretch(1); d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom] = new CSideTabBar(this, Qt::Vertical); rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom]); - d->Layout->addLayout(rightLayout, 0, 2); + d->Layout->addLayout(rightLayout, 1, 2); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) { d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 1, 1); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 2, 1); + } + + if (CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar)) + { + d->SideTabBarWidgets[CDockWidgetSideTab::Top] = new CSideTabBar(this, Qt::Horizontal); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Top], 0, 1); } } diff --git a/src/DockManager.h b/src/DockManager.h index e1f23c019..e9599ccf7 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -229,15 +229,18 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget DockContainerHasLeftSideBar = 0x01, //!< If the flag is set left side bar will prioritize showing icons only over text DockContainerHasRightSideBar = 0x02, //!< If the flag is set right side bar will prioritize showing icons only over text DockContainerHasBottomSideBar = 0x04, //!< If the flag is set right side bar will prioritize showing icons only over text - DockAreaHasAutoHideButton = 0x08, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set each container will have a left side bar - RightSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a right side bar - BottomSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set bottom side bar will prioritize showing icons only over text - AutoHideDockAreaHasTitle = 0x80, //!< If the flag is set overlay dock area title bar will show the window title - - DefaultAutoHideConfig = DockContainerHasLeftSideBar + DockContainerHasTopSideBar = 0x08, //!< If the flag is set right side bar will prioritize showing icons only over text + DockAreaHasAutoHideButton = 0x10, //!< If the flag is set each dock area has a auto hide menu button + LeftSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a left side bar + RightSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set each container will have a right side bar + BottomSideBarPrioritizeIconOnly = 0x80, //!< If the flag is set bottom side bar will prioritize showing icons only over text + TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set bottom side bar will prioritize showing icons only over text + AutoHideDockAreaHasTitle = 0x200, //!< If the flag is set overlay dock area title bar will show the window title + + DefaultAutoHideConfig = DockContainerHasLeftSideBar | BottomSideBarPrioritizeIconOnly | TopSideBarPrioritizeIconOnly | DockContainerHasRightSideBar | DockContainerHasBottomSideBar + | DockContainerHasTopSideBar | DockAreaHasAutoHideButton | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars }; diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 630770738..1ee9a7d87 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -106,7 +106,7 @@ struct DockWidgetSideTabPrivate } else if (Orientation == Qt::Horizontal) { - TitleLayout->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing); + TitleLayout->setContentsMargins(Spacing / 2, Spacing, Spacing, Spacing); if (IconLabel) { IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, Spacing / 2); @@ -276,7 +276,7 @@ void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) //============================================================================ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) { - setOrientation(area == Bottom ? Qt::Horizontal : Qt::Vertical); + setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); d->updateContentsMargins(); @@ -304,6 +304,13 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) return; } if (CDockManager::testConfigFlag(CDockManager::BottomSideBarPrioritizeIconOnly) && area == Bottom) + { + d->TitleLabel->hide(); + d->TitleLayout->setContentsMargins(0, 0, 0, 0); + d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing); + return; + } + if (CDockManager::testConfigFlag(CDockManager::TopSideBarPrioritizeIconOnly) && area == Top) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 42ebdcada..3a6e716d5 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -77,6 +77,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ enum SideTabBarArea { + Top, LeftTop, LeftBottom, RightTop, diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 672783cc4..1a6fe77df 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -27,17 +27,22 @@ ads--CDockWidgetSideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab[sideTabBarArea="0"],[sideTabBarArea="1"] { +ads--CDockWidgetSideTab[sideTabBarArea="0"] { + border-top: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="2"],[sideTabBarArea="3"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="4"] { +ads--CDockWidgetSideTab[sideTabBarArea="5"] { border-bottom: 3px solid grey; border-right: 1px solid white; } @@ -120,27 +125,39 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"],:hover[sideTabBarArea="1"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"],:hover[sideTabBarArea="3"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="4"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"],[sideTabBarArea="1"][focused="true"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][focused="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][focused="true"],[sideTabBarArea="2"][focused="true"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="2"][focused="true"],[sideTabBarArea="3"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"][focused="true"],[sideTabBarArea="4"][focused="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="4"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="5"][focused="true"] { border-bottom: 3px solid palette(highlight); } From b0544be068a86dff3f6ac040d2edb10b5e4339a4 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 21:32:05 +0800 Subject: [PATCH 096/236] Added activeTab property --- src/AutoHideDockContainer.cpp | 2 + src/DockWidgetSideTab.cpp | 12 ++++++ src/DockWidgetSideTab.h | 5 +++ src/stylesheets/default.css | 57 ++++++++++++++++++++++++++ src/stylesheets/focus_highlighting.css | 12 +++--- 5 files changed, 82 insertions(+), 6 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 0d6f70025..626b43889 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -459,6 +459,8 @@ void CAutoHideDockContainer::collapseView(bool Enable) d->DockManager->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); } + + d->DockWidget->sideTabWidget()->updateStyle(); } diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 1ee9a7d87..b62ca81a2 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -322,6 +322,18 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) } +//============================================================================ +bool CDockWidgetSideTab::isActiveTab() const +{ + if (d->DockWidget->autoHideDockContainer()) + { + return d->DockWidget->autoHideDockContainer()->isVisible(); + } + + return false; +} + + //============================================================================ CDockWidget* CDockWidgetSideTab::dockWidget() const { diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 3a6e716d5..bb8dc9f7f 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -52,6 +52,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) + Q_PROPERTY(bool activeTab READ isActiveTab) private: DockWidgetSideTabPrivate* d; ///< private data (pimpl) @@ -139,6 +140,10 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ void updateOrientationAndSpacing(SideTabBarArea area); + /** + * Returns true, if this is the active tab. The tab is active if the auto hide widget is visible + */ + bool isActiveTab() const; /** * returns the dock widget this belongs to diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 42cf1c14b..127baed1e 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -41,6 +41,63 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { ads--CDockWidgetSideTab { background: palette(window); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"] { + border-top: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { + border-left: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { + border-right: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"] { + border-bottom: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { + border-bottom: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { + border-bottom: 3px solid palette(highlight); } ads--CDockWidget { diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 1a6fe77df..a24aa9a9d 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -141,27 +141,27 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][focused="true"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][focused="true"],[sideTabBarArea="2"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="3"][focused="true"],[sideTabBarArea="4"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="5"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetTab[focused="true"] { +ads--CDockWidgetTab[activeTab="true"] { background: palette(highlight); border-color: palette(highlight); } From 754a41d11820651b97abf1849119befbec10b62a Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 21:41:39 +0800 Subject: [PATCH 097/236] Formatting and cleanup - Update user-guide.md - Remove incorrect configuration from dock manager.h - Fix spacing --- doc/user-guide.md | 10 +++++----- src/DockManager.h | 2 +- src/DockWidgetSideTab.h | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/user-guide.md b/doc/user-guide.md index 981826e2e..1d6cb178e 100644 --- a/doc/user-guide.md +++ b/doc/user-guide.md @@ -633,7 +633,7 @@ d->DockManager = new CDockManager(this); ### Adding Auto Hide Widgets -Adding an overlay widget is similar to adding a dock widget, simply call `dockManager->addAutoHideDockWidget`. +Adding an auto hide widget is similar to adding a dock widget, simply call `dockManager->addAutoHideDockWidget`. ```c++ d->DockManager = new CDockManager(this); @@ -646,17 +646,17 @@ See `autohide` example to learn how it works. ### Configuration Flags For Auto Hide Widgets -- `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar` -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable `DockContainerHasRightSideBar` and `DockContainerHasBottomSideBar` then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work. +- `DockContainerHasTopSideBar`,`DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar` -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable `DockContainerHasRightSideBar` and `DockContainerHasBottomSideBar` then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work. - `DockAreaHasAutoHideButton` -> Adds the auto hide button to the title bar of the dock area -- `LeftSideBarPrioritizeIconOnly`, `RightSideBarPrioritizeIconOnly`, `BottomSideBarPrioritizeIconOnly` -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable `LeftSideBarPrioritizeIconOnly`, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual. +- `TopSideBarPrioritizeIconOnly`, `LeftSideBarPrioritizeIconOnly`, `RightSideBarPrioritizeIconOnly`, `BottomSideBarPrioritizeIconOnly` -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable `LeftSideBarPrioritizeIconOnly`, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual. - `AutoHideDockAreaHasTitle` -> Adds the title of the dock window where the title bar would be. -- `DefaultAutoHideConfig` -> Enables `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `AutoHideDockAreaHasTitle` +- `DefaultAutoHideConfig` -> Enables `DockContainerHasTopSideBar`, `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `AutoHideDockAreaHasTitle` ### Limitations - Currently the `LeftBottom` and `RightBottom` areas can only be added programatically, and not through the pin icon. These are used if you'd like to add a new dock widget separated from the normal dock areas. -- Adding a `DockWidget` (e.g. via `addDockWidget`) to an overlayed `DockArea` that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be overlayed, check first if it's overlayed via `CDockArea::isAutoHide` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). +- Adding a `DockWidget` (e.g. via `addDockWidget`) to an `DockArea` in an Auto Hide Widget that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be in an auto hidden widget, check first if it's auto hidden via `CDockArea::isAutoHide` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). ## Styling diff --git a/src/DockManager.h b/src/DockManager.h index e9599ccf7..b3e6599e7 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -237,7 +237,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set bottom side bar will prioritize showing icons only over text AutoHideDockAreaHasTitle = 0x200, //!< If the flag is set overlay dock area title bar will show the window title - DefaultAutoHideConfig = DockContainerHasLeftSideBar | BottomSideBarPrioritizeIconOnly | TopSideBarPrioritizeIconOnly + DefaultAutoHideConfig = DockContainerHasLeftSideBar | DockContainerHasRightSideBar | DockContainerHasBottomSideBar | DockContainerHasTopSideBar diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index bb8dc9f7f..6c1d26b2d 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -83,7 +83,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame LeftBottom, RightTop, RightBottom, - Bottom + Bottom }; Q_ENUM(SideTabBarArea) From 4399f6ea29f32aba179b9a2eaaec9c161d699311 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 14 Oct 2022 21:49:53 +0800 Subject: [PATCH 098/236] Update css --- src/stylesheets/default.css | 2 + src/stylesheets/default_linux.css | 63 ++++++++++++++ src/stylesheets/focus_highlighting.css | 90 ++++++++++---------- src/stylesheets/focus_highlighting_linux.css | 78 ++++++++++------- 4 files changed, 157 insertions(+), 76 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 127baed1e..19d8b5885 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -39,6 +39,7 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +/* Side tab styling */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ @@ -99,6 +100,7 @@ ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4 ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { border-bottom: 3px solid palette(highlight); } +/* Side tab styling */ ads--CDockWidget { background: palette(light); diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index f9161f818..2a904026c 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -43,6 +43,69 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +/* Side tab styling */ +ads--CDockWidgetSideTab { + background: palette(window); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"] { + border-top: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { + border-left: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { + border-right: 3px solid grey; + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"] { + border-bottom: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { + border-bottom: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { + border-bottom: 3px solid palette(highlight); +} +/* Side tab styling */ + ads--CDockWidget { background: palette(light); border-color: palette(light); diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index a24aa9a9d..ccab90682 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -22,6 +22,21 @@ ads--CDockWidgetTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } +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)); + /*background: palette(highlight);*/ +} + +ads--CDockWidgetTab QLabel { + color: palette(dark); +} + +ads--CDockWidgetTab[activeTab="true"] QLabel { + color: palette(foreground); +} + +/* Side tab styling */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ @@ -47,20 +62,43 @@ ads--CDockWidgetSideTab[sideTabBarArea="5"] { border-right: 1px solid white; } -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)); - /*background: palette(highlight);*/ +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + border-top: 3px solid palette(highlight); } -ads--CDockWidgetTab QLabel { - color: palette(dark); +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { + border-left: 3px solid palette(highlight); } -ads--CDockWidgetTab[activeTab="true"] QLabel { - color: palette(foreground); +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { + border-bottom: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { + border-left: 3px solid palette(highlight); } +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { + border-bottom: 3px solid palette(highlight); +} +/* Side tab styling */ + ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -125,42 +163,6 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} - ads--CDockWidgetTab[activeTab="true"] { background: palette(highlight); border-color: palette(highlight); diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 594ce6b4b..e32c57a66 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -44,26 +44,69 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } +/* Side tab styling */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab[sideTabBarArea="0"],[sideTabBarArea="1"] { +ads--CDockWidgetSideTab[sideTabBarArea="0"] { + border-top: 3px solid grey; + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="2"],[sideTabBarArea="3"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="4"] { +ads--CDockWidgetSideTab[sideTabBarArea="5"] { border-bottom: 3px solid grey; border-right: 1px solid white; } +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { + border-bottom: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { + border-top: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { + border-left: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { + border-right: 3px solid palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { + border-bottom: 3px solid palette(highlight); +} +/* Side tab styling */ + ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -124,35 +167,6 @@ QScrollArea#dockWidgetScrollArea { /* Focus related styling */ -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"],:hover[sideTabBarArea="1"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"],:hover[sideTabBarArea="3"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="4"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][focused="true"],[sideTabBarArea="1"][focused="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"][focused="true"],[sideTabBarArea="3"][focused="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="4"][focused="true"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetTab[focused="true"] { - background: palette(highlight); - border-color: palette(highlight); -} - ads--CDockWidgetTab[focused="true"]>#tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } From 9f9d9792aa3505d9e160f7e538c7bc215e1c2351 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sat, 15 Oct 2022 14:24:19 +0200 Subject: [PATCH 099/236] Added sideTabBarArea property to CAutoHideDockContainer to improve CSS styling options --- src/AutoHideDockContainer.h | 5 +++-- src/stylesheets/default.css | 24 ++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 4aea9c653..6ba264eda 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -47,12 +47,13 @@ class CSideTabBar; class CDockAreaWidget; class CDockingStateReader; -// Note: This widget must be a QSplitter, inheriting from QWidget and keeping an internal splitter breaks ActiveX widgets +// Note: This widget must be a QSplitter, inheriting from QWidget and keeping an +// internal splitter breaks ActiveX widgets // likely due to layout issues between this widget and the internal splitter class ADS_EXPORT CAutoHideDockContainer : public QSplitter { Q_OBJECT - + Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 7f8d50237..8e813283f 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -74,6 +74,30 @@ QScrollArea#dockWidgetScrollArea { qproperty-iconSize: 16px; } +#autoHideTitleLabel { + padding-left: 4px; +} + +/* +ads--CAutoHideDockContainer::handle { + background: palette(dark); +} + +ads--CAutoHideDockContainer::handle:vertical { + height: 4px; +} + + +ads--CAutoHideDockContainer::handle:horizontal { + width: 4px; +} +*/ + +/*ads--CAutoHideDockContainer[sideTabBarArea="0"]:handle { + border: 1px solid palette(dark); + background: white; +}*/ + #tabCloseButton { margin-top: 2px; background: none; From e3117121cc6f9d16b8d1c68a4224addfb0f61dbf Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 09:52:00 +0200 Subject: [PATCH 100/236] Changed moveContentsToParent() logic when disabling auto dock for a certain widget --- src/AutoHideDockContainer.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 626b43889..24d09413e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -339,19 +339,10 @@ CDockAreaWidget* CAutoHideDockContainer::dockAreaWidget() const void CAutoHideDockContainer::moveContentsToParent() { cleanupAndDelete(); - - const auto position = mapToGlobal(d->getSimplifiedDockAreaPosition()); - - const auto dockAreaWidget = parentContainer()->dockAreaAt(position); - if (dockAreaWidget != nullptr && !dockAreaWidget->containsCentralWidget()) - { - parentContainer()->addDockWidget(CenterDockWidgetArea, d->DockWidget, dockAreaWidget); - } - else - { - parentContainer()->addDockWidget(d->getArea(d->SideTabBarArea), d->DockWidget); - } - + // If we unpin the auto hide tock widget, then we insert it into the same + // location like it had as a auto hide widget. This brings the least surprise + // to the user and he does not have to search where the widget was inserted. + parentContainer()->addDockWidget(d->getArea(d->SideTabBarArea), d->DockWidget); parentContainer()->removeDockArea(d->DockArea); } From bb630ca605f3b26aabd274f71b7a2074dcc7edca Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 09:59:40 +0200 Subject: [PATCH 101/236] Changed toggleAutoHideArea)= logic - only the current dock widget is pinned and not all dock widgets of this area --- src/DockAreaWidget.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 3e7934382..866833aaf 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1100,15 +1100,12 @@ void CDockAreaWidget::closeArea() void CDockAreaWidget::toggleAutoHideArea(bool Enable) { const auto area = dockContainer()->getDockAreaPosition(this); - for (const auto DockWidget : openedDockWidgets()) + const auto DockWidget = currentDockWidget(); + if (Enable == isAutoHide()) { - if (Enable == isAutoHide()) - { - continue; - } - - onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); + return; } + onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); } //============================================================================ From 14312442dba302eddc8626a33f3a437ca80ad542 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 11:34:59 +0200 Subject: [PATCH 102/236] Replaced tab bar areas LeftTop, LeftBottom, RightTop, RightBottom with Left and Right to reduce complexity --- examples/autohide/mainwindow.cpp | 4 ++-- src/AutoHideDockContainer.cpp | 32 +++++++++++--------------------- src/DockAreaWidget.cpp | 2 +- src/DockContainerWidget.cpp | 31 ++++++++++++++----------------- src/DockContainerWidget.h | 2 +- src/DockWidgetSideTab.cpp | 6 +++--- src/DockWidgetSideTab.h | 7 ++----- 7 files changed, 34 insertions(+), 50 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 2a8f06a4b..acde5674f 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -47,7 +47,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); TableDockWidget->setDefaultAutoHideDockProportion(0.5); - DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 24d09413e..3206380c7 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -66,13 +66,11 @@ struct AutoHideDockContainerPrivate { switch (area) { - case CDockWidgetSideTab::LeftBottom: - case CDockWidgetSideTab::LeftTop: + case CDockWidgetSideTab::Left: { return LeftDockWidgetArea; } - case CDockWidgetSideTab::RightBottom: - case CDockWidgetSideTab::RightTop: + case CDockWidgetSideTab::Right: { return RightDockWidgetArea; } @@ -96,13 +94,11 @@ struct AutoHideDockContainerPrivate { switch (SideTabBarArea) { - case CDockWidgetSideTab::LeftTop: - case CDockWidgetSideTab::LeftBottom: + case CDockWidgetSideTab::Left: { return QPoint(1, _this->height() / 2); } - case CDockWidgetSideTab::RightTop: - case CDockWidgetSideTab::RightBottom: + case CDockWidgetSideTab::Right: { return QPoint(_this->width() - 1, _this->height() / 2); } @@ -139,7 +135,7 @@ struct AutoHideDockContainerPrivate } auto offset = 0; - if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightTop || SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::RightBottom) + if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::Right) { offset = handleSize; } @@ -189,15 +185,13 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW addWidget(emptyWidget); break; } - case CDockWidgetSideTab::LeftBottom: - case CDockWidgetSideTab::LeftTop: + case CDockWidgetSideTab::Left: { addWidget(d->DockArea); addWidget(emptyWidget); break; } - case CDockWidgetSideTab::RightBottom: - case CDockWidgetSideTab::RightTop: + case CDockWidgetSideTab::Right: { addWidget(emptyWidget); addWidget(d->DockArea); @@ -305,14 +299,12 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) const auto remainingSize = INT_MAX - dockSize; switch (d->SideTabBarArea) { - case CDockWidgetSideTab::LeftBottom: - case CDockWidgetSideTab::LeftTop: + case CDockWidgetSideTab::Left: { setSizes({ dockSize, remainingSize }); break; } - case CDockWidgetSideTab::RightBottom: - case CDockWidgetSideTab::RightTop: + case CDockWidgetSideTab::Right: case CDockWidgetSideTab::Bottom: { setSizes({ remainingSize, dockSize }); @@ -467,13 +459,11 @@ bool CAutoHideDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarAr { switch (area) { - case CDockWidgetSideTab::LeftBottom: - case CDockWidgetSideTab::LeftTop: + case CDockWidgetSideTab::Left: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); } - case CDockWidgetSideTab::RightBottom: - case CDockWidgetSideTab::RightTop: + case CDockWidgetSideTab::Right: { return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 866833aaf..2f2c9fbdf 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1099,7 +1099,7 @@ void CDockAreaWidget::closeArea() //============================================================================ void CDockAreaWidget::toggleAutoHideArea(bool Enable) { - const auto area = dockContainer()->getDockAreaPosition(this); + const auto area = dockContainer()->calculateSideTabBarArea(this); const auto DockWidget = currentDockWidget(); if (Enable == isAutoHide()) { diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 77b430430..9d7c537d0 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1520,8 +1520,9 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid return dockContainer; } + //============================================================================ -CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDockAreaWidget* DockAreaWidget) +CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) { // Handle bottom case and top case // It's bottom if the width is wider than the height, and if it's below 50% of the window @@ -1542,39 +1543,39 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::getDockAreaPosition(CDo // Then handle left and right const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.center()); - const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::LeftTop : CDockWidgetSideTab::RightTop; - if (calculatedPosition == CDockWidgetSideTab::RightTop) + const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::Left : CDockWidgetSideTab::Right; + if (calculatedPosition == CDockWidgetSideTab::Right) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - return CDockWidgetSideTab::RightTop; + return CDockWidgetSideTab::Right; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return CDockWidgetSideTab::LeftTop; + return CDockWidgetSideTab::Left; } return CDockWidgetSideTab::Bottom; } - if (calculatedPosition == CDockWidgetSideTab::LeftTop) + if (calculatedPosition == CDockWidgetSideTab::Left) { if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { - return CDockWidgetSideTab::LeftTop; + return CDockWidgetSideTab::Left; } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { - return CDockWidgetSideTab::RightTop; + return CDockWidgetSideTab::Right; } return CDockWidgetSideTab::Bottom; } Q_ASSERT_X(false, "CDockContainerWidget::getDockAreaPosition", "Unhandled branch. All positions should be accounted for."); - return CDockWidgetSideTab::LeftTop; + return CDockWidgetSideTab::Left; } @@ -2055,22 +2056,18 @@ void CDockContainerWidget::createSideTabBarWidgets() if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { auto leftLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::LeftTop] = new CSideTabBar(this, Qt::Vertical); - leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::LeftTop]); + d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); + leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left]); leftLayout->addStretch(1); - d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom] = new CSideTabBar(this, Qt::Vertical); - leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::LeftBottom]); d->Layout->addLayout(leftLayout, 1, 0); } if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { auto rightLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::RightTop] = new CSideTabBar(this, Qt::Vertical); - rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::RightTop]); + d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); + rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right]); rightLayout->addStretch(1); - d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom] = new CSideTabBar(this, Qt::Vertical); - rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::RightBottom]); d->Layout->addLayout(rightLayout, 1, 2); } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 63e1d6de2..a26e7e29b 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -220,7 +220,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Get's the auto hide dock side tab bar area based on the dock area widget position */ - CDockWidgetSideTab::SideTabBarArea getDockAreaPosition(CDockAreaWidget* DockAreaWidget); + CDockWidgetSideTab::SideTabBarArea calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget); /** * Removes dockwidget diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index b62ca81a2..eafe96b67 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -216,7 +216,7 @@ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const return dockAreaWidget->autoHideDockContainer()->sideTabBarArea(); } - return LeftTop; + return Left; } @@ -289,14 +289,14 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) QFontMetrics fm(d->TitleLabel->font()); int Spacing = qRound(fm.height() / 2.0); - if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && (area == LeftTop || area == LeftBottom)) + if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); return; } - if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && (area == RightTop || area == RightBottom)) + if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 6c1d26b2d..76560e2ef 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -79,13 +79,10 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame enum SideTabBarArea { Top, - LeftTop, - LeftBottom, - RightTop, - RightBottom, + Left, + Right, Bottom }; - Q_ENUM(SideTabBarArea) /** From ffe6eccb05f75bc6b518651c13c918e35f9d8474 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 14:22:12 +0200 Subject: [PATCH 103/236] Improved logic for finding the auto hide side location --- src/DockAreaTitleBar.cpp | 9 ++- src/DockAreaTitleBar.h | 2 +- src/DockContainerWidget.cpp | 137 +++++++++++++++++++++++++----------- src/DockContainerWidget.h | 5 ++ 4 files changed, 105 insertions(+), 48 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index a86e82dae..ff0ce6ef9 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -195,13 +195,11 @@ void DockAreaTitleBarPrivate::createButtons() AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); - AutoHideButton->setCheckable(true); - AutoHideButton->setChecked(false); internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); Layout->addWidget(AutoHideButton, 0); - _this->connect(AutoHideButton, SIGNAL(toggled(bool)), SLOT(onAutoHideButtonClicked(bool))); + _this->connect(AutoHideButton, SIGNAL(clicked()), SLOT(onAutoHideButtonClicked())); // Close button CloseButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasCloseButton)); @@ -486,11 +484,12 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ -void CDockAreaTitleBar::onAutoHideButtonClicked(bool Checked) +void CDockAreaTitleBar::onAutoHideButtonClicked() { + qDebug() << "CDockAreaTitleBar::onAutoHideButtonClicked()"; if (d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)) { - d->DockArea->toggleAutoHideArea(Checked); + d->DockArea->toggleAutoHideArea(!d->DockArea->isAutoHide()); } } diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 0650ae817..5ccdc4a35 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -61,7 +61,7 @@ private Q_SLOTS: void onUndockButtonClicked(); void onTabsMenuActionTriggered(QAction* Action); void onCurrentTabChanged(int Index); - void onAutoHideButtonClicked(bool Checked); + void onAutoHideButtonClicked(); protected: /** diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 9d7c537d0..70e481db4 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1521,62 +1521,103 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid } +enum eBorderLocation +{ + BorderNone = 0, + BorderLeft = 0x01, + BorderRight = 0x02, + BorderTop = 0x04, + BorderBottom = 0x08, + BorderVertical = BorderLeft | BorderRight, + BorderHorizontal = BorderTop | BorderBottom, + BorderTopLeft = BorderTop | BorderLeft, + BorderTopRight = BorderTop | BorderRight, + BorderBottomLeft = BorderBottom | BorderLeft, + BorderBottomRight = BorderBottom | BorderRight, + BorderVerticalBottom = BorderVertical | BorderBottom, + BorderVerticalTop = BorderVertical | BorderTop, + BorderHorizontalLeft = BorderHorizontal | BorderLeft, + BorderHorizontalRight = BorderHorizontal | BorderRight, + BorderAll = BorderVertical | BorderHorizontal +}; + + //============================================================================ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) { - // Handle bottom case and top case - // It's bottom if the width is wider than the height, and if it's below 50% of the window - const auto dockWidgetFrameGeometry = DockAreaWidget->frameGeometry(); - const auto splitterCenter = rootSplitter()->mapToGlobal(rootSplitter()->frameGeometry().center()); - if (dockWidgetFrameGeometry.width() > dockWidgetFrameGeometry.height()) + auto DockMgrRect = d->DockManager->contentRect(); + int borders = BorderNone; // contains all borders that are touched by the dock ware + auto DockAreaTopLeft = DockAreaWidget->mapTo(d->DockManager, DockAreaWidget->rect().topLeft()); + auto DockAreaRect = DockAreaWidget->rect(); + DockAreaRect.moveTo(DockAreaTopLeft); + const qreal aspectRatio = DockAreaRect.width() / (qMax(1, DockAreaRect.height()) * 1.0); + const qreal sizeRatio = (qreal)DockMgrRect.width() / DockAreaRect.width(); + static const int MinBorderDistance = 16; + bool HorizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0); + + // measure border distances - a distance less than 16 px means we touch the + // border + int BorderDistance[4]; + int Distance = qAbs(DockMgrRect.topLeft().y() - DockAreaRect.topLeft().y()); + BorderDistance[CDockWidgetSideTab::Top] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[CDockWidgetSideTab::Top]) { - if (DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.topLeft()).y() > splitterCenter.y() && CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) - { - return CDockWidgetSideTab::Bottom; - } - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar)) - { - return CDockWidgetSideTab::Top; - } + borders |= BorderTop; } - - // Then handle left and right - const auto dockWidgetCenter = DockAreaWidget->mapToGlobal(dockWidgetFrameGeometry.center()); - const auto calculatedPosition = dockWidgetCenter.x() <= splitterCenter.x() ? CDockWidgetSideTab::Left : CDockWidgetSideTab::Right; - if (calculatedPosition == CDockWidgetSideTab::Right) + qDebug() << "BorderDistance[CDockWidgetSideTab::Top] " << BorderDistance[CDockWidgetSideTab::Top]; + Distance = qAbs(DockMgrRect.bottomRight().y() - DockAreaRect.bottomRight().y()); + BorderDistance[CDockWidgetSideTab::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[CDockWidgetSideTab::Bottom]) { - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) - { - return CDockWidgetSideTab::Right; - } - - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) - { - return CDockWidgetSideTab::Left; - } - - return CDockWidgetSideTab::Bottom; + borders |= BorderBottom; + } + qDebug() << "BorderDistance[CDockWidgetSideTab::Bottom] " << BorderDistance[CDockWidgetSideTab::Bottom]; + Distance = qAbs(DockMgrRect.topLeft().x() - DockAreaRect.topLeft().x()); + BorderDistance[CDockWidgetSideTab::Left] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[CDockWidgetSideTab::Left]) + { + borders |= BorderLeft; } + qDebug() << "BorderDistance[CDockWidgetSideTab::Left] " << BorderDistance[CDockWidgetSideTab::Left]; + Distance = qAbs(DockMgrRect.bottomRight().x() - DockAreaRect.bottomRight().x()); + BorderDistance[CDockWidgetSideTab::Right] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[CDockWidgetSideTab::Right]) + { + borders |= BorderRight; + } + qDebug() << "BorderDistance[CDockWidgetSideTab::Right] " << BorderDistance[CDockWidgetSideTab::Right]; - if (calculatedPosition == CDockWidgetSideTab::Left) + auto SideTab = CDockWidgetSideTab::Right; + switch (borders) { - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) - { - return CDockWidgetSideTab::Left; - } + // 1. It's touching all borders + case BorderAll: SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Right; break; - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) - { - return CDockWidgetSideTab::Right; - } + // 2. It's touching 3 borders + case BorderVerticalBottom : SideTab = CDockWidgetSideTab::Bottom; break; + case BorderVerticalTop : SideTab = CDockWidgetSideTab::Top; break; + case BorderHorizontalLeft: SideTab = CDockWidgetSideTab::Left; break; + case BorderHorizontalRight: SideTab = CDockWidgetSideTab::Right; break; - return CDockWidgetSideTab::Bottom; - } + // 3. Its touching horizontal or vertical borders + case BorderVertical : SideTab = CDockWidgetSideTab::Bottom; break; + case BorderHorizontal: SideTab = CDockWidgetSideTab::Right; break; - Q_ASSERT_X(false, "CDockContainerWidget::getDockAreaPosition", "Unhandled branch. All positions should be accounted for."); - return CDockWidgetSideTab::Left; + // 4. Its in a corner + case BorderTopLeft : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Top : CDockWidgetSideTab::Left; break; + case BorderTopRight : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Top : CDockWidgetSideTab::Right; break; + case BorderBottomLeft : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Left; break; + case BorderBottomRight : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Right; break; + + // 5 Ists touching only one border + case BorderLeft: SideTab = CDockWidgetSideTab::Left; break; + case BorderRight: SideTab = CDockWidgetSideTab::Right; break; + case BorderTop: SideTab = CDockWidgetSideTab::Top; break; + case BorderBottom: SideTab = CDockWidgetSideTab::Bottom; break; + } + return SideTab; } //============================================================================ @@ -2233,6 +2274,18 @@ CSideTabBar* CDockContainerWidget::sideTabBar(CDockWidgetSideTab::SideTabBarArea { return d->SideTabBarWidgets[area]; } + + +//============================================================================ +QRect CDockContainerWidget::contentRect() +{ + if (!d->RootSplitter) + { + return QRect(); + } + + return d->RootSplitter->geometry(); +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index a26e7e29b..005d37a0c 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -328,6 +328,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ QList autoHideWidgets() const; + /** + * Returns the content rectangle without the autohide side bars + */ + QRect contentRect(); + Q_SIGNALS: /** * This signal is emitted if one or multiple dock areas has been added to From 96a5443a0251f68b8317dc4c9c573408a96bc0f3 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 14:52:53 +0200 Subject: [PATCH 104/236] Added alternative auto hide button svg icon and modified stylesheet to show pinned icon for autohide widgets --- src/ads.qrc | 2 ++ src/images/vs-pin-button-pinned.svg | 2 ++ src/images/vs-pin-button.svg | 2 ++ src/stylesheets/default.css | 8 +++++++- src/stylesheets/default_linux.css | 8 +++++++- src/stylesheets/focus_highlighting.css | 8 +++++++- src/stylesheets/focus_highlighting_linux.css | 8 +++++++- 7 files changed, 34 insertions(+), 4 deletions(-) create mode 100644 src/images/vs-pin-button-pinned.svg create mode 100644 src/images/vs-pin-button.svg diff --git a/src/ads.qrc b/src/ads.qrc index 4068d7ba2..48ff5cca8 100644 --- a/src/ads.qrc +++ b/src/ads.qrc @@ -15,5 +15,7 @@ images/maximize-button-focused.svg images/restore-button.svg images/restore-button-focused.svg + images/vs-pin-button.svg + images/vs-pin-button-pinned.svg diff --git a/src/images/vs-pin-button-pinned.svg b/src/images/vs-pin-button-pinned.svg new file mode 100644 index 000000000..dfb98a88d --- /dev/null +++ b/src/images/vs-pin-button-pinned.svg @@ -0,0 +1,2 @@ + + diff --git a/src/images/vs-pin-button.svg b/src/images/vs-pin-button.svg new file mode 100644 index 000000000..d93a70117 --- /dev/null +++ b/src/images/vs-pin-button.svg @@ -0,0 +1,2 @@ + + diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index eaf6b2ddf..789062951 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -119,7 +119,13 @@ QScrollArea#dockWidgetScrollArea { } #dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); qproperty-iconSize: 16px; } diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index 2a904026c..e92531e27 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -123,7 +123,13 @@ QScrollArea#dockWidgetScrollArea { } #dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); qproperty-iconSize: 16px; } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index ccab90682..84df17e53 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -139,7 +139,13 @@ QScrollArea#dockWidgetScrollArea { } #dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); qproperty-iconSize: 16px; } diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index e32c57a66..140d6d72c 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -136,7 +136,13 @@ QScrollArea#dockWidgetScrollArea { } #dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/pin-button.svg); + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); qproperty-iconSize: 16px; } From 90b92900a1ddf1d36d86e1ef6804e71dbe96c054 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 17:41:56 +0200 Subject: [PATCH 105/236] Move autohide related CSS into a separate block to have all settings in one place --- src/stylesheets/default.css | 175 ++++++++++++++++++------------------ 1 file changed, 89 insertions(+), 86 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 789062951..10eac4ac0 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -17,6 +17,7 @@ ads--CDockAreaWidget { border: 1px solid white; } + ads--CDockWidgetTab { background: palette(window); border-color: palette(light); @@ -39,98 +40,130 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/* Side tab styling */ + +ads--CDockWidget { + background: palette(light); + border-color: palette(light); + border-style: solid; + border-width: 1px 0 0 0; +} + +ads--CTitleBarButton { + padding: 0px 0px; +} + +QScrollArea#dockWidgetScrollArea { + padding: 0px; + border: none; +} + +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + + +#tabCloseButton { + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#tabCloseButton:hover { + border: 1px solid rgba(0, 0, 0, 32); + background: rgba(0, 0, 0, 16); +} + +#tabCloseButton:pressed { + background: rgba(0, 0, 0, 32); +} + +#tabsMenuButton::menu-indicator { + image: none; +} + +#tabsMenuButton { + qproperty-icon: url(:/ads/images/tabs-menu-button.svg); + qproperty-iconSize: 16px; +} + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + + +/*----------------------------------------------------------------------------- + * Styling of auto hide functionality + *---------------------------------------------------------------------------- + */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-top: 3px solid grey; border-right: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { - border-left: 3px solid grey; +ads--CDockWidgetSideTab[sideTabBarArea="1"] { border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { - border-right: 3px solid grey; +ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="5"] { - border-bottom: 3px solid grey; +ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-right: 1px solid white; } ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { - border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { - border-right: 3px solid palette(highlight); -} +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { -ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { - border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { - border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} -/* Side tab styling */ +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { -ads--CDockWidget { - background: palette(light); - border-color: palette(light); - border-style: solid; - border-width: 1px 0 0 0; } -ads--CTitleBarButton { - padding: 0px 0px; -} +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { -QScrollArea#dockWidgetScrollArea { - padding: 0px; - border: none; } -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { + } -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); - qproperty-iconSize: 16px; +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { + } -#autoHideTitleLabel { - padding-left: 4px; +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { + } /* @@ -153,42 +186,12 @@ ads--CAutoHideDockContainer::handle:horizontal { background: white; }*/ -#tabCloseButton { - margin-top: 2px; - background: none; - border: none; - padding: 0px -2px; - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#tabCloseButton:hover { - border: 1px solid rgba(0, 0, 0, 32); - background: rgba(0, 0, 0, 16); -} - -#tabCloseButton:pressed { - background: rgba(0, 0, 0, 32); -} - -#tabsMenuButton::menu-indicator { - image: none; -} - -#tabsMenuButton { - qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconSize: 16px; -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); qproperty-iconSize: 16px; } -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; +#autoHideTitleLabel { + padding-left: 4px; } From 60e0201060e530ef7a7b0d9f8bbdc538bf4c4fed Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 17 Oct 2022 18:16:20 +0200 Subject: [PATCH 106/236] Added new auto hide config flag CDockManager::AutoHideButtonTogglesArea --- src/DockAreaWidget.cpp | 24 ++++++++++++++++++++---- src/DockManager.h | 17 +++++++++-------- 2 files changed, 29 insertions(+), 12 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 2f2c9fbdf..f23138f90 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1100,12 +1100,28 @@ void CDockAreaWidget::closeArea() void CDockAreaWidget::toggleAutoHideArea(bool Enable) { const auto area = dockContainer()->calculateSideTabBarArea(this); - const auto DockWidget = currentDockWidget(); - if (Enable == isAutoHide()) + + if (dockManager()->testConfigFlag(CDockManager::AutoHideButtonTogglesArea)) { - return; + 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); } - onAutoHideToggleRequested(DockWidget, !isAutoHide(), area); } //============================================================================ diff --git a/src/DockManager.h b/src/DockManager.h index b3e6599e7..a378486df 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -226,16 +226,17 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget enum eAutoHideFlag { - DockContainerHasLeftSideBar = 0x01, //!< If the flag is set left side bar will prioritize showing icons only over text - DockContainerHasRightSideBar = 0x02, //!< If the flag is set right side bar will prioritize showing icons only over text - DockContainerHasBottomSideBar = 0x04, //!< If the flag is set right side bar will prioritize showing icons only over text - DockContainerHasTopSideBar = 0x08, //!< If the flag is set right side bar will prioritize showing icons only over text + DockContainerHasLeftSideBar = 0x01, //!< If the flag is set the dock manager will have a left side bar + DockContainerHasRightSideBar = 0x02, //!< If the flag is set the dock manager will have a right side bar + DockContainerHasBottomSideBar = 0x04, //!< If the flag is set the dock manager will have a bottom side bar + DockContainerHasTopSideBar = 0x08, //!< If the flag is set the dock manager will have a top side bar DockAreaHasAutoHideButton = 0x10, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set each container will have a left side bar - RightSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set each container will have a right side bar - BottomSideBarPrioritizeIconOnly = 0x80, //!< If the flag is set bottom side bar will prioritize showing icons only over text - TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set bottom side bar will prioritize showing icons only over text + LeftSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set left side bar will prioritize showing icons only over text + RightSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set right side bar will prioritize showing icons only over text + BottomSideBarPrioritizeIconOnly = 0x80,//!< If the flag is set bottom side bar will prioritize showing icons only over text + TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set top side bar will prioritize showing icons only over text AutoHideDockAreaHasTitle = 0x200, //!< If the flag is set overlay dock area title bar will show the window title + AutoHideButtonTogglesArea = 0x400, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled DefaultAutoHideConfig = DockContainerHasLeftSideBar | DockContainerHasRightSideBar From fde80071746149b54f83e15513d73a5441c75fb8 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 18 Oct 2022 10:22:56 +0800 Subject: [PATCH 107/236] reduce margin a little bit for the horizontal component --- src/DockWidgetSideTab.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index eafe96b67..2f483f889 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -106,7 +106,7 @@ struct DockWidgetSideTabPrivate } else if (Orientation == Qt::Horizontal) { - TitleLayout->setContentsMargins(Spacing / 2, Spacing, Spacing, Spacing); + TitleLayout->setContentsMargins(Spacing / 2, Spacing, Spacing, Spacing / 2); if (IconLabel) { IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, Spacing / 2); From 1c6968525703a138440c694d74acbe313e52d29c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 18 Oct 2022 10:33:03 +0800 Subject: [PATCH 108/236] Update css --- src/stylesheets/default.css | 24 ++++++++--------- src/stylesheets/default_linux.css | 28 +++++++++----------- src/stylesheets/focus_highlighting.css | 28 +++++++++----------- src/stylesheets/focus_highlighting_linux.css | 28 +++++++++----------- 4 files changed, 51 insertions(+), 57 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 10eac4ac0..93c7971e3 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -115,55 +115,55 @@ ads--CDockWidgetSideTab { } ads--CDockWidgetSideTab[sideTabBarArea="0"] { + border-top: 3px solid grey; border-right: 1px solid white; } ads--CDockWidgetSideTab[sideTabBarArea="1"] { + border-left: 3px solid grey; border-bottom: 1px solid white; } ads--CDockWidgetSideTab[sideTabBarArea="2"] { + border-right: 3px solid grey; border-bottom: 1px solid white; } ads--CDockWidgetSideTab[sideTabBarArea="3"] { + border-bottom: 3px solid grey; border-right: 1px solid white; } ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - + border-top: 3px solid palette(highlight); } ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { - + border-left: 3px solid palette(highlight); } ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - + border-right: 3px solid palette(highlight); } ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { - -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - + border-bottom: 3px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - + border-top: 3px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { - + border-left: 3px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - + border-right: 3px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { - + border-bottom: 3px solid palette(highlight); } /* diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index e92531e27..19dfd4c64 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -43,7 +43,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/* Side tab styling */ +/*----------------------------------------------------------------------------- + * Styling of auto hide functionality + *---------------------------------------------------------------------------- + */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ @@ -54,17 +57,17 @@ ads--CDockWidgetSideTab[sideTabBarArea="0"] { border-right: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="5"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-bottom: 3px solid grey; border-right: 1px solid white; } @@ -73,38 +76,33 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 3px solid palette(highlight); } -/* Side tab styling */ ads--CDockWidget { background: palette(light); diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 84df17e53..cb1576262 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -36,7 +36,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/* Side tab styling */ +/*----------------------------------------------------------------------------- + * Styling of auto hide functionality + *---------------------------------------------------------------------------- + */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ @@ -47,17 +50,17 @@ ads--CDockWidgetSideTab[sideTabBarArea="0"] { border-right: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="5"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-bottom: 3px solid grey; border-right: 1px solid white; } @@ -66,38 +69,33 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 3px solid palette(highlight); } -/* Side tab styling */ ads--CDockWidget { background: palette(light); diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 140d6d72c..5c9e2d95c 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -44,7 +44,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/* Side tab styling */ +/*----------------------------------------------------------------------------- + * Styling of auto hide functionality + *---------------------------------------------------------------------------- + */ ads--CDockWidgetSideTab { background: palette(window); qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ @@ -55,17 +58,17 @@ ads--CDockWidgetSideTab[sideTabBarArea="0"] { border-right: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="1"],[sideTabBarArea="2"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"] { border-left: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="3"],[sideTabBarArea="4"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-right: 3px solid grey; border-bottom: 1px solid white; } -ads--CDockWidgetSideTab[sideTabBarArea="5"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-bottom: 3px solid grey; border-right: 1px solid white; } @@ -74,38 +77,33 @@ ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"],:hover[sideTabBarArea="2"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"],:hover[sideTabBarArea="4"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="5"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { border-bottom: 3px solid palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { border-top: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"],[sideTabBarArea="2"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { border-left: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"],[sideTabBarArea="4"][focused="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { border-right: 3px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="5"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 3px solid palette(highlight); } -/* Side tab styling */ ads--CDockWidget { background: palette(light); From 118e79e7ecb75f85d50459a8518332b60f8b41dc Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 18 Oct 2022 10:33:35 +0800 Subject: [PATCH 109/236] Remove config flag --- src/AutoHideDockContainer.cpp | 28 --------------------- src/AutoHideDockContainer.h | 5 ---- src/DockAreaTitleBar.cpp | 3 +-- src/DockContainerWidget.cpp | 47 +++++++---------------------------- src/DockManager.h | 26 +++++++------------ 5 files changed, 19 insertions(+), 90 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 3206380c7..b47bfe32b 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -453,34 +453,6 @@ void CAutoHideDockContainer::toggleCollapseState() collapseView(isVisible()); } - -//============================================================================ -bool CAutoHideDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) -{ - switch (area) - { - case CDockWidgetSideTab::Left: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); - } - case CDockWidgetSideTab::Right: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); - } - case CDockWidgetSideTab::Bottom: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); - } - case CDockWidgetSideTab::Top: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar); - } - } - - return true; -} - - //============================================================================ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) { diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 6ba264eda..7aa90f5b8 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -152,11 +152,6 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter * Toggles the current collapse state */ void toggleCollapseState(); - - /* - * Convenience function fr determining if area exists in config - */ - static bool areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area); }; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index ff0ce6ef9..9dd36417b 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -191,8 +191,7 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); // AutoHide Button - const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar) || testConfigFlag(CDockManager::DockContainerHasBottomSideBar); - AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); + AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton)); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 70e481db4..0fe88c973 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1048,11 +1048,6 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " << CurrentDockWidget); - if (!CAutoHideDockContainer::areaExistsInConfig(area)) - { - return false; - } - CDockAreaWidget* DockArea = nullptr; CAutoHideDockContainer* dockContainer = nullptr; if (!Testing) @@ -1503,12 +1498,6 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid { DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager } - if (!CAutoHideDockContainer::areaExistsInConfig(area)) - { - Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", - "Requested area does not exist in config"); - return nullptr; - } DockWidget->sideTabWidget()->updateOrientationAndSpacing(area); sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); @@ -2094,35 +2083,17 @@ void CDockContainerWidget::createRootSplitter() //============================================================================ void CDockContainerWidget::createSideTabBarWidgets() { - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) - { - auto leftLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); - leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left]); - leftLayout->addStretch(1); - d->Layout->addLayout(leftLayout, 1, 0); - } - - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) - { - auto rightLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); - rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right]); - rightLayout->addStretch(1); - d->Layout->addLayout(rightLayout, 1, 2); - } + d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left], 1, 0); + + d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right],1,2); - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) - { - d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 2, 1); - } + d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 2, 1); - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar)) - { - d->SideTabBarWidgets[CDockWidgetSideTab::Top] = new CSideTabBar(this, Qt::Horizontal); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Top], 0, 1); - } + d->SideTabBarWidgets[CDockWidgetSideTab::Top] = new CSideTabBar(this, Qt::Horizontal); + d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Top], 0, 1); } diff --git a/src/DockManager.h b/src/DockManager.h index a378486df..83f1e4565 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -226,23 +226,15 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget enum eAutoHideFlag { - DockContainerHasLeftSideBar = 0x01, //!< If the flag is set the dock manager will have a left side bar - DockContainerHasRightSideBar = 0x02, //!< If the flag is set the dock manager will have a right side bar - DockContainerHasBottomSideBar = 0x04, //!< If the flag is set the dock manager will have a bottom side bar - DockContainerHasTopSideBar = 0x08, //!< If the flag is set the dock manager will have a top side bar - DockAreaHasAutoHideButton = 0x10, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set left side bar will prioritize showing icons only over text - RightSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set right side bar will prioritize showing icons only over text - BottomSideBarPrioritizeIconOnly = 0x80,//!< If the flag is set bottom side bar will prioritize showing icons only over text - TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set top side bar will prioritize showing icons only over text - AutoHideDockAreaHasTitle = 0x200, //!< If the flag is set overlay dock area title bar will show the window title - AutoHideButtonTogglesArea = 0x400, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled - - DefaultAutoHideConfig = DockContainerHasLeftSideBar - | DockContainerHasRightSideBar - | DockContainerHasBottomSideBar - | DockContainerHasTopSideBar - | DockAreaHasAutoHideButton + DockAreaHasAutoHideButton = 0x01, //!< If the flag is set each dock area has a auto hide menu button + LeftSideBarPrioritizeIconOnly = 0x02, //!< If the flag is set left side bar will prioritize showing icons only over text + RightSideBarPrioritizeIconOnly = 0x04, //!< If the flag is set right side bar will prioritize showing icons only over text + BottomSideBarPrioritizeIconOnly = 0x08,//!< If the flag is set bottom side bar will prioritize showing icons only over text + TopSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set top side bar will prioritize showing icons only over text + AutoHideDockAreaHasTitle = 0x20, //!< If the flag is set overlay dock area title bar will show the window title + AutoHideButtonTogglesArea = 0x40, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled + + DefaultAutoHideConfig = DockAreaHasAutoHideButton | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars }; Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) From d83ec7c66fe4d34cb35e1f0fe1f386a2c7088bb4 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 18 Oct 2022 17:21:10 +0800 Subject: [PATCH 110/236] Add config to make auto hide button optionally checkable for styling purposes --- src/DockAreaTitleBar.cpp | 2 ++ src/DockManager.h | 1 + 2 files changed, 3 insertions(+) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 9dd36417b..a6e97ba3d 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -197,6 +197,8 @@ void DockAreaTitleBarPrivate::createButtons() internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); + AutoHideButton->setCheckable(testConfigFlag(CDockManager::AutoHideButtonCheckable)); + AutoHideButton->setChecked(false); Layout->addWidget(AutoHideButton, 0); _this->connect(AutoHideButton, SIGNAL(clicked()), SLOT(onAutoHideButtonClicked())); diff --git a/src/DockManager.h b/src/DockManager.h index 83f1e4565..3cc9e71af 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -233,6 +233,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget TopSideBarPrioritizeIconOnly = 0x10, //!< If the flag is set top side bar will prioritize showing icons only over text AutoHideDockAreaHasTitle = 0x20, //!< If the flag is set overlay dock area title bar will show the window title AutoHideButtonTogglesArea = 0x40, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled + AutoHideButtonCheckable = 0x80, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. DefaultAutoHideConfig = DockAreaHasAutoHideButton | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars From 0cbc810a5afe0c7c08e8d321d2282f26c66d9553 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 18 Oct 2022 15:29:31 +0200 Subject: [PATCH 111/236] Renamed SideTabIconLabel - added C prefix CSideTabIconLabel --- src/DockWidgetSideTab.cpp | 21 +++++++++++---------- src/DockWidgetSideTab.h | 7 ++++--- src/stylesheets/default.css | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index eafe96b67..d3a7a1d78 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -57,7 +57,7 @@ struct DockWidgetSideTabPrivate CSideTabBar* SideTabBar; QSize IconSize; Qt::Orientation Orientation{Qt::Vertical}; - SideTabIconLabel* IconLabel = nullptr; + CSideTabIconLabel* IconLabel = nullptr; QIcon Icon; /** @@ -129,7 +129,7 @@ void DockWidgetSideTabPrivate::createLayout() TitleLabel = new tTabLabel(); TitleLabel->setElideMode(Qt::ElideRight); TitleLabel->setText(DockWidget->windowTitle()); - TitleLabel->setObjectName("dockWidgetTabLabel"); + TitleLabel->setObjectName("sideTabLabel"); _this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool))); // Fill the layout @@ -231,7 +231,7 @@ void CDockWidgetSideTab::setIcon(const QIcon& Icon) if (!d->IconLabel) { - d->IconLabel = new SideTabIconLabel(); + d->IconLabel = new CSideTabIconLabel(); internal::setToolTip(d->IconLabel, d->TitleLabel->toolTip()); Layout->insertWidget(0, d->IconLabel, Qt::AlignHCenter); } @@ -345,27 +345,28 @@ CDockWidget* CDockWidgetSideTab::dockWidget() const */ struct SideTabIconLabelPrivate { - SideTabIconLabel* _this; + CSideTabIconLabel* _this; QLabel* IconLabel; QBoxLayout* Layout; - SideTabIconLabelPrivate(SideTabIconLabel* _public); + SideTabIconLabelPrivate(CSideTabIconLabel* _public); }; // struct SideTabIconLabelPrivate //============================================================================ -SideTabIconLabelPrivate::SideTabIconLabelPrivate(SideTabIconLabel* _public) : +SideTabIconLabelPrivate::SideTabIconLabelPrivate(CSideTabIconLabel* _public) : _this(_public) { } //============================================================================ -SideTabIconLabel::SideTabIconLabel(QWidget* parent) : QWidget(parent), +CSideTabIconLabel::CSideTabIconLabel(QWidget* parent) : QFrame(parent), d(new SideTabIconLabelPrivate(this)) { d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); d->Layout->addWidget(d->IconLabel = new QLabel()); + d->IconLabel->setObjectName("sideTabIconLabel"); d->Layout->setAlignment(Qt::AlignCenter); d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); setLayout(d->Layout); @@ -373,21 +374,21 @@ SideTabIconLabel::SideTabIconLabel(QWidget* parent) : QWidget(parent), //============================================================================ -SideTabIconLabel::~SideTabIconLabel() +CSideTabIconLabel::~CSideTabIconLabel() { delete d; } //============================================================================ -void SideTabIconLabel::setPixmap(const QPixmap& pixmap) +void CSideTabIconLabel::setPixmap(const QPixmap& pixmap) { d->IconLabel->setPixmap(pixmap); } //============================================================================ -void SideTabIconLabel::setContentsMargins(int left, int top, int right, int bottom) +void CSideTabIconLabel::setContentsMargins(int left, int top, int right, int bottom) { d->Layout->setContentsMargins(left, top, right, bottom); } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 76560e2ef..7e50dd8bc 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -152,14 +152,15 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame void clicked(); }; // class DockWidgetSideTab -class SideTabIconLabel : public QWidget +class CSideTabIconLabel : public QFrame { + Q_OBJECT private: SideTabIconLabelPrivate *d; ///< private data (pimpl) public: - SideTabIconLabel(QWidget* parent = nullptr); - virtual ~SideTabIconLabel(); + CSideTabIconLabel(QWidget* parent = nullptr); + virtual ~CSideTabIconLabel(); void setPixmap(const QPixmap &pixmap); void setContentsMargins(int left, int top, int right, int bottom); diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 10eac4ac0..342967bbc 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -116,10 +116,24 @@ ads--CDockWidgetSideTab { ads--CDockWidgetSideTab[sideTabBarArea="0"] { border-right: 1px solid white; + background: red; +} + +#sideTabLabel { + background: green; +} + +#sideTabIconLabel { + background: blue; +} + +ads--CSideTabIconLabel { + border: 1px solid yellow } ads--CDockWidgetSideTab[sideTabBarArea="1"] { border-bottom: 1px solid white; + background: red; } ads--CDockWidgetSideTab[sideTabBarArea="2"] { From 3a3c3a96d6d318c94b8b2444352c407542130711 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 18 Oct 2022 15:46:53 +0200 Subject: [PATCH 112/236] Fixed namespace comment in ElidingLabel --- src/ElidingLabel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ElidingLabel.h b/src/ElidingLabel.h index f1525e255..811a97474 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -124,7 +124,7 @@ class CVerticalElidingLabel : public CElidingLabel void setOrientation(Qt::Orientation orientation); }; // class CVerticalElidingLabel -} // namespace QtLabb +} // namespace ads //--------------------------------------------------------------------------- #endif // ElidingLabelH From cbc43e5e0e75150a277759c74be14ad83a7a9811 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 18 Oct 2022 15:47:34 +0200 Subject: [PATCH 113/236] Added PushButton to test new CDockWidgetSideTab --- src/PushButton.cpp | 69 ++++++++++++++++++++++++++++++++++++++++++++++ src/PushButton.h | 49 ++++++++++++++++++++++++++++++++ src/src.pro | 6 ++-- 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 src/PushButton.cpp create mode 100644 src/PushButton.h diff --git a/src/PushButton.cpp b/src/PushButton.cpp new file mode 100644 index 000000000..ad120cf73 --- /dev/null +++ b/src/PushButton.cpp @@ -0,0 +1,69 @@ +//============================================================================ +/// \file PushButton.cpp +/// \author Uwe Kindler +/// \date 18.10.2022 +/// \brief Implementation of CPushButton +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "PushButton.h" + +#include +#include +#include +#include + + +namespace ads +{ +QSize CPushButton::sizeHint() const +{ + QSize sh = QPushButton::sizeHint(); + + if (m_Orientation != CPushButton::Horizontal) + { + sh.transpose(); + } + + return sh; +} + +void CPushButton::paintEvent(QPaintEvent *event) +{ + Q_UNUSED(event); + + QStylePainter painter(this); + QStyleOptionButton option; + initStyleOption(&option); + + if (m_Orientation == CPushButton::VerticalTopToBottom) + { + painter.rotate(90); + painter.translate(0, -1 * width()); + option.rect = option.rect.transposed(); + } + else if (m_Orientation == CPushButton::VerticalBottomToTop) + { + painter.rotate(-90); + painter.translate(-1 * height(), 0); + option.rect = option.rect.transposed(); + } + + painter.drawControl(QStyle::CE_PushButton, option); +} + +CPushButton::Orientation CPushButton::orientation() const +{ + return m_Orientation; +} + +void CPushButton::setOrientation(Orientation &orientation) +{ + m_Orientation = orientation; +} +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF PushButton.cpp diff --git a/src/PushButton.h b/src/PushButton.h new file mode 100644 index 000000000..9eac3bc88 --- /dev/null +++ b/src/PushButton.h @@ -0,0 +1,49 @@ +#ifndef PushButtonH +#define PushButtonH +//============================================================================ +/// \file PushButton.h +/// \author Uwe Kindler +/// \date 18.10.2022 +/// \brief Declaration of CPushButton +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ + +/** + * ADS specific push button class + */ +class CPushButton : public QPushButton +{ + Q_OBJECT +public: + enum Orientation { + Horizontal, + VerticalTopToBottom, + VerticalBottomToTop + }; + + using QPushButton::QPushButton; + + virtual QSize sizeHint() const override; + + Orientation orientation() const; + void setOrientation(Orientation &orientation); + +protected: + virtual void paintEvent(QPaintEvent *event) override; + +private: + Orientation m_Orientation = Horizontal; +}; + +} // namespace ads + +//--------------------------------------------------------------------------- +#endif // PushButtonH + diff --git a/src/src.pro b/src/src.pro index e86ebad1f..d0422db83 100644 --- a/src/src.pro +++ b/src/src.pro @@ -50,7 +50,8 @@ HEADERS += \ DockFocusController.h \ AutoHideDockContainer.h \ SideTabBar.h \ - DockWidgetSideTab.h + DockWidgetSideTab.h \ + PushButton.h SOURCES += \ @@ -73,7 +74,8 @@ SOURCES += \ DockFocusController.cpp \ AutoHideDockContainer.cpp \ SideTabBar.cpp \ - DockWidgetSideTab.cpp + DockWidgetSideTab.cpp \ + PushButton.cpp unix:!macx { From 866ccb2c4e32435b76267052ce84f6a66d8daa5d Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 18 Oct 2022 16:43:39 +0200 Subject: [PATCH 114/236] Reimplemented DockWidgetSideTab based on QPushButton --- src/DockWidget.cpp | 2 +- src/DockWidgetSideTab.cpp | 216 ++---------------------------------- src/DockWidgetSideTab.h | 43 +------ src/PushButton.cpp | 2 +- src/PushButton.h | 2 +- src/stylesheets/default.css | 19 +--- 6 files changed, 16 insertions(+), 268 deletions(-) diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 50eaf15fc..15fb9c43f 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -326,7 +326,7 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : d->TabWidget = componentsFactory()->createDockWidgetTab(this); d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(this); - connect(d->SideTabWidget, &CDockWidgetSideTab::clicked, this, &CDockWidget::onDockWidgetSideTabClicked); + connect(d->SideTabWidget, &CDockWidgetSideTab::pressed, this, &CDockWidget::onDockWidgetSideTabClicked); d->ToggleViewAction = new QAction(title, this); d->ToggleViewAction->setCheckable(true); diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index d3a7a1d78..673a3b3fc 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -51,68 +51,13 @@ struct DockWidgetSideTabPrivate { CDockWidgetSideTab* _this; CDockWidget* DockWidget; - tTabLabel* TitleLabel; - QBoxLayout* Layout; - QBoxLayout* TitleLayout; // To have independent spacing from the icon CSideTabBar* SideTabBar; - QSize IconSize; Qt::Orientation Orientation{Qt::Vertical}; - CSideTabIconLabel* IconLabel = nullptr; - QIcon Icon; /** * Private data constructor */ DockWidgetSideTabPrivate(CDockWidgetSideTab* _public); - - /** - * Creates the complete layout - */ - void createLayout(); - - /** - * Update the icon in case the icon size changed - */ - void updateIcon() - { - if (!IconLabel || Icon.isNull()) - { - return; - } - - if (IconSize.isValid()) - { - IconLabel->setPixmap(Icon.pixmap(IconSize)); - } - else - { - IconLabel->setPixmap(Icon.pixmap(_this->style()->pixelMetric(QStyle::PM_SmallIconSize, nullptr, _this))); - } - IconLabel->setVisible(true); - } - - void updateContentsMargins() - { - QFontMetrics fm(TitleLabel->font()); - int Spacing = qRound(fm.height() / 2.0); - - if (Orientation == Qt::Vertical) - { - TitleLayout->setContentsMargins(Spacing, Spacing, 0, Spacing); - if (IconLabel) - { - IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, 0); - } - } - else if (Orientation == Qt::Horizontal) - { - TitleLayout->setContentsMargins(Spacing / 2, Spacing, Spacing, Spacing); - if (IconLabel) - { - IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, 0, Spacing / 2); - } - } - } }; // struct DockWidgetTabPrivate @@ -123,45 +68,6 @@ DockWidgetSideTabPrivate::DockWidgetSideTabPrivate(CDockWidgetSideTab* _public) } -//============================================================================ -void DockWidgetSideTabPrivate::createLayout() -{ - TitleLabel = new tTabLabel(); - TitleLabel->setElideMode(Qt::ElideRight); - TitleLabel->setText(DockWidget->windowTitle()); - TitleLabel->setObjectName("sideTabLabel"); - _this->connect(TitleLabel, SIGNAL(elidedChanged(bool)), SIGNAL(elidedChanged(bool))); - - // Fill the layout - // Purely for spacing on the text without messing up spacing on the icon - TitleLayout = new QBoxLayout(QBoxLayout::TopToBottom); - TitleLayout->setAlignment(Qt::AlignCenter); - TitleLayout->addWidget(TitleLabel); - TitleLayout->setSpacing(0); - - Layout = new QBoxLayout(QBoxLayout::TopToBottom); - Layout->setAlignment(Qt::AlignCenter); - Layout->setContentsMargins(0,0,0,0); - Layout->setSpacing(0); - _this->setLayout(Layout); - Layout->addLayout(TitleLayout); - - updateContentsMargins(); - - TitleLabel->setVisible(true); -} - -//============================================================================ -void CDockWidgetSideTab::mousePressEvent(QMouseEvent* event) -{ - if (event->button() == Qt::LeftButton) - { - emit clicked(); - } - - QFrame::mousePressEvent(event); -} - //============================================================================ void CDockWidgetSideTab::setSideTabBar(CSideTabBar* SideTabBar) @@ -183,13 +89,14 @@ void CDockWidgetSideTab::removeFromSideTabBar() //============================================================================ CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) : - QFrame(parent), + Super(parent), d(new DockWidgetSideTabPrivate(this)) { setAttribute(Qt::WA_NoMousePropagation); d->DockWidget = DockWidget; - d->createLayout(); + setText(DockWidget->windowTitle()); setFocusPolicy(Qt::NoFocus); + setFlat(true); } @@ -219,56 +126,12 @@ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const return Left; } - -//============================================================================ -void CDockWidgetSideTab::setIcon(const QIcon& Icon) -{ - QBoxLayout* Layout = qobject_cast(layout()); - if (!d->IconLabel && Icon.isNull()) - { - return; - } - - if (!d->IconLabel) - { - d->IconLabel = new CSideTabIconLabel(); - internal::setToolTip(d->IconLabel, d->TitleLabel->toolTip()); - Layout->insertWidget(0, d->IconLabel, Qt::AlignHCenter); - } - else if (Icon.isNull()) - { - // Remove icon label - Layout->removeWidget(d->IconLabel); - delete d->IconLabel; - d->IconLabel = nullptr; - } - - d->Icon = Icon; - d->updateIcon(); -} - - -//============================================================================ -QSize CDockWidgetSideTab::iconSize() const -{ - return d->IconSize; -} - - -//============================================================================ -void CDockWidgetSideTab::setIconSize(const QSize& Size) -{ - d->IconSize = Size; - d->updateIcon(); -} - - //============================================================================ void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) { d->Orientation = Orientation; - d->Layout->setDirection(Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); - d->TitleLabel->setOrientation(Orientation); + CPushButton::setOrientation((Qt::Horizontal == Orientation) + ? CPushButton::Horizontal : CPushButton::VerticalTopToBottom); updateStyle(); } @@ -278,18 +141,7 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) { setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); - d->updateContentsMargins(); - - // Handle Icon changes - if (d->Icon.isNull()) - { - return; - } - - QFontMetrics fm(d->TitleLabel->font()); - int Spacing = qRound(fm.height() / 2.0); - - if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) + /*if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) { d->TitleLabel->hide(); d->TitleLayout->setContentsMargins(0, 0, 0, 0); @@ -316,9 +168,7 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) d->TitleLayout->setContentsMargins(0, 0, 0, 0); d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); return; - } - - d->TitleLabel->show(); + }*/ } @@ -340,56 +190,4 @@ CDockWidget* CDockWidgetSideTab::dockWidget() const return d->DockWidget; } -/** - * Private data class of SideTabIcon class (pimpl) - */ -struct SideTabIconLabelPrivate -{ - CSideTabIconLabel* _this; - QLabel* IconLabel; - QBoxLayout* Layout; - - SideTabIconLabelPrivate(CSideTabIconLabel* _public); -}; // struct SideTabIconLabelPrivate - - -//============================================================================ -SideTabIconLabelPrivate::SideTabIconLabelPrivate(CSideTabIconLabel* _public) : - _this(_public) -{ -} - - -//============================================================================ -CSideTabIconLabel::CSideTabIconLabel(QWidget* parent) : QFrame(parent), - d(new SideTabIconLabelPrivate(this)) -{ - d->Layout = new QBoxLayout(QBoxLayout::TopToBottom); - d->Layout->addWidget(d->IconLabel = new QLabel()); - d->IconLabel->setObjectName("sideTabIconLabel"); - d->Layout->setAlignment(Qt::AlignCenter); - d->IconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); - setLayout(d->Layout); -} - - -//============================================================================ -CSideTabIconLabel::~CSideTabIconLabel() -{ - delete d; -} - - -//============================================================================ -void CSideTabIconLabel::setPixmap(const QPixmap& pixmap) -{ - d->IconLabel->setPixmap(pixmap); -} - - -//============================================================================ -void CSideTabIconLabel::setContentsMargins(int left, int top, int right, int bottom) -{ - d->Layout->setContentsMargins(left, top, right, bottom); -} } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 7e50dd8bc..924687677 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -29,7 +29,7 @@ //============================================================================ // INCLUDES //============================================================================ -#include +#include "PushButton.h" #include "ads_globals.h" @@ -46,12 +46,11 @@ struct SideTabIconLabelPrivate; * The dock widget tab is shown in the side tab bar to switch between * pinned dock widgets */ -class ADS_EXPORT CDockWidgetSideTab : public QFrame +class ADS_EXPORT CDockWidgetSideTab : public CPushButton { Q_OBJECT Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) - Q_PROPERTY(QSize iconSize READ iconSize WRITE setIconSize) Q_PROPERTY(bool activeTab READ isActiveTab) private: @@ -65,13 +64,11 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame friend class CDockAreaWidget; friend class CDockContainerWidget; - void mousePressEvent(QMouseEvent* event) override; - void setSideTabBar(CSideTabBar *SideTabBar); void removeFromSideTabBar(); public: - using Super = QFrame; + using Super = CPushButton; /** * Dock widget side tab bar locations @@ -108,25 +105,6 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame */ SideTabBarArea sideTabBarArea() const; - /** - * Sets the icon to show in title bar - */ - void setIcon(const QIcon& Icon); - - /** - * Returns the icon size. - * If no explicit icon size has been set, the function returns an invalid - * QSize - */ - QSize iconSize() const; - - /** - * Set an explicit icon size. - * If no icon size has been set explicitly, than the tab sets the icon size - * depending on the style - */ - void setIconSize(const QSize& Size); - /** * Set orientation vertical or horizontal */ @@ -149,22 +127,7 @@ class ADS_EXPORT CDockWidgetSideTab : public QFrame Q_SIGNALS: void elidedChanged(bool elided); - void clicked(); }; // class DockWidgetSideTab - -class CSideTabIconLabel : public QFrame -{ - Q_OBJECT -private: - SideTabIconLabelPrivate *d; ///< private data (pimpl) - -public: - CSideTabIconLabel(QWidget* parent = nullptr); - virtual ~CSideTabIconLabel(); - - void setPixmap(const QPixmap &pixmap); - void setContentsMargins(int left, int top, int right, int bottom); -}; // class SideTabIconLabel } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/PushButton.cpp b/src/PushButton.cpp index ad120cf73..e88a5008e 100644 --- a/src/PushButton.cpp +++ b/src/PushButton.cpp @@ -59,7 +59,7 @@ CPushButton::Orientation CPushButton::orientation() const return m_Orientation; } -void CPushButton::setOrientation(Orientation &orientation) +void CPushButton::setOrientation(Orientation orientation) { m_Orientation = orientation; } diff --git a/src/PushButton.h b/src/PushButton.h index 9eac3bc88..2d36961e9 100644 --- a/src/PushButton.h +++ b/src/PushButton.h @@ -33,7 +33,7 @@ class CPushButton : public QPushButton virtual QSize sizeHint() const override; Orientation orientation() const; - void setOrientation(Orientation &orientation); + void setOrientation(Orientation orientation); protected: virtual void paintEvent(QPaintEvent *event) override; diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 342967bbc..09cf2e08b 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -110,30 +110,17 @@ QScrollArea#dockWidgetScrollArea { *---------------------------------------------------------------------------- */ ads--CDockWidgetSideTab { - background: palette(window); + /*background: palette(window);*/ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-right: 1px solid white; - background: red; -} - -#sideTabLabel { - background: green; + /*border-right: 1px solid white;*/ } -#sideTabIconLabel { - background: blue; -} - -ads--CSideTabIconLabel { - border: 1px solid yellow -} ads--CDockWidgetSideTab[sideTabBarArea="1"] { - border-bottom: 1px solid white; - background: red; + /*border-bottom: 1px solid white;*/ } ads--CDockWidgetSideTab[sideTabBarArea="2"] { From 63fed89f26f2eb2829b3a398cc35fcca10253661 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 18 Oct 2022 17:00:42 +0200 Subject: [PATCH 115/236] Removed individual config flags for each sidebar with the global AutoHideFeatureEnabled flag --- demo/MainWindow.cpp | 2 +- src/AutoHideDockContainer.cpp | 27 --------------------------- src/AutoHideDockContainer.h | 5 ----- src/DockAreaTitleBar.cpp | 2 +- src/DockContainerWidget.cpp | 13 ++++++------- src/DockManager.h | 28 +++++++++++----------------- 6 files changed, 19 insertions(+), 58 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 8b43e2e6a..8a028e558 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -653,7 +653,7 @@ CMainWindow::CMainWindow(QWidget *parent) : //CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding - // CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); + CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 3206380c7..6d2884322 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -454,33 +454,6 @@ void CAutoHideDockContainer::toggleCollapseState() } -//============================================================================ -bool CAutoHideDockContainer::areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area) -{ - switch (area) - { - case CDockWidgetSideTab::Left: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar); - } - case CDockWidgetSideTab::Right: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar); - } - case CDockWidgetSideTab::Bottom: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar); - } - case CDockWidgetSideTab::Top: - { - return CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar); - } - } - - return true; -} - - //============================================================================ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) { diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 6ba264eda..7aa90f5b8 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -152,11 +152,6 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter * Toggles the current collapse state */ void toggleCollapseState(); - - /* - * Convenience function fr determining if area exists in config - */ - static bool areaExistsInConfig(CDockWidgetSideTab::SideTabBarArea area); }; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index ff0ce6ef9..9ef150163 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -191,7 +191,7 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); // AutoHide Button - const auto autoHideEnabled = testConfigFlag(CDockManager::DockContainerHasRightSideBar) || testConfigFlag(CDockManager::DockContainerHasLeftSideBar) || testConfigFlag(CDockManager::DockContainerHasBottomSideBar); + const auto autoHideEnabled = testConfigFlag(CDockManager::AutoHideFeatureEnabled); AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 70e481db4..5aba7e1be 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1048,7 +1048,7 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " << CurrentDockWidget); - if (!CAutoHideDockContainer::areaExistsInConfig(area)) + if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) { return false; } @@ -1452,7 +1452,10 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p { d->DockManager->registerDockContainer(this); createRootSplitter(); - createSideTabBarWidgets(); + if (CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + createSideTabBarWidgets(); + } } } @@ -1503,7 +1506,7 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid { DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager } - if (!CAutoHideDockContainer::areaExistsInConfig(area)) + if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) { Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", "Requested area does not exist in config"); @@ -2094,7 +2097,6 @@ void CDockContainerWidget::createRootSplitter() //============================================================================ void CDockContainerWidget::createSideTabBarWidgets() { - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasLeftSideBar)) { auto leftLayout = new QVBoxLayout(); d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); @@ -2103,7 +2105,6 @@ void CDockContainerWidget::createSideTabBarWidgets() d->Layout->addLayout(leftLayout, 1, 0); } - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasRightSideBar)) { auto rightLayout = new QVBoxLayout(); d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); @@ -2112,13 +2113,11 @@ void CDockContainerWidget::createSideTabBarWidgets() d->Layout->addLayout(rightLayout, 1, 2); } - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasBottomSideBar)) { d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 2, 1); } - if (CDockManager::testConfigFlag(CDockManager::DockContainerHasTopSideBar)) { d->SideTabBarWidgets[CDockWidgetSideTab::Top] = new CSideTabBar(this, Qt::Horizontal); d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Top], 0, 1); diff --git a/src/DockManager.h b/src/DockManager.h index a378486df..1aa4952b8 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -226,23 +226,17 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget enum eAutoHideFlag { - DockContainerHasLeftSideBar = 0x01, //!< If the flag is set the dock manager will have a left side bar - DockContainerHasRightSideBar = 0x02, //!< If the flag is set the dock manager will have a right side bar - DockContainerHasBottomSideBar = 0x04, //!< If the flag is set the dock manager will have a bottom side bar - DockContainerHasTopSideBar = 0x08, //!< If the flag is set the dock manager will have a top side bar - DockAreaHasAutoHideButton = 0x10, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set left side bar will prioritize showing icons only over text - RightSideBarPrioritizeIconOnly = 0x40, //!< If the flag is set right side bar will prioritize showing icons only over text - BottomSideBarPrioritizeIconOnly = 0x80,//!< If the flag is set bottom side bar will prioritize showing icons only over text - TopSideBarPrioritizeIconOnly = 0x100, //!< If the flag is set top side bar will prioritize showing icons only over text - AutoHideDockAreaHasTitle = 0x200, //!< If the flag is set overlay dock area title bar will show the window title - AutoHideButtonTogglesArea = 0x400, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled - - DefaultAutoHideConfig = DockContainerHasLeftSideBar - | DockContainerHasRightSideBar - | DockContainerHasBottomSideBar - | DockContainerHasTopSideBar - | DockAreaHasAutoHideButton + AutoHideFeatureEnabled = 0x01, + DockAreaHasAutoHideButton = 0x02, //!< If the flag is set each dock area has a auto hide menu button + LeftSideBarPrioritizeIconOnly = 0x04, //!< If the flag is set left side bar will prioritize showing icons only over text + RightSideBarPrioritizeIconOnly = 0x08, //!< If the flag is set right side bar will prioritize showing icons only over text + BottomSideBarPrioritizeIconOnly = 0x10,//!< If the flag is set bottom side bar will prioritize showing icons only over text + TopSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set top side bar will prioritize showing icons only over text + AutoHideDockAreaHasTitle = 0x40, //!< If the flag is set overlay dock area title bar will show the window title + AutoHideButtonTogglesArea = 0x80, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled + + DefaultAutoHideConfig = AutoHideFeatureEnabled + | DockAreaHasAutoHideButton | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars }; Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) From 7319c52d4d46fdd13fc1ef4c1b9e324e4f545c56 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 19 Oct 2022 17:13:34 +0800 Subject: [PATCH 116/236] FIxed CMakeLists --- src/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f74775e5e..355f5230f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -30,6 +30,7 @@ set(ads_SRCS SideTabBar.cpp DockWidgetSideTab.cpp AutoHideDockContainer.cpp + PushButton.cpp ads.qrc ) set(ads_HEADERS @@ -54,6 +55,7 @@ set(ads_HEADERS SideTabBar.h DockWidgetSideTab.h AutoHideDockContainer.h + PushButton.h ) add_compile_options("$<$:/utf-8>") if (UNIX AND NOT APPLE) From 7ed3f8b2d1cc804bcd80349ffb2f446704b0bd30 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 19 Oct 2022 17:30:08 +0800 Subject: [PATCH 117/236] Remove all dock widget focusable constraint on auto hide button --- src/DockAreaWidget.cpp | 22 ++-------------------- 1 file changed, 2 insertions(+), 20 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index f23138f90..e59f57ea2 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -315,11 +315,6 @@ struct DockAreaWidgetPrivate */ 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 */ @@ -387,7 +382,7 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) if (IsTopLevel) { TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating() && allDockWidgetsFocusable()); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating()); // Undock and tabs should never show when auto hidden TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isAutoHide()); TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide()); @@ -395,25 +390,12 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel) else { TitleBar->button(TitleBarButtonClose)->setVisible(true); - TitleBar->button(TitleBarButtonAutoHide)->setVisible(allDockWidgetsFocusable()); + TitleBar->button(TitleBarButtonAutoHide)->setVisible(true); 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) : From 9eb9ee407169fa50af5f820d935dfccadcb7fc65 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 19 Oct 2022 17:35:36 +0800 Subject: [PATCH 118/236] fix icon only config for side tab bars --- src/DockWidgetSideTab.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 673a3b3fc..048505750 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -141,34 +141,35 @@ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) { setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); - /*if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) + if (icon().isNull()) { - d->TitleLabel->hide(); - d->TitleLayout->setContentsMargins(0, 0, 0, 0); - d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); + return; + } + + if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) + { + setText(""); + setOrientation(Qt::Horizontal); return; } if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) { - d->TitleLabel->hide(); - d->TitleLayout->setContentsMargins(0, 0, 0, 0); - d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing, Spacing / 2); + setText(""); + setOrientation(Qt::Horizontal); return; } if (CDockManager::testConfigFlag(CDockManager::BottomSideBarPrioritizeIconOnly) && area == Bottom) { - d->TitleLabel->hide(); - d->TitleLayout->setContentsMargins(0, 0, 0, 0); - d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing); + setText(""); + setOrientation(Qt::Horizontal); return; } if (CDockManager::testConfigFlag(CDockManager::TopSideBarPrioritizeIconOnly) && area == Top) { - d->TitleLabel->hide(); - d->TitleLayout->setContentsMargins(0, 0, 0, 0); - d->IconLabel->setContentsMargins(Spacing / 2, Spacing / 2, Spacing / 2, Spacing / 2); + setText(""); + setOrientation(Qt::Horizontal); return; - }*/ + } } From 10a75b041315ce4f2616731e771b89bb1088969e Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 19 Oct 2022 17:44:55 +0800 Subject: [PATCH 119/236] remove unused and cleanup --- src/DockWidgetSideTab.cpp | 4 ---- src/DockWidgetSideTab.h | 1 - 2 files changed, 5 deletions(-) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 048505750..c25f36716 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -35,15 +35,11 @@ #include "DockAreaWidget.h" #include "DockManager.h" -#include "ElidingLabel.h" #include "DockWidget.h" namespace ads { - -using tTabLabel = CVerticalElidingLabel; - /** * Private data class of CDockWidgetTab class (pimpl) */ diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 924687677..f307f3774 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -85,7 +85,6 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton /** * 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); From bc1f12ba9303eee8c027ec28c2977a221a919936 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sun, 23 Oct 2022 16:42:14 +0200 Subject: [PATCH 120/236] Implemented experimental mouse event handling --- src/AutoHideDockContainer.cpp | 167 ++++++++++++++++++++++------------ src/AutoHideDockContainer.h | 6 +- src/stylesheets/default.css | 1 + 3 files changed, 114 insertions(+), 60 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6d2884322..e4c3c22de 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -46,6 +46,8 @@ namespace ads { +static const int ResizeMargin = 4; + struct AutoHideDockContainerPrivate { CAutoHideDockContainer* _this; @@ -122,7 +124,7 @@ struct AutoHideDockContainerPrivate { const auto rect = DockArea->frameGeometry(); const auto topLeft = rect.topLeft(); - const auto handleSize = _this->handleWidth(); + const auto handleSize = 0; if (SideTabBarArea == CDockWidgetSideTab::Bottom) { @@ -159,7 +161,7 @@ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const //============================================================================ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : - QSplitter((area == CDockWidgetSideTab::Bottom || area == CDockWidgetSideTab::Top) ? Qt::Orientation::Vertical : Qt::Orientation::Horizontal, parent), + Super(parent), d(new AutoHideDockContainerPrivate(this)) { d->DockManager = DockManager; @@ -170,69 +172,80 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW d->DockArea->updateAutoHideButtonCheckState(); d->DockArea->updateTitleBarButtonToolTip(); - setObjectName("autoHideSplitter"); - setChildrenCollapsible(false); - - const auto emptyWidget = new QWidget(); - emptyWidget->setMinimumWidth(50); - emptyWidget->setMinimumHeight(50); // Prevents you from dragging the splitter too far - - switch (area) - { - case CDockWidgetSideTab::Top: - { - addWidget(d->DockArea); - addWidget(emptyWidget); - break; - } - case CDockWidgetSideTab::Left: - { - addWidget(d->DockArea); - addWidget(emptyWidget); - break; - } - case CDockWidgetSideTab::Right: - { - addWidget(emptyWidget); - addWidget(d->DockArea); - break; - } - case CDockWidgetSideTab::Bottom: - { - addWidget(emptyWidget); - addWidget(d->DockArea); - break; - } - } + setObjectName("autoHideDockContainer"); + QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom); + l->setContentsMargins(0, 0, 0, 0); + l->setSpacing(0); + setLayout(l); + l->addWidget(d->DockArea); updateSize(); - updateMask(); - parent->registerAutoHideWidget(this); + setAutoFillBackground(true); + setMouseTracking(true); } + +//============================================================================ +CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : + CAutoHideDockContainer(DockWidget->dockManager(), area, parent) +{ + addDockWidget(DockWidget); + setDockSizeProportion(DockWidget->DefaultAutoHideDockProportion()); +} + + //============================================================================ void CAutoHideDockContainer::updateMask() { - setMask(d->getDockAreaWithSplitterRect()); + //setMask(d->getDockAreaWithSplitterRect()); } + //============================================================================ void CAutoHideDockContainer::updateSize() { + qDebug() << "CAutoHideDockContainer::updateSize()"; const auto dockContainerParent = parentContainer(); const auto rootSplitter = dockContainerParent->rootSplitter(); const auto rect = rootSplitter->frameGeometry(); - move(rect.topLeft()); - resize(rect.width(), rect.height()); -} -//============================================================================ -CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : - CAutoHideDockContainer(DockWidget->dockManager(), area, parent) -{ - addDockWidget(DockWidget); - setDockSizeProportion(DockWidget->DefaultAutoHideDockProportion()); + switch (sideTabBarArea()) + { + case CDockWidgetSideTab::Top: + move(rect.topLeft()); + resize(rect.width(), height()); + setContentsMargins(QMargins(0, 0, 0, ResizeMargin)); + break; + + case CDockWidgetSideTab::Left: + move(rect.topLeft()); + resize(width(), rect.height()); + setContentsMargins(QMargins(0, 0, ResizeMargin, 0)); + break; + + case CDockWidgetSideTab::Right: + { + QPoint p = rect.topRight(); + p.rx() -= (width() - 1); + move(p); + resize(width(), rect.height()); + setContentsMargins(QMargins(ResizeMargin, 0, 0, 0)); + } + break; + + case CDockWidgetSideTab::Bottom: + { + QPoint p = rect.bottomLeft(); + p.ry() -= (height() - 1); + move(p); + resize(rect.width(), height()); + setContentsMargins(QMargins(0, ResizeMargin, 0, 0)); + } + break; + } + + //resize(rect.width(), rect.height()); } //============================================================================ @@ -280,6 +293,8 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockArea->addDockWidget(DockWidget); d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); + qDebug() << "DockWidget->size(): " << DockWidget->size(); + this->resize(OldDockArea ? OldDockArea->size() : d->DockWidget->size()); updateSize(); updateMask(); @@ -297,7 +312,7 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) const auto dockSize = static_cast(static_cast(INT_MAX) * SplitterProportion); const auto remainingSize = INT_MAX - dockSize; - switch (d->SideTabBarArea) + /* switch (d->SideTabBarArea) { case CDockWidgetSideTab::Left: { @@ -310,7 +325,7 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) setSizes({ remainingSize, dockSize }); break; } - } + }*/ } @@ -360,10 +375,11 @@ void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); QStringList Sizes; - for (auto Size : sizes()) + // TODO implement auto hide dock container saving + /*for (auto Size : sizes()) { Sizes << QString::number(Size); - } + }*/ s.writeAttribute("Sizes", Sizes.join(" ")); } @@ -383,7 +399,8 @@ bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) Sizes.append(value); } - if (Sizes.count() != count()) + // TODO implement restore state + /*if (Sizes.count() != count()) { return false; } @@ -391,7 +408,7 @@ bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) if (!Testing) { setSizes(Sizes); - } + }*/ return true; } @@ -481,7 +498,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) if (!IsDockManager) { - return QSplitter::eventFilter(watched, event); + return Super::eventFilter(watched, event); } // Now we check, if the user clicked inside of this auto hide container. @@ -493,7 +510,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) auto rect = d->getDockAreaWithSplitterRect(); if (rect.contains(pos)) { - return QSplitter::eventFilter(watched, event); + return Super::eventFilter(watched, event); } // Now check, if the user clicked into the side tab and ignore this event, @@ -504,7 +521,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) pos = SideTab->mapFromGlobal(me->globalPos()); if (SideTab->rect().contains(pos)) { - return QSplitter::eventFilter(watched, event); + return Super::eventFilter(watched, event); } // If the mouse button down event is in the dock manager but outside @@ -513,15 +530,47 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) collapseView(true); } - return QSplitter::eventFilter(watched, event); + return Super::eventFilter(watched, event); } //============================================================================ void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) { + std::cout << "ResizeEvent" << std::endl; updateMask(); - QSplitter::resizeEvent(event); + Super::resizeEvent(event); +} + + +//============================================================================ +bool CAutoHideDockContainer::event(QEvent *event) +{ + return Super::event(event); +} + + +//============================================================================ +void CAutoHideDockContainer::mouseMoveEvent(QMouseEvent *event) +{ + qDebug() << "mouseMoveEvent: " << event->pos(); + qDebug() << "height: " << height(); + auto p = event->pos(); + if (p.y() > (height() - ResizeMargin - 1) && p.y() < height()) + { + setCursor(Qt::SizeVerCursor); + } + else + { + setCursor(Qt::ArrowCursor); + } +} + + +//============================================================================ +void CAutoHideDockContainer::mousePressEvent(QMouseEvent *event) +{ + qDebug() << "mousePressEvent: " << event->pos(); } } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 7aa90f5b8..1bfc36aff 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -50,7 +50,7 @@ class CDockingStateReader; // Note: This widget must be a QSplitter, inheriting from QWidget and keeping an // internal splitter breaks ActiveX widgets // likely due to layout issues between this widget and the internal splitter -class ADS_EXPORT CAutoHideDockContainer : public QSplitter +class ADS_EXPORT CAutoHideDockContainer : public QFrame { Q_OBJECT Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) @@ -63,10 +63,14 @@ class ADS_EXPORT CAutoHideDockContainer : public QSplitter void resizeEvent(QResizeEvent* event) override; void updateMask(); void updateSize(); + virtual bool event(QEvent *event) override; + virtual void mouseMoveEvent(QMouseEvent *event) override; + virtual void mousePressEvent(QMouseEvent *event) override; CDockContainerWidget* parentContainer() const; public: + using Super = QFrame; /** * Create Auto Hide widget with a dock manager */ diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 09cf2e08b..7946d62a7 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -187,6 +187,7 @@ ads--CAutoHideDockContainer::handle:horizontal { background: white; }*/ + ads--CAutoHideDockContainer #dockAreaAutoHideButton { qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); From f549a92c0196dee4e33fcd026e53757e39ad742e Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 24 Oct 2022 16:21:26 +0200 Subject: [PATCH 121/236] Added resize support for new QFrame based AutoHideDockContainer --- src/AutoHideDockContainer.cpp | 166 ++++++++++----------- src/AutoHideDockContainer.h | 4 - src/DockContainerWidget.cpp | 13 +- src/DockContainerWidget.h | 11 +- src/DockManager.cpp | 1 + src/ResizeHandle.cpp | 269 ++++++++++++++++++++++++++++++++++ src/ResizeHandle.h | 90 ++++++++++++ src/ads_globals.cpp | 9 ++ src/ads_globals.h | 5 + src/src.pro | 6 +- src/stylesheets/default.css | 6 + 11 files changed, 489 insertions(+), 91 deletions(-) create mode 100644 src/ResizeHandle.cpp create mode 100644 src/ResizeHandle.h diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index e4c3c22de..05135bfa8 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -34,6 +34,7 @@ #include "SideTabBar.h" #include "DockAreaWidget.h" #include "DockingStateReader.h" +#include "ResizeHandle.h" #include #include @@ -48,6 +49,51 @@ namespace ads { static const int ResizeMargin = 4; +//============================================================================ +bool static isHorizontalArea(CDockWidgetSideTab::SideTabBarArea Area) +{ + switch (Area) + { + case CDockWidgetSideTab::Top: + case CDockWidgetSideTab::Bottom: return true; + case CDockWidgetSideTab::Left: + case CDockWidgetSideTab::Right: return false; + } + + return true; +} + + +//============================================================================ +Qt::Edge static edgeFromSideTabBarArea(CDockWidgetSideTab::SideTabBarArea Area) +{ + switch (Area) + { + case CDockWidgetSideTab::Top: return Qt::BottomEdge; + case CDockWidgetSideTab::Bottom: return Qt::TopEdge; + case CDockWidgetSideTab::Left: return Qt::RightEdge; + case CDockWidgetSideTab::Right: return Qt::LeftEdge; + } + + return Qt::LeftEdge; +} + + +//============================================================================ +int resizeHandleLayoutPosition(CDockWidgetSideTab::SideTabBarArea Area) +{ + switch (Area) + { + case CDockWidgetSideTab::Bottom: + case CDockWidgetSideTab::Right: return 0; + + case CDockWidgetSideTab::Top: + case CDockWidgetSideTab::Left: return 1; + } + + return 0; +} + struct AutoHideDockContainerPrivate { CAutoHideDockContainer* _this; @@ -55,6 +101,9 @@ struct AutoHideDockContainerPrivate CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; CDockWidgetSideTab::SideTabBarArea SideTabBarArea; + QBoxLayout* Layout; + CResizeHandle* ResizeHandle = nullptr; + QSize Size; /** * Private data constructor @@ -117,35 +166,15 @@ struct AutoHideDockContainerPrivate return QPoint(); } - /* - * Convenience function to get dock area with splitter total size - */ - QRect getDockAreaWithSplitterRect() const + void updateResizeHandleSizeLimitMax() { - const auto rect = DockArea->frameGeometry(); - const auto topLeft = rect.topLeft(); - const auto handleSize = 0; - - if (SideTabBarArea == CDockWidgetSideTab::Bottom) - { - return QRect(QPoint(topLeft.x(), topLeft.y() - handleSize), QSize(rect.size().width(), rect.size().height() + handleSize)); - } - - if (SideTabBarArea == CDockWidgetSideTab::Top) - { - return QRect(QPoint(topLeft.x(), topLeft.y()), QSize(rect.size().width(), rect.size().height() + handleSize)); - } - - auto offset = 0; - if (SideTabBarArea == CDockWidgetSideTab::SideTabBarArea::Right) - { - offset = handleSize; - } - - return QRect(QPoint(topLeft.x() - offset, topLeft.y()), QSize(rect.size().width() + handleSize, rect.size().height())); + auto Rect = DockManager->contentRect(); + ResizeHandle->setMaxResizeSize(ResizeHandle->orientation() == Qt::Horizontal + ? Rect.width() : Rect.height()); } }; // struct AutoHideDockContainerPrivate + //============================================================================ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( CAutoHideDockContainer *_public) : @@ -154,11 +183,14 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( } + +//============================================================================ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const { return internal::findParent(this); } + //============================================================================ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : Super(parent), @@ -173,11 +205,16 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW d->DockArea->updateTitleBarButtonToolTip(); setObjectName("autoHideDockContainer"); - QBoxLayout *l = new QBoxLayout(QBoxLayout::TopToBottom); - l->setContentsMargins(0, 0, 0, 0); - l->setSpacing(0); - setLayout(l); - l->addWidget(d->DockArea); + + d->Layout = new QBoxLayout(isHorizontalArea(area) ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); + d->Layout->setContentsMargins(0, 0, 0, 0); + d->Layout->setSpacing(0); + setLayout(d->Layout); + d->Layout->addWidget(d->DockArea); + d->ResizeHandle = new CResizeHandle(edgeFromSideTabBarArea(area), this); + d->ResizeHandle->setMinResizeSize(64); + d->Layout->insertWidget(resizeHandleLayoutPosition(area), d->ResizeHandle); + d->Size = d->DockArea->size(); updateSize(); parent->registerAutoHideWidget(this); @@ -195,33 +232,23 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWid } -//============================================================================ -void CAutoHideDockContainer::updateMask() -{ - //setMask(d->getDockAreaWithSplitterRect()); -} - - //============================================================================ void CAutoHideDockContainer::updateSize() { qDebug() << "CAutoHideDockContainer::updateSize()"; - const auto dockContainerParent = parentContainer(); - const auto rootSplitter = dockContainerParent->rootSplitter(); - const auto rect = rootSplitter->frameGeometry(); + auto dockContainerParent = parentContainer(); + auto rect = dockContainerParent->contentRect(); switch (sideTabBarArea()) { case CDockWidgetSideTab::Top: move(rect.topLeft()); - resize(rect.width(), height()); - setContentsMargins(QMargins(0, 0, 0, ResizeMargin)); + resize(rect.width(), qMin(rect.height(), d->Size.height())); break; case CDockWidgetSideTab::Left: move(rect.topLeft()); - resize(width(), rect.height()); - setContentsMargins(QMargins(0, 0, ResizeMargin, 0)); + resize(qMin(d->Size.width(), rect.width()), rect.height()); break; case CDockWidgetSideTab::Right: @@ -229,8 +256,7 @@ void CAutoHideDockContainer::updateSize() QPoint p = rect.topRight(); p.rx() -= (width() - 1); move(p); - resize(width(), rect.height()); - setContentsMargins(QMargins(ResizeMargin, 0, 0, 0)); + resize(qMin(d->Size.width(), rect.width()), rect.height()); } break; @@ -239,8 +265,7 @@ void CAutoHideDockContainer::updateSize() QPoint p = rect.bottomLeft(); p.ry() -= (height() - 1); move(p); - resize(rect.width(), height()); - setContentsMargins(QMargins(0, ResizeMargin, 0, 0)); + resize(rect.width(), qMin(rect.height(), d->Size.height())); } break; } @@ -297,7 +322,6 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) this->resize(OldDockArea ? OldDockArea->size() : d->DockWidget->size()); updateSize(); - updateMask(); } @@ -450,12 +474,12 @@ void CAutoHideDockContainer::collapseView(bool Enable) } else { + d->updateResizeHandleSizeLimitMax(); raise(); show(); d->DockArea->show(); d->DockWidget->show(); updateSize(); - updateMask(); d->DockManager->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); } @@ -476,8 +500,10 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) { if (event->type() == QEvent::Resize) { - updateSize(); - updateMask(); + if (!d->ResizeHandle->isResizing()) + { + updateSize(); + } } else if (event->type() == QEvent::MouseButtonPress) { @@ -507,8 +533,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) // user works in it QMouseEvent* me = static_cast(event); auto pos = mapFromGlobal(me->globalPos()); - auto rect = d->getDockAreaWithSplitterRect(); - if (rect.contains(pos)) + if (rect().contains(pos)) { return Super::eventFilter(watched, event); } @@ -538,39 +563,14 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) { std::cout << "ResizeEvent" << std::endl; - updateMask(); Super::resizeEvent(event); -} - - -//============================================================================ -bool CAutoHideDockContainer::event(QEvent *event) -{ - return Super::event(event); -} - - -//============================================================================ -void CAutoHideDockContainer::mouseMoveEvent(QMouseEvent *event) -{ - qDebug() << "mouseMoveEvent: " << event->pos(); - qDebug() << "height: " << height(); - auto p = event->pos(); - if (p.y() > (height() - ResizeMargin - 1) && p.y() < height()) - { - setCursor(Qt::SizeVerCursor); - } - else + if (d->ResizeHandle->isResizing()) { - setCursor(Qt::ArrowCursor); + d->Size = this->size(); + qDebug() << "Size " << d->Size; + d->updateResizeHandleSizeLimitMax(); } } - -//============================================================================ -void CAutoHideDockContainer::mousePressEvent(QMouseEvent *event) -{ - qDebug() << "mousePressEvent: " << event->pos(); -} } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 1bfc36aff..821f49050 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -61,11 +61,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame protected: bool eventFilter(QObject* watched, QEvent* event) override; void resizeEvent(QResizeEvent* event) override; - void updateMask(); void updateSize(); - virtual bool event(QEvent *event) override; - virtual void mouseMoveEvent(QMouseEvent *event) override; - virtual void mousePressEvent(QMouseEvent *event) override; CDockContainerWidget* parentContainer() const; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 5aba7e1be..e7fa56102 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -2276,7 +2276,7 @@ CSideTabBar* CDockContainerWidget::sideTabBar(CDockWidgetSideTab::SideTabBarArea //============================================================================ -QRect CDockContainerWidget::contentRect() +QRect CDockContainerWidget::contentRect() const { if (!d->RootSplitter) { @@ -2285,6 +2285,17 @@ QRect CDockContainerWidget::contentRect() return d->RootSplitter->geometry(); } + + +//=========================================================================== +QRect CDockContainerWidget::contentRectGlobal() const +{ + if (!d->RootSplitter) + { + return QRect(); + } + return internal::globalGeometry(d->RootSplitter); +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 005d37a0c..e33a3a8e0 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -331,7 +331,16 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Returns the content rectangle without the autohide side bars */ - QRect contentRect(); + QRect contentRect() const; + + /** + * Returns the content rectangle mapped to global space. + * The content rectangle is the rectangle of the dock manager widget minus + * the auto hide side bars. So that means, it is the geometry of the + * internal root splitter mapped to global space. + */ + QRect contentRectGlobal() const; + Q_SIGNALS: /** diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 845d23bbb..d349b1a66 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -1312,6 +1312,7 @@ void CDockManager::setFloatingContainersTitle(const QString& Title) FloatingContainersTitle = Title; } + //=========================================================================== QString CDockManager::floatingContainersTitle() { diff --git a/src/ResizeHandle.cpp b/src/ResizeHandle.cpp new file mode 100644 index 000000000..fd4874fa2 --- /dev/null +++ b/src/ResizeHandle.cpp @@ -0,0 +1,269 @@ +//============================================================================ +/// \file ResizeHandle.cpp +/// \author Uwe Kindler +/// \date 24.10.2022 +/// \brief Implementation of CResizeHandle class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "ResizeHandle.h" + +#include +#include +#include +#include + +#include "ads_globals.h" + +namespace ads +{ +/** + * Private data class of CResizeHandle class (pimpl) + */ +struct ResizeHandlePrivate +{ + CResizeHandle *_this; + Qt::Edge HandlePosition = Qt::LeftEdge; + QWidget* Target = nullptr; + int MouseOffset = 0; + bool Pressed = false; + int MinSize = 0; + int MaxSize = 1; + + /** + * Private data constructor + */ + ResizeHandlePrivate(CResizeHandle *_public); + + /** + * Pick position component from pos depending on orientation + */ + int pick(const QPoint &pos) const + { + return _this->orientation() == Qt::Horizontal ? pos.x() : pos.y(); + } + + /** + * Returns true, if orientation is horizontal + */ + bool isHorizontal() const + { + return _this->orientation() == Qt::Horizontal; + } +}; +// struct ResizeHandlePrivate + +//============================================================================ +ResizeHandlePrivate::ResizeHandlePrivate(CResizeHandle *_public) : + _this(_public) +{ + +} + +//============================================================================ +CResizeHandle::CResizeHandle(Qt::Edge HandlePosition, QWidget* parent) : + Super(parent), + d(new ResizeHandlePrivate(this)) +{ + d->Target = parent; + setHandlePosition(HandlePosition); + setMinResizeSize(48); + setMaxResizeSize(d->isHorizontal() ? parent->height() : parent->width()); + + if (!d->isHorizontal()) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + else + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + } +} + + +//============================================================================ +CResizeHandle::~CResizeHandle() +{ + delete d; +} + + +//============================================================================ +void CResizeHandle::mouseMoveEvent(QMouseEvent* e) +{ + if (!(e->buttons() & Qt::LeftButton)) + { + return; + } + int pos = d->pick(e->pos()) - d->MouseOffset; + auto OldGeometry = d->Target->geometry(); + auto NewGeometry = OldGeometry; + switch (d->HandlePosition) + { + case Qt::LeftEdge: + { + NewGeometry.adjust(pos, 0, 0, 0); + int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize); + NewGeometry.setWidth(Size); + NewGeometry.moveTopRight(OldGeometry.topRight()); + } + break; + + + case Qt::RightEdge: + { + NewGeometry.adjust(0, 0, pos, 0); + int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize); + NewGeometry.setWidth(Size); + } + break; + + case Qt::TopEdge: + { + NewGeometry.adjust(0, pos, 0, 0); + int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize); + NewGeometry.setHeight(Size); + NewGeometry.moveBottomLeft(OldGeometry.bottomLeft()); + } + break; + + case Qt::BottomEdge: + { + NewGeometry.adjust(0, 0, 0, pos); + int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize); + NewGeometry.setHeight(Size); + } + break; + } + d->Target->setGeometry(NewGeometry); + //qDebug() << "globalGeometry(): " << internal::globalGeometry(d->Target); + //qDebug() << "parentGlobalGeometry(): " << internal::globalGeometry(d->Target->parentWidget()); + + + /*if (opaqueResize()) + { + moveSplitter(pos); + } + else + { + //d->s->setRubberBand(closestLegalPosition(pos)); + }*/ +} + + +//============================================================================ +void CResizeHandle::mousePressEvent(QMouseEvent* e) +{ + qDebug() << "CResizeHandle::mousePressEvent " << e; + if (e->button() == Qt::LeftButton) + { + d->MouseOffset = d->pick(e->pos()); + d->Pressed = true; + update(); + } +} + + +//============================================================================ +void CResizeHandle::mouseReleaseEvent(QMouseEvent* e) +{ + qDebug() << "CResizeHandle::mouseReleaseEvent " << e; + /*if (!opaqueResize() && e->button() == Qt::LeftButton) { + int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos())) + - d->mouseOffset; + d->s->setRubberBand(-1); + moveSplitter(pos); + }*/ + if (e->button() == Qt::LeftButton) + { + d->Pressed = false; + update(); + } +} + + +//============================================================================ +void CResizeHandle::setHandlePosition(Qt::Edge HandlePosition) +{ + d->HandlePosition = HandlePosition; + switch (d->HandlePosition) + { + case Qt::LeftEdge: // fall through + case Qt::RightEdge: setCursor(Qt::SizeHorCursor); break; + + case Qt::TopEdge: // fall through + case Qt::BottomEdge: setCursor(Qt::SizeVerCursor); break; + } +} + + +//============================================================================ +Qt::Edge CResizeHandle::handlePostion() const +{ + return d->HandlePosition; +} + + +//============================================================================ +Qt::Orientation CResizeHandle::orientation() const +{ + switch (d->HandlePosition) + { + case Qt::LeftEdge: // fall through + case Qt::RightEdge: return Qt::Horizontal; + + case Qt::TopEdge: // fall through + case Qt::BottomEdge: return Qt::Vertical; + } + + return Qt::Horizontal; +} + + +//============================================================================ +QSize CResizeHandle::sizeHint() const +{ + QSize Result; + switch (d->HandlePosition) + { + case Qt::LeftEdge: // fall through + case Qt::RightEdge: Result = QSize(4, d->Target->height()); break; + + case Qt::TopEdge: // fall through + case Qt::BottomEdge: Result = QSize(d->Target->width(), 4); break; + } + + qDebug() << "CResizeHandle::sizeHint(): " << Result; + return Result; + /*parentWidget()->style()->sizeFromContents(QStyle::CT_Splitter, &opt, QSize(hw, hw), d->s) + .expandedTo(QApplication::globalStrut());*/ +} + + +//============================================================================ +bool CResizeHandle::isResizing() const +{ + return d->Pressed; +} + + +//============================================================================ +void CResizeHandle::setMinResizeSize(int MinSize) +{ + qDebug() << "CResizeHandle::setMinResizeSize " << MinSize; + d->MinSize = MinSize; +} + + +//============================================================================ +void CResizeHandle::setMaxResizeSize(int MaxSize) +{ + qDebug() << "CResizeHandle::setMaxResizeSize " << MaxSize; + d->MaxSize = MaxSize; +} +} // namespace ads + +//--------------------------------------------------------------------------- +// EOF ResizeHandle.cpp diff --git a/src/ResizeHandle.h b/src/ResizeHandle.h new file mode 100644 index 000000000..a7a1360ee --- /dev/null +++ b/src/ResizeHandle.h @@ -0,0 +1,90 @@ +#ifndef ResizeHandleH +#define ResizeHandleH +//============================================================================ +/// \file ResizeHandle.h +/// \author Uwe Kindler +/// \date 24.10.2022 +/// \brief Declaration of CResizeHandle class +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +namespace ads +{ +struct ResizeHandlePrivate; + +/** + * Resize handle for resizing its parent widget + */ +class CResizeHandle : public QFrame +{ + Q_OBJECT + Q_DISABLE_COPY(CResizeHandle) +private: + ResizeHandlePrivate* d; ///< private data (pimpl) + friend struct ResizeHandlePrivate; + +protected: + void mouseMoveEvent(QMouseEvent *) override; + void mousePressEvent(QMouseEvent *) override; + void mouseReleaseEvent(QMouseEvent *) override; + +public: + using Super = QFrame; + + /** + * Default Constructor + */ + CResizeHandle(Qt::Edge HandlePosition, QWidget* parent); + + /** + * Virtual Destructor + */ + virtual ~CResizeHandle(); + + /** + * Sets the handle position + */ + void setHandlePosition(Qt::Edge HandlePosition); + + /** + * Returns the handle position + */ + Qt::Edge handlePostion() const; + + /** + * Returns the orientation of this resize handle + */ + Qt::Orientation orientation() const; + + /** + * Returns the size hint + */ + QSize sizeHint() const override; + + /** + * Returns true, if resizing is active + */ + bool isResizing() const; + + /** + * Sets the minimum size for the widget that is going to be resized. + * The resize handle will not resize the target widget to a size smaller + * than this value + */ + void setMinResizeSize(int MinSize); + + /** + * Sets the maximum size for the widget that is going to be resized + * The resize handle will not resize the target widget to a size bigger + * than this value + */ + void setMaxResizeSize(int MaxSize); +}; // class name +} + // namespace ads +//----------------------------------------------------------------------------- +#endif // ResizeHandleH diff --git a/src/ads_globals.cpp b/src/ads_globals.cpp index 8eca15946..3971abf3c 100644 --- a/src/ads_globals.cpp +++ b/src/ads_globals.cpp @@ -406,6 +406,15 @@ void repolishStyle(QWidget* w, eRepolishChildOptions Options) } } + +//============================================================================ +QRect globalGeometry(QWidget* w) +{ + QRect g = w->geometry(); + g.moveTopLeft(w->mapToGlobal(QPoint(0, 0))); + return g; +} + } // namespace internal } // namespace ads diff --git a/src/ads_globals.h b/src/ads_globals.h index 4748c277f..d8021b83d 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -307,6 +307,11 @@ enum eRepolishChildOptions void repolishStyle(QWidget* w, eRepolishChildOptions Options = RepolishIgnoreChildren); +/** + * Returns the geometry of the given widget in global space + */ +QRect globalGeometry(QWidget* w); + } // namespace internal } // namespace ads diff --git a/src/src.pro b/src/src.pro index d0422db83..101f7a30e 100644 --- a/src/src.pro +++ b/src/src.pro @@ -51,7 +51,8 @@ HEADERS += \ AutoHideDockContainer.h \ SideTabBar.h \ DockWidgetSideTab.h \ - PushButton.h + PushButton.h \ + ResizeHandle.h SOURCES += \ @@ -75,7 +76,8 @@ SOURCES += \ AutoHideDockContainer.cpp \ SideTabBar.cpp \ DockWidgetSideTab.cpp \ - PushButton.cpp + PushButton.cpp \ + ResizeHandle.cpp unix:!macx { diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 7946d62a7..9dbf7899f 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -197,3 +197,9 @@ ads--CAutoHideDockContainer #dockAreaAutoHideButton #autoHideTitleLabel { padding-left: 4px; } + +ads--CResizeHandle +{ + background: red; + border: 1px solid green; +} \ No newline at end of file From ff0b32a8e0d6bcdfc51b769389ebad37eab50353 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 24 Oct 2022 20:34:09 +0200 Subject: [PATCH 122/236] Added new Visual Studio Light theme --- demo/MainWindow.cpp | 2 +- src/DockManager.cpp | 2 +- src/ads.qrc | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 8a028e558..8275456fb 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -650,7 +650,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus - //CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); diff --git a/src/DockManager.cpp b/src/DockManager.cpp index d349b1a66..c61c42629 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -192,7 +192,7 @@ void DockManagerPrivate::loadStylesheet() QString Result; QString FileName = ":ads/stylesheets/"; FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) - ? "focus_highlighting" : "default"; + ? "visual_studio_light" : "default"; #ifdef Q_OS_LINUX FileName += "_linux"; #endif diff --git a/src/ads.qrc b/src/ads.qrc index 48ff5cca8..9a5404110 100644 --- a/src/ads.qrc +++ b/src/ads.qrc @@ -17,5 +17,6 @@ images/restore-button-focused.svg images/vs-pin-button.svg images/vs-pin-button-pinned.svg + stylesheets/visual_studio_light.css From 8e8ead0b4f5c62557cc17c14f91534a67e501c89 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 09:11:10 +0200 Subject: [PATCH 123/236] Improved visual_studio_light.css --- demo/main.cpp | 12 +- examples/hideshow/MainWindow.cpp | 2 + src/DockManager.cpp | 5 +- src/stylesheets/default.css | 10 +- src/stylesheets/visual_studio_light.css | 241 ++++++++++++++++++++++++ 5 files changed, 257 insertions(+), 13 deletions(-) create mode 100644 src/stylesheets/visual_studio_light.css diff --git a/demo/main.cpp b/demo/main.cpp index a9487867e..2b7e636af 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -46,16 +46,16 @@ int main(int argc, char *argv[]) a.setApplicationName("Advanced Docking System Demo"); a.setQuitOnLastWindowClosed(true); - QFile StyleSheetFile(":/adsdemo/app.css"); - StyleSheetFile.open(QIODevice::ReadOnly); - QTextStream StyleSheetStream(&StyleSheetFile); - a.setStyleSheet(StyleSheetStream.readAll()); - StyleSheetFile.close(); - qInstallMessageHandler(myMessageOutput); qDebug() << "Message handler test"; CMainWindow mw; mw.show(); + + QFile StyleSheetFile(":/adsdemo/app.css"); + StyleSheetFile.open(QIODevice::ReadOnly); + QTextStream StyleSheetStream(&StyleSheetFile); + a.setStyleSheet(StyleSheetStream.readAll()); + StyleSheetFile.close(); return a.exec(); } diff --git a/examples/hideshow/MainWindow.cpp b/examples/hideshow/MainWindow.cpp index e4d7449fb..44ce67219 100644 --- a/examples/hideshow/MainWindow.cpp +++ b/examples/hideshow/MainWindow.cpp @@ -5,6 +5,8 @@ #include #include +using namespace ads; + MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index c61c42629..1f7e1f9ef 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -191,8 +191,9 @@ void DockManagerPrivate::loadStylesheet() initResource(); QString Result; QString FileName = ":ads/stylesheets/"; - FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) - ? "visual_studio_light" : "default"; + FileName += "visual_studio_light"; + /*FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) + ? "focus_highlighting" : "default";*/ #ifdef Q_OS_LINUX FileName += "_linux"; #endif diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 9dbf7899f..d18a20353 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -57,11 +57,6 @@ QScrollArea#dockWidgetScrollArea { border: none; } -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - #tabCloseButton { margin-top: 2px; @@ -188,6 +183,11 @@ ads--CAutoHideDockContainer::handle:horizontal { }*/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + ads--CAutoHideDockContainer #dockAreaAutoHideButton { qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css new file mode 100644 index 000000000..f6b2f4603 --- /dev/null +++ b/src/stylesheets/visual_studio_light.css @@ -0,0 +1,241 @@ + +/* + * Default style sheet on Windows Platforms with focus highlighting flag enabled + */ +ads--CDockManager { + padding: 6px; + background: palette(window); +} + + +ads--CDockContainerWidget { + background: palette(window); +} + + +/*ads--CDockContainerWidget > QSplitter{ + padding: 1 0 1 0; +}*/ + +ads--CDockAreaWidget { + background: palette(window); + /*border: 1px solid palette(dark);*/ +} + + +ads--CDockWidgetTab { + background: palette(window); + border: none; + padding: 0 0px; + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetTab[activeTab="true"] { + background: rgb(204, 204, 204); +} + +ads--CDockWidgetTab QLabel { + color: palette(foreground); +} + +ads--CDockWidgetTab[activeTab="true"] QLabel { + color: palette(foreground); +} + +ads--CDockWidget { + background: palette(light); + /*border-color: palette(dark); + border-style: solid; + border-width: 1px 0 0 0;*/ + border: 1px solid rgb(204, 204, 204); + border-top: none; +} + +ads--CTitleBarButton { + padding: 0px 0px; +} + +QScrollArea#dockWidgetScrollArea { + padding: 0px; + border: none; +} + +#tabsMenuButton::menu-indicator { + image: none; +} + +#tabCloseButton { + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#tabCloseButton:hover { + /*border: 1px solid rgba(0, 0, 0, 32);*/ + background: rgba(0, 0, 0, 24); +} + +#tabCloseButton:pressed { + background: rgba(0, 0, 0, 48); +} + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +ads--CDockSplitter::handle { + /*background-color: palette(dark);*/ + /* uncomment the following line if you would like to change the size of + the splitter handles */ + /* height: 1px; */ +} + +/* Focus related styling */ +ads--CDockWidgetTab[focused="true"] { + background: palette(highlight); + border-color: palette(highlight); +} + +ads--CDockWidgetTab[focused="true"]>#tabCloseButton { + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + +ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed { + background: rgba(255, 255, 255, 92); +} + +ads--CDockWidgetTab[focused="true"] QLabel { + color: palette(light); +} + +ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid rgb(204, 204, 204); + padding-bottom: 0px; +} + +ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid palette(highlight); + padding-bottom: 0px; +} + +/*----------------------------------------------------------------------------- + * Styling of auto hide functionality + *---------------------------------------------------------------------------- + */ +ads--CDockWidgetSideTab { + /*background: palette(window);*/ + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"] { + /*border-right: 1px solid white;*/ +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"] { + /*border-bottom: 1px solid white;*/ +} + +ads--CDockWidgetSideTab[sideTabBarArea="2"] { + border-bottom: 1px solid white; +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"] { + border-right: 1px solid white; +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { + +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { + +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { + +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { + +} + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { + +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { + +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { + +} + +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { + +} + +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { + +} + +/* +ads--CAutoHideDockContainer::handle { + background: palette(dark); +} + +ads--CAutoHideDockContainer::handle:vertical { + height: 4px; +} + + +ads--CAutoHideDockContainer::handle:horizontal { + width: 4px; +} +*/ + +/*ads--CAutoHideDockContainer[sideTabBarArea="0"]:handle { + border: 1px solid palette(dark); + background: white; +}*/ + + +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); + qproperty-iconSize: 16px; +} + +#autoHideTitleLabel { + padding-left: 4px; +} + +ads--CResizeHandle +{ + background: red; + border: 1px solid green; +} From 7774aaa75a3ce3b2eefaaad009987f1281ba8545 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 09:58:15 +0200 Subject: [PATCH 124/236] Fixed calculateSideTabBarArea function to work properly with every dock container --- src/DockContainerWidget.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index e7fa56102..52f28a980 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1549,41 +1549,41 @@ enum eBorderLocation CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) { - auto DockMgrRect = d->DockManager->contentRect(); + auto ContentRect = this->contentRect(); int borders = BorderNone; // contains all borders that are touched by the dock ware - auto DockAreaTopLeft = DockAreaWidget->mapTo(d->DockManager, DockAreaWidget->rect().topLeft()); + auto DockAreaTopLeft = DockAreaWidget->mapTo(this, DockAreaWidget->rect().topLeft()); auto DockAreaRect = DockAreaWidget->rect(); DockAreaRect.moveTo(DockAreaTopLeft); const qreal aspectRatio = DockAreaRect.width() / (qMax(1, DockAreaRect.height()) * 1.0); - const qreal sizeRatio = (qreal)DockMgrRect.width() / DockAreaRect.width(); + const qreal sizeRatio = (qreal)ContentRect.width() / DockAreaRect.width(); static const int MinBorderDistance = 16; bool HorizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0); // measure border distances - a distance less than 16 px means we touch the // border int BorderDistance[4]; - int Distance = qAbs(DockMgrRect.topLeft().y() - DockAreaRect.topLeft().y()); + int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y()); BorderDistance[CDockWidgetSideTab::Top] = (Distance < MinBorderDistance) ? 0 : Distance; if (!BorderDistance[CDockWidgetSideTab::Top]) { borders |= BorderTop; } qDebug() << "BorderDistance[CDockWidgetSideTab::Top] " << BorderDistance[CDockWidgetSideTab::Top]; - Distance = qAbs(DockMgrRect.bottomRight().y() - DockAreaRect.bottomRight().y()); + Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y()); BorderDistance[CDockWidgetSideTab::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; if (!BorderDistance[CDockWidgetSideTab::Bottom]) { borders |= BorderBottom; } qDebug() << "BorderDistance[CDockWidgetSideTab::Bottom] " << BorderDistance[CDockWidgetSideTab::Bottom]; - Distance = qAbs(DockMgrRect.topLeft().x() - DockAreaRect.topLeft().x()); + Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x()); BorderDistance[CDockWidgetSideTab::Left] = (Distance < MinBorderDistance) ? 0 : Distance; if (!BorderDistance[CDockWidgetSideTab::Left]) { borders |= BorderLeft; } qDebug() << "BorderDistance[CDockWidgetSideTab::Left] " << BorderDistance[CDockWidgetSideTab::Left]; - Distance = qAbs(DockMgrRect.bottomRight().x() - DockAreaRect.bottomRight().x()); + Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x()); BorderDistance[CDockWidgetSideTab::Right] = (Distance < MinBorderDistance) ? 0 : Distance; if (!BorderDistance[CDockWidgetSideTab::Right]) { From 14acd0fe4a517cd934c1dcaeb6ff94928ecbe4b7 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 10:01:51 +0200 Subject: [PATCH 125/236] Fixed updateResizeHandleSizeLimitMax() function to work properly with all dock containers --- src/AutoHideDockContainer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 05135bfa8..7fc5d93da 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -168,7 +168,7 @@ struct AutoHideDockContainerPrivate void updateResizeHandleSizeLimitMax() { - auto Rect = DockManager->contentRect(); + auto Rect = _this->parentContainer()->contentRect(); ResizeHandle->setMaxResizeSize(ResizeHandle->orientation() == Qt::Horizontal ? Rect.width() : Rect.height()); } From 6eb46250b1aad70dcf89c2adb3b3cfa55185c82a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 10:59:01 +0200 Subject: [PATCH 126/236] Improved visual_studio_light.css theme --- src/AutoHideDockContainer.cpp | 2 - src/ads.qrc | 1 + src/images/vs-pin-button-pinned-focused.svg | 2 + src/stylesheets/visual_studio_light.css | 55 ++++++++++++++++++--- 4 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 src/images/vs-pin-button-pinned-focused.svg diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7fc5d93da..a45f455e4 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -218,8 +218,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW updateSize(); parent->registerAutoHideWidget(this); - setAutoFillBackground(true); - setMouseTracking(true); } diff --git a/src/ads.qrc b/src/ads.qrc index 9a5404110..3348820fd 100644 --- a/src/ads.qrc +++ b/src/ads.qrc @@ -18,5 +18,6 @@ images/vs-pin-button.svg images/vs-pin-button-pinned.svg stylesheets/visual_studio_light.css + images/vs-pin-button-pinned-focused.svg diff --git a/src/images/vs-pin-button-pinned-focused.svg b/src/images/vs-pin-button-pinned-focused.svg new file mode 100644 index 000000000..6608545ec --- /dev/null +++ b/src/images/vs-pin-button-pinned-focused.svg @@ -0,0 +1,2 @@ + + diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css index f6b2f4603..683aa8347 100644 --- a/src/stylesheets/visual_studio_light.css +++ b/src/stylesheets/visual_studio_light.css @@ -53,6 +53,16 @@ ads--CDockWidget { ads--CTitleBarButton { padding: 0px 0px; + background: transparent; + border: none; +} + +ads--CTitleBarButton:hover { + background: rgba(0, 0, 0, 24); +} + +ads--CTitleBarButton:pressed { + background: rgba(0, 0, 0, 48); } QScrollArea#dockWidgetScrollArea { @@ -108,7 +118,7 @@ ads--CDockWidgetTab[focused="true"] { border-color: palette(highlight); } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton { +ads--CDockWidgetTab[focused="true"] > #tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } @@ -131,9 +141,7 @@ ads--CDockAreaTitleBar { } ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - background: transparent; border-bottom: 2px solid palette(highlight); - padding-bottom: 0px; } /*----------------------------------------------------------------------------- @@ -198,6 +206,7 @@ ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { } + /* ads--CAutoHideDockContainer::handle { background: palette(dark); @@ -226,16 +235,48 @@ ads--CAutoHideDockContainer::handle:horizontal { ads--CAutoHideDockContainer #dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); qproperty-iconSize: 16px; } -#autoHideTitleLabel { +#autoHideTitleLabel +{ padding-left: 4px; + color: palette(light); } ads--CResizeHandle { - background: red; - border: 1px solid green; + /*background: red; + border: 1px solid green;*/ +} + + +ads--CAutoHideDockContainer +{ + background: palette(window); +} + + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar +{ + background: palette(highlight); + border: none; + padding: 0px; +} + +ads--CAutoHideDockContainer #dockAreaCloseButton +{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) } + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover +{ + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed +{ + background: rgba(255, 255, 255, 96); +} \ No newline at end of file From 0fbbef7609e76112d0d8d1fefbd5483e16b66638 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 11:09:13 +0200 Subject: [PATCH 127/236] Fixed initial size of AutoHideDockContainer --- src/AutoHideDockContainer.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index a45f455e4..f56cb6e8e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -317,7 +317,10 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) d->DockArea->addDockWidget(DockWidget); d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); qDebug() << "DockWidget->size(): " << DockWidget->size(); - this->resize(OldDockArea ? OldDockArea->size() : d->DockWidget->size()); + // The initial size should be a little bit bigger than the original dock + // area size to prevent that the resize handle of this auto hid dock area + // is near of the splitter of the old dock area. + d->Size = OldDockArea->size() + QSize(16, 16); updateSize(); } From 314ed4bbf23964179543b2c5a8187f11d9badfe0 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 25 Oct 2022 17:37:54 +0800 Subject: [PATCH 128/236] fix missing case statement --- src/AutoHideDockContainer.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6d2884322..4423be47f 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -299,6 +299,7 @@ void CAutoHideDockContainer::setDockSizeProportion(float SplitterProportion) const auto remainingSize = INT_MAX - dockSize; switch (d->SideTabBarArea) { + case CDockWidgetSideTab::Top: case CDockWidgetSideTab::Left: { setSizes({ dockSize, remainingSize }); From 54c7c7e2a580baf369734e16248e6040cd3f92fa Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 25 Oct 2022 18:00:36 +0800 Subject: [PATCH 129/236] iconsize -> iconSize in css --- src/stylesheets/default.css | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index b25624516..94790b6e1 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -64,7 +64,7 @@ QScrollArea#dockWidgetScrollArea { #dockAreaAutoHideButton { qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } #tabCloseButton { @@ -74,7 +74,7 @@ QScrollArea#dockWidgetScrollArea { padding: 0px -2px; qproperty-icon: url(:/ads/images/close-button.svg), url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } #tabCloseButton:hover { @@ -92,19 +92,19 @@ QScrollArea#dockWidgetScrollArea { #tabsMenuButton { qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } #dockAreaCloseButton { qproperty-icon: url(:/ads/images/close-button.svg), url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } #detachGroupButton { qproperty-icon: url(:/ads/images/detach-button.svg), url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } /*----------------------------------------------------------------------------- @@ -113,7 +113,7 @@ QScrollArea#dockWidgetScrollArea { */ ads--CDockWidgetSideTab { /*background: palette(window);*/ - qproperty-iconsize: 16px 16px; /* this is optional in case you would like to change icon size*/ + qproperty-iconSize: 16px 16px; /* this is optional in case you would like to change icon size*/ } ads--CDockWidgetSideTab[sideTabBarArea="0"] { @@ -190,7 +190,7 @@ ads--CAutoHideDockContainer::handle:horizontal { ads--CAutoHideDockContainer #dockAreaAutoHideButton { qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); - qproperty-iconsize: 16px; + qproperty-iconSize: 16px; } #autoHideTitleLabel { From fafa52a1baf10e476c97e7f045691e7c0847d42c Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Tue, 25 Oct 2022 18:03:41 +0800 Subject: [PATCH 130/236] fix bug where "right click -> detach group" would of an overlay dock would not remove the dockwidget side tab --- src/DockAreaTitleBar.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index cb2860f94..bc047dae3 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -412,6 +412,11 @@ void CDockAreaTitleBar::onUndockButtonClicked() { if (d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)) { + if (d->DockArea->autoHideDockContainer()) + { + d->DockArea->autoHideDockContainer()->cleanupAndDelete(); + } + d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive); } } From a74d8acb421dff3d94c0fdd5ab20b3828ec5f591 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 15:51:38 +0200 Subject: [PATCH 131/236] Improved visual_studio_light.css --- src/AutoHideDockContainer.cpp | 13 +++-- src/DockWidgetSideTab.cpp | 2 +- src/stylesheets/visual_studio_light.css | 77 +++++++++++++------------ 3 files changed, 49 insertions(+), 43 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index f56cb6e8e..a034d70eb 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -233,7 +233,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWid //============================================================================ void CAutoHideDockContainer::updateSize() { - qDebug() << "CAutoHideDockContainer::updateSize()"; auto dockContainerParent = parentContainer(); auto rect = dockContainerParent->contentRect(); @@ -485,6 +484,7 @@ void CAutoHideDockContainer::collapseView(bool Enable) qApp->installEventFilter(this); } + qDebug() << "CAutoHideDockContainer::collapseView " << Enable; d->DockWidget->sideTabWidget()->updateStyle(); } @@ -508,22 +508,23 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) } else if (event->type() == QEvent::MouseButtonPress) { - // First we check, if the mouse button press is inside the dock manager + auto Container = parentContainer(); + // First we check, if the mouse button press is inside the container // widget. If it is not, i.e. if someone resizes the main window or // clicks into the application menu or toolbar, then we ignore the // event auto widget = qobject_cast(watched); - bool IsDockManager = false; + bool IsContainer = false; while (widget) { - if (widget == d->DockManager) + if (widget == Container) { - IsDockManager = true; + IsContainer = true; } widget = widget->parentWidget(); } - if (!IsDockManager) + if (!IsContainer) { return Super::eventFilter(watched, event); } diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index c25f36716..ddea19524 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -92,7 +92,6 @@ CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) d->DockWidget = DockWidget; setText(DockWidget->windowTitle()); setFocusPolicy(Qt::NoFocus); - setFlat(true); } @@ -107,6 +106,7 @@ CDockWidgetSideTab::~CDockWidgetSideTab() void CDockWidgetSideTab::updateStyle() { internal::repolishStyle(this, internal::RepolishDirectChildren); + update(); } diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css index 683aa8347..8e01c52e9 100644 --- a/src/stylesheets/visual_studio_light.css +++ b/src/stylesheets/visual_studio_light.css @@ -2,14 +2,15 @@ /* * Default style sheet on Windows Platforms with focus highlighting flag enabled */ -ads--CDockManager { - padding: 6px; +ads--CDockManager +{ background: palette(window); } ads--CDockContainerWidget { background: palette(window); + padding: 2px; } @@ -153,57 +154,61 @@ ads--CDockWidgetSideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab[sideTabBarArea="0"] { - /*border-right: 1px solid white;*/ -} - - -ads--CDockWidgetSideTab[sideTabBarArea="1"] { - /*border-bottom: 1px solid white;*/ -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"] { - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"] { - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { +ads--CDockWidgetSideTab +{ + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; } -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - +ads--CDockWidgetSideTab[sideTabBarArea="0"], +ads--CDockWidgetSideTab[sideTabBarArea="2"] +{ + border-top: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; } -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"], +ads--CDockWidgetSideTab[sideTabBarArea="3"] +{ + border-bottom: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"][activeTab="true"] { - -} -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] +{ + border-top: 5px solid palette(highlight); + color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] +{ + border-bottom: 5px solid palette(highlight); + color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] +{ + border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] +{ + border-bottom: 5px solid palette(highlight); } @@ -279,4 +284,4 @@ ads--CAutoHideDockContainer ads--CTitleBarButton:hover ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { background: rgba(255, 255, 255, 96); -} \ No newline at end of file +} From c3aefff3b43c2eb878e26ed6e069297eea0bb422 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 16:05:08 +0200 Subject: [PATCH 132/236] Added missing exports for ResizeHandle and PushButton --- src/AutoHideDockContainer.h | 6 +++--- src/PushButton.h | 13 +++++++++++-- src/ResizeHandle.h | 3 ++- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 6ecf7db30..7bd3e92f1 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -47,9 +47,9 @@ class CSideTabBar; class CDockAreaWidget; class CDockingStateReader; -// Note: This widget must be a QSplitter, inheriting from QWidget and keeping an -// internal splitter breaks ActiveX widgets -// likely due to layout issues between this widget and the internal splitter +/** + * Auto hide container for hosting an auto hide dock widget + */ class ADS_EXPORT CAutoHideDockContainer : public QFrame { Q_OBJECT diff --git a/src/PushButton.h b/src/PushButton.h index 2d36961e9..e375d20d3 100644 --- a/src/PushButton.h +++ b/src/PushButton.h @@ -10,15 +10,17 @@ //============================================================================ // INCLUDES //============================================================================ +#include "ads_globals.h" + #include namespace ads { /** - * ADS specific push button class + * ADS specific push button class with orientation support */ -class CPushButton : public QPushButton +class ADS_EXPORT CPushButton : public QPushButton { Q_OBJECT public: @@ -32,7 +34,14 @@ class CPushButton : public QPushButton virtual QSize sizeHint() const override; + /** + * Returns the current orientation + */ Orientation orientation() const; + + /** + * Set the orientation of this button + */ void setOrientation(Orientation orientation); protected: diff --git a/src/ResizeHandle.h b/src/ResizeHandle.h index a7a1360ee..703130688 100644 --- a/src/ResizeHandle.h +++ b/src/ResizeHandle.h @@ -10,6 +10,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include "ads_globals.h" #include namespace ads @@ -19,7 +20,7 @@ struct ResizeHandlePrivate; /** * Resize handle for resizing its parent widget */ -class CResizeHandle : public QFrame +class ADS_EXPORT CResizeHandle : public QFrame { Q_OBJECT Q_DISABLE_COPY(CResizeHandle) From 293bf9b74fd33d3221884f21d0ba4b3285a25ae0 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 25 Oct 2022 21:10:20 +0200 Subject: [PATCH 133/236] Updated stylesheet to default --- src/DockManager.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 1f7e1f9ef..d349b1a66 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -191,9 +191,8 @@ void DockManagerPrivate::loadStylesheet() initResource(); QString Result; QString FileName = ":ads/stylesheets/"; - FileName += "visual_studio_light"; - /*FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) - ? "focus_highlighting" : "default";*/ + FileName += CDockManager::testConfigFlag(CDockManager::FocusHighlighting) + ? "focus_highlighting" : "default"; #ifdef Q_OS_LINUX FileName += "_linux"; #endif From 43c8d69281009ae9140503c08760c927ea82e0d0 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 07:28:58 +0200 Subject: [PATCH 134/236] Restored initial implementation of ElidingLabel because vertical label is not required anymore - SideBarButton implements orientation feature --- src/ElidingLabel.cpp | 116 ++----------------------------------------- src/ElidingLabel.h | 26 +--------- 2 files changed, 5 insertions(+), 137 deletions(-) diff --git a/src/ElidingLabel.cpp b/src/ElidingLabel.cpp index f865941ec..ac521228f 100644 --- a/src/ElidingLabel.cpp +++ b/src/ElidingLabel.cpp @@ -29,7 +29,6 @@ //============================================================================ #include "ElidingLabel.h" #include -#include namespace ads @@ -118,7 +117,7 @@ Qt::TextElideMode CElidingLabel::elideMode() const void CElidingLabel::setElideMode(Qt::TextElideMode mode) { d->ElideMode = mode; - d->elideText(availableWidthForText()); + d->elideText(size().width()); } //============================================================================ @@ -155,26 +154,12 @@ void CElidingLabel::resizeEvent(QResizeEvent *event) { if (!d->isModeElideNone()) { - d->elideText(availableWidthForText(event)); + d->elideText(event->size().width()); } Super::resizeEvent(event); } -//============================================================================ -int CElidingLabel::availableWidthForText() const -{ - return size().width(); -} - - -//============================================================================ -int CElidingLabel::availableWidthForText(QResizeEvent* event) const -{ - return event->size().width(); -} - - //============================================================================ QSize CElidingLabel::minimumSizeHint() const { @@ -230,7 +215,7 @@ void CElidingLabel::setText(const QString &text) else { internal::setToolTip(this, text); - d->elideText(availableWidthForText()); + d->elideText(this->size().width()); } } @@ -240,101 +225,6 @@ QString CElidingLabel::text() const { return d->Text; } - - -/** - * Private data of public CVerticalElidingLabel - */ -struct VerticalElidingLabelPrivate -{ - CVerticalElidingLabel* _this; - Qt::Orientation Orientation {Qt::Horizontal}; - - VerticalElidingLabelPrivate(CVerticalElidingLabel* _public); -}; - - -//============================================================================ -VerticalElidingLabelPrivate::VerticalElidingLabelPrivate(CVerticalElidingLabel* _public) - : _this(_public) -{ -} - - -//============================================================================ -CVerticalElidingLabel::CVerticalElidingLabel(QWidget* parent, Qt::WindowFlags f) : - CElidingLabel(parent, f), - d(new VerticalElidingLabelPrivate(this)) -{ -} - - -//============================================================================ -void CVerticalElidingLabel::setOrientation(Qt::Orientation orientation) -{ - d->Orientation = orientation; - updateGeometry(); -} - -//============================================================================ -void CVerticalElidingLabel::paintEvent(QPaintEvent* event) -{ - if (d->Orientation == Qt::Vertical) - { - QPainter painter(this); - painter.rotate(90); - painter.drawText(0,0, QLabel::text()); - return; - } - - CElidingLabel::paintEvent(event); -} - -//============================================================================ -QSize CVerticalElidingLabel::sizeHint() const -{ - if (d->Orientation == Qt::Vertical) - { - QSize s = CElidingLabel::minimumSizeHint(); - return QSize(s.height(), s.width()); - } - - return CElidingLabel::sizeHint(); -} - -//============================================================================ -QSize CVerticalElidingLabel::minimumSizeHint() const -{ - if (d->Orientation == Qt::Vertical) - { - QSize s = CElidingLabel::sizeHint(); - return QSize(s.height(), s.width()); - } - - return CElidingLabel::minimumSizeHint(); -} - -//============================================================================ -int CVerticalElidingLabel::availableWidthForText() const -{ - if (d->Orientation == Qt::Vertical) - { - return size().height(); - } - - return CElidingLabel::availableWidthForText(); -} - -//============================================================================ -int CVerticalElidingLabel::availableWidthForText(QResizeEvent* event) const -{ - if (d->Orientation == Qt::Vertical) - { - return event->size().height(); - } - - return CElidingLabel::availableWidthForText(event); -} } // namespace QtLabb //--------------------------------------------------------------------------- diff --git a/src/ElidingLabel.h b/src/ElidingLabel.h index 811a97474..894dcb069 100644 --- a/src/ElidingLabel.h +++ b/src/ElidingLabel.h @@ -36,7 +36,7 @@ namespace ads { struct ElidingLabelPrivate; -struct VerticalElidingLabelPrivate; + /** * A QLabel that supports eliding text. * Because the functions setText() and text() are no virtual functions setting @@ -55,9 +55,6 @@ class ADS_EXPORT CElidingLabel : public QLabel virtual void resizeEvent( QResizeEvent *event ) override; virtual void mouseDoubleClickEvent( QMouseEvent *ev ) override; - virtual int availableWidthForText() const; - virtual int availableWidthForText(QResizeEvent* event) const; - public: using Super = QLabel; @@ -105,26 +102,7 @@ class ADS_EXPORT CElidingLabel : public QLabel void elidedChanged(bool elided); }; //class CElidingLabel - -class CVerticalElidingLabel : public CElidingLabel -{ -private: - VerticalElidingLabelPrivate* d; - -protected: - void paintEvent(QPaintEvent* event) override; - QSize sizeHint() const override; - QSize minimumSizeHint() const override; - int availableWidthForText() const override; - int availableWidthForText(QResizeEvent* event) const override; - -public: - CVerticalElidingLabel(QWidget* parent = 0, Qt::WindowFlags f = Qt::WindowFlags ()); - - void setOrientation(Qt::Orientation orientation); -}; // class CVerticalElidingLabel - -} // namespace ads +} // namespace QtLabb //--------------------------------------------------------------------------- #endif // ElidingLabelH From cd58e6e9b5037b9ff99e6512a2ffe40f8954715f Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 07:29:58 +0200 Subject: [PATCH 135/236] Reverted stylesheets to initial code to restart with styling --- src/stylesheets/default.css | 195 ++++--------------- src/stylesheets/default_linux.css | 72 ------- src/stylesheets/focus_highlighting.css | 80 +------- src/stylesheets/focus_highlighting_linux.css | 77 +------- 4 files changed, 51 insertions(+), 373 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index dd2d5df09..7952bd11a 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -2,206 +2,95 @@ * Default style sheet on Windows Platforms */ ads--CDockContainerWidget { - background: palette(window); + background: palette(dark); } -ads--CDockContainerWidget > QSplitter { - padding: 1 0 1 0; +ads--CDockContainerWidget > QSplitter{ + padding: 1 0 1 0; } ads--CDockContainerWidget ads--CDockSplitter::handle { - background: palette(dark); + background: palette(dark); } ads--CDockAreaWidget { - background: palette(window); - border: 1px solid white; + background: palette(window); + border: 1px solid white; } ads--CDockWidgetTab { - background: palette(window); - border-color: palette(light); - border-style: solid; - border-width: 0 1px 0 0; - padding: 0 0px; + background: palette(window); + border-color: palette(light); + border-style: solid; + border-width: 0 1px 0 0; + 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) - ); - /*background: palette(highlight);*/ + background: qlineargradient(spread : pad, x1 : 0, y1 : 0, x2 : 0, y2 : 0.5, stop : 0 + palette(window), stop:1 palette(light)); + /*background: palette(highlight);*/ } ads--CDockWidgetTab QLabel { - color: palette(dark); + color: palette(dark); } ads--CDockWidgetTab[activeTab="true"] QLabel { - color: palette(foreground); + color: palette(foreground); } ads--CDockWidget { - background: palette(light); - border-color: palette(light); - border-style: solid; - border-width: 1px 0 0 0; + background: palette(light); + border-color: palette(light); + border-style: solid; + border-width: 1px 0 0 0; } ads--CTitleBarButton { - padding: 0px 0px; + padding: 0px 0px; } QScrollArea#dockWidgetScrollArea { - padding: 0px; - border: none; + padding: 0px; + border: none; } - #tabCloseButton { - margin-top: 2px; - background: none; - border: none; - padding: 0px -2px; - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; } #tabCloseButton:hover { - border: 1px solid rgba(0, 0, 0, 32); - background: rgba(0, 0, 0, 16); + border: 1px solid rgba(0, 0, 0, 32); + background: rgba(0, 0, 0, 16); } #tabCloseButton:pressed { - background: rgba(0, 0, 0, 32); + background: rgba(0, 0, 0, 32); } #tabsMenuButton::menu-indicator { - image: none; + image: none; } #tabsMenuButton { - qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconSize: 16px; -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -/*----------------------------------------------------------------------------- - * Styling of auto hide functionality - *---------------------------------------------------------------------------- - */ -ads--CDockWidgetSideTab { - /*background: palette(window);*/ - qproperty-iconSize: 16px 16px; /* this is optional in case you would like to change icon size*/ -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-top: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"] { - border-left: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"] { - border-right: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"] { - border-bottom: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} - -/* -ads--CAutoHideDockContainer::handle { - background: palette(dark); -} - -ads--CAutoHideDockContainer::handle:vertical { - height: 4px; -} - - -ads--CAutoHideDockContainer::handle:horizontal { - width: 4px; -} -*/ - -/*ads--CAutoHideDockContainer[sideTabBarArea="0"]:handle { - border: 1px solid palette(dark); - background: white; -}*/ - - -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-icon: url(:/ads/images/tabs-menu-button.svg); qproperty-iconSize: 16px; } -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; qproperty-iconSize: 16px; } -#autoHideTitleLabel { - padding-left: 4px; +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; } - -ads--CResizeHandle -{ - background: red; - border: 1px solid green; -} \ No newline at end of file diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index 19dfd4c64..ac41491eb 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -43,67 +43,6 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/*----------------------------------------------------------------------------- - * Styling of auto hide functionality - *---------------------------------------------------------------------------- - */ -ads--CDockWidgetSideTab { - background: palette(window); - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-top: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"] { - border-left: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"] { - border-right: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"] { - border-bottom: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} - ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -120,17 +59,6 @@ QScrollArea#dockWidgetScrollArea { border: none; } -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); - qproperty-iconSize: 16px; -} - #tabCloseButton { margin-top: 2px; background: none; diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index cb1576262..555172184 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(window); + background: palette(dark); } ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; @@ -10,7 +10,7 @@ ads--CDockContainerWidget > QSplitter{ ads--CDockAreaWidget { background: palette(window); - border: 1px solid white + border: 1px solid white; } ads--CDockWidgetTab { @@ -36,67 +36,6 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/*----------------------------------------------------------------------------- - * Styling of auto hide functionality - *---------------------------------------------------------------------------- - */ -ads--CDockWidgetSideTab { - background: palette(window); - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-top: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"] { - border-left: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"] { - border-right: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"] { - border-bottom: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} - ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -136,17 +75,6 @@ QScrollArea#dockWidgetScrollArea { background: rgba(0, 0, 0, 48); } -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); - qproperty-iconSize: 16px; -} - #dockAreaCloseButton { qproperty-icon: url(:/ads/images/close-button.svg), url(:/ads/images/close-button-disabled.svg) disabled; @@ -167,7 +95,7 @@ ads--CDockSplitter::handle { } /* Focus related styling */ -ads--CDockWidgetTab[activeTab="true"] { +ads--CDockWidgetTab[focused="true"] { background: palette(highlight); border-color: palette(highlight); } @@ -198,4 +126,4 @@ ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { background: transparent; border-bottom: 2px solid palette(highlight); padding-bottom: 0px; -} \ No newline at end of file +} diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 5c9e2d95c..f16ab5e82 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -44,67 +44,6 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -/*----------------------------------------------------------------------------- - * Styling of auto hide functionality - *---------------------------------------------------------------------------- - */ -ads--CDockWidgetSideTab { - background: palette(window); - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"] { - border-top: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"] { - border-left: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"] { - border-right: 3px solid grey; - border-bottom: 1px solid white; -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"] { - border-bottom: 3px solid grey; - border-right: 1px solid white; -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { - border-bottom: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"] { - border-top: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"] { - border-left: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { - border-right: 3px solid palette(highlight); -} - -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { - border-bottom: 3px solid palette(highlight); -} - ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -133,17 +72,6 @@ QScrollArea#dockWidgetScrollArea { qproperty-iconSize: 16px; } -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned.svg); - qproperty-iconSize: 16px; -} - #tabCloseButton { margin-top: 2px; background: none; @@ -171,6 +99,11 @@ ads--CAutoHideDockContainer #dockAreaAutoHideButton /* Focus related styling */ +ads--CDockWidgetTab[focused="true"] { + background: palette(highlight); + border-color: palette(highlight); +} + ads--CDockWidgetTab[focused="true"]>#tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } From 875a3586004b99cbb8144f63f818a966f3d4d477 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 09:50:16 +0200 Subject: [PATCH 136/236] Ensure the SideTab is hidden if empty --- doc/taiwan_ukraine.jpg | Bin 0 -> 143665 bytes src/SideTabBar.cpp | 41 +++++++++++++++++++++++++++++++++++++---- src/SideTabBar.h | 21 +++++++++++++-------- 3 files changed, 50 insertions(+), 12 deletions(-) create mode 100644 doc/taiwan_ukraine.jpg diff --git a/doc/taiwan_ukraine.jpg b/doc/taiwan_ukraine.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f2f58229b04d06da4fda08e95a68ec294c200a32 GIT binary patch literal 143665 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 D-yuHm7$8F>dm-FNpyu@u&mOr|0O-Dt_{Auom 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�$O$XpkTf`QqMnyFDcDqvKCz2tMUDOCx` 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 tSy&1)m&3p<$%YnZWTb5SideTabArea = area; d->ContainerWidget = parent; - d->Orientation = orientation; + d->Orientation = (area == CDockWidgetSideTab::Bottom || area == CDockWidgetSideTab::Top) + ? Qt::Horizontal : Qt::Vertical; auto mainLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); @@ -80,9 +91,19 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, Qt::Orientation orientati mainLayout->setContentsMargins(0, 0, 0, 0); mainLayout->setSpacing(0); mainLayout->addStretch(1); - setLayout(mainLayout); + setFocusPolicy(Qt::NoFocus); + if (d->isHorizontal()) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + else + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + } + + hide(); } @@ -98,6 +119,7 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) { d->TabsLayout->insertWidget(Index, SideTab); SideTab->setSideTabBar(this); + show(); } @@ -105,6 +127,10 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { d->TabsLayout->removeWidget(SideTab); + if (d->TabsLayout->isEmpty()) + { + hide(); + } } @@ -139,4 +165,11 @@ int CSideTabBar::tabCount() const { return d->TabsLayout->count(); } + + +//============================================================================ +CDockWidgetSideTab::SideTabBarArea CSideTabBar::sideTabBarArea() const +{ + return d->SideTabArea; +} } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 47d0d490a..bf587b372 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -29,7 +29,8 @@ //============================================================================ // INCLUDES //============================================================================ -#include +#include +#include "DockWidgetSideTab.h" #include "ads_globals.h" namespace ads @@ -37,15 +38,14 @@ 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 +class ADS_EXPORT CSideTabBar : public QFrame { Q_OBJECT - + Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) private: @@ -57,12 +57,12 @@ class ADS_EXPORT CSideTabBar : public QWidget void paintEvent(QPaintEvent* event) override; public: - using Super = QWidget; + using Super = QFrame; /** * Default Constructor */ - CSideTabBar(CDockContainerWidget* parent, Qt::Orientation orientation); + CSideTabBar(CDockContainerWidget* parent, CDockWidgetSideTab::SideTabBarArea area); /** * Virtual Destructor @@ -94,8 +94,13 @@ class ADS_EXPORT CSideTabBar : public QWidget */ int tabCount() const; - Q_SIGNALS: - void sideTabAutoHideToggleRequested(); + /** + * Getter for side tab bar area property + */ + CDockWidgetSideTab::SideTabBarArea sideTabBarArea() const; + +Q_SIGNALS: + void sideTabAutoHideToggleRequested(); }; } From b43770de370e2a5b8afecdbb33bc479f8d794cd4 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 09:51:37 +0200 Subject: [PATCH 137/236] Added properties to auto hide widgets to improve CSS styling options --- src/AutoHideDockContainer.cpp | 3 +-- src/DockContainerWidget.cpp | 26 ++++++++++++-------------- src/DockWidgetSideTab.cpp | 10 +++++++++- src/DockWidgetSideTab.h | 6 ++++++ src/PushButton.cpp | 4 ++-- src/PushButton.h | 4 ++-- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 41f5c2eb8..ac7da00aa 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -314,7 +314,6 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockArea->addDockWidget(DockWidget); d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); - qDebug() << "DockWidget->size(): " << DockWidget->size(); // The initial size should be a little bit bigger than the original dock // area size to prevent that the resize handle of this auto hid dock area // is near of the splitter of the old dock area. @@ -454,7 +453,7 @@ void CAutoHideDockContainer::collapseView(bool Enable) qApp->installEventFilter(this); } - qDebug() << "CAutoHideDockContainer::collapseView " << Enable; + ADS_PRINT("CAutoHideDockContainer::collapseView " << Enable); d->DockWidget->sideTabWidget()->updateStyle(); } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 52f28a980..27ac1ce23 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -2098,29 +2098,27 @@ void CDockContainerWidget::createRootSplitter() void CDockContainerWidget::createSideTabBarWidgets() { { - auto leftLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::Left] = new CSideTabBar(this, Qt::Vertical); - leftLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Left]); - leftLayout->addStretch(1); - d->Layout->addLayout(leftLayout, 1, 0); + auto Area = CDockWidgetSideTab::Left; + d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 0); } { - auto rightLayout = new QVBoxLayout(); - d->SideTabBarWidgets[CDockWidgetSideTab::Right] = new CSideTabBar(this, Qt::Vertical); - rightLayout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Right]); - rightLayout->addStretch(1); - d->Layout->addLayout(rightLayout, 1, 2); + auto Area = CDockWidgetSideTab::Right; + d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 2); } { - d->SideTabBarWidgets[CDockWidgetSideTab::Bottom] = new CSideTabBar(this, Qt::Horizontal); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Bottom], 2, 1); + auto Area = CDockWidgetSideTab::Bottom; + d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->Layout->addWidget(d->SideTabBarWidgets[Area], 2, 1); } { - d->SideTabBarWidgets[CDockWidgetSideTab::Top] = new CSideTabBar(this, Qt::Horizontal); - d->Layout->addWidget(d->SideTabBarWidgets[CDockWidgetSideTab::Top], 0, 1); + auto Area = CDockWidgetSideTab::Top; + d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->Layout->addWidget(d->SideTabBarWidgets[Area], 0, 1); } } diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index ddea19524..41000e06f 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -122,16 +122,24 @@ CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const return Left; } + //============================================================================ void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) { d->Orientation = Orientation; - CPushButton::setOrientation((Qt::Horizontal == Orientation) + CPushButton::setButtonOrientation((Qt::Horizontal == Orientation) ? CPushButton::Horizontal : CPushButton::VerticalTopToBottom); updateStyle(); } +//============================================================================ +Qt::Orientation CDockWidgetSideTab::orientation() const +{ + return d->Orientation; +} + + //============================================================================ void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) { diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index f307f3774..6668ff4c7 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -51,6 +51,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton Q_OBJECT Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(Qt::Orientation orientation READ orientation) Q_PROPERTY(bool activeTab READ isActiveTab) private: @@ -109,6 +110,11 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton */ void setOrientation(Qt::Orientation Orientation); + /** + * Returns the current orientation + */ + Qt::Orientation orientation() const; + /** * Update the orientation, visibility and spacing based on the area and the config */ diff --git a/src/PushButton.cpp b/src/PushButton.cpp index e88a5008e..9d6faa599 100644 --- a/src/PushButton.cpp +++ b/src/PushButton.cpp @@ -54,12 +54,12 @@ void CPushButton::paintEvent(QPaintEvent *event) painter.drawControl(QStyle::CE_PushButton, option); } -CPushButton::Orientation CPushButton::orientation() const +CPushButton::Orientation CPushButton::buttonOrientation() const { return m_Orientation; } -void CPushButton::setOrientation(Orientation orientation) +void CPushButton::setButtonOrientation(Orientation orientation) { m_Orientation = orientation; } diff --git a/src/PushButton.h b/src/PushButton.h index e375d20d3..5c4ac7e44 100644 --- a/src/PushButton.h +++ b/src/PushButton.h @@ -37,12 +37,12 @@ class ADS_EXPORT CPushButton : public QPushButton /** * Returns the current orientation */ - Orientation orientation() const; + Orientation buttonOrientation() const; /** * Set the orientation of this button */ - void setOrientation(Orientation orientation); + void setButtonOrientation(Orientation orientation); protected: virtual void paintEvent(QPaintEvent *event) override; From b14d3ff30f60ea8b0884e013c9b97d4efd5b8b3c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 09:51:58 +0200 Subject: [PATCH 138/236] Added auto hide styling to focus_highlighting.css --- src/stylesheets/focus_highlighting.css | 270 ++++++++++++++++++++++--- 1 file changed, 243 insertions(+), 27 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 555172184..8b013dc8d 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -1,18 +1,34 @@ /* * Default style sheet on Windows Platforms with focus highlighting flag enabled */ + + +/***************************************************************************** + * CDockContainerWidget + *****************************************************************************/ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } + ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; } + + +/***************************************************************************** + * CDockAreaWidget + *****************************************************************************/ ads--CDockAreaWidget { background: palette(window); - border: 1px solid white; + /*border: 1px solid white;*/ } + + +/***************************************************************************** + * CDockWidgetTab + *****************************************************************************/ ads--CDockWidgetTab { background: palette(window); border-color: palette(light); @@ -36,6 +52,11 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } + + +/***************************************************************************** + * CDockWidget + *****************************************************************************/ ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -43,19 +64,17 @@ ads--CDockWidget { border-width: 1px 0 0 0; } -ads--CTitleBarButton { - padding: 0px 0px; -} QScrollArea#dockWidgetScrollArea { padding: 0px; border: none; } -#tabsMenuButton::menu-indicator { - image: none; -} + +/***************************************************************************** + * Dock widget tab styling + *****************************************************************************/ #tabCloseButton { margin-top: 2px; background: none; @@ -75,6 +94,53 @@ QScrollArea#dockWidgetScrollArea { background: rgba(0, 0, 0, 48); } +/* Focus related styling */ +ads--CDockWidgetTab[focused="true"] { + background: palette(highlight); + border-color: palette(highlight); +} + +ads--CDockWidgetTab[focused="true"] > #tabCloseButton { + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + +ads--CDockWidgetTab[focused="true"] > #tabCloseButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CDockWidgetTab[focused="true"] > #tabCloseButton:pressed { + background: rgba(255, 255, 255, 92); +} + +ads--CDockWidgetTab[focused="true"] QLabel { + color: palette(light); +} + + + +/***************************************************************************** + * Dock area title bar and buttons styling + *****************************************************************************/ + ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid palette(light); + padding-bottom: 0px; +} + +ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + border-bottom: 2px solid palette(highlight); +} + +ads--CTitleBarButton { + padding: 0px 0px; +} + + +#tabsMenuButton::menu-indicator { + image: none; +} + + #dockAreaCloseButton { qproperty-icon: url(:/ads/images/close-button.svg), url(:/ads/images/close-button-disabled.svg) disabled; @@ -94,36 +160,186 @@ ads--CDockSplitter::handle { /* height: 1px; */ } -/* Focus related styling */ -ads--CDockWidgetTab[focused="true"] { - background: palette(highlight); - border-color: palette(highlight); + + +/***************************************************************************** + * Styling of auto hide functionality + *****************************************************************************/ +ads--CDockWidgetSideTab { + /*background: palette(window);*/ + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton { - qproperty-icon: url(:/ads/images/close-button-focused.svg) + +ads--CDockWidgetSideTab +{ + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover { - background: rgba(255, 255, 255, 48); + +ads--CDockWidgetSideTab[sideTabBarArea="0"], +ads--CDockWidgetSideTab[sideTabBarArea="2"] +{ + border-top: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed { - background: rgba(255, 255, 255, 92); + +ads--CDockWidgetSideTab[sideTabBarArea="1"], +ads--CDockWidgetSideTab[sideTabBarArea="3"] +{ + border-bottom: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; } -ads--CDockWidgetTab[focused="true"] QLabel { + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] +{ + border-top: 5px solid palette(highlight); + color: palette(highlight); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] +{ + border-bottom: 5px solid palette(highlight); + color: palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] +{ + border-top: 5px solid palette(highlight); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] +{ + border-bottom: 5px solid palette(highlight); +} + +ads--CSideTabBar +{ + background: palette(window); +} + + +ads--CSideTabBar[sideTabBarArea="0"] +{ + border-bottom: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="1"] +{ + border-right: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="2"] +{ + border-left: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="3"] +{ + border-top: 1px solid palette(dark); +} + + + +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton +{ + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; +} + +#autoHideTitleLabel +{ + padding-left: 4px; color: palette(light); } -ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid palette(light); - padding-bottom: 0px; + +ads--CAutoHideDockContainer +{ + background: palette(window); } -ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid palette(highlight); - padding-bottom: 0px; + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar +{ + background: palette(highlight); + padding: 0px; + border: none; } + +ads--CResizeHandle +{ + background: palette(window); +} + + +ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle +{ + border-top: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle +{ + border-left: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle +{ + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle +{ + border-top: 1px solid palette(dark); +} + + +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar +{ + background: palette(highlight); + padding: 0px; + border: none; +} + + +ads--CAutoHideDockContainer #dockAreaCloseButton +{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover +{ + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed +{ + background: rgba(255, 255, 255, 96); +} + + From b2399bb2799252ea3f7f25be7e04fa52416f11c4 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 10:57:50 +0200 Subject: [PATCH 139/236] Removed superfluous code from AutoHideDockContainer.cpp --- src/AutoHideDockContainer.cpp | 52 ++++------------------------------- 1 file changed, 6 insertions(+), 46 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index ac7da00aa..2d40dcf3a 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -113,59 +113,19 @@ struct AutoHideDockContainerPrivate /** * Convenience function to get a dock widget area */ - DockWidgetArea getArea(CDockWidgetSideTab::SideTabBarArea area) + DockWidgetArea getDockWidgetArea(CDockWidgetSideTab::SideTabBarArea area) { switch (area) { - case CDockWidgetSideTab::Left: - { - return LeftDockWidgetArea; - } - case CDockWidgetSideTab::Right: - { - return RightDockWidgetArea; - } - case CDockWidgetSideTab::Bottom: - { - return BottomDockWidgetArea; - } - case CDockWidgetSideTab::Top: - { - return TopDockWidgetArea; - } + case CDockWidgetSideTab::Left: return LeftDockWidgetArea; + case CDockWidgetSideTab::Right: return RightDockWidgetArea; + case CDockWidgetSideTab::Bottom: return BottomDockWidgetArea; + case CDockWidgetSideTab::Top: return TopDockWidgetArea; } return LeftDockWidgetArea; } - /* - * Convenience function to get dock position - */ - QPoint getSimplifiedDockAreaPosition() const - { - switch (SideTabBarArea) - { - case CDockWidgetSideTab::Left: - { - return QPoint(1, _this->height() / 2); - } - case CDockWidgetSideTab::Right: - { - return QPoint(_this->width() - 1, _this->height() / 2); - } - case CDockWidgetSideTab::Bottom: - { - return QPoint(_this->width() / 2, _this->height() - 1); - } - case CDockWidgetSideTab::Top: - { - return QPoint(_this->width() / 2, 1); - } - } - - return QPoint(); - } - void updateResizeHandleSizeLimitMax() { auto Rect = _this->parentContainer()->contentRect(); @@ -342,7 +302,7 @@ void CAutoHideDockContainer::moveContentsToParent() // If we unpin the auto hide tock widget, then we insert it into the same // location like it had as a auto hide widget. This brings the least surprise // to the user and he does not have to search where the widget was inserted. - parentContainer()->addDockWidget(d->getArea(d->SideTabBarArea), d->DockWidget); + parentContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); parentContainer()->removeDockArea(d->DockArea); } From 5199fa45d1dbe988e03a29e46ceb39e28ab313c5 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 11:17:05 +0200 Subject: [PATCH 140/236] Implemented save and restore function in AutoHideDockContainer --- src/AutoHideDockContainer.cpp | 48 +++++++++++++++++------------------ 1 file changed, 23 insertions(+), 25 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 2d40dcf3a..7692ea07f 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -132,6 +132,15 @@ struct AutoHideDockContainerPrivate ResizeHandle->setMaxResizeSize(ResizeHandle->orientation() == Qt::Horizontal ? Rect.width() : Rect.height()); } + + /** + * Convenience function to check, if this is an horizontal area + */ + bool isHorizontal() const + { + return isHorizontalArea(SideTabBarArea); + } + }; // struct AutoHideDockContainerPrivate @@ -225,8 +234,6 @@ void CAutoHideDockContainer::updateSize() } break; } - - //resize(rect.width(), rect.height()); } //============================================================================ @@ -236,7 +243,6 @@ CAutoHideDockContainer::~CAutoHideDockContainer() // Remove event filter in case there are any queued messages qApp->removeEventFilter(this); - if (d->DockManager) { parentContainer()->removeAutoHideWidget(this); @@ -327,41 +333,33 @@ void CAutoHideDockContainer::cleanupAndDelete() void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); - QStringList Sizes; - // TODO implement auto hide dock container saving - /*for (auto Size : sizes()) - { - Sizes << QString::number(Size); - }*/ - - s.writeAttribute("Sizes", Sizes.join(" ")); + s.writeAttribute("Size", QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width())); } //============================================================================ bool CAutoHideDockContainer::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()) + bool ok; + int Size = s.attributes().value("Size").toInt(&ok); + if (!ok) { - int value; - TextStream >> value; - Sizes.append(value); + return false; } - // TODO implement restore state - /*if (Sizes.count() != count()) + if (Testing) { - return false; + return true; } - if (!Testing) + if (d->isHorizontal()) { - setSizes(Sizes); - }*/ + d->Size.setHeight(Size); + } + else + { + d->Size.setWidth(Size); + } return true; } From f22d62a85b584d1ff500f19e7ffe876a3cc571a9 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 14:35:11 +0200 Subject: [PATCH 141/236] Implemented non opaque resizing for ResizeHandle --- src/ResizeHandle.cpp | 163 +++++++++++++++++++++++++++++-------------- src/ResizeHandle.h | 12 ++++ 2 files changed, 123 insertions(+), 52 deletions(-) diff --git a/src/ResizeHandle.cpp b/src/ResizeHandle.cpp index fd4874fa2..a29e60ced 100644 --- a/src/ResizeHandle.cpp +++ b/src/ResizeHandle.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include "ads_globals.h" @@ -31,6 +33,9 @@ struct ResizeHandlePrivate bool Pressed = false; int MinSize = 0; int MaxSize = 1; + QPointer RubberBand; + bool OpaqueResize = false; + int HandleWidth = 4; /** * Private data constructor @@ -52,6 +57,16 @@ struct ResizeHandlePrivate { return _this->orientation() == Qt::Horizontal; } + + /** + * Set rubberband position + */ + void setRubberBand(int Pos); + + /** + * Calculates the resize position and geometry + */ + void doResizing(QMouseEvent* e, bool ForceResize = false); }; // struct ResizeHandlePrivate @@ -62,50 +77,44 @@ ResizeHandlePrivate::ResizeHandlePrivate(CResizeHandle *_public) : } + //============================================================================ -CResizeHandle::CResizeHandle(Qt::Edge HandlePosition, QWidget* parent) : - Super(parent), - d(new ResizeHandlePrivate(this)) +void ResizeHandlePrivate::setRubberBand(int Pos) { - d->Target = parent; - setHandlePosition(HandlePosition); - setMinResizeSize(48); - setMaxResizeSize(d->isHorizontal() ? parent->height() : parent->width()); - - if (!d->isHorizontal()) + if (!RubberBand) { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + RubberBand = new QRubberBand(QRubberBand::Line, Target->parentWidget()); } - else + + auto Geometry = _this->geometry(); + auto TopLeft = Target->mapTo(Target->parentWidget(), Geometry.topLeft()); + switch (HandlePosition) { - setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + case Qt::LeftEdge: + case Qt::RightEdge: TopLeft.rx() += Pos; break; + case Qt::TopEdge: + case Qt::BottomEdge: TopLeft.ry() += Pos; break; } -} - -//============================================================================ -CResizeHandle::~CResizeHandle() -{ - delete d; + Geometry.moveTopLeft(TopLeft); + RubberBand->setGeometry(Geometry); + RubberBand->show(); } //============================================================================ -void CResizeHandle::mouseMoveEvent(QMouseEvent* e) +void ResizeHandlePrivate::doResizing(QMouseEvent* e, bool ForceResize) { - if (!(e->buttons() & Qt::LeftButton)) - { - return; - } - int pos = d->pick(e->pos()) - d->MouseOffset; - auto OldGeometry = d->Target->geometry(); + int pos = pick(e->pos()) - MouseOffset; + auto OldGeometry = Target->geometry(); auto NewGeometry = OldGeometry; - switch (d->HandlePosition) + switch (HandlePosition) { case Qt::LeftEdge: { NewGeometry.adjust(pos, 0, 0, 0); - int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize); + int Size = qBound(MinSize, NewGeometry.width(), MaxSize); + pos += (NewGeometry.width() - Size); NewGeometry.setWidth(Size); NewGeometry.moveTopRight(OldGeometry.topRight()); } @@ -115,7 +124,8 @@ void CResizeHandle::mouseMoveEvent(QMouseEvent* e) case Qt::RightEdge: { NewGeometry.adjust(0, 0, pos, 0); - int Size = qBound(d->MinSize, NewGeometry.width(), d->MaxSize); + int Size = qBound(MinSize, NewGeometry.width(), MaxSize); + pos -= (NewGeometry.width() - Size); NewGeometry.setWidth(Size); } break; @@ -123,7 +133,8 @@ void CResizeHandle::mouseMoveEvent(QMouseEvent* e) case Qt::TopEdge: { NewGeometry.adjust(0, pos, 0, 0); - int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize); + int Size = qBound(MinSize, NewGeometry.height(), MaxSize); + pos += (NewGeometry.height() - Size); NewGeometry.setHeight(Size); NewGeometry.moveBottomLeft(OldGeometry.bottomLeft()); } @@ -132,31 +143,67 @@ void CResizeHandle::mouseMoveEvent(QMouseEvent* e) case Qt::BottomEdge: { NewGeometry.adjust(0, 0, 0, pos); - int Size = qBound(d->MinSize, NewGeometry.height(), d->MaxSize); + int Size = qBound(MinSize, NewGeometry.height(), MaxSize); + pos -= (NewGeometry.height() - Size); NewGeometry.setHeight(Size); } break; } - d->Target->setGeometry(NewGeometry); - //qDebug() << "globalGeometry(): " << internal::globalGeometry(d->Target); - //qDebug() << "parentGlobalGeometry(): " << internal::globalGeometry(d->Target->parentWidget()); + + if (_this->opaqueResize() || ForceResize) + { + Target->setGeometry(NewGeometry); + } + else + { + setRubberBand(pos); + } +} + + +//============================================================================ +CResizeHandle::CResizeHandle(Qt::Edge HandlePosition, QWidget* parent) : + Super(parent), + d(new ResizeHandlePrivate(this)) +{ + d->Target = parent; + setHandlePosition(HandlePosition); + setMinResizeSize(48); + setMaxResizeSize(d->isHorizontal() ? parent->height() : parent->width()); + + if (!d->isHorizontal()) + { + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + } + else + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); + } +} + + +//============================================================================ +CResizeHandle::~CResizeHandle() +{ + delete d; +} - /*if (opaqueResize()) +//============================================================================ +void CResizeHandle::mouseMoveEvent(QMouseEvent* e) +{ + if (!(e->buttons() & Qt::LeftButton)) { - moveSplitter(pos); + return; } - else - { - //d->s->setRubberBand(closestLegalPosition(pos)); - }*/ + + d->doResizing(e); } //============================================================================ void CResizeHandle::mousePressEvent(QMouseEvent* e) { - qDebug() << "CResizeHandle::mousePressEvent " << e; if (e->button() == Qt::LeftButton) { d->MouseOffset = d->pick(e->pos()); @@ -169,13 +216,14 @@ void CResizeHandle::mousePressEvent(QMouseEvent* e) //============================================================================ void CResizeHandle::mouseReleaseEvent(QMouseEvent* e) { - qDebug() << "CResizeHandle::mouseReleaseEvent " << e; - /*if (!opaqueResize() && e->button() == Qt::LeftButton) { - int pos = d->pick(parentWidget()->mapFromGlobal(e->globalPos())) - - d->mouseOffset; - d->s->setRubberBand(-1); - moveSplitter(pos); - }*/ + if (!opaqueResize() && e->button() == Qt::LeftButton) + { + if (d->RubberBand) + { + d->RubberBand->deleteLater(); + } + d->doResizing(e, true); + } if (e->button() == Qt::LeftButton) { d->Pressed = false; @@ -229,16 +277,13 @@ QSize CResizeHandle::sizeHint() const switch (d->HandlePosition) { case Qt::LeftEdge: // fall through - case Qt::RightEdge: Result = QSize(4, d->Target->height()); break; + case Qt::RightEdge: Result = QSize(d->HandleWidth, d->Target->height()); break; case Qt::TopEdge: // fall through - case Qt::BottomEdge: Result = QSize(d->Target->width(), 4); break; + case Qt::BottomEdge: Result = QSize(d->Target->width(), d->HandleWidth); break; } - qDebug() << "CResizeHandle::sizeHint(): " << Result; return Result; - /*parentWidget()->style()->sizeFromContents(QStyle::CT_Splitter, &opt, QSize(hw, hw), d->s) - .expandedTo(QApplication::globalStrut());*/ } @@ -263,6 +308,20 @@ void CResizeHandle::setMaxResizeSize(int MaxSize) qDebug() << "CResizeHandle::setMaxResizeSize " << MaxSize; d->MaxSize = MaxSize; } + + +//============================================================================ +void CResizeHandle::setOpaqueResize(bool opaque) +{ + d->OpaqueResize = opaque; +} + + +//============================================================================ +bool CResizeHandle::opaqueResize() const +{ + return d->OpaqueResize; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/ResizeHandle.h b/src/ResizeHandle.h index 703130688..390782438 100644 --- a/src/ResizeHandle.h +++ b/src/ResizeHandle.h @@ -24,6 +24,7 @@ class ADS_EXPORT CResizeHandle : public QFrame { Q_OBJECT Q_DISABLE_COPY(CResizeHandle) + Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize) private: ResizeHandlePrivate* d; ///< private data (pimpl) friend struct ResizeHandlePrivate; @@ -84,6 +85,17 @@ class ADS_EXPORT CResizeHandle : public QFrame * than this value */ void setMaxResizeSize(int MaxSize); + + /** + * Enable / disable opaque resizing + */ + void setOpaqueResize(bool opaque = true); + + /** + * Returns true if widgets are resized dynamically (opaquely) while + * interactively moving the resize handle. Otherwise returns false. + */ + bool opaqueResize() const; }; // class name } // namespace ads From f5ac29c19e7ff0a912d40b7a1ef4ef7d1e635d6f Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 15:06:23 +0200 Subject: [PATCH 142/236] Implemented support for Opaque / Non Opaque auto hide container resizing --- demo/MainWindow.cpp | 2 +- src/AutoHideDockContainer.cpp | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 8275456fb..285b26c50 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -616,7 +616,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line if you want to use opaque undocking and // opaque splitter resizing - // CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); + //CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); // uncomment the following line if you want a fixed tab width that does // not change if the visibility of the close button changes diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7692ea07f..de41960c7 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -94,6 +94,10 @@ int resizeHandleLayoutPosition(CDockWidgetSideTab::SideTabBarArea Area) return 0; } + +/** + * Private data of CAutoHideDockContainer - pimpl + */ struct AutoHideDockContainerPrivate { CAutoHideDockContainer* _this; @@ -126,6 +130,9 @@ struct AutoHideDockContainerPrivate return LeftDockWidgetArea; } + /** + * Update the resize limit of the resize handle + */ void updateResizeHandleSizeLimitMax() { auto Rect = _this->parentContainer()->contentRect(); @@ -182,6 +189,8 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW d->Layout->addWidget(d->DockArea); d->ResizeHandle = new CResizeHandle(edgeFromSideTabBarArea(area), this); d->ResizeHandle->setMinResizeSize(64); + bool OpaqueResize = CDockManager::testConfigFlag(CDockManager::OpaqueSplitterResize); + d->ResizeHandle->setOpaqueResize(OpaqueResize); d->Layout->insertWidget(resizeHandleLayoutPosition(area), d->ResizeHandle); d->Size = d->DockArea->size(); From eb008be404e6b8cc8c31d1fd880c04b229b2b44f Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 15:14:32 +0200 Subject: [PATCH 143/236] Cleanup of focus_highlighting.css --- src/stylesheets/focus_highlighting.css | 157 ++++++++++++------------- 1 file changed, 78 insertions(+), 79 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 8b013dc8d..9bf052c69 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -163,7 +163,14 @@ ads--CDockSplitter::handle { /***************************************************************************** + * * Styling of auto hide functionality + * + *****************************************************************************/ + + +/***************************************************************************** + * CDockWidgetSideTab *****************************************************************************/ ads--CDockWidgetSideTab { /*background: palette(window);*/ @@ -171,8 +178,7 @@ ads--CDockWidgetSideTab { } -ads--CDockWidgetSideTab -{ +ads--CDockWidgetSideTab { background: none; border: none; padding-left: 2px; @@ -182,8 +188,7 @@ ads--CDockWidgetSideTab ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] -{ +ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; @@ -191,8 +196,7 @@ ads--CDockWidgetSideTab[sideTabBarArea="2"] ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] -{ +ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; @@ -201,145 +205,140 @@ ads--CDockWidgetSideTab[sideTabBarArea="3"] ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] -{ +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] -{ +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] -{ +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] -{ +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } -ads--CSideTabBar -{ + +/***************************************************************************** + * CSideTabBar + *****************************************************************************/ +ads--CSideTabBar{ background: palette(window); } -ads--CSideTabBar[sideTabBarArea="0"] -{ +ads--CSideTabBar[sideTabBarArea="0"] { border-bottom: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="1"] -{ +ads--CSideTabBar[sideTabBarArea="1"] { border-right: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="2"] -{ +ads--CSideTabBar[sideTabBarArea="2"] { border-left: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="3"] -{ +ads--CSideTabBar[sideTabBarArea="3"] { border-top: 1px solid palette(dark); } - -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); - qproperty-iconSize: 16px; -} - -#autoHideTitleLabel -{ - padding-left: 4px; - color: palette(light); +/***************************************************************************** + * CAutoHideDockContainer + *****************************************************************************/ +ads--CAutoHideDockContainer { + background: palette(window); } -ads--CAutoHideDockContainer -{ - background: palette(window); +ads--CAutoHideDockContainer ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; } -ads--CAutoHideDockContainer ads--CDockAreaTitleBar -{ +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { background: palette(highlight); padding: 0px; border: none; } -ads--CResizeHandle -{ - background: palette(window); + +#autoHideTitleLabel { + padding-left: 4px; + color: palette(light); } -ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle -{ - border-top: 1px solid palette(dark); +/***************************************************************************** + * CAutoHideDockContainer titlebar buttons + *****************************************************************************/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; } -ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle -{ - border-left: 1px solid palette(dark); +ads--CAutoHideDockContainer #dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; } -ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle -{ - border-right: 1px solid palette(dark); -} -ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle -{ - border-top: 1px solid palette(dark); +ads--CAutoHideDockContainer #dockAreaCloseButton{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) } -/* - * This is required because the ads--CDockAreaWidget[focused="true"] will - * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule - */ -ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar -{ - background: palette(highlight); - padding: 0px; - border: none; +ads--CAutoHideDockContainer ads--CTitleBarButton:hover { + background: rgba(255, 255, 255, 48); } +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { + background: rgba(255, 255, 255, 96); +} -ads--CAutoHideDockContainer #dockAreaCloseButton -{ - qproperty-icon: url(:/ads/images/close-button-focused.svg) +/***************************************************************************** + * CAutoHideDockContainer Titlebar and Buttons + *****************************************************************************/ + + +/***************************************************************************** + * CResizeHandle + *****************************************************************************/ +ads--CResizeHandle { + background: palette(window); } -ads--CAutoHideDockContainer ads--CTitleBarButton:hover -{ - background: rgba(255, 255, 255, 48); +ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { + border-top: 1px solid palette(dark); } -ads--CAutoHideDockContainer ads--CTitleBarButton:pressed -{ - background: rgba(255, 255, 255, 96); +ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { + border-left: 1px solid palette(dark); } +ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} From ea8e4421535a60b846413b3f675f1c28aef95ce7 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 15:36:17 +0200 Subject: [PATCH 144/236] Updated default.css to support the new auto hide functionality --- src/AutoHideDockContainer.cpp | 2 - src/stylesheets/default.css | 229 ++++++++++++++++++++++++- src/stylesheets/focus_highlighting.css | 23 +-- 3 files changed, 235 insertions(+), 19 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index de41960c7..80698f2ca 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -500,12 +500,10 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) //============================================================================ void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) { - std::cout << "ResizeEvent" << std::endl; Super::resizeEvent(event); if (d->ResizeHandle->isResizing()) { d->Size = this->size(); - qDebug() << "Size " << d->Size; d->updateResizeHandleSizeLimitMax(); } } diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 7952bd11a..fd431b1c4 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -1,22 +1,39 @@ /* * Default style sheet on Windows Platforms */ + +/***************************************************************************** + * CDockContainerWidget + *****************************************************************************/ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } -ads--CDockContainerWidget > QSplitter{ - padding: 1 0 1 0; + + +/***************************************************************************** + * CDockSplitter + *****************************************************************************/ +ads--CDockContainerWidget > QSplitter { + padding: 1 0 1 0; } ads--CDockContainerWidget ads--CDockSplitter::handle { background: palette(dark); } + +/***************************************************************************** + * CDockAreaWidget + *****************************************************************************/ ads--CDockAreaWidget { background: palette(window); - border: 1px solid white; } + + +/***************************************************************************** + * CDockWidgetTab + *****************************************************************************/ ads--CDockWidgetTab { background: palette(window); border-color: palette(light); @@ -39,6 +56,10 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } + +/***************************************************************************** + * CDockWidget + *****************************************************************************/ ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -46,15 +67,16 @@ ads--CDockWidget { border-width: 1px 0 0 0; } -ads--CTitleBarButton { - padding: 0px 0px; -} QScrollArea#dockWidgetScrollArea { padding: 0px; border: none; } + +/***************************************************************************** + * Dock widget tab styling + *****************************************************************************/ #tabCloseButton { margin-top: 2px; background: none; @@ -74,6 +96,16 @@ QScrollArea#dockWidgetScrollArea { background: rgba(0, 0, 0, 32); } + + +/***************************************************************************** + * Dock area title bar and buttons styling + *****************************************************************************/ + ads--CTitleBarButton { + padding: 0px 0px; +} + + #tabsMenuButton::menu-indicator { image: none; } @@ -94,3 +126,186 @@ QScrollArea#dockWidgetScrollArea { url(:/ads/images/detach-button-disabled.svg) disabled; qproperty-iconSize: 16px; } + + +/***************************************************************************** + * + * Styling of auto hide functionality + * + *****************************************************************************/ + + +/***************************************************************************** + * CDockWidgetSideTab + *****************************************************************************/ +ads--CDockWidgetSideTab { + /*background: palette(window);*/ + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + + +ads--CDockWidgetSideTab { + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; +} + + +ads--CDockWidgetSideTab[sideTabBarArea="0"], +ads--CDockWidgetSideTab[sideTabBarArea="2"] { + border-top: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"], +ads--CDockWidgetSideTab[sideTabBarArea="3"] { + border-bottom: 5px solid rgba(0, 0, 0, 48); + margin-right: 6px; + min-height: 20; +} + + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { + border-top: 5px solid palette(highlight); + color: palette(highlight); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { + border-bottom: 5px solid palette(highlight); + color: palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { + border-top: 5px solid palette(highlight); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { + border-bottom: 5px solid palette(highlight); +} + + +/***************************************************************************** + * CSideTabBar + *****************************************************************************/ +ads--CSideTabBar{ + background: palette(window); +} + + +ads--CSideTabBar[sideTabBarArea="0"] { + border-bottom: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="1"] { + border-right: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="2"] { + border-left: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="3"] { + border-top: 1px solid palette(dark); +} + + +/***************************************************************************** + * CAutoHideDockContainer + *****************************************************************************/ +ads--CAutoHideDockContainer { + background: palette(window); +} + + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +#autoHideTitleLabel { + padding-left: 4px; + color: palette(light); +} + + +/***************************************************************************** + * CAutoHideDockContainer titlebar buttons + *****************************************************************************/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; +} + + +ads--CAutoHideDockContainer #dockAreaCloseButton{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { + background: rgba(255, 255, 255, 96); +} + +/***************************************************************************** + * CAutoHideDockContainer Titlebar and Buttons + *****************************************************************************/ + + +/***************************************************************************** + * CResizeHandle + *****************************************************************************/ +ads--CResizeHandle { + background: palette(window); +} + + +ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { + border-left: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + + diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 9bf052c69..d55971620 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -10,18 +10,28 @@ ads--CDockContainerWidget { background: palette(window); } -ads--CDockContainerWidget > QSplitter{ - padding: 1 0 1 0; + +/***************************************************************************** + * CDockSplitter + *****************************************************************************/ +ads--CDockContainerWidget > QSplitter { + padding: 1 0 1 0; } +ads--CDockSplitter::handle { + background-color: palette(dark); + /* uncomment the following line if you would like to change the size of + the splitter handles */ + /* height: 1px; */ +} + /***************************************************************************** * CDockAreaWidget *****************************************************************************/ ads--CDockAreaWidget { background: palette(window); - /*border: 1px solid white;*/ } @@ -153,13 +163,6 @@ ads--CTitleBarButton { qproperty-iconSize: 16px; } -ads--CDockSplitter::handle { - background-color: palette(dark); - /* uncomment the following line if you would like to change the size of - the splitter handles */ - /* height: 1px; */ -} - /***************************************************************************** From 822ad481522c898f572f632e0f2aeb91a7857461 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 26 Oct 2022 15:40:35 +0200 Subject: [PATCH 145/236] Code cleanup --- src/ResizeHandle.h | 3 +-- src/SideTabBar.h | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/ResizeHandle.h b/src/ResizeHandle.h index 390782438..81264b129 100644 --- a/src/ResizeHandle.h +++ b/src/ResizeHandle.h @@ -97,7 +97,6 @@ class ADS_EXPORT CResizeHandle : public QFrame */ bool opaqueResize() const; }; // class name -} - // namespace ads +} // namespace ads //----------------------------------------------------------------------------- #endif // ResizeHandleH diff --git a/src/SideTabBar.h b/src/SideTabBar.h index bf587b372..82fea12ce 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -102,6 +102,6 @@ class ADS_EXPORT CSideTabBar : public QFrame Q_SIGNALS: void sideTabAutoHideToggleRequested(); }; -} - +} // namespace ads +//----------------------------------------------------------------------------- #endif From c94155fb06450e87f9d7c068997f18ddf00247c0 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 10:22:28 +0200 Subject: [PATCH 146/236] Moved SideBarLocation enum out of CDockWidgetSideTab into global ads namespace --- demo/MainWindow.cpp | 4 +- examples/autohide/mainwindow.cpp | 4 +- src/AutoHideDockContainer.cpp | 56 +++++++++++----------- src/AutoHideDockContainer.h | 8 ++-- src/DockAreaTabBar.cpp | 1 + src/DockAreaTitleBar.cpp | 1 - src/DockAreaWidget.cpp | 1 + src/DockContainerWidget.cpp | 81 ++++++++++++++++---------------- src/DockContainerWidget.h | 7 +-- src/DockManager.cpp | 6 ++- src/DockManager.h | 6 ++- src/DockWidget.cpp | 4 ++ src/DockWidgetSideTab.cpp | 5 +- src/DockWidgetSideTab.h | 18 ++----- src/DockWidgetTab.cpp | 1 + src/FloatingDockContainer.cpp | 1 + src/ResizeHandle.cpp | 2 - src/SideTabBar.cpp | 9 ++-- src/SideTabBar.h | 6 +-- src/ads_globals.h | 14 ++++++ 20 files changed, 125 insertions(+), 110 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 285b26c50..a47451031 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -650,7 +650,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus - CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + //CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); @@ -748,7 +748,7 @@ void CMainWindow::onViewToggled(bool Open) return; } - qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; + //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; } diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index acde5674f..9669268ee 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -47,7 +47,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); TableDockWidget->setDefaultAutoHideDockProportion(0.5); - DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea::Left, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 80698f2ca..51e00cbfa 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -50,14 +50,14 @@ namespace ads static const int ResizeMargin = 4; //============================================================================ -bool static isHorizontalArea(CDockWidgetSideTab::SideTabBarArea Area) +bool static isHorizontalArea(SideBarLocation Area) { switch (Area) { - case CDockWidgetSideTab::Top: - case CDockWidgetSideTab::Bottom: return true; - case CDockWidgetSideTab::Left: - case CDockWidgetSideTab::Right: return false; + case SideBarLocation::Top: + case SideBarLocation::Bottom: return true; + case SideBarLocation::Left: + case SideBarLocation::Right: return false; } return true; @@ -65,14 +65,14 @@ bool static isHorizontalArea(CDockWidgetSideTab::SideTabBarArea Area) //============================================================================ -Qt::Edge static edgeFromSideTabBarArea(CDockWidgetSideTab::SideTabBarArea Area) +Qt::Edge static edgeFromSideTabBarArea(SideBarLocation Area) { switch (Area) { - case CDockWidgetSideTab::Top: return Qt::BottomEdge; - case CDockWidgetSideTab::Bottom: return Qt::TopEdge; - case CDockWidgetSideTab::Left: return Qt::RightEdge; - case CDockWidgetSideTab::Right: return Qt::LeftEdge; + case SideBarLocation::Top: return Qt::BottomEdge; + case SideBarLocation::Bottom: return Qt::TopEdge; + case SideBarLocation::Left: return Qt::RightEdge; + case SideBarLocation::Right: return Qt::LeftEdge; } return Qt::LeftEdge; @@ -80,15 +80,15 @@ Qt::Edge static edgeFromSideTabBarArea(CDockWidgetSideTab::SideTabBarArea Area) //============================================================================ -int resizeHandleLayoutPosition(CDockWidgetSideTab::SideTabBarArea Area) +int resizeHandleLayoutPosition(SideBarLocation Area) { switch (Area) { - case CDockWidgetSideTab::Bottom: - case CDockWidgetSideTab::Right: return 0; + case SideBarLocation::Bottom: + case SideBarLocation::Right: return 0; - case CDockWidgetSideTab::Top: - case CDockWidgetSideTab::Left: return 1; + case SideBarLocation::Top: + case SideBarLocation::Left: return 1; } return 0; @@ -104,7 +104,7 @@ struct AutoHideDockContainerPrivate CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; QPointer DockManager{nullptr}; - CDockWidgetSideTab::SideTabBarArea SideTabBarArea; + SideBarLocation SideTabBarArea; QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; QSize Size; @@ -117,14 +117,14 @@ struct AutoHideDockContainerPrivate /** * Convenience function to get a dock widget area */ - DockWidgetArea getDockWidgetArea(CDockWidgetSideTab::SideTabBarArea area) + DockWidgetArea getDockWidgetArea(SideBarLocation area) { switch (area) { - case CDockWidgetSideTab::Left: return LeftDockWidgetArea; - case CDockWidgetSideTab::Right: return RightDockWidgetArea; - case CDockWidgetSideTab::Bottom: return BottomDockWidgetArea; - case CDockWidgetSideTab::Top: return TopDockWidgetArea; + case SideBarLocation::Left: return LeftDockWidgetArea; + case SideBarLocation::Right: return RightDockWidgetArea; + case SideBarLocation::Bottom: return BottomDockWidgetArea; + case SideBarLocation::Top: return TopDockWidgetArea; } return LeftDockWidgetArea; @@ -168,7 +168,7 @@ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const //============================================================================ -CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : +CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBarLocation area, CDockContainerWidget* parent) : Super(parent), d(new AutoHideDockContainerPrivate(this)) { @@ -200,7 +200,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, CDockW //============================================================================ -CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent) : +CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarLocation area, CDockContainerWidget* parent) : CAutoHideDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); @@ -215,17 +215,17 @@ void CAutoHideDockContainer::updateSize() switch (sideTabBarArea()) { - case CDockWidgetSideTab::Top: + case SideBarLocation::Top: move(rect.topLeft()); resize(rect.width(), qMin(rect.height(), d->Size.height())); break; - case CDockWidgetSideTab::Left: + case SideBarLocation::Left: move(rect.topLeft()); resize(qMin(d->Size.width(), rect.width()), rect.height()); break; - case CDockWidgetSideTab::Right: + case SideBarLocation::Right: { QPoint p = rect.topRight(); p.rx() -= (width() - 1); @@ -234,7 +234,7 @@ void CAutoHideDockContainer::updateSize() } break; - case CDockWidgetSideTab::Bottom: + case SideBarLocation::Bottom: { QPoint p = rect.bottomLeft(); p.ry() -= (height() - 1); @@ -299,7 +299,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -CDockWidgetSideTab::SideTabBarArea CAutoHideDockContainer::sideTabBarArea() const +SideBarLocation CAutoHideDockContainer::sideTabBarArea() const { return d->SideTabBarArea; } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 7bd3e92f1..047290f97 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -53,7 +53,7 @@ class CDockingStateReader; class ADS_EXPORT CAutoHideDockContainer : public QFrame { Q_OBJECT - Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; @@ -70,12 +70,12 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Create Auto Hide widget with a dock manager */ - CAutoHideDockContainer(CDockManager* DockManager, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockManager* DockManager, SideBarLocation area, CDockContainerWidget* parent); /** * Create Auto Hide widget with the given dock widget */ - CAutoHideDockContainer(CDockWidget* DockWidget, CDockWidgetSideTab::SideTabBarArea area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockWidget* DockWidget, SideBarLocation area, CDockContainerWidget* parent); /** * Virtual Destructor @@ -100,7 +100,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Returns the side tab bar area of this Auto Hide dock container */ - CDockWidgetSideTab::SideTabBarArea sideTabBarArea() const; + SideBarLocation sideTabBarArea() const; /** * Returns the dock area widget of this Auto Hide dock container diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index d06313afd..34a37d490 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -146,6 +146,7 @@ CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) : //============================================================================ CDockAreaTabBar::~CDockAreaTabBar() { + qDebug() << "~CDockAreaTabBar count " << count(); delete d; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index bc047dae3..95eae211c 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -493,7 +493,6 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - qDebug() << "CDockAreaTitleBar::onAutoHideButtonClicked()"; if (d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)) { d->DockArea->toggleAutoHideArea(!d->DockArea->isAutoHide()); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 31a4a7990..94fa8b873 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -867,6 +867,7 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const 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()) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 27ac1ce23..fad92b8a6 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -139,7 +139,7 @@ class DockContainerWidgetPrivate unsigned int zOrderIndex = 0; QList DockAreas; QList AutoHideWidgets; - QMap SideTabBarWidgets; + QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; bool isFloating = false; @@ -255,7 +255,7 @@ class DockContainerWidgetPrivate * Assumes that there are no auto hidden dock areas, and then restores all the dock areas that * exist in the XML */ - bool restoreAutoHideDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing); + bool restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing); /** * Restores either a dock area or an auto hide dock area depending on the value in the XML @@ -1033,7 +1033,7 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, } //============================================================================ -bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, CDockWidgetSideTab::SideTabBarArea area, bool Testing) +bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing) { bool Ok; #ifdef ADS_DEBUG_PRINT @@ -1126,7 +1126,7 @@ bool DockContainerWidgetPrivate::restoreDockOrAutoHideDockArea(CDockingStateRead const auto sideTabAreaValue = Stream.attributes().value("SideTabBarArea"); if (!sideTabAreaValue.isNull()) { - auto sideTabBarArea = static_cast(sideTabAreaValue.toInt(&Ok)); + auto sideTabBarArea = static_cast(sideTabAreaValue.toInt(&Ok)); if (!Ok) { return false; @@ -1500,7 +1500,8 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWidgetContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) +CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWidgetContainer( + SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { if (d->DockManager != DockWidget->dockManager()) { @@ -1546,7 +1547,7 @@ enum eBorderLocation //============================================================================ -CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) +SideBarLocation CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) { auto ContentRect = this->contentRect(); @@ -1562,62 +1563,62 @@ CDockWidgetSideTab::SideTabBarArea CDockContainerWidget::calculateSideTabBarArea // measure border distances - a distance less than 16 px means we touch the // border int BorderDistance[4]; + int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y()); - BorderDistance[CDockWidgetSideTab::Top] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[CDockWidgetSideTab::Top]) + BorderDistance[SideBarLocation::Top] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Top]) { borders |= BorderTop; } - qDebug() << "BorderDistance[CDockWidgetSideTab::Top] " << BorderDistance[CDockWidgetSideTab::Top]; + Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y()); - BorderDistance[CDockWidgetSideTab::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[CDockWidgetSideTab::Bottom]) + BorderDistance[SideBarLocation::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Bottom]) { borders |= BorderBottom; } - qDebug() << "BorderDistance[CDockWidgetSideTab::Bottom] " << BorderDistance[CDockWidgetSideTab::Bottom]; + Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x()); - BorderDistance[CDockWidgetSideTab::Left] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[CDockWidgetSideTab::Left]) + BorderDistance[SideBarLocation::Left] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Left]) { borders |= BorderLeft; } - qDebug() << "BorderDistance[CDockWidgetSideTab::Left] " << BorderDistance[CDockWidgetSideTab::Left]; + Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x()); - BorderDistance[CDockWidgetSideTab::Right] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[CDockWidgetSideTab::Right]) + BorderDistance[SideBarLocation::Right] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Right]) { borders |= BorderRight; } - qDebug() << "BorderDistance[CDockWidgetSideTab::Right] " << BorderDistance[CDockWidgetSideTab::Right]; - auto SideTab = CDockWidgetSideTab::Right; + auto SideTab = SideBarLocation::Right; switch (borders) { // 1. It's touching all borders - case BorderAll: SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Right; break; + case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; // 2. It's touching 3 borders - case BorderVerticalBottom : SideTab = CDockWidgetSideTab::Bottom; break; - case BorderVerticalTop : SideTab = CDockWidgetSideTab::Top; break; - case BorderHorizontalLeft: SideTab = CDockWidgetSideTab::Left; break; - case BorderHorizontalRight: SideTab = CDockWidgetSideTab::Right; break; + case BorderVerticalBottom : SideTab = SideBarLocation::Bottom; break; + case BorderVerticalTop : SideTab = SideBarLocation::Top; break; + case BorderHorizontalLeft: SideTab = SideBarLocation::Left; break; + case BorderHorizontalRight: SideTab = SideBarLocation::Right; break; // 3. Its touching horizontal or vertical borders - case BorderVertical : SideTab = CDockWidgetSideTab::Bottom; break; - case BorderHorizontal: SideTab = CDockWidgetSideTab::Right; break; + case BorderVertical : SideTab = SideBarLocation::Bottom; break; + case BorderHorizontal: SideTab = SideBarLocation::Right; break; // 4. Its in a corner - case BorderTopLeft : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Top : CDockWidgetSideTab::Left; break; - case BorderTopRight : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Top : CDockWidgetSideTab::Right; break; - case BorderBottomLeft : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Left; break; - case BorderBottomRight : SideTab = HorizontalOrientation ? CDockWidgetSideTab::Bottom : CDockWidgetSideTab::Right; break; + case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Left; break; + case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Right; break; + case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Left; break; + case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; // 5 Ists touching only one border - case BorderLeft: SideTab = CDockWidgetSideTab::Left; break; - case BorderRight: SideTab = CDockWidgetSideTab::Right; break; - case BorderTop: SideTab = CDockWidgetSideTab::Top; break; - case BorderBottom: SideTab = CDockWidgetSideTab::Bottom; break; + case BorderLeft: SideTab = SideBarLocation::Left; break; + case BorderRight: SideTab = SideBarLocation::Right; break; + case BorderTop: SideTab = SideBarLocation::Top; break; + case BorderBottom: SideTab = SideBarLocation::Bottom; break; } return SideTab; @@ -2016,7 +2017,7 @@ bool CDockContainerWidget::restoreState(CDockingStateReader& s, bool Testing) bool IsFloating = s.attributes().value("Floating").toInt(); ADS_PRINT("Restore CDockContainerWidget Floating" << IsFloating); - QWidget*NewRootSplitter {}; + QWidget* NewRootSplitter {}; if (!Testing) { d->VisibleDockAreaCount = -1;// invalidate the dock area count @@ -2098,25 +2099,25 @@ void CDockContainerWidget::createRootSplitter() void CDockContainerWidget::createSideTabBarWidgets() { { - auto Area = CDockWidgetSideTab::Left; + auto Area = SideBarLocation::Left; d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 0); } { - auto Area = CDockWidgetSideTab::Right; + auto Area = SideBarLocation::Right; d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 2); } { - auto Area = CDockWidgetSideTab::Bottom; + auto Area = SideBarLocation::Bottom; d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 2, 1); } { - auto Area = CDockWidgetSideTab::Top; + auto Area = SideBarLocation::Top; d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 0, 1); } @@ -2267,7 +2268,7 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea) } //============================================================================ -CSideTabBar* CDockContainerWidget::sideTabBar(CDockWidgetSideTab::SideTabBarArea area) const +CSideTabBar* CDockContainerWidget::sideTabBar(SideBarLocation area) const { return d->SideTabBarWidgets[area]; } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index e33a3a8e0..0efc75d09 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -100,7 +100,8 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - CAutoHideDockContainer* createAndInitializeAutoHideDockWidgetContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder); + CAutoHideDockContainer* createAndInitializeAutoHideDockWidgetContainer( + SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder); /** * Helper function for creation of the root splitter @@ -220,7 +221,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Get's the auto hide dock side tab bar area based on the dock area widget position */ - CDockWidgetSideTab::SideTabBarArea calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget); + SideBarLocation calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget); /** * Removes dockwidget @@ -320,7 +321,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Returns the side tab widget for the given area */ - CSideTabBar* sideTabBar(CDockWidgetSideTab::SideTabBarArea area) const; + CSideTabBar* sideTabBar(SideBarLocation area) const; /** diff --git a/src/DockManager.cpp b/src/DockManager.cpp index d349b1a66..d1aed23b6 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -867,13 +867,15 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eAutoHideInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget, + CDockWidget::eAutoHideInsertOrder insertOrder) { return addAutoHideDockWidgetToContainer(area, Dockwidget, this, insertOrder); } //============================================================================ -CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(SideBarLocation area, CDockWidget* Dockwidget, + CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); auto container = DockContainerWidget->createAndInitializeAutoHideDockWidgetContainer(area, Dockwidget, insertOrder); diff --git a/src/DockManager.h b/src/DockManager.h index 96840c90f..f68367a18 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -340,14 +340,16 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * An overlay widget is used for auto hide functionality * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addAutoHideDockWidget(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockWidget::eAutoHideInsertOrder insertOrder = CDockWidget::Last); + CAutoHideDockContainer* addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget, + CDockWidget::eAutoHideInsertOrder insertOrder = CDockWidget::Last); /** * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. * An overlay widget is used for auto hide functionality * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addAutoHideDockWidgetToContainer(CDockWidgetSideTab::SideTabBarArea area, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder = CDockWidget::Last); + CAutoHideDockContainer* addAutoHideDockWidgetToContainer(SideBarLocation area, + CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder = CDockWidget::Last); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 15fb9c43f..745a6fe0e 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -344,6 +344,10 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : CDockWidget::~CDockWidget() { ADS_PRINT("~CDockWidget()"); + if (d->SideTabWidget) + { + delete d->SideTabWidget; + } delete d; } diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 41000e06f..e4e6423e7 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -98,6 +98,7 @@ CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) //============================================================================ CDockWidgetSideTab::~CDockWidgetSideTab() { + qDebug() << "~CDockWidgetSideTab()"; delete d; } @@ -111,7 +112,7 @@ void CDockWidgetSideTab::updateStyle() //============================================================================ -CDockWidgetSideTab::SideTabBarArea CDockWidgetSideTab::sideTabBarArea() const +SideBarLocation CDockWidgetSideTab::sideTabBarArea() const { auto dockAreaWidget = d->DockWidget->dockAreaWidget(); if (dockAreaWidget && dockAreaWidget->isAutoHide()) @@ -141,7 +142,7 @@ Qt::Orientation CDockWidgetSideTab::orientation() const //============================================================================ -void CDockWidgetSideTab::updateOrientationAndSpacing(SideTabBarArea area) +void CDockWidgetSideTab::updateOrientationAndSpacing(SideBarLocation area) { setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 6668ff4c7..0585bb9aa 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -50,7 +50,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton { Q_OBJECT - Q_PROPERTY(SideTabBarArea sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) Q_PROPERTY(bool activeTab READ isActiveTab) @@ -71,18 +71,6 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton public: using Super = CPushButton; - /** - * Dock widget side tab bar locations - */ - enum SideTabBarArea - { - Top, - Left, - Right, - Bottom - }; - Q_ENUM(SideTabBarArea) - /** * Default Constructor * param[in] DockWidget The dock widget this title bar belongs to @@ -103,7 +91,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton /** * Getter for side tab bar area property */ - SideTabBarArea sideTabBarArea() const; + SideBarLocation sideTabBarArea() const; /** * Set orientation vertical or horizontal @@ -118,7 +106,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton /** * Update the orientation, visibility and spacing based on the area and the config */ - void updateOrientationAndSpacing(SideTabBarArea area); + void updateOrientationAndSpacing(SideBarLocation area); /** * Returns true, if this is the active tab. The tab is active if the auto hide widget is visible diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index e82ae77a4..b97cac074 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -352,6 +352,7 @@ CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) : //============================================================================ CDockWidgetTab::~CDockWidgetTab() { + qDebug() << "~CDockWidgetTab " << text(); ADS_PRINT("~CDockWidgetTab()"); delete d; } diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 2152b6b1d..571c5f12f 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -721,6 +721,7 @@ CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) : //============================================================================ CFloatingDockContainer::~CFloatingDockContainer() { + qDebug() << "~CFloatingDockContainer " << windowTitle(); ADS_PRINT("~CFloatingDockContainer"); if (d->DockManager) { diff --git a/src/ResizeHandle.cpp b/src/ResizeHandle.cpp index a29e60ced..84f02d2ad 100644 --- a/src/ResizeHandle.cpp +++ b/src/ResizeHandle.cpp @@ -297,7 +297,6 @@ bool CResizeHandle::isResizing() const //============================================================================ void CResizeHandle::setMinResizeSize(int MinSize) { - qDebug() << "CResizeHandle::setMinResizeSize " << MinSize; d->MinSize = MinSize; } @@ -305,7 +304,6 @@ void CResizeHandle::setMinResizeSize(int MinSize) //============================================================================ void CResizeHandle::setMaxResizeSize(int MaxSize) { - qDebug() << "CResizeHandle::setMaxResizeSize " << MaxSize; d->MaxSize = MaxSize; } diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 38d4dc1c5..610e40b35 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -54,7 +54,7 @@ struct SideTabBarPrivate CDockContainerWidget* ContainerWidget; QBoxLayout* TabsLayout; Qt::Orientation Orientation; - CDockWidgetSideTab::SideTabBarArea SideTabArea = CDockWidgetSideTab::Left; + SideBarLocation SideTabArea = SideBarLocation::Left; /** * Convenience function to check if this is a horizontal side bar @@ -73,13 +73,13 @@ SideTabBarPrivate::SideTabBarPrivate(CSideTabBar* _public) : //============================================================================ -CSideTabBar::CSideTabBar(CDockContainerWidget* parent, CDockWidgetSideTab::SideTabBarArea area) : +CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : Super(parent), d(new SideTabBarPrivate(this)) { d->SideTabArea = area; d->ContainerWidget = parent; - d->Orientation = (area == CDockWidgetSideTab::Bottom || area == CDockWidgetSideTab::Top) + d->Orientation = (area == SideBarLocation::Bottom || area == SideBarLocation::Top) ? Qt::Horizontal : Qt::Vertical; auto mainLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); @@ -126,6 +126,7 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) //============================================================================ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { + qDebug() << "CSideTabBar::removeSideTab " << SideTab->text(); d->TabsLayout->removeWidget(SideTab); if (d->TabsLayout->isEmpty()) { @@ -168,7 +169,7 @@ int CSideTabBar::tabCount() const //============================================================================ -CDockWidgetSideTab::SideTabBarArea CSideTabBar::sideTabBarArea() const +SideBarLocation CSideTabBar::sideTabBarArea() const { return d->SideTabArea; } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 82fea12ce..f3baa8f86 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -45,7 +45,7 @@ class CDockWidgetSideTab; class ADS_EXPORT CSideTabBar : public QFrame { Q_OBJECT - Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) private: @@ -62,7 +62,7 @@ class ADS_EXPORT CSideTabBar : public QFrame /** * Default Constructor */ - CSideTabBar(CDockContainerWidget* parent, CDockWidgetSideTab::SideTabBarArea area); + CSideTabBar(CDockContainerWidget* parent, SideBarLocation area); /** * Virtual Destructor @@ -97,7 +97,7 @@ class ADS_EXPORT CSideTabBar : public QFrame /** * Getter for side tab bar area property */ - CDockWidgetSideTab::SideTabBarArea sideTabBarArea() const; + SideBarLocation sideTabBarArea() const; Q_SIGNALS: void sideTabAutoHideToggleRequested(); diff --git a/src/ads_globals.h b/src/ads_globals.h index d8021b83d..006ccb7b1 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -69,6 +69,7 @@ QT_FORWARD_DECLARE_CLASS(QSplitter) namespace ads { +Q_NAMESPACE class CDockSplitter; enum DockWidgetArea @@ -130,6 +131,19 @@ enum eBitwiseOperator }; +/** + * Each dock container supports 4 sidbars + */ +enum SideBarLocation +{ + Top, + Left, + Right, + Bottom +}; +Q_ENUMS(SideBarLocation); + + namespace internal { static const bool RestoreTesting = true; From 11223bf6640f17992aaed860255c6e1314582aed Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 10:23:11 +0200 Subject: [PATCH 147/236] Prevent deletion of DockWidgetSideTabs if SideTabBar is deleted - the DockWidget is the real owner --- src/SideTabBar.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 610e40b35..3089983fc 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -110,6 +110,13 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : //============================================================================ CSideTabBar::~CSideTabBar() { + // The SideTabeBar is not the owner of the tabs and to prevent deletion + // we set the parent here to nullptr to remove it from the children + auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto Tab : Tabs) + { + Tab->setParent(nullptr); + } delete d; } From f20c3bc63a3755b12a86e9dd10309cddd9c85fff Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 10:52:05 +0200 Subject: [PATCH 148/236] Fixed wrong position of AutoHideDockContainer when uncollapsing --- src/AutoHideDockContainer.cpp | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 51e00cbfa..6768a234e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -216,30 +216,30 @@ void CAutoHideDockContainer::updateSize() switch (sideTabBarArea()) { case SideBarLocation::Top: - move(rect.topLeft()); resize(rect.width(), qMin(rect.height(), d->Size.height())); + move(rect.topLeft()); break; case SideBarLocation::Left: - move(rect.topLeft()); resize(qMin(d->Size.width(), rect.width()), rect.height()); + move(rect.topLeft()); break; case SideBarLocation::Right: { + resize(qMin(d->Size.width(), rect.width()), rect.height()); QPoint p = rect.topRight(); p.rx() -= (width() - 1); move(p); - resize(qMin(d->Size.width(), rect.width()), rect.height()); } break; case SideBarLocation::Bottom: { + resize(rect.width(), qMin(rect.height(), d->Size.height())); QPoint p = rect.bottomLeft(); p.ry() -= (height() - 1); move(p); - resize(rect.width(), qMin(rect.height(), d->Size.height())); } break; } @@ -404,18 +404,14 @@ void CAutoHideDockContainer::collapseView(bool Enable) if (Enable) { hide(); - d->DockArea->hide(); - d->DockWidget->hide(); qApp->removeEventFilter(this); } else { + updateSize(); d->updateResizeHandleSizeLimitMax(); raise(); show(); - d->DockArea->show(); - d->DockWidget->show(); - updateSize(); d->DockManager->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); } From da9062ef620829450638f66891932dd3a35103fa Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 10:56:42 +0200 Subject: [PATCH 149/236] Fixed wrong rendering of DockWidgetSideTab if orientation changed when loading perspective --- src/PushButton.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/PushButton.cpp b/src/PushButton.cpp index 9d6faa599..54883c88d 100644 --- a/src/PushButton.cpp +++ b/src/PushButton.cpp @@ -62,6 +62,7 @@ CPushButton::Orientation CPushButton::buttonOrientation() const void CPushButton::setButtonOrientation(Orientation orientation) { m_Orientation = orientation; + updateGeometry(); } } // namespace ads From 2d67e9e1e5de782e93998a5fa9a719f5acee79ab Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 11:53:15 +0200 Subject: [PATCH 150/236] Some small changes --- src/AutoHideDockContainer.cpp | 9 ++++++++- src/DockAreaTabBar.cpp | 1 - src/DockWidgetSideTab.h | 3 --- src/DockWidgetTab.cpp | 1 - 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6768a234e..bd3f14a4e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -107,7 +107,7 @@ struct AutoHideDockContainerPrivate SideBarLocation SideTabBarArea; QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; - QSize Size; + QSize Size; // creates invalid size /** * Private data constructor @@ -194,6 +194,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa d->Layout->insertWidget(resizeHandleLayoutPosition(area), d->ResizeHandle); d->Size = d->DockArea->size(); + updateSize(); parent->registerAutoHideWidget(this); } @@ -212,6 +213,7 @@ void CAutoHideDockContainer::updateSize() { auto dockContainerParent = parentContainer(); auto rect = dockContainerParent->contentRect(); + qDebug() << "Size " << d->Size; switch (sideTabBarArea()) { @@ -343,6 +345,9 @@ void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); s.writeAttribute("Size", QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width())); + + qDebug() << ": saveState Size: " << d->Size; + qDebug() << ": saveState Size " << QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width()); } @@ -368,8 +373,10 @@ bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) else { d->Size.setWidth(Size); + qDebug() << ": restoreState Width " << Size; } + qDebug() << ": restoreState Size: " << d->Size; return true; } diff --git a/src/DockAreaTabBar.cpp b/src/DockAreaTabBar.cpp index 34a37d490..d06313afd 100644 --- a/src/DockAreaTabBar.cpp +++ b/src/DockAreaTabBar.cpp @@ -146,7 +146,6 @@ CDockAreaTabBar::CDockAreaTabBar(CDockAreaWidget* parent) : //============================================================================ CDockAreaTabBar::~CDockAreaTabBar() { - qDebug() << "~CDockAreaTabBar count " << count(); delete d; } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 0585bb9aa..f9c2bc6ea 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -117,9 +117,6 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton * returns the dock widget this belongs to */ CDockWidget* dockWidget() const; - -Q_SIGNALS: - void elidedChanged(bool elided); }; // class DockWidgetSideTab } // namespace ads diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index b97cac074..e82ae77a4 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -352,7 +352,6 @@ CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) : //============================================================================ CDockWidgetTab::~CDockWidgetTab() { - qDebug() << "~CDockWidgetTab " << text(); ADS_PRINT("~CDockWidgetTab()"); delete d; } From 85d7b3047cefcc2383e73453bc0e6d0acb2ad4e1 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 13:25:40 +0200 Subject: [PATCH 151/236] Changed AutoHide save and restore code --- src/AutoHideDockContainer.cpp | 15 +++-- src/DockAreaWidget.cpp | 4 +- src/DockContainerWidget.cpp | 111 ++++++++++++++++++++++------------ src/DockContainerWidget.h | 2 +- src/DockManager.cpp | 4 +- src/DockManager.h | 2 + src/SideTabBar.cpp | 38 +++++++++++- src/SideTabBar.h | 11 ++++ 8 files changed, 135 insertions(+), 52 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index bd3f14a4e..7e8bae4eb 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -291,10 +291,16 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockArea->addDockWidget(DockWidget); d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); - // The initial size should be a little bit bigger than the original dock - // area size to prevent that the resize handle of this auto hid dock area - // is near of the splitter of the old dock area. - d->Size = OldDockArea->size() + QSize(16, 16); + + // Prevent overriding of d->Size parameter when this function is called during + // state restoring + if (!DockWidget->dockManager()->isRestoringState()) + { + // The initial size should be a little bit bigger than the original dock + // area size to prevent that the resize handle of this auto hid dock area + // is near of the splitter of the old dock area. + d->Size = OldDockArea->size() + QSize(16, 16); + } updateSize(); } @@ -343,7 +349,6 @@ void CAutoHideDockContainer::cleanupAndDelete() //============================================================================ void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { - s.writeAttribute("SideTabBarArea", QString::number(sideTabBarArea())); s.writeAttribute("Size", QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width())); qDebug() << ": saveState Size: " << d->Size; diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 94fa8b873..c116e3b50 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1099,7 +1099,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) continue; } - dockContainer()->createAndInitializeAutoHideDockWidgetContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); + dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); } } else @@ -1109,7 +1109,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) { return; } - dockContainer()->createAndInitializeAutoHideDockWidgetContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); + dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); } } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index fad92b8a6..3fb36e2f4 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -257,10 +257,10 @@ class DockContainerWidgetPrivate */ bool restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing); - /** - * Restores either a dock area or an auto hide dock area depending on the value in the XML - */ - bool restoreDockOrAutoHideDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, + /** + * Restores a auto hide side bar + */ + bool restoreSideBar(CDockingStateReader& Stream, QWidget*& CreatedWidget, bool Testing); /** @@ -898,21 +898,32 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge } } -void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& Stream) +void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& s) { - for (const auto sideTabBar : SideTabBarWidgets.values()) + for (const auto sideTabBar : SideTabBarWidgets.values()) { - for (auto itemIndex = 0; itemIndex < sideTabBar->tabCount(); itemIndex++) + if (!sideTabBar->tabCount()) + { + continue; + } + + s.writeStartElement("SideBar"); + s.writeAttribute("Area", QString::number(sideTabBar->sideTabBarArea())); + s.writeAttribute("Tabs", QString::number(sideTabBar->tabCount())); + + for (auto i = 0; i < sideTabBar->tabCount(); ++i) { - const auto sideTab = sideTabBar->tabAt(itemIndex); - if (sideTab == nullptr) + auto Tab = sideTabBar->tabAt(i); + if (!Tab) { continue; } - const auto dockArea = sideTab->dockWidget()->dockAreaWidget(); - dockArea->saveState(Stream); + auto DockArea = Tab->dockWidget()->dockAreaWidget(); + DockArea->saveState(s); } + + s.writeEndElement(); } } @@ -1118,29 +1129,6 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, } -//============================================================================ -bool DockContainerWidgetPrivate::restoreDockOrAutoHideDockArea(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; - } - - return restoreAutoHideDockArea(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, QWidget*& CreatedWidget, bool Testing) @@ -1233,6 +1221,42 @@ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, } +//============================================================================ +bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s, + QWidget*& CreatedWidget, bool Testing) +{ + Q_UNUSED(CreatedWidget) + // Simply ignore side bar auto hide widgets + if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + return true; + } + + bool Ok; + //int Tabs = s.attributes().value("Tabs").toInt(&Ok); + auto Area = (ads::SideBarLocation)s.attributes().value("Area").toInt(&Ok); + if (!Ok) + { + return false; + } + + while (s.readNextStartElement()) + { + if (s.name() != QLatin1String("Area")) + { + continue; + } + + if (!restoreAutoHideDockArea(s, Area, Testing)) + { + return false; + } + } + + return true; +} + + //============================================================================ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s, QWidget*& CreatedWidget, bool Testing) @@ -1247,9 +1271,14 @@ bool DockContainerWidgetPrivate::restoreChildNodes(CDockingStateReader& s, } else if (s.name() == QLatin1String("Area")) { - Result = restoreDockOrAutoHideDockArea(s, CreatedWidget, Testing); + Result = restoreDockArea(s, CreatedWidget, Testing); ADS_PRINT("DockAreaWidget"); } + else if (s.name() == QLatin1String("SideBar")) + { + Result = restoreSideBar(s, CreatedWidget, Testing); + ADS_PRINT("SideBar"); + } else { s.skipCurrentElement(); @@ -1500,7 +1529,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ -CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWidgetContainer( +CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { if (d->DockManager != DockWidget->dockManager()) @@ -1518,10 +1547,12 @@ CAutoHideDockContainer* CDockContainerWidget::createAndInitializeAutoHideDockWid sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); - const auto dockContainer = new CAutoHideDockContainer(DockWidget, area, this); - dockContainer->hide(); + auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); + AutoHideContainer->hide(); d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); - return dockContainer; + + //auto AutoHideContainer = sideTabBar(area)->insertDockWidget(insertOrder == CDockWidget::First ? 0 : -1, DockWidget); + return AutoHideContainer; } @@ -1861,7 +1892,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto autoHideWidgets = FloatingWidget->dockContainer()->autoHideWidgets(); for (const auto autohideWidget : autoHideWidgets) { - createAndInitializeAutoHideDockWidgetContainer(autohideWidget->sideTabBarArea(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); + createAndSetupAutoHideContainer(autohideWidget->sideTabBarArea(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); } if (DockArea) diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 0efc75d09..709d555a2 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -100,7 +100,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - CAutoHideDockContainer* createAndInitializeAutoHideDockWidgetContainer( + CAutoHideDockContainer* createAndSetupAutoHideContainer( SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder); /** diff --git a/src/DockManager.cpp b/src/DockManager.cpp index d1aed23b6..cb5586901 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -718,6 +718,8 @@ QByteArray CDockManager::saveState(int version) const s.writeEndElement(); s.writeEndDocument(); + std::cout << xmldata.toStdString() << std::endl; + return ConfigFlags.testFlag(XmlCompressionEnabled) ? qCompress(xmldata, 9) : xmldata; } @@ -878,7 +880,7 @@ CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(SideBarLo CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); - auto container = DockContainerWidget->createAndInitializeAutoHideDockWidgetContainer(area, Dockwidget, insertOrder); + auto container = DockContainerWidget->createAndSetupAutoHideContainer(area, Dockwidget, insertOrder); container->collapseView(true); Q_EMIT dockWidgetAdded(Dockwidget); diff --git a/src/DockManager.h b/src/DockManager.h index f68367a18..19ea2a008 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -54,6 +54,7 @@ struct DockAreaWidgetPrivate; class CIconProvider; class CDockComponentsFactory; class CDockFocusController; +class CSideTabBar; /** * The central dock manager that maintains the complete docking system. @@ -85,6 +86,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget friend struct FloatingDragPreviewPrivate; friend class CDockAreaTitleBar; friend class CAutoHideDockContainer; + friend CSideTabBar; protected: diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 3089983fc..8f81a872f 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -30,14 +30,17 @@ // INCLUDES //============================================================================ #include "SideTabBar.h" -#include "DockContainerWidget.h" -#include "DockWidgetSideTab.h" -#include "DockWidgetTab.h" #include #include #include +#include "DockContainerWidget.h" +#include "DockWidgetSideTab.h" +#include "DockWidgetTab.h" +#include "DockFocusController.h" +#include "AutoHideDockContainer.h" + namespace ads { /** @@ -130,6 +133,35 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) } +//============================================================================ +CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* DockWidget) +{ + CDockWidgetSideTab* Tab = new CDockWidgetSideTab(DockWidget); + auto area = sideTabBarArea(); + qDebug() << "area " << area; + Tab->setSideTabBar(this); + Tab->updateOrientationAndSpacing(area); + d->TabsLayout->insertWidget(Index, Tab); + Tab->show(); + + auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, d->ContainerWidget); + AutoHideContainer->hide(); + DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); + Tab->updateStyle(); + + connect(Tab, &CDockWidgetSideTab::pressed, AutoHideContainer, &CAutoHideDockContainer::toggleCollapseState); + show(); + return AutoHideContainer; +} + + +//============================================================================ +void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) +{ + +} + + //============================================================================ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { diff --git a/src/SideTabBar.h b/src/SideTabBar.h index f3baa8f86..ecafb6e26 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -38,6 +38,7 @@ namespace ads struct SideTabBarPrivate; class CDockContainerWidget; class CDockWidgetSideTab; +class CAutoHideDockContainer; /** * Side tab widget that is shown at the edges of a dock container. @@ -79,6 +80,16 @@ class ADS_EXPORT CSideTabBar : public QFrame */ void removeSideTab(CDockWidgetSideTab* SideTab); + /** + * Insert dock widget + */ + CAutoHideDockContainer* insertDockWidget(int Index, CDockWidget* DockWidget); + + /** + * Remove dock widget from sidebar + */ + void removeDockWidget(CDockWidget* DockWidget); + /** * Returns orientation of side tab. */ From 3f256f72499fd1fb82c08a0dc264e69ca5004598 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 13:39:00 +0200 Subject: [PATCH 152/236] Some small renamings --- src/AutoHideDockContainer.cpp | 6 ++---- src/DockContainerWidget.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7e8bae4eb..ed1c5c63f 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -103,7 +103,6 @@ struct AutoHideDockContainerPrivate CAutoHideDockContainer* _this; CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; - QPointer DockManager{nullptr}; SideBarLocation SideTabBarArea; QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; @@ -172,7 +171,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa Super(parent), d(new AutoHideDockContainerPrivate(this)) { - d->DockManager = DockManager; d->SideTabBarArea = area; d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); @@ -254,7 +252,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer() // Remove event filter in case there are any queued messages qApp->removeEventFilter(this); - if (d->DockManager) + if (parentContainer()) { parentContainer()->removeAutoHideWidget(this); } @@ -424,7 +422,7 @@ void CAutoHideDockContainer::collapseView(bool Enable) d->updateResizeHandleSizeLimitMax(); raise(); show(); - d->DockManager->setDockWidgetFocused(d->DockWidget); + d->DockWidget->dockManager()->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 3fb36e2f4..35ed4fb24 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1065,17 +1065,17 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, } CDockAreaWidget* DockArea = nullptr; - CAutoHideDockContainer* dockContainer = nullptr; + CAutoHideDockContainer* AutoHideContainer = nullptr; if (!Testing) { - dockContainer = new CAutoHideDockContainer(DockManager, area, _this); - if (!dockContainer->restoreState(s, Testing)) + AutoHideContainer = new CAutoHideDockContainer(DockManager, area, _this); + if (!AutoHideContainer->restoreState(s, Testing)) { return false; } - dockContainer->hide(); - DockArea = dockContainer->dockAreaWidget(); + AutoHideContainer->hide(); + DockArea = AutoHideContainer->dockAreaWidget(); DockArea->updateAutoHideButtonCheckState(); DockArea->updateTitleBarButtonToolTip(); } @@ -1120,9 +1120,9 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, DockArea->autoHideDockContainer()->toggleView(!Closed); } - if (dockContainer && !dockContainer->dockWidget()) + if (AutoHideContainer && !AutoHideContainer->dockWidget()) { - dockContainer->cleanupAndDelete(); + AutoHideContainer->cleanupAndDelete(); } return true; From c80174e7e5fc78ebd226255e05fb3da5bddd9839 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 27 Oct 2022 15:59:08 +0200 Subject: [PATCH 153/236] Removed superfluous code and simplified some things --- src/AutoHideDockContainer.cpp | 4 ++-- src/DockAreaWidget.cpp | 1 + src/DockContainerWidget.cpp | 30 ++++++++++++------------------ 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index ed1c5c63f..079c3a34c 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -211,7 +211,6 @@ void CAutoHideDockContainer::updateSize() { auto dockContainerParent = parentContainer(); auto rect = dockContainerParent->contentRect(); - qDebug() << "Size " << d->Size; switch (sideTabBarArea()) { @@ -248,6 +247,7 @@ void CAutoHideDockContainer::updateSize() //============================================================================ CAutoHideDockContainer::~CAutoHideDockContainer() { + qDebug() << "~CAutoHideDockContainer()" ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages @@ -323,8 +323,8 @@ void CAutoHideDockContainer::moveContentsToParent() // If we unpin the auto hide tock widget, then we insert it into the same // location like it had as a auto hide widget. This brings the least surprise // to the user and he does not have to search where the widget was inserted. + d->DockWidget->setDockArea(nullptr); parentContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); - parentContainer()->removeDockArea(d->DockArea); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index c116e3b50..fa66f8564 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -501,6 +501,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, //============================================================================ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { + qDebug() << "CDockAreaWidget::removeDockWidget"; ADS_PRINT("CDockAreaWidget::removeDockWidget"); auto CurrentDockWidget = currentDockWidget(); auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 35ed4fb24..2fe9e0561 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -853,6 +853,7 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList NewDockAreas) { + qDebug() << "DockContainerWidgetPrivate::appendDockAreas"; DockAreas.append(NewDockAreas); for (auto DockArea : NewDockAreas) { @@ -898,6 +899,8 @@ void DockContainerWidgetPrivate::saveChildNodesState(QXmlStreamWriter& s, QWidge } } + +//============================================================================ void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& s) { for (const auto sideTabBar : SideTabBarWidgets.values()) @@ -1730,7 +1733,15 @@ void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget, //============================================================================ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) { + qDebug() << "CDockContainerWidget::removeDockArea " << d->DockAreas.contains(area); ADS_PRINT("CDockContainerWidget::removeDockArea"); + // If it is an auto hide area, then there is nothing much to do + if (area->isAutoHide()) + { + area->setAutoHideDockContainer(nullptr); + return; + } + area->disconnect(this); d->DockAreas.removeAll(area); CDockSplitter* Splitter = internal::findParent(area); @@ -1746,24 +1757,6 @@ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) *p = nullptr; } - if (area->isAutoHide()) - { - // Removing an area from an auto hide container widget implies deleting the whole auto hide widget - // So cleanup will be done when the auto hide container 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->setAutoHideDockContainer(nullptr); - area->updateAutoHideButtonCheckState(); - area->updateTitleBarButtonToolTip(); - return; - } - // If splitter has more than 1 widgets, we are finished and can leave if (Splitter->count() > 1) { @@ -1953,6 +1946,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget) { CDockWidget* SingleDockWidget = topLevelDockWidget(); + qDebug() << "CDockContainerWidget::dropWidget"; if (TargetAreaWidget) { d->moveToNewSection(Widget, TargetAreaWidget, DropArea); From 85da93c2fe6ae9ae99b5a4b023fe2fbe5d032b1d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 28 Oct 2022 14:19:12 +0800 Subject: [PATCH 154/236] fix crash when adding auto hide dock container without a previous dock area --- src/AutoHideDockContainer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7e8bae4eb..efc2774e1 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -294,7 +294,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) // Prevent overriding of d->Size parameter when this function is called during // state restoring - if (!DockWidget->dockManager()->isRestoringState()) + if (!DockWidget->dockManager()->isRestoringState() && OldDockArea) { // The initial size should be a little bit bigger than the original dock // area size to prevent that the resize handle of this auto hid dock area From c2bd56e2e9a9c6cb26dc88e3049b7f2520c8ae45 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 28 Oct 2022 14:20:30 +0800 Subject: [PATCH 155/236] add set size to allow the user to set a size for the pinned widget manually --- src/AutoHideDockContainer.cpp | 10 ++++++++-- src/AutoHideDockContainer.h | 9 ++++++++- src/DockWidget.cpp | 15 --------------- 3 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index efc2774e1..16544bb72 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -322,7 +322,7 @@ CDockAreaWidget* CAutoHideDockContainer::dockAreaWidget() const void CAutoHideDockContainer::moveContentsToParent() { cleanupAndDelete(); - // If we unpin the auto hide tock widget, then we insert it into the same + // If we unpin the auto hide dock widget, then we insert it into the same // location like it had as a auto hide widget. This brings the least surprise // to the user and he does not have to search where the widget was inserted. parentContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); @@ -439,6 +439,12 @@ void CAutoHideDockContainer::toggleCollapseState() collapseView(isVisible()); } +void CAutoHideDockContainer::setSize(int width, int height) +{ + d->Size = QSize(width, height); + updateSize(); +} + //============================================================================ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) @@ -511,7 +517,7 @@ void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) Super::resizeEvent(event); if (d->ResizeHandle->isResizing()) { - d->Size = this->size(); + d->Size = this->size(); d->updateResizeHandleSizeLimitMax(); } } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 047290f97..a26f545c4 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -97,7 +97,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame */ void addDockWidget(CDockWidget* DockWidget); - /** + /** * Returns the side tab bar area of this Auto Hide dock container */ SideBarLocation sideTabBarArea() const; @@ -144,6 +144,13 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame * Toggles the current collapse state */ void toggleCollapseState(); + + /** + * Use this instead of resize. This will ensure the size is consistent internally. + * E.g. If you set a height less than the parent height when it's vertical + * It will simply be rescaled to the parent height while the width will be resized + */ + void setSize(int width, int height); }; } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 745a6fe0e..d3d63b40b 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -95,7 +95,6 @@ struct DockWidgetPrivate QList TitleBarActions; CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; - double DefaultAutoHideDockProportion = 0.25; CDockWidget::eAutoHideInsertOrder AutoHideInsertOrder = CDockWidget::Last; /** @@ -1131,20 +1130,6 @@ bool CDockWidget::isCurrentTab() const } -//============================================================================ -void CDockWidget::setDefaultAutoHideDockProportion(float Proportion) -{ - d->DefaultAutoHideDockProportion = Proportion; -} - - -//============================================================================ -float CDockWidget::DefaultAutoHideDockProportion() const -{ - return d->DefaultAutoHideDockProportion; -} - - //============================================================================ void CDockWidget::setAutoHideInsertOrder(eAutoHideInsertOrder insertOrder) { From 2a97833d02e5c99ad59af2f163efb68e5ab7da9b Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 28 Oct 2022 14:21:12 +0800 Subject: [PATCH 156/236] fix cmakelists and remove setDefaultDockProportion from dock widget --- examples/autohide/mainwindow.cpp | 6 +++--- src/CMakeLists.txt | 2 ++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 9669268ee..42dc49c5d 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -12,6 +12,7 @@ #include #include +#include "AutoHideDockContainer.h" #include "DockAreaWidget.h" #include "DockAreaTitleBar.h" @@ -44,10 +45,9 @@ CMainWindow::CMainWindow(QWidget *parent) CDockWidget* TableDockWidget = new CDockWidget("Table 1"); TableDockWidget->setWidget(table); TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); - TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - TableDockWidget->setDefaultAutoHideDockProportion(0.5); - DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); + const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); + autoHideContainer->setSize(480, 100); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 355f5230f..70c0276a4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ set(ads_SRCS DockWidgetSideTab.cpp AutoHideDockContainer.cpp PushButton.cpp + ResizeHandle.cpp ads.qrc ) set(ads_HEADERS @@ -56,6 +57,7 @@ set(ads_HEADERS DockWidgetSideTab.h AutoHideDockContainer.h PushButton.h + ResizeHandle.h ) add_compile_options("$<$:/utf-8>") if (UNIX AND NOT APPLE) From ee2ef8ac69e931b1b6c9cb310d7e4c74fecd80ab Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 28 Oct 2022 14:24:44 +0800 Subject: [PATCH 157/236] Use resize margin - disallow users from resizing to the size of the parent container --- src/AutoHideDockContainer.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 16544bb72..5745908e1 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -47,7 +47,7 @@ namespace ads { -static const int ResizeMargin = 4; +static const int ResizeMargin = 30; //============================================================================ bool static isHorizontalArea(SideBarLocation Area) @@ -136,8 +136,9 @@ struct AutoHideDockContainerPrivate void updateResizeHandleSizeLimitMax() { auto Rect = _this->parentContainer()->contentRect(); - ResizeHandle->setMaxResizeSize(ResizeHandle->orientation() == Qt::Horizontal - ? Rect.width() : Rect.height()); + const auto maxResizeHandleSize = ResizeHandle->orientation() == Qt::Horizontal + ? Rect.width() : Rect.height(); + ResizeHandle->setMaxResizeSize(maxResizeHandleSize - ResizeMargin); } /** @@ -218,18 +219,18 @@ void CAutoHideDockContainer::updateSize() switch (sideTabBarArea()) { case SideBarLocation::Top: - resize(rect.width(), qMin(rect.height(), d->Size.height())); + resize(rect.width(), qMin(rect.height(), d->Size.height() - ResizeMargin)); move(rect.topLeft()); break; case SideBarLocation::Left: - resize(qMin(d->Size.width(), rect.width()), rect.height()); + resize(qMin(d->Size.width(), rect.width() - ResizeMargin), rect.height()); move(rect.topLeft()); break; case SideBarLocation::Right: { - resize(qMin(d->Size.width(), rect.width()), rect.height()); + resize(qMin(d->Size.width(), rect.width() - ResizeMargin), rect.height()); QPoint p = rect.topRight(); p.rx() -= (width() - 1); move(p); @@ -238,7 +239,7 @@ void CAutoHideDockContainer::updateSize() case SideBarLocation::Bottom: { - resize(rect.width(), qMin(rect.height(), d->Size.height())); + resize(rect.width(), qMin(rect.height(), d->Size.height() - ResizeMargin)); QPoint p = rect.bottomLeft(); p.ry() -= (height() - 1); move(p); From a012426f9b97b71a7043e6cf8b2e1fd9bfbe02c0 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Fri, 28 Oct 2022 14:26:55 +0800 Subject: [PATCH 158/236] cleanup - remove unused code, fix comments, add const --- src/DockContainerWidget.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 3fb36e2f4..71d17a1d9 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1534,7 +1534,7 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( { if (d->DockManager != DockWidget->dockManager()) { - DockWidget->setDockManager(d->DockManager); // Overlay Dock Container needs a valid dock manager + DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager } if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) { @@ -1547,11 +1547,10 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); - auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); + const auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); AutoHideContainer->hide(); d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); - //auto AutoHideContainer = sideTabBar(area)->insertDockWidget(insertOrder == CDockWidget::First ? 0 : -1, DockWidget); return AutoHideContainer; } From f6b77f5c3c813a74ab25e09890e5a1e30beb2b86 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 11:11:35 +0200 Subject: [PATCH 159/236] Implemented showing and hiding of side bar when it does not contain any visible tab --- src/AutoHideDockContainer.cpp | 1 + src/AutoHideDockContainer.h | 6 ++-- src/DockWidget.cpp | 4 ++- src/SideTabBar.cpp | 63 +++++++++++++++++++++++++++++++++++ src/SideTabBar.h | 4 ++- 5 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 079c3a34c..aa183ca09 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -107,6 +107,7 @@ struct AutoHideDockContainerPrivate QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; QSize Size; // creates invalid size + CDockWidgetSideTab* SideTab = nullptr; /** * Private data constructor diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 047290f97..b684bb4a0 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -70,12 +70,14 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Create Auto Hide widget with a dock manager */ - CAutoHideDockContainer(CDockManager* DockManager, SideBarLocation area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockManager* DockManager, SideBarLocation area, + CDockContainerWidget* parent); /** * Create Auto Hide widget with the given dock widget */ - CAutoHideDockContainer(CDockWidget* DockWidget, SideBarLocation area, CDockContainerWidget* parent); + CAutoHideDockContainer(CDockWidget* DockWidget, SideBarLocation area, + CDockContainerWidget* parent); /** * Virtual Destructor diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 745a6fe0e..9611f7c46 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -79,7 +79,6 @@ 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; @@ -97,6 +96,7 @@ struct DockWidgetPrivate WidgetFactory* Factory = nullptr; double DefaultAutoHideDockProportion = 0.25; CDockWidget::eAutoHideInsertOrder AutoHideInsertOrder = CDockWidget::Last; + QPointer SideTabWidget; /** * Private data constructor @@ -246,6 +246,8 @@ void DockWidgetPrivate::updateParentDockArea() } } + +//============================================================================ void DockWidgetPrivate::closeAutoHideDockWidgetsIfNeeded() { if (_this->dockContainer() && _this->dockContainer()->openedDockWidgets().isEmpty() && !_this->dockManager()->isRestoringState()) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 8f81a872f..85718cac0 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -113,6 +113,7 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : //============================================================================ CSideTabBar::~CSideTabBar() { + qDebug() << "~CSideTabBar() "; // The SideTabeBar is not the owner of the tabs and to prevent deletion // we set the parent here to nullptr to remove it from the children auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); @@ -127,6 +128,7 @@ CSideTabBar::~CSideTabBar() //============================================================================ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) { + SideTab->installEventFilter(this); d->TabsLayout->insertWidget(Index, SideTab); SideTab->setSideTabBar(this); show(); @@ -166,6 +168,7 @@ void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { qDebug() << "CSideTabBar::removeSideTab " << SideTab->text(); + SideTab->removeEventFilter(this); d->TabsLayout->removeWidget(SideTab); if (d->TabsLayout->isEmpty()) { @@ -174,6 +177,65 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) } +//============================================================================ +bool CSideTabBar::event(QEvent* e) +{ + qDebug() << e; + switch (e->type()) + { + case QEvent::ChildRemoved: + if (d->TabsLayout->isEmpty()) + { + hide(); + } + break; + + case QEvent::Resize: + if (d->TabsLayout->count()) + { + auto ev = static_cast(e); + auto Tab = tabAt(0); + int Size = d->isHorizontal() ? ev->size().height() : ev->size().width(); + int TabSize = d->isHorizontal() ? Tab->size().height() : Tab->size().width(); + // If the size of the side bar is less than the size of the first tab + // then there are no visible tabs in this side bar. This check will + // fail if someone will force a very big border via CSS!! + if (Size < TabSize) + { + hide(); + } + } + else + { + hide(); + } + break; + + default: + break; + } + return Super::event(e); +} + + +//============================================================================ +bool CSideTabBar::eventFilter(QObject *watched, QEvent *event) +{ + if (event->type() != QEvent::ShowToParent) + { + return false; + } + + // As soon as on tab is shhown, we need to show the side tab bar + auto Tab = qobject_cast(watched); + if (Tab) + { + show(); + } + return false; +} + + //============================================================================ void CSideTabBar::paintEvent(QPaintEvent* event) { @@ -212,4 +274,5 @@ SideBarLocation CSideTabBar::sideTabBarArea() const { return d->SideTabArea; } + } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index ecafb6e26..890a10d1c 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -55,7 +55,9 @@ class ADS_EXPORT CSideTabBar : public QFrame friend class DockWidgetSideTab; protected: - void paintEvent(QPaintEvent* event) override; + virtual void paintEvent(QPaintEvent* event) override; + virtual bool event(QEvent* e) override; + virtual bool eventFilter(QObject *watched, QEvent *event) override; public: using Super = QFrame; From 6cf05c3438edf057dd78dcd06b13330a6befc05a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 11:13:18 +0200 Subject: [PATCH 160/236] Removed debug output --- src/SideTabBar.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 85718cac0..f373fbf80 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -180,7 +180,6 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) //============================================================================ bool CSideTabBar::event(QEvent* e) { - qDebug() << e; switch (e->type()) { case QEvent::ChildRemoved: From b85a6b55d9321d8773e0daf926a95ea0d8d4a941 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 11:14:04 +0200 Subject: [PATCH 161/236] Removed debug output --- src/SideTabBar.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index f373fbf80..5cd1d4e8f 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -160,7 +160,8 @@ CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* Do //============================================================================ void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) { - + Q_UNUSED(DockWidget); + // TODO implement } From b70fc7b3e837a6724add021ed5b1c5c8c6b880b5 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 11:22:42 +0200 Subject: [PATCH 162/236] Added some SideBar documentation --- src/SideTabBar.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 890a10d1c..eb08973f0 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -41,7 +41,11 @@ class CDockWidgetSideTab; class CAutoHideDockContainer; /** - * Side tab widget that is shown at the edges of a dock container. + * Side tab bar widget that is shown at the edges of a dock container. + * The tab bar is only visible, if it contains visible content, that means if + * it contains visible tabs. If it is empty or all tabs are hidden, then the + * side bar is also hidden. As soon as one single tab becomes visible, this + * tab bar will be shown. */ class ADS_EXPORT CSideTabBar : public QFrame { From ae5a75bc3f9ab77a559e037dd75d366b1bbaebb8 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 13:19:38 +0200 Subject: [PATCH 163/236] Removed DockWidget->sideTabWidget()->setProperty("focused", Focused), DockWidget->sideTabWidget()->updateStyle() because it is not required --- src/AutoHideDockContainer.cpp | 31 +++++++++++++++++++------------ src/AutoHideDockContainer.h | 5 +++++ src/DockContainerWidget.cpp | 1 - src/DockFocusController.cpp | 2 -- src/DockWidget.h | 4 +++- src/DockWidgetSideTab.cpp | 2 +- src/DockWidgetSideTab.h | 2 +- src/SideTabBar.cpp | 3 ++- 8 files changed, 31 insertions(+), 19 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 954f2a5a3..d3ba068a0 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -268,6 +268,14 @@ CSideTabBar* CAutoHideDockContainer::sideTabBar() const return parentContainer()->sideTabBar(d->SideTabBarArea); } + +//============================================================================ +CDockWidgetSideTab* CAutoHideDockContainer::sideTab() const +{ + return d->SideTab; +} + + //============================================================================ CDockWidget* CAutoHideDockContainer::dockWidget() const { @@ -284,13 +292,13 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockWidget = DockWidget; + d->SideTab = DockWidget->sideTabWidget(); CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); if (OldDockArea) { OldDockArea->removeDockWidget(DockWidget); } d->DockArea->addDockWidget(DockWidget); - d->DockWidget->sideTabWidget()->updateOrientationAndSpacing(d->SideTabBarArea); // Prevent overriding of d->Size parameter when this function is called during // state restoring @@ -336,9 +344,10 @@ void CAutoHideDockContainer::cleanupAndDelete() const auto dockWidget = d->DockWidget; if (dockWidget) { - dockWidget->sideTabWidget()->removeFromSideTabBar(); - dockWidget->sideTabWidget()->setParent(dockWidget); - dockWidget->sideTabWidget()->hide(); + auto SideTab = d->SideTab; + SideTab->removeFromSideTabBar(); + SideTab->setParent(dockWidget); + SideTab->hide(); } hide(); @@ -391,18 +400,16 @@ void CAutoHideDockContainer::toggleView(bool Enable) { if (Enable) { - const auto dockWidget = d->DockWidget; - if (dockWidget) + if (d->SideTab) { - dockWidget->sideTabWidget()->show(); + d->SideTab->show(); } } else { - const auto dockWidget = d->DockWidget; - if (dockWidget) + if (d->SideTab) { - dockWidget->sideTabWidget()->hide(); + d->SideTab->hide(); } hide(); qApp->removeEventFilter(this); @@ -429,7 +436,7 @@ void CAutoHideDockContainer::collapseView(bool Enable) } ADS_PRINT("CAutoHideDockContainer::collapseView " << Enable); - d->DockWidget->sideTabWidget()->updateStyle(); + d->SideTab->updateStyle(); } @@ -494,7 +501,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) // because the side tab click handler will call collapseView(). If we // do not ignore this here, then we will collapse the container and the side tab // click handler will uncollapse it - auto SideTab = d->DockWidget->sideTabWidget(); + auto SideTab = d->SideTab; pos = SideTab->mapFromGlobal(me->globalPos()); if (SideTab->rect().contains(pos)) { diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index c55f9ccad..2c0538e0a 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -89,6 +89,11 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame */ CSideTabBar* sideTabBar() const; + /** + * Returns the side tab + */ + CDockWidgetSideTab* sideTab() const; + /** * Get's the dock widget in this dock container */ diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index f6b15ed25..d628ab3c0 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1546,7 +1546,6 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( return nullptr; } - DockWidget->sideTabWidget()->updateOrientationAndSpacing(area); sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index f1d3435ba..3056c077c 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -70,8 +70,6 @@ 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); } diff --git a/src/DockWidget.h b/src/DockWidget.h index 60df0e38c..52d87b235 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -365,7 +365,9 @@ private Q_SLOTS: CDockAreaWidget* dockAreaWidget() const; /** - * Returns the side tab widget for this dock + * Returns the side tab widget for this dock, if this dock widget is in + * a auto hide container. If it is not in a auto hide container, then this + * function returns a nullptr, */ CDockWidgetSideTab* sideTabWidget() const; diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index e4e6423e7..3eb284523 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -142,7 +142,7 @@ Qt::Orientation CDockWidgetSideTab::orientation() const //============================================================================ -void CDockWidgetSideTab::updateOrientationAndSpacing(SideBarLocation area) +void CDockWidgetSideTab::updateOrientationForArea(SideBarLocation area) { setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index f9c2bc6ea..f01e8b809 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -106,7 +106,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton /** * Update the orientation, visibility and spacing based on the area and the config */ - void updateOrientationAndSpacing(SideBarLocation area); + void updateOrientationForArea(SideBarLocation area); /** * Returns true, if this is the active tab. The tab is active if the auto hide widget is visible diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 5cd1d4e8f..cf380e4bb 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -128,6 +128,7 @@ CSideTabBar::~CSideTabBar() //============================================================================ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) { + SideTab->updateOrientationForArea(d->SideTabArea); SideTab->installEventFilter(this); d->TabsLayout->insertWidget(Index, SideTab); SideTab->setSideTabBar(this); @@ -142,7 +143,7 @@ CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* Do auto area = sideTabBarArea(); qDebug() << "area " << area; Tab->setSideTabBar(this); - Tab->updateOrientationAndSpacing(area); + Tab->updateOrientationForArea(area); d->TabsLayout->insertWidget(Index, Tab); Tab->show(); From 1eaeed6c566e7666b7c0eb9e7ade7c030ec5de7b Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 13:20:27 +0200 Subject: [PATCH 164/236] Changed root index of file system model to prevent lagging UI if network folders are missing --- demo/MainWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index a47451031..57d52861a 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -216,6 +216,7 @@ struct MainWindowPrivate QFileSystemModel* m = new QFileSystemModel(w); m->setRootPath(QDir::currentPath()); w->setModel(m); + w->setRootIndex(m->index(QDir::currentPath())); ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1") .arg(FileSystemCount++)); DockWidget->setWidget(w); From 6adce7337b6cc067755a0000e2faeb7ff578754c Mon Sep 17 00:00:00 2001 From: Uwe Date: Fri, 28 Oct 2022 13:35:52 +0200 Subject: [PATCH 165/236] Some restructuring in default.css and default_linux.css to improve readibility --- src/stylesheets/default.css | 46 ++++++++++----------- src/stylesheets/default_linux.css | 68 +++++++++++++++++++++++-------- 2 files changed, 71 insertions(+), 43 deletions(-) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index fd431b1c4..3a9fddb36 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -32,7 +32,7 @@ ads--CDockAreaWidget { /***************************************************************************** - * CDockWidgetTab + * CDockWidgetTab and close button styling *****************************************************************************/ ads--CDockWidgetTab { background: palette(window); @@ -57,6 +57,26 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { } +#tabCloseButton { + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#tabCloseButton:hover { + border: 1px solid rgba(0, 0, 0, 32); + background: rgba(0, 0, 0, 16); +} + +#tabCloseButton:pressed { + background: rgba(0, 0, 0, 32); +} + + /***************************************************************************** * CDockWidget *****************************************************************************/ @@ -74,30 +94,6 @@ QScrollArea#dockWidgetScrollArea { } -/***************************************************************************** - * Dock widget tab styling - *****************************************************************************/ -#tabCloseButton { - margin-top: 2px; - background: none; - border: none; - padding: 0px -2px; - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#tabCloseButton:hover { - border: 1px solid rgba(0, 0, 0, 32); - background: rgba(0, 0, 0, 16); -} - -#tabCloseButton:pressed { - background: rgba(0, 0, 0, 32); -} - - - /***************************************************************************** * Dock area title bar and buttons styling *****************************************************************************/ diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index ac41491eb..43f6e1777 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -1,9 +1,18 @@ /* * Default style sheet on Linux Platforms */ + +/***************************************************************************** + * CDockContainerWidget + *****************************************************************************/ ads--CDockContainerWidget { background: palette(dark); } + + +/***************************************************************************** + * CDockSplitter + *****************************************************************************/ ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; } @@ -12,6 +21,10 @@ ads--CDockContainerWidget ads--CDockSplitter::handle { background: palette(dark); } + +/***************************************************************************** + * CDockAreaWidget + *****************************************************************************/ ads--CDockAreaWidget { background: palette(window); border: 1px solid white; @@ -21,6 +34,11 @@ ads--CDockAreaWidget #tabsMenuButton::menu-indicator { image: none; } + + +/***************************************************************************** + * CDockWidgetTab and close button styling + *****************************************************************************/ ads--CDockWidgetTab { background: palette(window); border-color: palette(light); @@ -43,6 +61,30 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } + +#tabCloseButton { + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#tabCloseButton:hover { + border: 1px solid rgba(0, 0, 0, 32); + background: rgba(0, 0, 0, 16); +} + +#tabCloseButton:pressed { + background: rgba(0, 0, 0, 32); +} + + +/***************************************************************************** + * CDockWidget + *****************************************************************************/ ads--CDockWidget { background: palette(light); border-color: palette(light); @@ -50,33 +92,20 @@ ads--CDockWidget { border-width: 1px 0 0 0; } -ads--CTitleBarButton { - padding: 0px 0px; -} QScrollArea#dockWidgetScrollArea { padding: 0px; border: none; } -#tabCloseButton { - margin-top: 2px; - background: none; - border: none; - padding: 0px -2px; - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} -#tabCloseButton:hover { - border: 1px solid rgba(0, 0, 0, 32); - background: rgba(0, 0, 0, 16); +/***************************************************************************** + * Dock area title bar and buttons styling + *****************************************************************************/ +ads--CTitleBarButton { + padding: 0px 0px; } -#tabCloseButton:pressed { - background: rgba(0, 0, 0, 32); -} #tabsMenuButton { qproperty-icon: url(:/ads/images/tabs-menu-button.svg); @@ -96,6 +125,9 @@ QScrollArea#dockWidgetScrollArea { } +/***************************************************************************** + * Floating widget styling + *****************************************************************************/ ads--CFloatingWidgetTitleBar { background: palette(midlight); qproperty-maximizeIcon: url(:/ads/images/maximize-button.svg); From f4bfa0f3c5ec4bf61f911da925e9ccd1365780d0 Mon Sep 17 00:00:00 2001 From: Uwe Date: Fri, 28 Oct 2022 15:20:56 +0200 Subject: [PATCH 166/236] Changed type of sideTabBarArea properties to int to fix non working Linux stylesheet selectors --- src/AutoHideDockContainer.h | 2 +- src/DockWidgetSideTab.cpp | 10 +++++----- src/DockWidgetSideTab.h | 2 +- src/ResizeHandle.h | 2 +- src/SideTabBar.cpp | 4 ++-- src/SideTabBar.h | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 2c0538e0a..3a6b8c735 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -53,7 +53,7 @@ class CDockingStateReader; class ADS_EXPORT CAutoHideDockContainer : public QFrame { Q_OBJECT - Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 3eb284523..19cae324d 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -47,7 +47,7 @@ struct DockWidgetSideTabPrivate { CDockWidgetSideTab* _this; CDockWidget* DockWidget; - CSideTabBar* SideTabBar; + CSideTabBar* SideTabBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; /** @@ -106,7 +106,7 @@ CDockWidgetSideTab::~CDockWidgetSideTab() //============================================================================ void CDockWidgetSideTab::updateStyle() { - internal::repolishStyle(this, internal::RepolishDirectChildren); + internal::repolishStyle(this, internal::RepolishDirectChildren); update(); } @@ -114,10 +114,10 @@ void CDockWidgetSideTab::updateStyle() //============================================================================ SideBarLocation CDockWidgetSideTab::sideTabBarArea() const { - auto dockAreaWidget = d->DockWidget->dockAreaWidget(); - if (dockAreaWidget && dockAreaWidget->isAutoHide()) + if (d->SideTabBar) { - return dockAreaWidget->autoHideDockContainer()->sideTabBarArea(); + qDebug() << "CDockWidgetSideTab::sideTabBarArea() " << d->SideTabBar->sideTabBarArea(); + return d->SideTabBar->sideTabBarArea(); } return Left; diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index f01e8b809..4da3c7599 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -50,7 +50,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton { Q_OBJECT - Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) Q_PROPERTY(bool activeTab READ isActiveTab) diff --git a/src/ResizeHandle.h b/src/ResizeHandle.h index 81264b129..1b5af3216 100644 --- a/src/ResizeHandle.h +++ b/src/ResizeHandle.h @@ -24,7 +24,7 @@ class ADS_EXPORT CResizeHandle : public QFrame { Q_OBJECT Q_DISABLE_COPY(CResizeHandle) - Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize) + Q_PROPERTY(bool opaqueResize READ opaqueResize WRITE setOpaqueResize) private: ResizeHandlePrivate* d; ///< private data (pimpl) friend struct ResizeHandlePrivate; diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index cf380e4bb..d996ede95 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -128,10 +128,10 @@ CSideTabBar::~CSideTabBar() //============================================================================ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) { - SideTab->updateOrientationForArea(d->SideTabArea); SideTab->installEventFilter(this); - d->TabsLayout->insertWidget(Index, SideTab); SideTab->setSideTabBar(this); + SideTab->updateOrientationForArea(d->SideTabArea); + d->TabsLayout->insertWidget(Index, SideTab); show(); } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index eb08973f0..4ba757a85 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -50,7 +50,7 @@ class CAutoHideDockContainer; class ADS_EXPORT CSideTabBar : public QFrame { Q_OBJECT - Q_PROPERTY(ads::SideBarLocation sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) private: From 1189945ef13e9f0bdacd20f2e8dc2797a5e199bc Mon Sep 17 00:00:00 2001 From: Uwe Date: Fri, 28 Oct 2022 15:21:21 +0200 Subject: [PATCH 167/236] Updated Linux css files to properly support new auto hide feature --- demo/MainWindow.cpp | 2 +- src/stylesheets/default.css | 74 ++--- src/stylesheets/default_linux.css | 238 +++++++++++++-- src/stylesheets/focus_highlighting_linux.css | 297 ++++++++++++++++--- 4 files changed, 490 insertions(+), 121 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 57d52861a..733a9e880 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -651,7 +651,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus - //CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 3a9fddb36..b72c50b69 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -18,7 +18,7 @@ ads--CDockContainerWidget > QSplitter { } ads--CDockContainerWidget ads--CDockSplitter::handle { - background: palette(dark); + background: palette(dark); } @@ -26,7 +26,33 @@ ads--CDockContainerWidget ads--CDockSplitter::handle { * CDockAreaWidget *****************************************************************************/ ads--CDockAreaWidget { - background: palette(window); + background: palette(window); +} + +ads--CTitleBarButton { + padding: 0px 0px; +} + + +#tabsMenuButton::menu-indicator { + image: none; +} + +#tabsMenuButton { + qproperty-icon: url(:/ads/images/tabs-menu-button.svg); + qproperty-iconSize: 16px; +} + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; } @@ -94,36 +120,6 @@ QScrollArea#dockWidgetScrollArea { } -/***************************************************************************** - * Dock area title bar and buttons styling - *****************************************************************************/ - ads--CTitleBarButton { - padding: 0px 0px; -} - - -#tabsMenuButton::menu-indicator { - image: none; -} - -#tabsMenuButton { - qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconSize: 16px; -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - - /***************************************************************************** * * Styling of auto hide functionality @@ -135,33 +131,27 @@ QScrollArea#dockWidgetScrollArea { * CDockWidgetSideTab *****************************************************************************/ ads--CDockWidgetSideTab { - /*background: palette(window);*/ - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - - -ads--CDockWidgetSideTab { + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ background: none; border: none; padding-left: 2px; padding-right: 0px; text-align: center; + margin-right: 6px; + min-height: 20; } ads--CDockWidgetSideTab[sideTabBarArea="0"], ads--CDockWidgetSideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; + } ads--CDockWidgetSideTab[sideTabBarArea="1"], ads--CDockWidgetSideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; } diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index 43f6e1777..f8dedfe43 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -6,7 +6,7 @@ * CDockContainerWidget *****************************************************************************/ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } @@ -14,11 +14,11 @@ ads--CDockContainerWidget { * CDockSplitter *****************************************************************************/ ads--CDockContainerWidget > QSplitter{ - padding: 1 0 1 0; + padding: 1 0 1 0; } ads--CDockContainerWidget ads--CDockSplitter::handle { - background: palette(dark); + background: palette(dark); } @@ -26,15 +26,38 @@ ads--CDockContainerWidget ads--CDockSplitter::handle { * CDockAreaWidget *****************************************************************************/ ads--CDockAreaWidget { - background: palette(window); - border: 1px solid white; + background: palette(window); } ads--CDockAreaWidget #tabsMenuButton::menu-indicator { - image: none; + image: none; +} + + +ads--CTitleBarButton { + padding: 0px 0px; +} + + +#tabsMenuButton { + qproperty-icon: url(:/ads/images/tabs-menu-button.svg); + qproperty-iconSize: 16px; } +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + /***************************************************************************** * CDockWidgetTab and close button styling @@ -47,16 +70,19 @@ ads--CDockWidgetTab { 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)); /*background: palette(highlight);*/ } + ads--CDockWidgetTab QLabel { color: palette(dark); } + ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } @@ -99,32 +125,6 @@ QScrollArea#dockWidgetScrollArea { } -/***************************************************************************** - * Dock area title bar and buttons styling - *****************************************************************************/ -ads--CTitleBarButton { - padding: 0px 0px; -} - - -#tabsMenuButton { - qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconSize: 16px; -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - - /***************************************************************************** * Floating widget styling *****************************************************************************/ @@ -154,3 +154,177 @@ ads--CFloatingWidgetTitleBar { #floatingTitleCloseButton:pressed { background: rgba(0, 0, 0, 48); } + + +/***************************************************************************** + * + * Styling of auto hide functionality + * + *****************************************************************************/ + + +/***************************************************************************** + * CDockWidgetSideTab + *****************************************************************************/ +ads--CDockWidgetSideTab { + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + padding-left: 2px; + padding-right: 0px; + text-align: center; + margin-right: 6px; + min-height: 20; + border: none; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"], +ads--CDockWidgetSideTab[sideTabBarArea="3"] { + border-bottom: 5px solid rgba(0, 0, 0, 48); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="0"], +ads--CDockWidgetSideTab[sideTabBarArea="2"] { + border-top: 5px solid rgba(0, 0, 0, 48); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { + border-top: 5px solid palette(highlight); + color: palette(highlight); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { + border-bottom: 5px solid palette(highlight); + color: palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { + border-top: 5px solid palette(highlight); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { + border-bottom: 5px solid palette(highlight); +} + + +/***************************************************************************** + * CSideTabBar + *****************************************************************************/ +ads--CSideTabBar{ + background: palette(window); +} + + +ads--CSideTabBar[sideTabBarArea="0"] { + border-bottom: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="1"] { + border-right: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="2"] { + border-left: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="3"] { + border-top: 1px solid palette(dark); +} + + +/***************************************************************************** + * CAutoHideDockContainer + *****************************************************************************/ +ads--CAutoHideDockContainer { + background: palette(window); +} + + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +#autoHideTitleLabel { + padding-left: 4px; + color: palette(light); +} + + +/***************************************************************************** + * CAutoHideDockContainer titlebar buttons + *****************************************************************************/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; +} + + +ads--CAutoHideDockContainer #dockAreaCloseButton{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { + background: rgba(255, 255, 255, 96); +} + +/***************************************************************************** + * CAutoHideDockContainer Titlebar and Buttons + *****************************************************************************/ + + +/***************************************************************************** + * CResizeHandle + *****************************************************************************/ +ads--CResizeHandle { + background: palette(window); +} + + +ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { + border-left: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + + + diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index f16ab5e82..dfa8a10eb 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -1,9 +1,18 @@ /* * Default style sheet on Linux Platforms with focus highlighting flag enabled */ + +/***************************************************************************** + * CDockContainerWidget + *****************************************************************************/ ads--CDockContainerWidget { - background: palette(dark); + background: palette(window); } + + +/***************************************************************************** + * CDockSplitter + *****************************************************************************/ ads--CDockContainerWidget > QSplitter{ padding: 1 0 1 0; } @@ -13,15 +22,64 @@ ads--CDockContainerWidget ads--CDockSplitter::handle { background: palette(dark); } + +/***************************************************************************** + * CDockAreaWidget + *****************************************************************************/ ads--CDockAreaWidget { background: palette(window); - border: 1px solid white; } ads--CDockAreaWidget #tabsMenuButton::menu-indicator { image: none; } + +ads--CTitleBarButton { + padding: 0px 0px; +} + + +#tabsMenuButton { + qproperty-icon: url(:/ads/images/tabs-menu-button.svg); + qproperty-iconSize: 16px; +} + + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + + +/***************************************************************************** + * CDockAreaTitleBar + *****************************************************************************/ +ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid palette(light); + padding-bottom: 0px; +} + +ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid palette(highlight); + padding-bottom: 0px; +} + + +/***************************************************************************** + * CDockWidgetTab and close button styling + *****************************************************************************/ ads--CDockWidgetTab { background: palette(window); border-color: palette(light); @@ -44,33 +102,6 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { color: palette(foreground); } -ads--CDockWidget { - background: palette(light); - border-color: palette(light); - border-style: solid; - border-width: 1px 0 0 0; -} - -ads--CTitleBarButton { - padding: 0px 0px; -} - -QScrollArea#dockWidgetScrollArea { - padding: 0px; - border: none; -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} #tabCloseButton { margin-top: 2px; @@ -92,27 +123,21 @@ QScrollArea#dockWidgetScrollArea { } -#tabsMenuButton { - qproperty-icon: url(:/ads/images/tabs-menu-button.svg); - qproperty-iconSize: 16px; -} - - /* Focus related styling */ ads--CDockWidgetTab[focused="true"] { background: palette(highlight); border-color: palette(highlight); } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton { +ads--CDockWidgetTab[focused="true"] > #tabCloseButton { qproperty-icon: url(:/ads/images/close-button-focused.svg) } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover { +ads--CDockWidgetTab[focused="true"] > #tabCloseButton:hover { background: rgba(255, 255, 255, 48); } -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed { +ads--CDockWidgetTab[focused="true"] > #tabCloseButton:pressed { background: rgba(255, 255, 255, 92); } @@ -120,19 +145,28 @@ ads--CDockWidgetTab[focused="true"] QLabel { color: palette(light); } -ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid palette(light); - padding-bottom: 0px; + +/***************************************************************************** + * CDockWidget + *****************************************************************************/ +ads--CDockWidget { + background: palette(light); + border-color: palette(light); + border-style: solid; + border-width: 1px 0 0 0; } -ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid palette(highlight); - padding-bottom: 0px; + +QScrollArea#dockWidgetScrollArea { + padding: 0px; + border: none; } + +/***************************************************************************** + * Floating widget styling + *****************************************************************************/ ads--CFloatingWidgetTitleBar { qproperty-maximizeIcon: url(:/ads/images/maximize-button.svg); qproperty-normalIcon: url(:/ads/images/restore-button.svg); @@ -197,3 +231,174 @@ ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton: } */ + +/***************************************************************************** + * + * Styling of auto hide functionality + * + *****************************************************************************/ + + +/***************************************************************************** + * CDockWidgetSideTab + *****************************************************************************/ +ads--CDockWidgetSideTab { + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + padding-left: 2px; + padding-right: 0px; + text-align: center; + margin-right: 6px; + min-height: 20; + border: none; +} + +ads--CDockWidgetSideTab[sideTabBarArea="1"], +ads--CDockWidgetSideTab[sideTabBarArea="3"] { + border-bottom: 5px solid rgba(0, 0, 0, 48); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="0"], +ads--CDockWidgetSideTab[sideTabBarArea="2"] { + border-top: 5px solid rgba(0, 0, 0, 48); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { + border-top: 5px solid palette(highlight); + color: palette(highlight); +} + + +ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], +ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { + border-bottom: 5px solid palette(highlight); + color: palette(highlight); +} + +ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { + border-top: 5px solid palette(highlight); +} + + +ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], +ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { + border-bottom: 5px solid palette(highlight); +} + + +/***************************************************************************** + * CSideTabBar + *****************************************************************************/ +ads--CSideTabBar{ + background: palette(window); +} + + +ads--CSideTabBar[sideTabBarArea="0"] { + border-bottom: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="1"] { + border-right: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="2"] { + border-left: 1px solid palette(dark); +} + +ads--CSideTabBar[sideTabBarArea="3"] { + border-top: 1px solid palette(dark); +} + + +/***************************************************************************** + * CAutoHideDockContainer + *****************************************************************************/ +ads--CAutoHideDockContainer { + background: palette(window); +} + + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +#autoHideTitleLabel { + padding-left: 4px; + color: palette(light); +} + + +/***************************************************************************** + * CAutoHideDockContainer titlebar buttons + *****************************************************************************/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; +} + + +ads--CAutoHideDockContainer #dockAreaCloseButton{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { + background: rgba(255, 255, 255, 96); +} + +/***************************************************************************** + * CAutoHideDockContainer Titlebar and Buttons + *****************************************************************************/ + + +/***************************************************************************** + * CResizeHandle + *****************************************************************************/ +ads--CResizeHandle { + background: palette(window); +} + + +ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { + border-left: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + From af4a3ef2a8b3a01c4c518599a6169f29437ae63c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 15:52:52 +0200 Subject: [PATCH 168/236] Removed config flag CDockManager::AutoHideDockAreaHasTitle - this should not be configurable --- demo/MainWindow.cpp | 2 +- src/DockAreaWidget.cpp | 2 +- src/DockManager.h | 14 ++-- src/DockWidgetSideTab.cpp | 37 ++++++----- src/stylesheets/focus_highlighting.css | 92 ++++++++++++-------------- 5 files changed, 69 insertions(+), 78 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 733a9e880..ba5db06dd 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -654,7 +654,7 @@ CMainWindow::CMainWindow(QWidget *parent) : CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding - CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); + CDockManager::setConfigFlags(CDockManager::DefaultAutoHideConfig); // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index fa66f8564..db49d6923 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -820,7 +820,7 @@ void CDockAreaWidget::updateTitleBarVisibility() 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 + d->TitleBar->autoHideTitleLabel()->setVisible(isAutoHide()); // Always show when auto hidden, never otherwise updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); } } diff --git a/src/DockManager.h b/src/DockManager.h index 19ea2a008..74ba44a5b 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -230,17 +230,15 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget { AutoHideFeatureEnabled = 0x01, DockAreaHasAutoHideButton = 0x02, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarPrioritizeIconOnly = 0x04, //!< If the flag is set left side bar will prioritize showing icons only over text - RightSideBarPrioritizeIconOnly = 0x08, //!< If the flag is set right side bar will prioritize showing icons only over text - BottomSideBarPrioritizeIconOnly = 0x10,//!< If the flag is set bottom side bar will prioritize showing icons only over text - TopSideBarPrioritizeIconOnly = 0x20, //!< If the flag is set top side bar will prioritize showing icons only over text - AutoHideDockAreaHasTitle = 0x40, //!< If the flag is set overlay dock area title bar will show the window title - AutoHideButtonTogglesArea = 0x80, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled + LeftSideBarIconOnly = 0x04, //!< If the flag is set left side bar will show only icon if a the dock widget has an icon assigned + RightSideBarIconOnly = 0x08, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned + BottomSideBarIconOnly = 0x10,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned + TopSideBarIconOnly = 0x20, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned + AutoHideButtonTogglesArea = 0x40, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled AutoHideButtonCheckable = 0x80, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. DefaultAutoHideConfig = AutoHideFeatureEnabled - | DockAreaHasAutoHideButton - | AutoHideDockAreaHasTitle, ///< the default configuration for left and right side bars + | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars }; Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 19cae324d..bfc59b1a8 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -151,29 +151,30 @@ void CDockWidgetSideTab::updateOrientationForArea(SideBarLocation area) return; } - if (CDockManager::testConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly) && area == Left) + bool IconOnly = false; + switch (area) { - setText(""); - setOrientation(Qt::Horizontal); - return; - } - if (CDockManager::testConfigFlag(CDockManager::RightSideBarPrioritizeIconOnly) && area == Right) - { - setText(""); - setOrientation(Qt::Horizontal); - return; - } - if (CDockManager::testConfigFlag(CDockManager::BottomSideBarPrioritizeIconOnly) && area == Bottom) - { - setText(""); - setOrientation(Qt::Horizontal); - return; + case SideBarLocation::Left: + IconOnly = CDockManager::testConfigFlag(CDockManager::LeftSideBarIconOnly); + break; + + case SideBarLocation::Right: + IconOnly = CDockManager::testConfigFlag(CDockManager::RightSideBarIconOnly); + break; + + case SideBarLocation::Top: + IconOnly = CDockManager::testConfigFlag(CDockManager::BottomSideBarIconOnly); + break; + + case SideBarLocation::Bottom: + IconOnly = CDockManager::testConfigFlag(CDockManager::TopSideBarIconOnly); + break; } - if (CDockManager::testConfigFlag(CDockManager::TopSideBarPrioritizeIconOnly) && area == Top) + + if (IconOnly) { setText(""); setOrientation(Qt::Horizontal); - return; } } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index d55971620..34ece1915 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -35,6 +35,39 @@ ads--CDockAreaWidget { } +ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid palette(light); + padding-bottom: 0px; +} + +ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + border-bottom: 2px solid palette(highlight); +} + +ads--CTitleBarButton { + padding: 0px 0px; +} + + +#tabsMenuButton::menu-indicator { + image: none; +} + + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + /***************************************************************************** * CDockWidgetTab @@ -63,28 +96,6 @@ ads--CDockWidgetTab[activeTab="true"] QLabel { } - -/***************************************************************************** - * CDockWidget - *****************************************************************************/ -ads--CDockWidget { - background: palette(light); - border-color: palette(light); - border-style: solid; - border-width: 1px 0 0 0; -} - - -QScrollArea#dockWidgetScrollArea { - padding: 0px; - border: none; -} - - - -/***************************************************************************** - * Dock widget tab styling - *****************************************************************************/ #tabCloseButton { margin-top: 2px; background: none; @@ -129,38 +140,19 @@ ads--CDockWidgetTab[focused="true"] QLabel { /***************************************************************************** - * Dock area title bar and buttons styling + * CDockWidget *****************************************************************************/ - ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid palette(light); - padding-bottom: 0px; -} - -ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - border-bottom: 2px solid palette(highlight); -} - -ads--CTitleBarButton { - padding: 0px 0px; -} - - -#tabsMenuButton::menu-indicator { - image: none; +ads--CDockWidget { + background: palette(light); + border-color: palette(light); + border-style: solid; + border-width: 1px 0 0 0; } -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; +QScrollArea#dockWidgetScrollArea { + padding: 0px; + border: none; } From 8d670577a96a121466f85e04562996c1e5cfcb11 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 28 Oct 2022 16:28:23 +0200 Subject: [PATCH 169/236] Moved creation of SideTabWidget into AutoHideDockContainer.cpp --- src/AutoHideDockContainer.cpp | 17 ++++++++++++++--- src/DockContainerWidget.cpp | 13 +++++++------ src/DockWidget.cpp | 3 ++- src/DockWidgetSideTab.cpp | 20 +++++++++++++++----- src/DockWidgetSideTab.h | 7 ++++++- src/SideTabBar.cpp | 24 +++++++++++------------- 6 files changed, 55 insertions(+), 29 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index d3ba068a0..5f7a728e3 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -107,7 +107,7 @@ struct AutoHideDockContainerPrivate QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; QSize Size; // creates invalid size - CDockWidgetSideTab* SideTab = nullptr; + QPointer SideTab; /** * Private data constructor @@ -174,6 +174,8 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa d(new AutoHideDockContainerPrivate(this)) { d->SideTabBarArea = area; + d->SideTab = new CDockWidgetSideTab(); + connect(d->SideTab, &CDockWidgetSideTab::pressed, this, &CAutoHideDockContainer::toggleCollapseState); d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); d->DockArea->setAutoHideDockContainer(this); @@ -194,7 +196,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa d->Layout->insertWidget(resizeHandleLayoutPosition(area), d->ResizeHandle); d->Size = d->DockArea->size(); - updateSize(); parent->registerAutoHideWidget(this); } @@ -205,6 +206,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarL CAutoHideDockContainer(DockWidget->dockManager(), area, parent) { addDockWidget(DockWidget); + hide(); } @@ -292,7 +294,14 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockWidget = DockWidget; - d->SideTab = DockWidget->sideTabWidget(); + if (!d->SideTab) + { + d->SideTab = DockWidget->sideTabWidget(); + } + else + { + d->SideTab->setDockWidget(DockWidget); + } CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); if (OldDockArea) { @@ -446,6 +455,8 @@ void CAutoHideDockContainer::toggleCollapseState() collapseView(isVisible()); } + +//============================================================================ void CAutoHideDockContainer::setSize(int width, int height) { d->Size = QSize(width, height); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index d628ab3c0..95f865fc5 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1535,25 +1535,26 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { - if (d->DockManager != DockWidget->dockManager()) - { - DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager - } if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) { Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", "Requested area does not exist in config"); return nullptr; } + if (d->DockManager != DockWidget->dockManager()) + { + DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager + } - sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); + /*sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); DockWidget->sideTabWidget()->show(); const auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); AutoHideContainer->hide(); d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); + return AutoHideContainer;*/ - return AutoHideContainer; + return sideTabBar(area)->insertDockWidget(insertOrder == CDockWidget::First ? 0 : -1, DockWidget); } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 031be22c5..855eba811 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -325,7 +325,8 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : setObjectName(title); d->TabWidget = componentsFactory()->createDockWidgetTab(this); - d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(this); + d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(nullptr); + d->SideTabWidget->hide(); connect(d->SideTabWidget, &CDockWidgetSideTab::pressed, this, &CDockWidget::onDockWidgetSideTabClicked); diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index bfc59b1a8..4b90cdd92 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -46,7 +46,7 @@ namespace ads struct DockWidgetSideTabPrivate { CDockWidgetSideTab* _this; - CDockWidget* DockWidget; + CDockWidget* DockWidget = nullptr; CSideTabBar* SideTabBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; @@ -84,13 +84,11 @@ void CDockWidgetSideTab::removeFromSideTabBar() } //============================================================================ -CDockWidgetSideTab::CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent) : +CDockWidgetSideTab::CDockWidgetSideTab(QWidget* parent) : Super(parent), d(new DockWidgetSideTabPrivate(this)) { setAttribute(Qt::WA_NoMousePropagation); - d->DockWidget = DockWidget; - setText(DockWidget->windowTitle()); setFocusPolicy(Qt::NoFocus); } @@ -182,7 +180,7 @@ void CDockWidgetSideTab::updateOrientationForArea(SideBarLocation area) //============================================================================ bool CDockWidgetSideTab::isActiveTab() const { - if (d->DockWidget->autoHideDockContainer()) + if (d->DockWidget && d->DockWidget->autoHideDockContainer()) { return d->DockWidget->autoHideDockContainer()->isVisible(); } @@ -197,4 +195,16 @@ CDockWidget* CDockWidgetSideTab::dockWidget() const return d->DockWidget; } + +//============================================================================ +void CDockWidgetSideTab::setDockWidget(CDockWidget* DockWidget) +{ + if (!DockWidget) + { + return; + } + d->DockWidget = DockWidget; + setText(DockWidget->windowTitle()); +} + } diff --git a/src/DockWidgetSideTab.h b/src/DockWidgetSideTab.h index 4da3c7599..04bdacd38 100644 --- a/src/DockWidgetSideTab.h +++ b/src/DockWidgetSideTab.h @@ -76,7 +76,7 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton * param[in] DockWidget The dock widget this title bar belongs to * param[in] parent The parent widget of this title bar */ - CDockWidgetSideTab(CDockWidget* DockWidget, QWidget* parent = nullptr); + CDockWidgetSideTab(QWidget* parent = nullptr); /** * Virtual Destructor @@ -117,6 +117,11 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton * returns the dock widget this belongs to */ CDockWidget* dockWidget() const; + + /** + * Sets the dock widget that is controlled by this tab + */ + void setDockWidget(CDockWidget* DockWidget); }; // class DockWidgetSideTab } // namespace ads diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index d996ede95..c1c0a19c2 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -139,21 +139,19 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) //============================================================================ CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* DockWidget) { - CDockWidgetSideTab* Tab = new CDockWidgetSideTab(DockWidget); - auto area = sideTabBarArea(); - qDebug() << "area " << area; - Tab->setSideTabBar(this); - Tab->updateOrientationForArea(area); - d->TabsLayout->insertWidget(Index, Tab); - Tab->show(); - - auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, d->ContainerWidget); + /* + * sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); + DockWidget->sideTabWidget()->show(); + + const auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); AutoHideContainer->hide(); - DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); - Tab->updateStyle(); + d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); + return AutoHideContainer;*/ - connect(Tab, &CDockWidgetSideTab::pressed, AutoHideContainer, &CAutoHideDockContainer::toggleCollapseState); - show(); + auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, d->SideTabArea, d->ContainerWidget); + DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); + auto Tab = AutoHideContainer->sideTab(); + insertSideTab(Index, Tab); return AutoHideContainer; } From d1d801cf1695fbd111b732710b6f024dbecae98a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sun, 30 Oct 2022 19:44:33 +0100 Subject: [PATCH 170/236] Moved dock area restore code into CDockAreaWidget --- src/AutoHideDockContainer.cpp | 28 ++++---- src/DockAreaWidget.cpp | 93 +++++++++++++++++++++++++++ src/DockAreaWidget.h | 9 +++ src/DockContainerWidget.cpp | 118 +++++----------------------------- src/DockContainerWidget.h | 5 ++ src/DockWidget.cpp | 46 +++++++------ src/DockWidget.h | 26 +++++--- src/DockWidgetSideTab.cpp | 1 + src/SideTabBar.cpp | 29 +++++++++ src/SideTabBar.h | 9 +++ 10 files changed, 216 insertions(+), 148 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 5f7a728e3..267039ce1 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -27,7 +27,15 @@ //============================================================================ // INCLUDES //============================================================================ -#include +#include "AutoHideDockContainer.h" + +#include +#include +#include +#include +#include +#include + #include "DockManager.h" #include "DockWidgetSideTab.h" #include "DockWidgetTab.h" @@ -35,13 +43,8 @@ #include "DockAreaWidget.h" #include "DockingStateReader.h" #include "ResizeHandle.h" +#include "DockComponentsFactory.h" -#include -#include -#include -#include -#include -#include #include @@ -174,7 +177,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa d(new AutoHideDockContainerPrivate(this)) { d->SideTabBarArea = area; - d->SideTab = new CDockWidgetSideTab(); + d->SideTab = componentsFactory()->createDockWidgetSideTab(nullptr); connect(d->SideTab, &CDockWidgetSideTab::pressed, this, &CAutoHideDockContainer::toggleCollapseState); d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); @@ -294,14 +297,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) } d->DockWidget = DockWidget; - if (!d->SideTab) - { - d->SideTab = DockWidget->sideTabWidget(); - } - else - { - d->SideTab->setDockWidget(DockWidget); - } + d->SideTab->setDockWidget(DockWidget); CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); if (OldDockArea) { diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index db49d6923..4d47cb1a3 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -53,6 +53,7 @@ #include "DockComponentsFactory.h" #include "DockWidgetTab.h" #include "DockWidgetSideTab.h" +#include "DockingStateReader.h" namespace ads @@ -895,6 +896,98 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const } +//============================================================================ +bool CDockAreaWidget::restoreDockArea(CDockingStateReader& s, CDockAreaWidget*& CreatedWidget, + bool Testing, CDockContainerWidget* Container) +{ + 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); + + auto DockManager = Container->dockManager(); + CDockAreaWidget* DockArea = nullptr; + if (!Testing) + { + DockArea = new CDockAreaWidget(DockManager, Container); + const auto AllowedAreasAttribute = s.attributes().value("AllowedAreas"); + if (!AllowedAreasAttribute.isEmpty()) + { + DockArea->setAllowedAreas((DockWidgetArea)AllowedAreasAttribute.toInt(nullptr, 16)); + } + + const auto FlagsAttribute = s.attributes().value("Flags"); + if (!FlagsAttribute.isEmpty()) + { + DockArea->setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(nullptr, 16)); + } + } + + while (s.readNextStartElement()) + { + if (s.name() != QLatin1String("Widget")) + { + continue; + } + + auto ObjectName = s.attributes().value("Name"); + if (ObjectName.isEmpty()) + { + return false; + } + + bool Closed = s.attributes().value("Closed").toInt(&Ok); + if (!Ok) + { + 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(); + DockArea->addDockWidget(DockWidget); + DockWidget->setToggleViewActionChecked(!Closed); + DockWidget->setClosedState(Closed); + DockWidget->setProperty(internal::ClosedProperty, Closed); + DockWidget->setProperty(internal::DirtyProperty, false); + } + + if (Testing) + { + return true; + } + + if (!DockArea->dockWidgetsCount()) + { + delete DockArea; + DockArea = nullptr; + } + else + { + DockArea->setProperty("currentDockWidget", CurrentDockWidget); + } + + CreatedWidget = DockArea; + return true; +} + + //============================================================================ CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const { diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 6a5b5f2a7..61862bee2 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -46,6 +46,7 @@ class CDockManager; class CDockContainerWidget; class DockContainerWidgetPrivate; class CDockAreaTitleBar; +class CDockingStateReader; /** @@ -296,6 +297,13 @@ protected Q_SLOTS: */ void saveState(QXmlStreamWriter& Stream) const; + /** + * Restores a dock area. + * \see restoreChildNodes() for details + */ + static bool restoreDockArea(CDockingStateReader& Stream, CDockAreaWidget*& CreatedWidget, + bool Testing, CDockContainerWidget* Container); + /** * This functions returns the dock widget features of all dock widget in * this area. @@ -362,6 +370,7 @@ protected Q_SLOTS: */ bool containsCentralWidget() const; + public Q_SLOTS: /** * This activates the tab for the given tab index. diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 95f865fc5..f6c51b325 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -910,23 +910,7 @@ void DockContainerWidgetPrivate::saveAutoHideWidgetsState(QXmlStreamWriter& s) continue; } - s.writeStartElement("SideBar"); - s.writeAttribute("Area", QString::number(sideTabBar->sideTabBarArea())); - s.writeAttribute("Tabs", QString::number(sideTabBar->tabCount())); - - for (auto i = 0; i < sideTabBar->tabCount(); ++i) - { - auto Tab = sideTabBar->tabAt(i); - if (!Tab) - { - continue; - } - - auto DockArea = Tab->dockWidget()->dockAreaWidget(); - DockArea->saveState(s); - } - - s.writeEndElement(); + sideTabBar->saveState(s); } } @@ -1049,6 +1033,11 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, //============================================================================ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing) { + if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + return false; + } + bool Ok; #ifdef ADS_DEBUG_PRINT int Tabs = s.attributes().value("Tabs").toInt(&Ok); @@ -1062,11 +1051,6 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: " << CurrentDockWidget); - if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) - { - return false; - } - CDockAreaWidget* DockArea = nullptr; CAutoHideDockContainer* AutoHideContainer = nullptr; if (!Testing) @@ -1136,91 +1120,14 @@ bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, QWidget*& CreatedWidget, 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); - CDockAreaWidget* DockArea = nullptr; - if (!Testing) + auto Result = CDockAreaWidget::restoreDockArea(s, DockArea, Testing, _this); + if (Result && DockArea) { - DockArea = new CDockAreaWidget(DockManager, _this); - const auto AllowedAreasAttribute = s.attributes().value("AllowedAreas"); - if (!AllowedAreasAttribute.isEmpty()) - { - DockArea->setAllowedAreas((DockWidgetArea)AllowedAreasAttribute.toInt(nullptr, 16)); - } - - const auto FlagsAttribute = s.attributes().value("Flags"); - if (!FlagsAttribute.isEmpty()) - { - DockArea->setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(nullptr, 16)); - } - } - - while (s.readNextStartElement()) - { - if (s.name() != QLatin1String("Widget")) - { - continue; - } - - auto ObjectName = s.attributes().value("Name"); - if (ObjectName.isEmpty()) - { - return false; - } - - bool Closed = s.attributes().value("Closed").toInt(&Ok); - if (!Ok) - { - 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(); - DockArea->addDockWidget(DockWidget); - DockWidget->setToggleViewActionChecked(!Closed); - DockWidget->setClosedState(Closed); - DockWidget->setProperty(internal::ClosedProperty, Closed); - DockWidget->setProperty(internal::DirtyProperty, false); - } - - if (Testing) - { - return true; - } - - if (!DockArea->dockWidgetsCount()) - { - delete DockArea; - DockArea = nullptr; - } - else - { - DockArea->setProperty("currentDockWidget", CurrentDockWidget); appendDockAreas({DockArea}); } - CreatedWidget = DockArea; - return true; + return Result; } @@ -2319,6 +2226,13 @@ QRect CDockContainerWidget::contentRectGlobal() const } return internal::globalGeometry(d->RootSplitter); } + + +//=========================================================================== +CDockManager* CDockContainerWidget::dockManager() const +{ + return d->DockManager; +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 709d555a2..b97783a24 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -342,6 +342,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ QRect contentRectGlobal() const; + /** + * Returns the dock manager that owns this container + */ + CDockManager* dockManager() const; + Q_SIGNALS: /** diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 855eba811..529bd1a46 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -325,10 +325,6 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : setObjectName(title); d->TabWidget = componentsFactory()->createDockWidgetTab(this); - d->SideTabWidget = componentsFactory()->createDockWidgetSideTab(nullptr); - d->SideTabWidget->hide(); - - connect(d->SideTabWidget, &CDockWidgetSideTab::pressed, this, &CDockWidget::onDockWidgetSideTabClicked); d->ToggleViewAction = new QAction(title, this); d->ToggleViewAction->setCheckable(true); @@ -346,10 +342,6 @@ CDockWidget::CDockWidget(const QString &title, QWidget *parent) : CDockWidget::~CDockWidget() { ADS_PRINT("~CDockWidget()"); - if (d->SideTabWidget) - { - delete d->SideTabWidget; - } delete d; } @@ -443,6 +435,8 @@ CDockWidgetTab* CDockWidget::tabWidget() const return d->TabWidget; } + +//============================================================================ CAutoHideDockContainer* CDockWidget::autoHideDockContainer() const { if (!d->DockArea) @@ -534,6 +528,20 @@ CDockWidgetSideTab* CDockWidget::sideTabWidget() const } +//============================================================================ +void CDockWidget::setSideTabWidget(CDockWidgetSideTab* SideTab) const +{ + d->SideTabWidget = SideTab; +} + + +//============================================================================ +bool CDockWidget::isAutoHide() const +{ + return !d->SideTabWidget.isNull(); +} + + //============================================================================ bool CDockWidget::isFloating() const { @@ -741,6 +749,10 @@ bool CDockWidget::event(QEvent *e) { d->TabWidget->setText(title); } + if (d->SideTabWidget) + { + d->SideTabWidget->setText(title); + } if (d->ToggleViewAction) { d->ToggleViewAction->setText(title); @@ -791,7 +803,12 @@ void CDockWidget::setTabToolTip(const QString &text) void CDockWidget::setIcon(const QIcon& Icon) { d->TabWidget->setIcon(Icon); - d->SideTabWidget->setIcon(Icon); + + if (d->SideTabWidget) + { + d->SideTabWidget->setIcon(Icon); + } + if (!d->ToggleViewAction->isCheckable()) { d->ToggleViewAction->setIcon(Icon); @@ -1082,17 +1099,6 @@ void CDockWidget::showNormal() } } -//============================================================================ -void CDockWidget::onDockWidgetSideTabClicked() -{ - const auto autoHideContainer = autoHideDockContainer(); - if (!autoHideContainer) - { - return; - } - - autoHideContainer->toggleCollapseState(); -} //============================================================================ bool CDockWidget::isFullScreen() const diff --git a/src/DockWidget.h b/src/DockWidget.h index 52d87b235..ae8852cf9 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -315,12 +315,6 @@ private Q_SLOTS: */ CDockWidgetTab* tabWidget() const; - /** - * Returns the auto hide dock container of this dock widget - * or 0 if there is none - */ - CAutoHideDockContainer* autoHideDockContainer() const; - /** * Sets, whether the dock widget is movable, closable, and floatable. */ @@ -371,6 +365,22 @@ private Q_SLOTS: */ CDockWidgetSideTab* sideTabWidget() const; + /** + * Assign a side tab widget if this dock widget is an auto hide container + */ + void setSideTabWidget(CDockWidgetSideTab* SideTab) const; + + /** + * Returns true, if this dock widget is in an auto hide container + */ + bool isAutoHide() const; + + /** + * Returns the auto hide dock container of this dock widget + * or 0 if there is none + */ + CAutoHideDockContainer* autoHideDockContainer() 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 @@ -613,10 +623,6 @@ public Q_SLOTS: */ void showNormal(); - /** - * Toggles the dock auto hide container when the side tab is clicked - */ - void onDockWidgetSideTabClicked(); Q_SIGNALS: /** diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 4b90cdd92..29e8ccce5 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -205,6 +205,7 @@ void CDockWidgetSideTab::setDockWidget(CDockWidget* DockWidget) } d->DockWidget = DockWidget; setText(DockWidget->windowTitle()); + setIcon(d->DockWidget->icon()); } } diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index c1c0a19c2..8c7296d67 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -34,12 +34,14 @@ #include #include #include +#include #include "DockContainerWidget.h" #include "DockWidgetSideTab.h" #include "DockWidgetTab.h" #include "DockFocusController.h" #include "AutoHideDockContainer.h" +#include "DockAreaWidget.h" namespace ads { @@ -274,4 +276,31 @@ SideBarLocation CSideTabBar::sideTabBarArea() const return d->SideTabArea; } + +//============================================================================ +void CSideTabBar::saveState(QXmlStreamWriter& s) const +{ + if (!tabCount()) + { + return; + } + + s.writeStartElement("SideBar"); + s.writeAttribute("Area", QString::number(sideTabBarArea())); + s.writeAttribute("Tabs", QString::number(tabCount())); + + for (auto i = 0; i < tabCount(); ++i) + { + auto Tab = tabAt(i); + if (!Tab) + { + continue; + } + + auto DockArea = Tab->dockWidget()->dockAreaWidget(); + DockArea->saveState(s); + } + + s.writeEndElement(); +} } diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 4ba757a85..585be3957 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -33,9 +33,12 @@ #include "DockWidgetSideTab.h" #include "ads_globals.h" +class QXmlStreamWriter; + namespace ads { struct SideTabBarPrivate; +class DockContainerWidgetPrivate; class CDockContainerWidget; class CDockWidgetSideTab; class CAutoHideDockContainer; @@ -57,12 +60,18 @@ class ADS_EXPORT CSideTabBar : public QFrame SideTabBarPrivate* d; ///< private data (pimpl) friend struct SideTabBarPrivate; friend class DockWidgetSideTab; + friend DockContainerWidgetPrivate; protected: virtual void paintEvent(QPaintEvent* event) override; virtual bool event(QEvent* e) override; virtual bool eventFilter(QObject *watched, QEvent *event) override; + /** + * Saves the state into the given stream + */ + void saveState(QXmlStreamWriter& Stream) const; + public: using Super = QFrame; From d56281e8600d3a9c9648afa7deb6674ae4654169 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Mon, 31 Oct 2022 12:25:09 +0800 Subject: [PATCH 171/236] Fix crash that can happen on loading certain configurations Prior we were adding dock widgets without removing them from the old dock area. This can cause the old dock areas current index to become invalid as the old dock area still thinks it has an equivalent amount of dock widgets. Attempting to setCurrentIndex on these areas would then cause a crash as it's out of bounds! --- src/DockContainerWidget.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 71d17a1d9..382613787 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1189,6 +1189,12 @@ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, continue; } + const auto oldDockArea = DockWidget->dockAreaWidget(); + if (oldDockArea) + { + oldDockArea->removeDockWidget(DockWidget); + } + 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 From 44790307d80199d0456add407993e01a623d31f8 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 11:02:01 +0100 Subject: [PATCH 172/236] Properly implemented restore functionality for auto hide container --- examples/autohide/mainwindow.cpp | 2 +- src/AutoHideDockContainer.cpp | 64 ++++++-------- src/AutoHideDockContainer.h | 35 ++++---- src/DockAreaWidget.cpp | 9 +- src/DockAreaWidget.h | 4 +- src/DockContainerWidget.cpp | 143 ++++++++----------------------- src/DockManager.cpp | 3 +- src/DockWidget.h | 2 + src/DockWidgetSideTab.cpp | 1 - src/SideTabBar.cpp | 17 ++-- src/SideTabBar.h | 1 + 11 files changed, 95 insertions(+), 186 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 42dc49c5d..30061aa8e 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -47,7 +47,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->setMinimumSize(200,150); const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); - autoHideContainer->setSize(480, 100); + autoHideContainer->setSize(480); ui->menuView->addAction(TableDockWidget->toggleViewAction()); table = new QTableWidget(); diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 267039ce1..936782cf3 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -167,7 +167,14 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( //============================================================================ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const { - return internal::findParent(this); + if (d->DockArea) + { + return d->DockArea->dockContainer(); + } + else + { + return internal::findParent(this); + } } @@ -176,6 +183,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa Super(parent), d(new AutoHideDockContainerPrivate(this)) { + hide(); // auto hide dock container is initially always hidden d->SideTabBarArea = area; d->SideTab = componentsFactory()->createDockWidgetSideTab(nullptr); connect(d->SideTab, &CDockWidgetSideTab::pressed, this, &CAutoHideDockContainer::toggleCollapseState); @@ -363,40 +371,11 @@ void CAutoHideDockContainer::cleanupAndDelete() //============================================================================ void CAutoHideDockContainer::saveState(QXmlStreamWriter& s) { + s.writeStartElement("Widget"); + s.writeAttribute("Name", d->DockWidget->objectName()); + s.writeAttribute("Closed", QString::number(d->DockWidget->isClosed() ? 1 : 0)); s.writeAttribute("Size", QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width())); - - qDebug() << ": saveState Size: " << d->Size; - qDebug() << ": saveState Size " << QString::number(d->isHorizontal() ? d->Size.height() : d->Size.width()); -} - - -//============================================================================ -bool CAutoHideDockContainer::restoreState(CDockingStateReader& s, bool Testing) -{ - bool ok; - int Size = s.attributes().value("Size").toInt(&ok); - if (!ok) - { - return false; - } - - if (Testing) - { - return true; - } - - if (d->isHorizontal()) - { - d->Size.setHeight(Size); - } - else - { - d->Size.setWidth(Size); - qDebug() << ": restoreState Width " << Size; - } - - qDebug() << ": restoreState Size: " << d->Size; - return true; + s.writeEndElement(); } @@ -438,6 +417,11 @@ void CAutoHideDockContainer::collapseView(bool Enable) show(); d->DockWidget->dockManager()->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); + + qDebug() << "CAutoHideDockContainer.hidden " << this->isHidden(); + qDebug() << "d->DockArea->isHidden() " << d->DockArea->isHidden(); + qDebug() << "d->DockWidget->isHidden() " << d->DockWidget->isHidden(); + qDebug() << "CAutoHideDockContainer.geometry() " << this->geometry(); } ADS_PRINT("CAutoHideDockContainer::collapseView " << Enable); @@ -453,9 +437,17 @@ void CAutoHideDockContainer::toggleCollapseState() //============================================================================ -void CAutoHideDockContainer::setSize(int width, int height) +void CAutoHideDockContainer::setSize(int Size) { - d->Size = QSize(width, height); + if (d->isHorizontal()) + { + d->Size.setHeight(Size); + } + else + { + d->Size.setWidth(Size); + } + updateSize(); } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 3a6b8c735..eb93cf247 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -46,6 +46,7 @@ class CDockContainerWidget; class CSideTabBar; class CDockAreaWidget; class CDockingStateReader; +struct SideTabBarPrivate; /** * Auto hide container for hosting an auto hide dock widget @@ -57,13 +58,18 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; + friend CSideTabBar; + friend SideTabBarPrivate; protected: bool eventFilter(QObject* watched, QEvent* event) override; void resizeEvent(QResizeEvent* event) override; void updateSize(); - CDockContainerWidget* parentContainer() const; + /* + * Saves the state and size + */ + void saveState(QXmlStreamWriter& Stream); public: using Super = QFrame; @@ -114,6 +120,11 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame */ CDockAreaWidget* dockAreaWidget() const; + /** + * Returns the parent container that hosts this auto hide container + */ + CDockContainerWidget* parentContainer() const; + /** * Moves the contents to the parent container widget * Used before removing this Auto Hide dock container @@ -125,16 +136,6 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame */ void cleanupAndDelete(); - /* - * Saves the state and size - */ - void saveState(QXmlStreamWriter& Stream); - - /* - * Restores the size of the splitter - */ - bool restoreState(CDockingStateReader& Stream, bool Testing); - /* * Toggles the auto Hide dock container widget * This will also hide the side tab widget @@ -153,13 +154,13 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame void toggleCollapseState(); /** - * Use this instead of resize. This will ensure the size is consistent internally. - * E.g. If you set a height less than the parent height when it's vertical - * It will simply be rescaled to the parent height while the width will be resized + * Use this instead of resize. + * Depending on the sidebar location this will set the width or heigth + * of this auto hide container. */ - void setSize(int width, int height); + void setSize(int Size); }; -} - +} // namespace ads +//----------------------------------------------------------------------------- #endif diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 4d47cb1a3..adaad984b 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -870,13 +870,6 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const 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)); @@ -897,7 +890,7 @@ void CDockAreaWidget::saveState(QXmlStreamWriter& s) const //============================================================================ -bool CDockAreaWidget::restoreDockArea(CDockingStateReader& s, CDockAreaWidget*& CreatedWidget, +bool CDockAreaWidget::restoreState(CDockingStateReader& s, CDockAreaWidget*& CreatedWidget, bool Testing, CDockContainerWidget* Container) { bool Ok; diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 61862bee2..edb1b025d 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -301,8 +301,8 @@ protected Q_SLOTS: * Restores a dock area. * \see restoreChildNodes() for details */ - static bool restoreDockArea(CDockingStateReader& Stream, CDockAreaWidget*& CreatedWidget, - bool Testing, CDockContainerWidget* Container); + static bool restoreState(CDockingStateReader& Stream, CDockAreaWidget*& CreatedWidget, + bool Testing, CDockContainerWidget* ParentContainer); /** * This functions returns the dock widget features of all dock widget in diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index f6c51b325..2569539a3 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -250,13 +250,6 @@ class DockContainerWidgetPrivate bool restoreDockArea(CDockingStateReader& Stream, QWidget*& CreatedWidget, bool Testing); - /** - * Restores the auto hide dock area. - * Assumes that there are no auto hidden dock areas, and then restores all the dock areas that - * exist in the XML - */ - bool restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing); - /** * Restores a auto hide side bar */ @@ -1030,98 +1023,13 @@ bool DockContainerWidgetPrivate::restoreSplitter(CDockingStateReader& s, return true; } -//============================================================================ -bool DockContainerWidgetPrivate::restoreAutoHideDockArea(CDockingStateReader& s, SideBarLocation area, bool Testing) -{ - if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) - { - return false; - } - - 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); - - CDockAreaWidget* DockArea = nullptr; - CAutoHideDockContainer* AutoHideContainer = nullptr; - if (!Testing) - { - AutoHideContainer = new CAutoHideDockContainer(DockManager, area, _this); - if (!AutoHideContainer->restoreState(s, Testing)) - { - return false; - } - - AutoHideContainer->hide(); - DockArea = AutoHideContainer->dockAreaWidget(); - DockArea->updateAutoHideButtonCheckState(); - DockArea->updateTitleBarButtonToolTip(); - } - - while (s.readNextStartElement()) - { - if (s.name() != QLatin1String("Widget")) - { - continue; - } - - auto ObjectName = s.attributes().value("Name"); - if (ObjectName.isEmpty()) - { - return false; - } - - bool Closed = s.attributes().value("Closed").toInt(&Ok); - if (!Ok) - { - 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(!Closed); - DockWidget->setClosedState(Closed); - DockWidget->setProperty(internal::ClosedProperty, Closed); - DockWidget->setProperty(internal::DirtyProperty, false); - _this->sideTabBar(area)->insertSideTab(-1, DockWidget->sideTabWidget()); - DockArea->autoHideDockContainer()->addDockWidget(DockWidget); - DockWidget->sideTabWidget()->updateStyle(); // Needed as the side tab widget get it's left/right property from the overlay dock container which was just added - DockArea->autoHideDockContainer()->toggleView(!Closed); - } - - if (AutoHideContainer && !AutoHideContainer->dockWidget()) - { - AutoHideContainer->cleanupAndDelete(); - } - - return true; -} - //============================================================================ bool DockContainerWidgetPrivate::restoreDockArea(CDockingStateReader& s, QWidget*& CreatedWidget, bool Testing) { CDockAreaWidget* DockArea = nullptr; - auto Result = CDockAreaWidget::restoreDockArea(s, DockArea, Testing, _this); + auto Result = CDockAreaWidget::restoreState(s, DockArea, Testing, _this); if (Result && DockArea) { appendDockAreas({DockArea}); @@ -1136,14 +1044,14 @@ bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s, QWidget*& CreatedWidget, bool Testing) { Q_UNUSED(CreatedWidget) - // Simply ignore side bar auto hide widgets + // Simply ignore side bar auto hide widgets from saved state if + // auto hide support is disabled if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) { return true; } bool Ok; - //int Tabs = s.attributes().value("Tabs").toInt(&Ok); auto Area = (ads::SideBarLocation)s.attributes().value("Area").toInt(&Ok); if (!Ok) { @@ -1152,15 +1060,42 @@ bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s, while (s.readNextStartElement()) { - if (s.name() != QLatin1String("Area")) + if (s.name() != QLatin1String("Widget")) { continue; } - if (!restoreAutoHideDockArea(s, Area, Testing)) - { - return false; - } + auto Name = s.attributes().value("Name"); + if (Name.isEmpty()) + { + return false; + } + + bool Ok; + bool Closed = s.attributes().value("Closed").toInt(&Ok); + if (!Ok) + { + return false; + } + + int Size = s.attributes().value("Size").toInt(&Ok); + if (!Ok) + { + return false; + } + + s.skipCurrentElement(); + CDockWidget* DockWidget = DockManager->findDockWidget(Name.toString()); + if (!DockWidget || Testing) + { + continue; + } + + auto SideBar = _this->sideTabBar(Area); + auto AutoHideContainer = SideBar->insertDockWidget(-1, DockWidget); + AutoHideContainer->setSize(Size); + DockWidget->setProperty(internal::ClosedProperty, Closed); + DockWidget->setProperty(internal::DirtyProperty, false); } return true; @@ -1453,14 +1388,6 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager } - /*sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); - DockWidget->sideTabWidget()->show(); - - const auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); - AutoHideContainer->hide(); - d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); - return AutoHideContainer;*/ - return sideTabBar(area)->insertDockWidget(insertOrder == CDockWidget::First ? 0 : -1, DockWidget); } diff --git a/src/DockManager.cpp b/src/DockManager.cpp index cb5586901..5899192eb 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -700,7 +700,8 @@ QByteArray CDockManager::saveState(int version) const QByteArray xmldata; QXmlStreamWriter s(&xmldata); auto ConfigFlags = CDockManager::configFlags(); - s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled)); + //s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled)); + s.setAutoFormatting(true); s.writeStartDocument(); s.writeStartElement("QtAdvancedDockingSystem"); s.writeAttribute("Version", QString::number(CurrentVersion)); diff --git a/src/DockWidget.h b/src/DockWidget.h index ae8852cf9..d8048a2ce 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -48,6 +48,7 @@ class DockContainerWidgetPrivate; class CFloatingDockContainer; class CDockWidgetSideTab; class CAutoHideDockContainer; +class CSideTabBar; /** * The QDockWidget class provides a widget that can be docked inside a @@ -78,6 +79,7 @@ private Q_SLOTS: friend struct DockWidgetTabPrivate; friend struct DockAreaTitleBarPrivate; friend class CAutoHideDockContainer; + friend CSideTabBar; /** * Assigns the dock manager that manages this dock widget diff --git a/src/DockWidgetSideTab.cpp b/src/DockWidgetSideTab.cpp index 29e8ccce5..c7c1b1a35 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/DockWidgetSideTab.cpp @@ -114,7 +114,6 @@ SideBarLocation CDockWidgetSideTab::sideTabBarArea() const { if (d->SideTabBar) { - qDebug() << "CDockWidgetSideTab::sideTabBarArea() " << d->SideTabBar->sideTabBarArea(); return d->SideTabBar->sideTabBarArea(); } diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 8c7296d67..8ee67a3b7 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -42,6 +42,7 @@ #include "DockFocusController.h" #include "AutoHideDockContainer.h" #include "DockAreaWidget.h" +#include "DockingStateReader.h" namespace ads { @@ -141,15 +142,6 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) //============================================================================ CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* DockWidget) { - /* - * sideTabBar(area)->insertSideTab(insertOrder == CDockWidget::First ? 0 : -1, DockWidget->sideTabWidget()); - DockWidget->sideTabWidget()->show(); - - const auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, area, this); - AutoHideContainer->hide(); - d->DockManager->dockFocusController()->clearDockWidgetFocus(DockWidget); - return AutoHideContainer;*/ - auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, d->SideTabArea, d->ContainerWidget); DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); auto Tab = AutoHideContainer->sideTab(); @@ -297,10 +289,11 @@ void CSideTabBar::saveState(QXmlStreamWriter& s) const continue; } - auto DockArea = Tab->dockWidget()->dockAreaWidget(); - DockArea->saveState(s); + Tab->dockWidget()->autoHideDockContainer()->saveState(s); } s.writeEndElement(); } -} + + +} // namespace ads diff --git a/src/SideTabBar.h b/src/SideTabBar.h index 585be3957..f11e3e3f2 100644 --- a/src/SideTabBar.h +++ b/src/SideTabBar.h @@ -42,6 +42,7 @@ class DockContainerWidgetPrivate; class CDockContainerWidget; class CDockWidgetSideTab; class CAutoHideDockContainer; +class CDockingStateReader; /** * Side tab bar widget that is shown at the edges of a dock container. From fba9c7ce5d665e274b14ca9f875035e2e59f0b39 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 11:22:15 +0100 Subject: [PATCH 173/236] Create auto hide sidebars only if config flag is set --- src/AutoHideDockContainer.cpp | 6 ------ src/DockAreaWidget.cpp | 1 - src/DockContainerWidget.cpp | 14 +++++++------- src/SideTabBar.cpp | 2 +- 4 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 936782cf3..08370a36b 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -262,7 +262,6 @@ void CAutoHideDockContainer::updateSize() //============================================================================ CAutoHideDockContainer::~CAutoHideDockContainer() { - qDebug() << "~CAutoHideDockContainer()" ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages @@ -417,11 +416,6 @@ void CAutoHideDockContainer::collapseView(bool Enable) show(); d->DockWidget->dockManager()->setDockWidgetFocused(d->DockWidget); qApp->installEventFilter(this); - - qDebug() << "CAutoHideDockContainer.hidden " << this->isHidden(); - qDebug() << "d->DockArea->isHidden() " << d->DockArea->isHidden(); - qDebug() << "d->DockWidget->isHidden() " << d->DockWidget->isHidden(); - qDebug() << "CAutoHideDockContainer.geometry() " << this->geometry(); } ADS_PRINT("CAutoHideDockContainer::collapseView " << Enable); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index adaad984b..a48883cee 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -502,7 +502,6 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, //============================================================================ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { - qDebug() << "CDockAreaWidget::removeDockWidget"; ADS_PRINT("CDockAreaWidget::removeDockWidget"); auto CurrentDockWidget = currentDockWidget(); auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 2569539a3..9727062f6 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -846,7 +846,6 @@ void DockContainerWidgetPrivate::addDockAreasToList(const QList NewDockAreas) { - qDebug() << "DockContainerWidgetPrivate::appendDockAreas"; DockAreas.append(NewDockAreas); for (auto DockArea : NewDockAreas) { @@ -1326,13 +1325,11 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p { d->DockManager->registerDockContainer(this); createRootSplitter(); - if (CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) - { - createSideTabBarWidgets(); - } + createSideTabBarWidgets(); } } + //============================================================================ CDockContainerWidget::~CDockContainerWidget() { @@ -1566,7 +1563,6 @@ void CDockContainerWidget::addDockArea(CDockAreaWidget* DockAreaWidget, //============================================================================ void CDockContainerWidget::removeDockArea(CDockAreaWidget* area) { - qDebug() << "CDockContainerWidget::removeDockArea " << d->DockAreas.contains(area); ADS_PRINT("CDockContainerWidget::removeDockArea"); // If it is an auto hide area, then there is nothing much to do if (area->isAutoHide()) @@ -1779,7 +1775,6 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi void CDockContainerWidget::dropWidget(QWidget* Widget, DockWidgetArea DropArea, CDockAreaWidget* TargetAreaWidget) { CDockWidget* SingleDockWidget = topLevelDockWidget(); - qDebug() << "CDockContainerWidget::dropWidget"; if (TargetAreaWidget) { d->moveToNewSection(Widget, TargetAreaWidget, DropArea); @@ -1956,6 +1951,11 @@ void CDockContainerWidget::createRootSplitter() //============================================================================ void CDockContainerWidget::createSideTabBarWidgets() { + if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + return; + } + { auto Area = SideBarLocation::Left; d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 8ee67a3b7..7bd03c1ed 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -117,6 +117,7 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : CSideTabBar::~CSideTabBar() { qDebug() << "~CSideTabBar() "; + qDebug() << "parent " << d->ContainerWidget; // The SideTabeBar is not the owner of the tabs and to prevent deletion // we set the parent here to nullptr to remove it from the children auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); @@ -161,7 +162,6 @@ void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) //============================================================================ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) { - qDebug() << "CSideTabBar::removeSideTab " << SideTab->text(); SideTab->removeEventFilter(this); d->TabsLayout->removeWidget(SideTab); if (d->TabsLayout->isEmpty()) From 760c0365e0ed8fd289abb2a435f55b5dcca83238 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 11:35:07 +0100 Subject: [PATCH 174/236] Use explicit naming for functions to configure auto hide flags and disable auto hide feature by default --- demo/MainWindow.cpp | 4 ++-- examples/autohide/mainwindow.cpp | 2 +- src/DockManager.cpp | 6 +++--- src/DockManager.h | 12 +++++++++--- src/SideTabBar.cpp | 1 - 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index ba5db06dd..f0bf1fef5 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -654,7 +654,7 @@ CMainWindow::CMainWindow(QWidget *parent) : CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); // uncomment if you would like to enable dock widget auto hiding - CDockManager::setConfigFlags(CDockManager::DefaultAutoHideConfig); + CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets @@ -749,7 +749,7 @@ void CMainWindow::onViewToggled(bool Open) return; } - //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; + qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; } diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 30061aa8e..4ae68be55 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -27,7 +27,7 @@ CMainWindow::CMainWindow(QWidget *parent) CDockManager::setConfigFlag(CDockManager::OpaqueSplitterResize, true); CDockManager::setConfigFlag(CDockManager::XmlCompressionEnabled, false); CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); - CDockManager::setConfigFlag(CDockManager::DefaultAutoHideConfig, true); + CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); DockManager = new CDockManager(this); // Set central widget diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 5899192eb..13cf7318e 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -93,7 +93,7 @@ enum eStateFileVersion }; static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig; -static CDockManager::AutoHideFlags StaticAutoHideConfigFlags = CDockManager::DefaultAutoHideConfig; +static CDockManager::AutoHideFlags StaticAutoHideConfigFlags; // auto hide feature is disabled by default static QString FloatingContainersTitle; @@ -1159,7 +1159,7 @@ void CDockManager::setConfigFlags(const ConfigFlags Flags) //=========================================================================== -void CDockManager::setConfigFlags(const AutoHideFlags Flags) +void CDockManager::setAutoHideConfigFlags(const AutoHideFlags Flags) { StaticAutoHideConfigFlags = Flags; } @@ -1173,7 +1173,7 @@ void CDockManager::setConfigFlag(eConfigFlag Flag, bool On) //=========================================================================== -void CDockManager::setConfigFlag(eAutoHideFlag Flag, bool On) +void CDockManager::setAutoHideConfigFlag(eAutoHideFlag Flag, bool On) { internal::setFlag(StaticAutoHideConfigFlags, Flag, On); } diff --git a/src/DockManager.h b/src/DockManager.h index 74ba44a5b..9591945a6 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -226,9 +226,15 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget }; Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag) + + /** + * These global configuration flags configure some dock manager auto hide + * settings + * Set the dock manager flags, before you create the dock manager instance. + */ enum eAutoHideFlag { - AutoHideFeatureEnabled = 0x01, + AutoHideFeatureEnabled = 0x01, //!< enables / disables auto hide feature DockAreaHasAutoHideButton = 0x02, //!< If the flag is set each dock area has a auto hide menu button LeftSideBarIconOnly = 0x04, //!< If the flag is set left side bar will show only icon if a the dock widget has an icon assigned RightSideBarIconOnly = 0x08, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned @@ -279,7 +285,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * Call this function before you create the dock manager and before * your create the first dock widget. */ - static void setConfigFlags(const AutoHideFlags Flags); + static void setAutoHideConfigFlags(const AutoHideFlags Flags); /** * Set a certain config flag. @@ -291,7 +297,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * Set a certain overlay config flag. * \see setConfigFlags() */ - static void setConfigFlag(eAutoHideFlag Flag, bool On = true); + static void setAutoHideConfigFlag(eAutoHideFlag Flag, bool On = true); /** * Returns true if the given config flag is set diff --git a/src/SideTabBar.cpp b/src/SideTabBar.cpp index 7bd03c1ed..beb2d6197 100644 --- a/src/SideTabBar.cpp +++ b/src/SideTabBar.cpp @@ -117,7 +117,6 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : CSideTabBar::~CSideTabBar() { qDebug() << "~CSideTabBar() "; - qDebug() << "parent " << d->ContainerWidget; // The SideTabeBar is not the owner of the tabs and to prevent deletion // we set the parent here to nullptr to remove it from the children auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); From 2370d79ca6d96c3eba5394c2cced6c4da220149a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 11:39:34 +0100 Subject: [PATCH 175/236] Removed debug code from DockManager saveState function --- src/DockManager.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 13cf7318e..5b4aefabe 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -700,8 +700,7 @@ QByteArray CDockManager::saveState(int version) const QByteArray xmldata; QXmlStreamWriter s(&xmldata); auto ConfigFlags = CDockManager::configFlags(); - //s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled)); - s.setAutoFormatting(true); + s.setAutoFormatting(ConfigFlags.testFlag(XmlAutoFormattingEnabled)); s.writeStartDocument(); s.writeStartElement("QtAdvancedDockingSystem"); s.writeAttribute("Version", QString::number(CurrentVersion)); @@ -719,8 +718,6 @@ QByteArray CDockManager::saveState(int version) const s.writeEndElement(); s.writeEndDocument(); - std::cout << xmldata.toStdString() << std::endl; - return ConfigFlags.testFlag(XmlCompressionEnabled) ? qCompress(xmldata, 9) : xmldata; } From 782af9a1fc01e5fda9561b9aff063374fc0d2ea4 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 12:06:59 +0100 Subject: [PATCH 176/236] Renamed SideTabBar and DockWidgetSideTab into AutoHideSideBar and AutoHideTab for consistent naming --- src/AutoHideDockContainer.cpp | 14 ++--- src/AutoHideDockContainer.h | 11 ++-- src/{SideTabBar.cpp => AutoHideSideBar.cpp} | 55 +++++++++---------- src/{SideTabBar.h => AutoHideSideBar.h} | 32 +++++------ ...{DockWidgetSideTab.cpp => AutoHideTab.cpp} | 53 +++++++++--------- src/{DockWidgetSideTab.h => AutoHideTab.h} | 20 +++---- src/DockAreaWidget.cpp | 2 +- src/DockAreaWidget.h | 2 +- src/DockComponentsFactory.cpp | 6 +- src/DockComponentsFactory.h | 4 +- src/DockContainerWidget.cpp | 16 +++--- src/DockContainerWidget.h | 6 +- src/DockFocusController.cpp | 2 +- src/DockManager.h | 4 +- src/DockWidget.cpp | 10 ++-- src/DockWidget.h | 10 ++-- src/src.pro | 8 +-- src/stylesheets/default.css | 40 +++++++------- src/stylesheets/default_linux.css | 40 +++++++------- src/stylesheets/focus_highlighting.css | 42 +++++++------- src/stylesheets/focus_highlighting_linux.css | 40 +++++++------- src/stylesheets/visual_studio_light.css | 28 +++++----- 22 files changed, 221 insertions(+), 224 deletions(-) rename src/{SideTabBar.cpp => AutoHideSideBar.cpp} (82%) rename src/{SideTabBar.h => AutoHideSideBar.h} (83%) rename src/{DockWidgetSideTab.cpp => AutoHideTab.cpp} (78%) rename src/{DockWidgetSideTab.h => AutoHideTab.h} (89%) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 08370a36b..14d3c8a16 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -27,6 +27,8 @@ //============================================================================ // INCLUDES //============================================================================ +#include +#include #include "AutoHideDockContainer.h" #include @@ -37,9 +39,7 @@ #include #include "DockManager.h" -#include "DockWidgetSideTab.h" #include "DockWidgetTab.h" -#include "SideTabBar.h" #include "DockAreaWidget.h" #include "DockingStateReader.h" #include "ResizeHandle.h" @@ -110,7 +110,7 @@ struct AutoHideDockContainerPrivate QBoxLayout* Layout; CResizeHandle* ResizeHandle = nullptr; QSize Size; // creates invalid size - QPointer SideTab; + QPointer SideTab; /** * Private data constructor @@ -186,7 +186,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa hide(); // auto hide dock container is initially always hidden d->SideTabBarArea = area; d->SideTab = componentsFactory()->createDockWidgetSideTab(nullptr); - connect(d->SideTab, &CDockWidgetSideTab::pressed, this, &CAutoHideDockContainer::toggleCollapseState); + connect(d->SideTab, &CAutoHideTab::pressed, this, &CAutoHideDockContainer::toggleCollapseState); d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); d->DockArea->setAutoHideDockContainer(this); @@ -275,14 +275,14 @@ CAutoHideDockContainer::~CAutoHideDockContainer() } //============================================================================ -CSideTabBar* CAutoHideDockContainer::sideTabBar() const +CAutoHideSideBar* CAutoHideDockContainer::sideTabBar() const { return parentContainer()->sideTabBar(d->SideTabBarArea); } //============================================================================ -CDockWidgetSideTab* CAutoHideDockContainer::sideTab() const +CAutoHideTab* CAutoHideDockContainer::sideTab() const { return d->SideTab; } @@ -357,7 +357,7 @@ void CAutoHideDockContainer::cleanupAndDelete() if (dockWidget) { auto SideTab = d->SideTab; - SideTab->removeFromSideTabBar(); + SideTab->removeFromSideBar(); SideTab->setParent(dockWidget); SideTab->hide(); } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index eb93cf247..4943cd655 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -31,9 +31,8 @@ //============================================================================ #include "ads_globals.h" -#include "DockWidgetSideTab.h" - #include +#include "AutoHideTab.h" class QXmlStreamWriter; @@ -43,7 +42,7 @@ struct AutoHideDockContainerPrivate; class CDockManager; class CDockWidget; class CDockContainerWidget; -class CSideTabBar; +class CAutoHideSideBar; class CDockAreaWidget; class CDockingStateReader; struct SideTabBarPrivate; @@ -58,7 +57,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; - friend CSideTabBar; + friend CAutoHideSideBar; friend SideTabBarPrivate; protected: @@ -93,12 +92,12 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Get's the side tab bar */ - CSideTabBar* sideTabBar() const; + CAutoHideSideBar* sideTabBar() const; /** * Returns the side tab */ - CDockWidgetSideTab* sideTab() const; + CAutoHideTab* sideTab() const; /** * Get's the dock widget in this dock container diff --git a/src/SideTabBar.cpp b/src/AutoHideSideBar.cpp similarity index 82% rename from src/SideTabBar.cpp rename to src/AutoHideSideBar.cpp index beb2d6197..7b0a5c0d4 100644 --- a/src/SideTabBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -29,15 +29,14 @@ //============================================================================ // INCLUDES //============================================================================ -#include "SideTabBar.h" - +#include +#include #include #include #include #include #include "DockContainerWidget.h" -#include "DockWidgetSideTab.h" #include "DockWidgetTab.h" #include "DockFocusController.h" #include "AutoHideDockContainer.h" @@ -49,14 +48,14 @@ namespace ads /** * Private data class of CSideTabBar class (pimpl) */ -struct SideTabBarPrivate +struct AutoHideSideBarPrivate { /** * Private data constructor */ - SideTabBarPrivate(CSideTabBar* _public); + AutoHideSideBarPrivate(CAutoHideSideBar* _public); - CSideTabBar* _this; + CAutoHideSideBar* _this; CDockContainerWidget* ContainerWidget; QBoxLayout* TabsLayout; Qt::Orientation Orientation; @@ -69,19 +68,19 @@ struct SideTabBarPrivate { return Qt::Horizontal == Orientation; } -}; // struct SideTabBarPrivate +}; // struct AutoHideSideBarPrivate //============================================================================ -SideTabBarPrivate::SideTabBarPrivate(CSideTabBar* _public) : +AutoHideSideBarPrivate::AutoHideSideBarPrivate(CAutoHideSideBar* _public) : _this(_public) { } //============================================================================ -CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : +CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation area) : Super(parent), - d(new SideTabBarPrivate(this)) + d(new AutoHideSideBarPrivate(this)) { d->SideTabArea = area; d->ContainerWidget = parent; @@ -114,12 +113,12 @@ CSideTabBar::CSideTabBar(CDockContainerWidget* parent, SideBarLocation area) : //============================================================================ -CSideTabBar::~CSideTabBar() +CAutoHideSideBar::~CAutoHideSideBar() { qDebug() << "~CSideTabBar() "; // The SideTabeBar is not the owner of the tabs and to prevent deletion // we set the parent here to nullptr to remove it from the children - auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); + auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); for (auto Tab : Tabs) { Tab->setParent(nullptr); @@ -129,10 +128,10 @@ CSideTabBar::~CSideTabBar() //============================================================================ -void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) +void CAutoHideSideBar::insertSideTab(int Index, CAutoHideTab* SideTab) { SideTab->installEventFilter(this); - SideTab->setSideTabBar(this); + SideTab->setSideBar(this); SideTab->updateOrientationForArea(d->SideTabArea); d->TabsLayout->insertWidget(Index, SideTab); show(); @@ -140,7 +139,7 @@ void CSideTabBar::insertSideTab(int Index, CDockWidgetSideTab* SideTab) //============================================================================ -CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* DockWidget) +CAutoHideDockContainer* CAutoHideSideBar::insertDockWidget(int Index, CDockWidget* DockWidget) { auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, d->SideTabArea, d->ContainerWidget); DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); @@ -151,7 +150,7 @@ CAutoHideDockContainer* CSideTabBar::insertDockWidget(int Index, CDockWidget* Do //============================================================================ -void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) +void CAutoHideSideBar::removeDockWidget(CDockWidget* DockWidget) { Q_UNUSED(DockWidget); // TODO implement @@ -159,7 +158,7 @@ void CSideTabBar::removeDockWidget(CDockWidget* DockWidget) //============================================================================ -void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) +void CAutoHideSideBar::removeSideTab(CAutoHideTab* SideTab) { SideTab->removeEventFilter(this); d->TabsLayout->removeWidget(SideTab); @@ -171,7 +170,7 @@ void CSideTabBar::removeSideTab(CDockWidgetSideTab* SideTab) //============================================================================ -bool CSideTabBar::event(QEvent* e) +bool CAutoHideSideBar::event(QEvent* e) { switch (e->type()) { @@ -211,7 +210,7 @@ bool CSideTabBar::event(QEvent* e) //============================================================================ -bool CSideTabBar::eventFilter(QObject *watched, QEvent *event) +bool CAutoHideSideBar::eventFilter(QObject *watched, QEvent *event) { if (event->type() != QEvent::ShowToParent) { @@ -219,7 +218,7 @@ bool CSideTabBar::eventFilter(QObject *watched, QEvent *event) } // As soon as on tab is shhown, we need to show the side tab bar - auto Tab = qobject_cast(watched); + auto Tab = qobject_cast(watched); if (Tab) { show(); @@ -229,7 +228,7 @@ bool CSideTabBar::eventFilter(QObject *watched, QEvent *event) //============================================================================ -void CSideTabBar::paintEvent(QPaintEvent* event) +void CAutoHideSideBar::paintEvent(QPaintEvent* event) { Q_UNUSED(event) @@ -241,35 +240,35 @@ void CSideTabBar::paintEvent(QPaintEvent* event) //============================================================================ -Qt::Orientation CSideTabBar::orientation() const +Qt::Orientation CAutoHideSideBar::orientation() const { return d->Orientation; } //============================================================================ -CDockWidgetSideTab* CSideTabBar::tabAt(int index) const +CAutoHideTab* CAutoHideSideBar::tabAt(int index) const { - return qobject_cast(d->TabsLayout->itemAt(index)->widget()); + return qobject_cast(d->TabsLayout->itemAt(index)->widget()); } //============================================================================ -int CSideTabBar::tabCount() const +int CAutoHideSideBar::tabCount() const { return d->TabsLayout->count(); } //============================================================================ -SideBarLocation CSideTabBar::sideTabBarArea() const +SideBarLocation CAutoHideSideBar::sideBarArea() const { return d->SideTabArea; } //============================================================================ -void CSideTabBar::saveState(QXmlStreamWriter& s) const +void CAutoHideSideBar::saveState(QXmlStreamWriter& s) const { if (!tabCount()) { @@ -277,7 +276,7 @@ void CSideTabBar::saveState(QXmlStreamWriter& s) const } s.writeStartElement("SideBar"); - s.writeAttribute("Area", QString::number(sideTabBarArea())); + s.writeAttribute("Area", QString::number(sideBarArea())); s.writeAttribute("Tabs", QString::number(tabCount())); for (auto i = 0; i < tabCount(); ++i) diff --git a/src/SideTabBar.h b/src/AutoHideSideBar.h similarity index 83% rename from src/SideTabBar.h rename to src/AutoHideSideBar.h index f11e3e3f2..c27820ce3 100644 --- a/src/SideTabBar.h +++ b/src/AutoHideSideBar.h @@ -1,5 +1,5 @@ -#ifndef SideTabBarH -#define SideTabBarH +#ifndef AutoHideSideBarH +#define AutoHideSideBarH /******************************************************************************* ** Qt Advanced Docking System ** Copyright (C) 2017 Uwe Kindler @@ -23,24 +23,24 @@ /// \file DockWidgetTab.h /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Declaration of CSideTabBar class +/// \brief Declaration of CAutoHideSideBar class //============================================================================ //============================================================================ // INCLUDES //============================================================================ #include -#include "DockWidgetSideTab.h" #include "ads_globals.h" +#include "AutoHideTab.h" class QXmlStreamWriter; namespace ads { -struct SideTabBarPrivate; +struct AutoHideSideBarPrivate; class DockContainerWidgetPrivate; class CDockContainerWidget; -class CDockWidgetSideTab; +class CAutoHideTab; class CAutoHideDockContainer; class CDockingStateReader; @@ -51,15 +51,15 @@ class CDockingStateReader; * side bar is also hidden. As soon as one single tab becomes visible, this * tab bar will be shown. */ -class ADS_EXPORT CSideTabBar : public QFrame +class ADS_EXPORT CAutoHideSideBar : public QFrame { Q_OBJECT - Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideBarArea READ sideBarArea) Q_PROPERTY(Qt::Orientation orientation READ orientation) private: - SideTabBarPrivate* d; ///< private data (pimpl) - friend struct SideTabBarPrivate; + AutoHideSideBarPrivate* d; ///< private data (pimpl) + friend struct AutoHideSideBarPrivate; friend class DockWidgetSideTab; friend DockContainerWidgetPrivate; @@ -79,22 +79,22 @@ class ADS_EXPORT CSideTabBar : public QFrame /** * Default Constructor */ - CSideTabBar(CDockContainerWidget* parent, SideBarLocation area); + CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation area); /** * Virtual Destructor */ - virtual ~CSideTabBar(); + virtual ~CAutoHideSideBar(); /** * Inserts the given dock widget tab at the given position. */ - void insertSideTab(int Index, CDockWidgetSideTab* SideTab); + void insertSideTab(int Index, CAutoHideTab* SideTab); /** * Removes the given DockWidgetSideTab from the tabbar */ - void removeSideTab(CDockWidgetSideTab* SideTab); + void removeSideTab(CAutoHideTab* SideTab); /** * Insert dock widget @@ -114,7 +114,7 @@ class ADS_EXPORT CSideTabBar : public QFrame /* * get the side tab widget at position, returns nullptr if it's out of bounds */ - CDockWidgetSideTab* tabAt(int index) const; + CAutoHideTab* tabAt(int index) const; /* * Gets the count of the tab widgets @@ -124,7 +124,7 @@ class ADS_EXPORT CSideTabBar : public QFrame /** * Getter for side tab bar area property */ - SideBarLocation sideTabBarArea() const; + SideBarLocation sideBarArea() const; Q_SIGNALS: void sideTabAutoHideToggleRequested(); diff --git a/src/DockWidgetSideTab.cpp b/src/AutoHideTab.cpp similarity index 78% rename from src/DockWidgetSideTab.cpp rename to src/AutoHideTab.cpp index c7c1b1a35..86676573f 100644 --- a/src/DockWidgetSideTab.cpp +++ b/src/AutoHideTab.cpp @@ -28,9 +28,8 @@ // INCLUDES //============================================================================ #include -#include "DockWidgetSideTab.h" -#include "SideTabBar.h" - +#include +#include #include #include "DockAreaWidget.h" @@ -43,22 +42,22 @@ namespace ads /** * Private data class of CDockWidgetTab class (pimpl) */ -struct DockWidgetSideTabPrivate +struct AutoHideTabPrivate { - CDockWidgetSideTab* _this; + CAutoHideTab* _this; CDockWidget* DockWidget = nullptr; - CSideTabBar* SideTabBar = nullptr; + CAutoHideSideBar* SideBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; /** * Private data constructor */ - DockWidgetSideTabPrivate(CDockWidgetSideTab* _public); + AutoHideTabPrivate(CAutoHideTab* _public); }; // struct DockWidgetTabPrivate //============================================================================ -DockWidgetSideTabPrivate::DockWidgetSideTabPrivate(CDockWidgetSideTab* _public) : +AutoHideTabPrivate::AutoHideTabPrivate(CAutoHideTab* _public) : _this(_public) { @@ -66,27 +65,27 @@ DockWidgetSideTabPrivate::DockWidgetSideTabPrivate(CDockWidgetSideTab* _public) //============================================================================ -void CDockWidgetSideTab::setSideTabBar(CSideTabBar* SideTabBar) +void CAutoHideTab::setSideBar(CAutoHideSideBar* SideTabBar) { - d->SideTabBar = SideTabBar; + d->SideBar = SideTabBar; } //============================================================================ -void CDockWidgetSideTab::removeFromSideTabBar() +void CAutoHideTab::removeFromSideBar() { - if (d->SideTabBar == nullptr) + if (d->SideBar == nullptr) { return; } - d->SideTabBar->removeSideTab(this); - setSideTabBar(nullptr); + d->SideBar->removeSideTab(this); + setSideBar(nullptr); } //============================================================================ -CDockWidgetSideTab::CDockWidgetSideTab(QWidget* parent) : +CAutoHideTab::CAutoHideTab(QWidget* parent) : Super(parent), - d(new DockWidgetSideTabPrivate(this)) + d(new AutoHideTabPrivate(this)) { setAttribute(Qt::WA_NoMousePropagation); setFocusPolicy(Qt::NoFocus); @@ -94,7 +93,7 @@ CDockWidgetSideTab::CDockWidgetSideTab(QWidget* parent) : //============================================================================ -CDockWidgetSideTab::~CDockWidgetSideTab() +CAutoHideTab::~CAutoHideTab() { qDebug() << "~CDockWidgetSideTab()"; delete d; @@ -102,7 +101,7 @@ CDockWidgetSideTab::~CDockWidgetSideTab() //============================================================================ -void CDockWidgetSideTab::updateStyle() +void CAutoHideTab::updateStyle() { internal::repolishStyle(this, internal::RepolishDirectChildren); update(); @@ -110,11 +109,11 @@ void CDockWidgetSideTab::updateStyle() //============================================================================ -SideBarLocation CDockWidgetSideTab::sideTabBarArea() const +SideBarLocation CAutoHideTab::sideTabBarArea() const { - if (d->SideTabBar) + if (d->SideBar) { - return d->SideTabBar->sideTabBarArea(); + return d->SideBar->sideBarArea(); } return Left; @@ -122,7 +121,7 @@ SideBarLocation CDockWidgetSideTab::sideTabBarArea() const //============================================================================ -void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) +void CAutoHideTab::setOrientation(Qt::Orientation Orientation) { d->Orientation = Orientation; CPushButton::setButtonOrientation((Qt::Horizontal == Orientation) @@ -132,14 +131,14 @@ void CDockWidgetSideTab::setOrientation(Qt::Orientation Orientation) //============================================================================ -Qt::Orientation CDockWidgetSideTab::orientation() const +Qt::Orientation CAutoHideTab::orientation() const { return d->Orientation; } //============================================================================ -void CDockWidgetSideTab::updateOrientationForArea(SideBarLocation area) +void CAutoHideTab::updateOrientationForArea(SideBarLocation area) { setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); @@ -177,7 +176,7 @@ void CDockWidgetSideTab::updateOrientationForArea(SideBarLocation area) //============================================================================ -bool CDockWidgetSideTab::isActiveTab() const +bool CAutoHideTab::isActiveTab() const { if (d->DockWidget && d->DockWidget->autoHideDockContainer()) { @@ -189,14 +188,14 @@ bool CDockWidgetSideTab::isActiveTab() const //============================================================================ -CDockWidget* CDockWidgetSideTab::dockWidget() const +CDockWidget* CAutoHideTab::dockWidget() const { return d->DockWidget; } //============================================================================ -void CDockWidgetSideTab::setDockWidget(CDockWidget* DockWidget) +void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) { if (!DockWidget) { diff --git a/src/DockWidgetSideTab.h b/src/AutoHideTab.h similarity index 89% rename from src/DockWidgetSideTab.h rename to src/AutoHideTab.h index 04bdacd38..d616415be 100644 --- a/src/DockWidgetSideTab.h +++ b/src/AutoHideTab.h @@ -35,9 +35,9 @@ namespace ads { -struct DockWidgetSideTabPrivate; +struct AutoHideTabPrivate; class CDockWidget; -class CSideTabBar; +class CAutoHideSideBar; class CDockWidgetTab; struct SideTabIconLabelPrivate; @@ -46,7 +46,7 @@ struct SideTabIconLabelPrivate; * The dock widget tab is shown in the side tab bar to switch between * pinned dock widgets */ -class ADS_EXPORT CDockWidgetSideTab : public CPushButton +class ADS_EXPORT CAutoHideTab : public CPushButton { Q_OBJECT @@ -55,18 +55,18 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton Q_PROPERTY(bool activeTab READ isActiveTab) private: - DockWidgetSideTabPrivate* d; ///< private data (pimpl) - friend struct DockWidgetSideTabPrivate; + AutoHideTabPrivate* d; ///< private data (pimpl) + friend struct AutoHideTabPrivate; friend class CDockWidget; friend class CAutoHideDockContainer; protected: - friend class CSideTabBar; + friend class CAutoHideSideBar; friend class CDockAreaWidget; friend class CDockContainerWidget; - void setSideTabBar(CSideTabBar *SideTabBar); - void removeFromSideTabBar(); + void setSideBar(CAutoHideSideBar *SideTabBar); + void removeFromSideBar(); public: using Super = CPushButton; @@ -76,12 +76,12 @@ class ADS_EXPORT CDockWidgetSideTab : public CPushButton * param[in] DockWidget The dock widget this title bar belongs to * param[in] parent The parent widget of this title bar */ - CDockWidgetSideTab(QWidget* parent = nullptr); + CAutoHideTab(QWidget* parent = nullptr); /** * Virtual Destructor */ - virtual ~CDockWidgetSideTab(); + virtual ~CAutoHideTab(); /** * Update stylesheet style if a property changes diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index a48883cee..c6d5523d7 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -29,6 +29,7 @@ // INCLUDES //============================================================================ #include +#include #include "DockAreaWidget.h" #include @@ -52,7 +53,6 @@ #include "DockAreaTitleBar.h" #include "DockComponentsFactory.h" #include "DockWidgetTab.h" -#include "DockWidgetSideTab.h" #include "DockingStateReader.h" diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index edb1b025d..4059a8321 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -33,8 +33,8 @@ #include #include "ads_globals.h" +#include "AutoHideTab.h" #include "DockWidget.h" -#include "DockWidgetSideTab.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) QT_FORWARD_DECLARE_CLASS(QAbstractButton) diff --git a/src/DockComponentsFactory.cpp b/src/DockComponentsFactory.cpp index 3e7ebc1ff..05259d7b4 100644 --- a/src/DockComponentsFactory.cpp +++ b/src/DockComponentsFactory.cpp @@ -8,6 +8,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockComponentsFactory.h" #include @@ -17,7 +18,6 @@ #include "DockAreaTitleBar.h" #include "DockWidget.h" #include "DockAreaWidget.h" -#include "DockWidgetSideTab.h" namespace ads { @@ -31,9 +31,9 @@ CDockWidgetTab* CDockComponentsFactory::createDockWidgetTab(CDockWidget* DockWid } //============================================================================ -CDockWidgetSideTab* CDockComponentsFactory::createDockWidgetSideTab(CDockWidget *DockWidget) const +CAutoHideTab* CDockComponentsFactory::createDockWidgetSideTab(CDockWidget *DockWidget) const { - return new CDockWidgetSideTab(DockWidget); + return new CAutoHideTab(DockWidget); } diff --git a/src/DockComponentsFactory.h b/src/DockComponentsFactory.h index 3e726aef0..0d2b7d4c8 100644 --- a/src/DockComponentsFactory.h +++ b/src/DockComponentsFactory.h @@ -19,7 +19,7 @@ class CDockAreaTitleBar; class CDockAreaTabBar; class CDockAreaWidget; class CDockWidget; -class CDockWidgetSideTab; +class CAutoHideTab; @@ -51,7 +51,7 @@ class ADS_EXPORT CDockComponentsFactory * This default implementation just creates a dock widget side tab with * new CDockWidgetTab(DockWidget). */ - virtual CDockWidgetSideTab* createDockWidgetSideTab(CDockWidget* DockWidget) const; + virtual CAutoHideTab* createDockWidgetSideTab(CDockWidget* DockWidget) const; /** * This default implementation just creates a dock area tab bar with diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 9727062f6..4a6ef86cb 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -29,6 +29,8 @@ // INCLUDES //============================================================================ #include +#include +#include #include "DockContainerWidget.h" #include @@ -49,9 +51,7 @@ #include "DockOverlay.h" #include "ads_globals.h" #include "DockSplitter.h" -#include "SideTabBar.h" #include "DockWidgetTab.h" -#include "DockWidgetSideTab.h" #include "DockAreaTitleBar.h" #include "DockFocusController.h" @@ -139,7 +139,7 @@ class DockContainerWidgetPrivate unsigned int zOrderIndex = 0; QList DockAreas; QList AutoHideWidgets; - QMap SideTabBarWidgets; + QMap SideTabBarWidgets; QGridLayout* Layout = nullptr; QSplitter* RootSplitter = nullptr; bool isFloating = false; @@ -1958,25 +1958,25 @@ void CDockContainerWidget::createSideTabBarWidgets() { auto Area = SideBarLocation::Left; - d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 0); } { auto Area = SideBarLocation::Right; - d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 2); } { auto Area = SideBarLocation::Bottom; - d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 2, 1); } { auto Area = SideBarLocation::Top; - d->SideTabBarWidgets[Area] = new CSideTabBar(this, Area); + d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 0, 1); } } @@ -2126,7 +2126,7 @@ void CDockContainerWidget::closeOtherAreas(CDockAreaWidget* KeepOpenArea) } //============================================================================ -CSideTabBar* CDockContainerWidget::sideTabBar(SideBarLocation area) const +CAutoHideSideBar* CDockContainerWidget::sideTabBar(SideBarLocation area) const { return d->SideTabBarWidgets[area]; } diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index b97783a24..e8737e823 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -33,8 +33,8 @@ #include #include "ads_globals.h" +#include "AutoHideTab.h" #include "DockWidget.h" -#include "DockWidgetSideTab.h" QT_FORWARD_DECLARE_CLASS(QXmlStreamWriter) @@ -51,7 +51,7 @@ struct FloatingDockContainerPrivate; class CFloatingDragPreview; struct FloatingDragPreviewPrivate; class CDockingStateReader; -class CSideTabBar; +class CAutoHideSideBar; /** @@ -321,7 +321,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Returns the side tab widget for the given area */ - CSideTabBar* sideTabBar(SideBarLocation area) const; + CAutoHideSideBar* sideTabBar(SideBarLocation area) const; /** diff --git a/src/DockFocusController.cpp b/src/DockFocusController.cpp index 3056c077c..322ff29a8 100644 --- a/src/DockFocusController.cpp +++ b/src/DockFocusController.cpp @@ -8,6 +8,7 @@ //============================================================================ // INCLUDES //============================================================================ +#include #include "DockFocusController.h" #include @@ -25,7 +26,6 @@ #include "FloatingDockContainer.h" #include "DockManager.h" #include "DockAreaTitleBar.h" -#include "DockWidgetSideTab.h" #ifdef Q_OS_LINUX #include "linux/FloatingWidgetTitleBar.h" diff --git a/src/DockManager.h b/src/DockManager.h index 9591945a6..810ebbfba 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -54,7 +54,7 @@ struct DockAreaWidgetPrivate; class CIconProvider; class CDockComponentsFactory; class CDockFocusController; -class CSideTabBar; +class CAutoHideSideBar; /** * The central dock manager that maintains the complete docking system. @@ -86,7 +86,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget friend struct FloatingDragPreviewPrivate; friend class CDockAreaTitleBar; friend class CAutoHideDockContainer; - friend CSideTabBar; + friend CAutoHideSideBar; protected: diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 529bd1a46..be44c37db 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -29,6 +29,8 @@ // INCLUDES //============================================================================ #include +#include +#include #include "DockWidgetTab.h" #include "DockWidget.h" @@ -51,8 +53,6 @@ #include #include -#include "SideTabBar.h" -#include "DockWidgetSideTab.h" #include "DockContainerWidget.h" #include "DockAreaWidget.h" #include "DockManager.h" @@ -95,7 +95,7 @@ struct DockWidgetPrivate CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; CDockWidget::eAutoHideInsertOrder AutoHideInsertOrder = CDockWidget::Last; - QPointer SideTabWidget; + QPointer SideTabWidget; /** * Private data constructor @@ -522,14 +522,14 @@ CDockAreaWidget* CDockWidget::dockAreaWidget() const } //============================================================================ -CDockWidgetSideTab* CDockWidget::sideTabWidget() const +CAutoHideTab* CDockWidget::sideTabWidget() const { return d->SideTabWidget; } //============================================================================ -void CDockWidget::setSideTabWidget(CDockWidgetSideTab* SideTab) const +void CDockWidget::setSideTabWidget(CAutoHideTab* SideTab) const { d->SideTabWidget = SideTab; } diff --git a/src/DockWidget.h b/src/DockWidget.h index d8048a2ce..76f2dce4f 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -46,9 +46,9 @@ class CDockContainerWidget; class CDockAreaWidget; class DockContainerWidgetPrivate; class CFloatingDockContainer; -class CDockWidgetSideTab; +class CAutoHideTab; class CAutoHideDockContainer; -class CSideTabBar; +class CAutoHideSideBar; /** * The QDockWidget class provides a widget that can be docked inside a @@ -79,7 +79,7 @@ private Q_SLOTS: friend struct DockWidgetTabPrivate; friend struct DockAreaTitleBarPrivate; friend class CAutoHideDockContainer; - friend CSideTabBar; + friend CAutoHideSideBar; /** * Assigns the dock manager that manages this dock widget @@ -365,12 +365,12 @@ private Q_SLOTS: * a auto hide container. If it is not in a auto hide container, then this * function returns a nullptr, */ - CDockWidgetSideTab* sideTabWidget() const; + CAutoHideTab* sideTabWidget() const; /** * Assign a side tab widget if this dock widget is an auto hide container */ - void setSideTabWidget(CDockWidgetSideTab* SideTab) const; + void setSideTabWidget(CAutoHideTab* SideTab) const; /** * Returns true, if this dock widget is in an auto hide container diff --git a/src/src.pro b/src/src.pro index 101f7a30e..79344b124 100644 --- a/src/src.pro +++ b/src/src.pro @@ -49,8 +49,8 @@ HEADERS += \ DockComponentsFactory.h \ DockFocusController.h \ AutoHideDockContainer.h \ - SideTabBar.h \ - DockWidgetSideTab.h \ + AutoHideSideBar.h \ + AutoHideTab.h \ PushButton.h \ ResizeHandle.h @@ -74,8 +74,8 @@ SOURCES += \ DockComponentsFactory.cpp \ DockFocusController.cpp \ AutoHideDockContainer.cpp \ - SideTabBar.cpp \ - DockWidgetSideTab.cpp \ + AutoHideSideBar.cpp \ + AutoHideTab.cpp \ PushButton.cpp \ ResizeHandle.cpp diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index b72c50b69..c7e067b24 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -128,9 +128,9 @@ QScrollArea#dockWidgetScrollArea { /***************************************************************************** - * CDockWidgetSideTab + * CAutoHideTab *****************************************************************************/ -ads--CDockWidgetSideTab { +ads--CAutoHideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ background: none; border: none; @@ -142,66 +142,66 @@ ads--CDockWidgetSideTab { } -ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideTabBarArea="0"], +ads--CAutoHideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideTabBarArea="1"], +ads--CAutoHideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideTabBarArea="0"], +ads--CAutoHideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideTabBarArea="1"], +ads--CAutoHideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CSideTabBar + * CAutoHideBar *****************************************************************************/ -ads--CSideTabBar{ +ads--CAutoHideBar{ background: palette(window); } -ads--CSideTabBar[sideTabBarArea="0"] { +ads--CAutoHideBar[sideTabBarArea="0"] { border-bottom: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="1"] { +ads--CAutoHideBar[sideTabBarArea="1"] { border-right: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="2"] { +ads--CAutoHideBar[sideTabBarArea="2"] { border-left: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="3"] { +ads--CAutoHideBar[sideTabBarArea="3"] { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index f8dedfe43..0fac1fce5 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -164,9 +164,9 @@ ads--CFloatingWidgetTitleBar { /***************************************************************************** - * CDockWidgetSideTab + * CAutoHideTab *****************************************************************************/ -ads--CDockWidgetSideTab { +ads--CAutoHideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ padding-left: 2px; padding-right: 0px; @@ -176,64 +176,64 @@ ads--CDockWidgetSideTab { border: none; } -ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideTabBarArea="1"], +ads--CAutoHideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideTabBarArea="0"], +ads--CAutoHideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideTabBarArea="0"], +ads--CAutoHideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideTabBarArea="1"], +ads--CAutoHideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CSideTabBar + * CAutoHideBar *****************************************************************************/ -ads--CSideTabBar{ +ads--CAutoHideBar{ background: palette(window); } -ads--CSideTabBar[sideTabBarArea="0"] { +ads--CAutoHideBar[sideTabBarArea="0"] { border-bottom: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="1"] { +ads--CAutoHideBar[sideTabBarArea="1"] { border-right: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="2"] { +ads--CAutoHideBar[sideTabBarArea="2"] { border-left: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="3"] { +ads--CAutoHideBar[sideTabBarArea="3"] { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 34ece1915..a1ebd5ac8 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -165,15 +165,15 @@ QScrollArea#dockWidgetScrollArea { /***************************************************************************** - * CDockWidgetSideTab + * CAutoHideTab *****************************************************************************/ -ads--CDockWidgetSideTab { +ads--CAutoHideTab { /*background: palette(window);*/ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab { +ads--CAutoHideTab { background: none; border: none; padding-left: 2px; @@ -182,16 +182,16 @@ ads--CDockWidgetSideTab { } -ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideTabBarArea="0"], +ads--CAutoHideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; } -ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideTabBarArea="1"], +ads--CAutoHideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; @@ -199,52 +199,52 @@ ads--CDockWidgetSideTab[sideTabBarArea="3"] { -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideTabBarArea="0"], +ads--CAutoHideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideTabBarArea="1"], +ads--CAutoHideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CSideTabBar + * CAutoHideBar *****************************************************************************/ -ads--CSideTabBar{ +ads--CAutoHideBar{ background: palette(window); } -ads--CSideTabBar[sideTabBarArea="0"] { +ads--CAutoHideBar[sideTabBarArea="0"] { border-bottom: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="1"] { +ads--CAutoHideBar[sideTabBarArea="1"] { border-right: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="2"] { +ads--CAutoHideBar[sideTabBarArea="2"] { border-left: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="3"] { +ads--CAutoHideBar[sideTabBarArea="3"] { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index dfa8a10eb..03e88e91b 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -240,9 +240,9 @@ ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton: /***************************************************************************** - * CDockWidgetSideTab + * CAutoHideTab *****************************************************************************/ -ads--CDockWidgetSideTab { +ads--CAutoHideTab { qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ padding-left: 2px; padding-right: 0px; @@ -252,64 +252,64 @@ ads--CDockWidgetSideTab { border: none; } -ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideTabBarArea="1"], +ads--CAutoHideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideTabBarArea="0"], +ads--CAutoHideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideTabBarArea="0"], +ads--CAutoHideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideTabBarArea="1"], +ads--CAutoHideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CSideTabBar + * CAutoHideBar *****************************************************************************/ -ads--CSideTabBar{ +ads--CAutoHideBar{ background: palette(window); } -ads--CSideTabBar[sideTabBarArea="0"] { +ads--CAutoHideBar[sideTabBarArea="0"] { border-bottom: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="1"] { +ads--CAutoHideBar[sideTabBarArea="1"] { border-right: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="2"] { +ads--CAutoHideBar[sideTabBarArea="2"] { border-left: 1px solid palette(dark); } -ads--CSideTabBar[sideTabBarArea="3"] { +ads--CAutoHideBar[sideTabBarArea="3"] { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css index 8e01c52e9..892ab0769 100644 --- a/src/stylesheets/visual_studio_light.css +++ b/src/stylesheets/visual_studio_light.css @@ -149,13 +149,13 @@ ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { * Styling of auto hide functionality *---------------------------------------------------------------------------- */ -ads--CDockWidgetSideTab { +ads--CAutoHideTab { /*background: palette(window);*/ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ } -ads--CDockWidgetSideTab +ads--CAutoHideTab { background: none; border: none; @@ -164,8 +164,8 @@ ads--CDockWidgetSideTab text-align: center; } -ads--CDockWidgetSideTab[sideTabBarArea="0"], -ads--CDockWidgetSideTab[sideTabBarArea="2"] +ads--CAutoHideTab[sideTabBarArea="0"], +ads--CAutoHideTab[sideTabBarArea="2"] { border-top: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; @@ -173,8 +173,8 @@ ads--CDockWidgetSideTab[sideTabBarArea="2"] } -ads--CDockWidgetSideTab[sideTabBarArea="1"], -ads--CDockWidgetSideTab[sideTabBarArea="3"] +ads--CAutoHideTab[sideTabBarArea="1"], +ads--CAutoHideTab[sideTabBarArea="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; @@ -183,30 +183,30 @@ ads--CDockWidgetSideTab[sideTabBarArea="3"] -ads--CDockWidgetSideTab:hover[sideTabBarArea="0"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="2"] +ads--CAutoHideTab:hover[sideTabBarArea="0"], +ads--CAutoHideTab:hover[sideTabBarArea="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab:hover[sideTabBarArea="1"], -ads--CDockWidgetSideTab:hover[sideTabBarArea="3"] +ads--CAutoHideTab:hover[sideTabBarArea="1"], +ads--CAutoHideTab:hover[sideTabBarArea="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="0"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="2"][activeTab="true"] +ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CDockWidgetSideTab[sideTabBarArea="1"][activeTab="true"], -ads--CDockWidgetSideTab[sideTabBarArea="3"][activeTab="true"] +ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], +ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } From 075ef6187f1abaa8b78e074405f182a63cc624ad Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 13:34:08 +0100 Subject: [PATCH 177/236] Refactoring: renamed CDockWidgetSideTab to CAutoHideTab and CSideTabBar top CAutoHideSideBar --- src/AutoHideDockContainer.cpp | 16 ++-- src/AutoHideDockContainer.h | 12 ++- src/AutoHideSideBar.cpp | 34 ++----- src/AutoHideSideBar.h | 27 +++--- src/AutoHideTab.cpp | 93 +++++++++++--------- src/AutoHideTab.h | 12 +-- src/CMakeLists.txt | 8 +- src/DockContainerWidget.cpp | 2 +- src/stylesheets/default.css | 44 ++++----- src/stylesheets/default_linux.css | 44 ++++----- src/stylesheets/focus_highlighting.css | 44 ++++----- src/stylesheets/focus_highlighting_linux.css | 44 ++++----- src/stylesheets/visual_studio_light.css | 26 +++--- 13 files changed, 199 insertions(+), 207 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 14d3c8a16..7cb2ee1f7 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -227,7 +227,7 @@ void CAutoHideDockContainer::updateSize() auto dockContainerParent = parentContainer(); auto rect = dockContainerParent->contentRect(); - switch (sideTabBarArea()) + switch (sideBarLocation()) { case SideBarLocation::Top: resize(rect.width(), qMin(rect.height(), d->Size.height() - ResizeMargin)); @@ -271,18 +271,23 @@ CAutoHideDockContainer::~CAutoHideDockContainer() parentContainer()->removeAutoHideWidget(this); } + if (d->SideTab) + { + delete d->SideTab; + } + delete d; } //============================================================================ -CAutoHideSideBar* CAutoHideDockContainer::sideTabBar() const +CAutoHideSideBar* CAutoHideDockContainer::sideBar() const { return parentContainer()->sideTabBar(d->SideTabBarArea); } //============================================================================ -CAutoHideTab* CAutoHideDockContainer::sideTab() const +CAutoHideTab* CAutoHideDockContainer::autoHideTab() const { return d->SideTab; } @@ -327,7 +332,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) //============================================================================ -SideBarLocation CAutoHideDockContainer::sideTabBarArea() const +SideBarLocation CAutoHideDockContainer::sideBarLocation() const { return d->SideTabBarArea; } @@ -356,9 +361,10 @@ void CAutoHideDockContainer::cleanupAndDelete() const auto dockWidget = d->DockWidget; if (dockWidget) { + auto SideTab = d->SideTab; SideTab->removeFromSideBar(); - SideTab->setParent(dockWidget); + SideTab->setParent(nullptr); SideTab->hide(); } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 4943cd655..9823ac071 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -53,7 +53,7 @@ struct SideTabBarPrivate; class ADS_EXPORT CAutoHideDockContainer : public QFrame { Q_OBJECT - Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideBarLocation READ sideBarLocation) private: AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; @@ -63,6 +63,10 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame protected: bool eventFilter(QObject* watched, QEvent* event) override; void resizeEvent(QResizeEvent* event) override; + + /** + * Updates the size considering the size limits and the resize margins + */ void updateSize(); /* @@ -92,12 +96,12 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Get's the side tab bar */ - CAutoHideSideBar* sideTabBar() const; + CAutoHideSideBar* sideBar() const; /** * Returns the side tab */ - CAutoHideTab* sideTab() const; + CAutoHideTab* autoHideTab() const; /** * Get's the dock widget in this dock container @@ -112,7 +116,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Returns the side tab bar area of this Auto Hide dock container */ - SideBarLocation sideTabBarArea() const; + SideBarLocation sideBarLocation() const; /** * Returns the dock area widget of this Auto Hide dock container diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index 7b0a5c0d4..e384624a0 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -128,11 +128,10 @@ CAutoHideSideBar::~CAutoHideSideBar() //============================================================================ -void CAutoHideSideBar::insertSideTab(int Index, CAutoHideTab* SideTab) +void CAutoHideSideBar::insertTab(int Index, CAutoHideTab* SideTab) { SideTab->installEventFilter(this); SideTab->setSideBar(this); - SideTab->updateOrientationForArea(d->SideTabArea); d->TabsLayout->insertWidget(Index, SideTab); show(); } @@ -143,22 +142,14 @@ CAutoHideDockContainer* CAutoHideSideBar::insertDockWidget(int Index, CDockWidge { auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, d->SideTabArea, d->ContainerWidget); DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); - auto Tab = AutoHideContainer->sideTab(); - insertSideTab(Index, Tab); + auto Tab = AutoHideContainer->autoHideTab(); + insertTab(Index, Tab); return AutoHideContainer; } //============================================================================ -void CAutoHideSideBar::removeDockWidget(CDockWidget* DockWidget) -{ - Q_UNUSED(DockWidget); - // TODO implement -} - - -//============================================================================ -void CAutoHideSideBar::removeSideTab(CAutoHideTab* SideTab) +void CAutoHideSideBar::removeTab(CAutoHideTab* SideTab) { SideTab->removeEventFilter(this); d->TabsLayout->removeWidget(SideTab); @@ -226,19 +217,6 @@ bool CAutoHideSideBar::eventFilter(QObject *watched, QEvent *event) return false; } - -//============================================================================ -void CAutoHideSideBar::paintEvent(QPaintEvent* event) -{ - Q_UNUSED(event) - - QStyleOption option; - option.initFrom(this); - QPainter painter(this); - style()->drawPrimitive(QStyle::PE_Widget, &option, &painter, this); -} - - //============================================================================ Qt::Orientation CAutoHideSideBar::orientation() const { @@ -261,7 +239,7 @@ int CAutoHideSideBar::tabCount() const //============================================================================ -SideBarLocation CAutoHideSideBar::sideBarArea() const +SideBarLocation CAutoHideSideBar::sideBarLocation() const { return d->SideTabArea; } @@ -276,7 +254,7 @@ void CAutoHideSideBar::saveState(QXmlStreamWriter& s) const } s.writeStartElement("SideBar"); - s.writeAttribute("Area", QString::number(sideBarArea())); + s.writeAttribute("Area", QString::number(sideBarLocation())); s.writeAttribute("Tabs", QString::number(tabCount())); for (auto i = 0; i < tabCount(); ++i) diff --git a/src/AutoHideSideBar.h b/src/AutoHideSideBar.h index c27820ce3..385bd38e1 100644 --- a/src/AutoHideSideBar.h +++ b/src/AutoHideSideBar.h @@ -54,7 +54,7 @@ class CDockingStateReader; class ADS_EXPORT CAutoHideSideBar : public QFrame { Q_OBJECT - Q_PROPERTY(int sideBarArea READ sideBarArea) + Q_PROPERTY(int sideBarLocation READ sideBarLocation) Q_PROPERTY(Qt::Orientation orientation READ orientation) private: @@ -64,7 +64,6 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame friend DockContainerWidgetPrivate; protected: - virtual void paintEvent(QPaintEvent* event) override; virtual bool event(QEvent* e) override; virtual bool eventFilter(QObject *watched, QEvent *event) override; @@ -73,6 +72,12 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame */ void saveState(QXmlStreamWriter& Stream) const; + /** + * Inserts the given dock widget tab at the given position. + * An Index value of -1 appends the side tab at the end. + */ + void insertTab(int Index, CAutoHideTab* SideTab); + public: using Super = QFrame; @@ -86,26 +91,18 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame */ virtual ~CAutoHideSideBar(); - /** - * Inserts the given dock widget tab at the given position. - */ - void insertSideTab(int Index, CAutoHideTab* SideTab); - /** * Removes the given DockWidgetSideTab from the tabbar */ - void removeSideTab(CAutoHideTab* SideTab); + void removeTab(CAutoHideTab* SideTab); /** - * Insert dock widget + * Insert dock widget into the side bar. + * The function creates the auto hide dock container, inserts the + * auto hide tab */ CAutoHideDockContainer* insertDockWidget(int Index, CDockWidget* DockWidget); - /** - * Remove dock widget from sidebar - */ - void removeDockWidget(CDockWidget* DockWidget); - /** * Returns orientation of side tab. */ @@ -124,7 +121,7 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame /** * Getter for side tab bar area property */ - SideBarLocation sideBarArea() const; + SideBarLocation sideBarLocation() const; Q_SIGNALS: void sideTabAutoHideToggleRequested(); diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 86676573f..4b901efc1 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -53,6 +53,12 @@ struct AutoHideTabPrivate * Private data constructor */ AutoHideTabPrivate(CAutoHideTab* _public); + + /** + * Update the orientation, visibility and spacing based on the area of + * the side bar + */ + void updateOrientation(); }; // struct DockWidgetTabPrivate @@ -64,10 +70,53 @@ AutoHideTabPrivate::AutoHideTabPrivate(CAutoHideTab* _public) : } +//============================================================================ +void AutoHideTabPrivate::updateOrientation() +{ + auto area = SideBar->sideBarLocation(); + _this->setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); + + if (_this->icon().isNull()) + { + return; + } + + bool IconOnly = false; + switch (area) + { + case SideBarLocation::Left: + IconOnly = CDockManager::testConfigFlag(CDockManager::LeftSideBarIconOnly); + break; + + case SideBarLocation::Right: + IconOnly = CDockManager::testConfigFlag(CDockManager::RightSideBarIconOnly); + break; + + case SideBarLocation::Top: + IconOnly = CDockManager::testConfigFlag(CDockManager::BottomSideBarIconOnly); + break; + + case SideBarLocation::Bottom: + IconOnly = CDockManager::testConfigFlag(CDockManager::TopSideBarIconOnly); + break; + } + + if (IconOnly) + { + _this->setText(""); + _this->setOrientation(Qt::Horizontal); + } +} + + //============================================================================ void CAutoHideTab::setSideBar(CAutoHideSideBar* SideTabBar) { d->SideBar = SideTabBar; + if (d->SideBar) + { + d->updateOrientation(); + } } @@ -78,7 +127,7 @@ void CAutoHideTab::removeFromSideBar() { return; } - d->SideBar->removeSideTab(this); + d->SideBar->removeTab(this); setSideBar(nullptr); } @@ -109,11 +158,11 @@ void CAutoHideTab::updateStyle() //============================================================================ -SideBarLocation CAutoHideTab::sideTabBarArea() const +SideBarLocation CAutoHideTab::sideBarLocation() const { if (d->SideBar) { - return d->SideBar->sideBarArea(); + return d->SideBar->sideBarLocation(); } return Left; @@ -137,44 +186,6 @@ Qt::Orientation CAutoHideTab::orientation() const } -//============================================================================ -void CAutoHideTab::updateOrientationForArea(SideBarLocation area) -{ - setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); - - if (icon().isNull()) - { - return; - } - - bool IconOnly = false; - switch (area) - { - case SideBarLocation::Left: - IconOnly = CDockManager::testConfigFlag(CDockManager::LeftSideBarIconOnly); - break; - - case SideBarLocation::Right: - IconOnly = CDockManager::testConfigFlag(CDockManager::RightSideBarIconOnly); - break; - - case SideBarLocation::Top: - IconOnly = CDockManager::testConfigFlag(CDockManager::BottomSideBarIconOnly); - break; - - case SideBarLocation::Bottom: - IconOnly = CDockManager::testConfigFlag(CDockManager::TopSideBarIconOnly); - break; - } - - if (IconOnly) - { - setText(""); - setOrientation(Qt::Horizontal); - } -} - - //============================================================================ bool CAutoHideTab::isActiveTab() const { diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index d616415be..ba20badc7 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -50,7 +50,7 @@ class ADS_EXPORT CAutoHideTab : public CPushButton { Q_OBJECT - Q_PROPERTY(int sideTabBarArea READ sideTabBarArea) + Q_PROPERTY(int sideBarLocation READ sideBarLocation) Q_PROPERTY(Qt::Orientation orientation READ orientation) Q_PROPERTY(bool activeTab READ isActiveTab) @@ -91,7 +91,7 @@ class ADS_EXPORT CAutoHideTab : public CPushButton /** * Getter for side tab bar area property */ - SideBarLocation sideTabBarArea() const; + SideBarLocation sideBarLocation() const; /** * Set orientation vertical or horizontal @@ -104,12 +104,8 @@ class ADS_EXPORT CAutoHideTab : public CPushButton Qt::Orientation orientation() const; /** - * Update the orientation, visibility and spacing based on the area and the config - */ - void updateOrientationForArea(SideBarLocation area); - - /** - * Returns true, if this is the active tab. The tab is active if the auto hide widget is visible + * Returns true, if this is the active tab. The tab is active if the auto + * hide widget is visible */ bool isActiveTab() const; diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 70c0276a4..ba62e48e3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -27,8 +27,8 @@ set(ads_SRCS FloatingDragPreview.cpp IconProvider.cpp DockComponentsFactory.cpp - SideTabBar.cpp - DockWidgetSideTab.cpp + AutoHideSideBar.cpp + AutoHideTab.cpp AutoHideDockContainer.cpp PushButton.cpp ResizeHandle.cpp @@ -53,8 +53,8 @@ set(ads_HEADERS FloatingDragPreview.h IconProvider.h DockComponentsFactory.h - SideTabBar.h - DockWidgetSideTab.h + AutoHideSideBar.h + AutoHideTab.h AutoHideDockContainer.h PushButton.h ResizeHandle.h diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 4a6ef86cb..459b166d7 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1714,7 +1714,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto autoHideWidgets = FloatingWidget->dockContainer()->autoHideWidgets(); for (const auto autohideWidget : autoHideWidgets) { - createAndSetupAutoHideContainer(autohideWidget->sideTabBarArea(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); + createAndSetupAutoHideContainer(autohideWidget->sideBarLocation(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); } if (DockArea) diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index c7e067b24..155de9ea0 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -142,66 +142,66 @@ ads--CAutoHideTab { } -ads--CAutoHideTab[sideTabBarArea="0"], -ads--CAutoHideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideBarLocation="0"], +ads--CAutoHideTab[sideBarLocation="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideTabBarArea="1"], -ads--CAutoHideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideTabBarArea="0"], -ads--CAutoHideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideBarLocation="0"], +ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab:hover[sideTabBarArea="1"], -ads--CAutoHideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideBarLocation="1"], +ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CAutoHideBar + * CAutoHideSideBar *****************************************************************************/ -ads--CAutoHideBar{ +ads--CAutoHideSideBar{ background: palette(window); } -ads--CAutoHideBar[sideTabBarArea="0"] { +ads--CAutoHideSideBar[sideBarLocation="0"] { border-bottom: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="1"] { +ads--CAutoHideSideBar[sideBarLocation="1"] { border-right: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="2"] { +ads--CAutoHideSideBar[sideBarLocation="2"] { border-left: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="3"] { +ads--CAutoHideSideBar[sideBarLocation="3"] { border-top: 1px solid palette(dark); } @@ -278,19 +278,19 @@ ads--CResizeHandle { } -ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle { border-top: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle { border-left: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { border-right: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index 0fac1fce5..28d2b5a24 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -176,64 +176,64 @@ ads--CAutoHideTab { border: none; } -ads--CAutoHideTab[sideTabBarArea="1"], -ads--CAutoHideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideTabBarArea="0"], -ads--CAutoHideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideBarLocation="0"], +ads--CAutoHideTab[sideBarLocation="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideTabBarArea="0"], -ads--CAutoHideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideBarLocation="0"], +ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab:hover[sideTabBarArea="1"], -ads--CAutoHideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideBarLocation="1"], +ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CAutoHideBar + * CAutoHideSideBar *****************************************************************************/ -ads--CAutoHideBar{ +ads--CAutoHideSideBar{ background: palette(window); } -ads--CAutoHideBar[sideTabBarArea="0"] { +ads--CAutoHideSideBar[sideBarLocation="0"] { border-bottom: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="1"] { +ads--CAutoHideSideBar[sideBarLocation="1"] { border-right: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="2"] { +ads--CAutoHideSideBar[sideBarLocation="2"] { border-left: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="3"] { +ads--CAutoHideSideBar[sideBarLocation="3"] { border-top: 1px solid palette(dark); } @@ -310,19 +310,19 @@ ads--CResizeHandle { } -ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle { border-top: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle { border-left: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { border-right: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index a1ebd5ac8..1e09c4308 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -182,16 +182,16 @@ ads--CAutoHideTab { } -ads--CAutoHideTab[sideTabBarArea="0"], -ads--CAutoHideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideBarLocation="0"], +ads--CAutoHideTab[sideBarLocation="2"] { border-top: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; } -ads--CAutoHideTab[sideTabBarArea="1"], -ads--CAutoHideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; min-height: 20; @@ -199,52 +199,52 @@ ads--CAutoHideTab[sideTabBarArea="3"] { -ads--CAutoHideTab:hover[sideTabBarArea="0"], -ads--CAutoHideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideBarLocation="0"], +ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab:hover[sideTabBarArea="1"], -ads--CAutoHideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideBarLocation="1"], +ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CAutoHideBar + * CAutoHideSideBar *****************************************************************************/ -ads--CAutoHideBar{ +ads--CAutoHideSideBar{ background: palette(window); } -ads--CAutoHideBar[sideTabBarArea="0"] { +ads--CAutoHideSideBar[sideBarLocation="0"] { border-bottom: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="1"] { +ads--CAutoHideSideBar[sideBarLocation="1"] { border-right: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="2"] { +ads--CAutoHideSideBar[sideBarLocation="2"] { border-left: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="3"] { +ads--CAutoHideSideBar[sideBarLocation="3"] { border-top: 1px solid palette(dark); } @@ -321,19 +321,19 @@ ads--CResizeHandle { } -ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle { border-top: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle { border-left: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { border-right: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 03e88e91b..3a78cef14 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -252,64 +252,64 @@ ads--CAutoHideTab { border: none; } -ads--CAutoHideTab[sideTabBarArea="1"], -ads--CAutoHideTab[sideTabBarArea="3"] { +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideTabBarArea="0"], -ads--CAutoHideTab[sideTabBarArea="2"] { +ads--CAutoHideTab[sideBarLocation="0"], +ads--CAutoHideTab[sideBarLocation="2"] { border-top: 5px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideTabBarArea="0"], -ads--CAutoHideTab:hover[sideTabBarArea="2"] { +ads--CAutoHideTab:hover[sideBarLocation="0"], +ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab:hover[sideTabBarArea="1"], -ads--CAutoHideTab:hover[sideTabBarArea="3"] { +ads--CAutoHideTab:hover[sideBarLocation="1"], +ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] { +ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } /***************************************************************************** - * CAutoHideBar + * CAutoHideSideBar *****************************************************************************/ -ads--CAutoHideBar{ +ads--CAutoHideSideBar{ background: palette(window); } -ads--CAutoHideBar[sideTabBarArea="0"] { +ads--CAutoHideSideBar[sideBarLocation="0"] { border-bottom: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="1"] { +ads--CAutoHideSideBar[sideBarLocation="1"] { border-right: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="2"] { +ads--CAutoHideSideBar[sideBarLocation="2"] { border-left: 1px solid palette(dark); } -ads--CAutoHideBar[sideTabBarArea="3"] { +ads--CAutoHideSideBar[sideBarLocation="3"] { border-top: 1px solid palette(dark); } @@ -386,19 +386,19 @@ ads--CResizeHandle { } -ads--CAutoHideDockContainer[sideTabBarArea="0"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle { border-top: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="1"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle { border-left: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="2"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { border-right: 1px solid palette(dark); } -ads--CAutoHideDockContainer[sideTabBarArea="3"] ads--CResizeHandle { +ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { border-top: 1px solid palette(dark); } diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css index 892ab0769..845c3d674 100644 --- a/src/stylesheets/visual_studio_light.css +++ b/src/stylesheets/visual_studio_light.css @@ -164,8 +164,8 @@ ads--CAutoHideTab text-align: center; } -ads--CAutoHideTab[sideTabBarArea="0"], -ads--CAutoHideTab[sideTabBarArea="2"] +ads--CAutoHideTab[sideBarLocation="0"], +ads--CAutoHideTab[sideBarLocation="2"] { border-top: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; @@ -173,8 +173,8 @@ ads--CAutoHideTab[sideTabBarArea="2"] } -ads--CAutoHideTab[sideTabBarArea="1"], -ads--CAutoHideTab[sideTabBarArea="3"] +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { border-bottom: 5px solid rgba(0, 0, 0, 48); margin-right: 6px; @@ -183,30 +183,30 @@ ads--CAutoHideTab[sideTabBarArea="3"] -ads--CAutoHideTab:hover[sideTabBarArea="0"], -ads--CAutoHideTab:hover[sideTabBarArea="2"] +ads--CAutoHideTab:hover[sideBarLocation="0"], +ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab:hover[sideTabBarArea="1"], -ads--CAutoHideTab:hover[sideTabBarArea="3"] +ads--CAutoHideTab:hover[sideBarLocation="1"], +ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 5px solid palette(highlight); color: palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="0"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="2"][activeTab="true"] +ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { border-top: 5px solid palette(highlight); } -ads--CAutoHideTab[sideTabBarArea="1"][activeTab="true"], -ads--CAutoHideTab[sideTabBarArea="3"][activeTab="true"] +ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { border-bottom: 5px solid palette(highlight); } @@ -227,7 +227,7 @@ ads--CAutoHideDockContainer::handle:horizontal { } */ -/*ads--CAutoHideDockContainer[sideTabBarArea="0"]:handle { +/*ads--CAutoHideDockContainer[sideBarLocation="0"]:handle { border: 1px solid palette(dark); background: white; }*/ From da6bf2b9abe50920678c176a33a16a0862317747 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 13:36:32 +0100 Subject: [PATCH 178/236] Fixed typo --- src/ads_globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ads_globals.h b/src/ads_globals.h index 006ccb7b1..3260f87f4 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -132,7 +132,7 @@ enum eBitwiseOperator /** - * Each dock container supports 4 sidbars + * Each dock container supports 4 sidebars */ enum SideBarLocation { From bfad80c54021029e08e9cc1b3c327a025bc9ee41 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 13:41:36 +0100 Subject: [PATCH 179/236] Some code cleanup --- src/AutoHideDockContainer.cpp | 6 +++--- src/AutoHideSideBar.cpp | 10 +++++----- src/AutoHideSideBar.h | 2 +- src/AutoHideTab.cpp | 12 ++++++------ src/AutoHideTab.h | 10 +++++----- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7cb2ee1f7..6256b78e8 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -18,7 +18,7 @@ //============================================================================ -/// \file AutoHideDockContainer.h +/// \file AutoHideDockContainer.cpp /// \author Syarif Fakhri /// \date 05.09.2022 /// \brief Implementation of CAutoHideDockContainer class @@ -27,8 +27,6 @@ //============================================================================ // INCLUDES //============================================================================ -#include -#include #include "AutoHideDockContainer.h" #include @@ -44,6 +42,8 @@ #include "DockingStateReader.h" #include "ResizeHandle.h" #include "DockComponentsFactory.h" +#include "AutoHideSideBar.h" +#include "AutoHideTab.h" #include diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index e384624a0..9fd7709f7 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -18,19 +18,18 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideSideBar.cpp /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Implementation of CSideTabBar class +/// \brief Implementation of CAutoHideSideBar class //============================================================================ - //============================================================================ // INCLUDES //============================================================================ -#include -#include +#include "AutoHideSideBar.h" + #include #include #include @@ -42,6 +41,7 @@ #include "AutoHideDockContainer.h" #include "DockAreaWidget.h" #include "DockingStateReader.h" +#include "AutoHideTab.h" namespace ads { diff --git a/src/AutoHideSideBar.h b/src/AutoHideSideBar.h index 385bd38e1..11f734586 100644 --- a/src/AutoHideSideBar.h +++ b/src/AutoHideSideBar.h @@ -20,7 +20,7 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideSideBar.h /// \author Syarif Fakhri /// \date 05.09.2022 /// \brief Declaration of CAutoHideSideBar class diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 4b901efc1..b0b447105 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -18,23 +18,23 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideTab.cpp /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Implementation of CDockWidgetSideTab class +/// \brief Implementation of CAutoHideTab class //============================================================================ //============================================================================ // INCLUDES //============================================================================ -#include -#include -#include +#include "AutoHideTab.h" + #include +#include "AutoHideDockContainer.h" +#include "AutoHideSideBar.h" #include "DockAreaWidget.h" #include "DockManager.h" - #include "DockWidget.h" namespace ads diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index ba20badc7..d3783b9fc 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -1,5 +1,5 @@ -#ifndef DockWidgetSideTabH -#define DockWidgetSideTabH +#ifndef AutoHideTabH +#define AutoHideTabH /******************************************************************************* ** Qt Advanced Docking System ** Copyright (C) 2017 Uwe Kindler @@ -20,10 +20,10 @@ //============================================================================ -/// \file DockWidgetTab.h +/// \file AutoHideTab.h /// \author Syarif Fakhri /// \date 05.09.2022 -/// \brief Declaration of CDockWidgetSideTab class +/// \brief Declaration of CAutoHideTab class //============================================================================ //============================================================================ @@ -118,7 +118,7 @@ class ADS_EXPORT CAutoHideTab : public CPushButton * Sets the dock widget that is controlled by this tab */ void setDockWidget(CDockWidget* DockWidget); -}; // class DockWidgetSideTab +}; // class AutoHideTab } // namespace ads //----------------------------------------------------------------------------- From 94b80423d73a38fa1a7110f0522c05d389919d10 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 14:36:09 +0100 Subject: [PATCH 180/236] Made naming of auto hide config flags explicit --- src/AutoHideTab.cpp | 8 ++++---- src/DockAreaTitleBar.cpp | 10 +++++----- src/DockAreaWidget.cpp | 2 +- src/DockContainerWidget.cpp | 6 +++--- src/DockManager.cpp | 2 +- src/DockManager.h | 2 +- src/DockWidgetTab.cpp | 4 ---- 7 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index b0b447105..461085d9e 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -85,19 +85,19 @@ void AutoHideTabPrivate::updateOrientation() switch (area) { case SideBarLocation::Left: - IconOnly = CDockManager::testConfigFlag(CDockManager::LeftSideBarIconOnly); + IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::LeftSideBarIconOnly); break; case SideBarLocation::Right: - IconOnly = CDockManager::testConfigFlag(CDockManager::RightSideBarIconOnly); + IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::RightSideBarIconOnly); break; case SideBarLocation::Top: - IconOnly = CDockManager::testConfigFlag(CDockManager::BottomSideBarIconOnly); + IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::BottomSideBarIconOnly); break; case SideBarLocation::Bottom: - IconOnly = CDockManager::testConfigFlag(CDockManager::TopSideBarIconOnly); + IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::TopSideBarIconOnly); break; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 95eae211c..1ca898ee3 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -124,9 +124,9 @@ struct DockAreaTitleBarPrivate * Returns true if the given config flag is set * Convenience function to ease config flag testing */ - static bool testConfigFlag(CDockManager::eAutoHideFlag Flag) + static bool testAutoHideConfigFlag(CDockManager::eAutoHideFlag Flag) { - return CDockManager::testConfigFlag(Flag); + return CDockManager::testAutoHideConfigFlag(Flag); } /** @@ -191,14 +191,14 @@ void DockAreaTitleBarPrivate::createButtons() _this->connect(UndockButton, SIGNAL(clicked()), SLOT(onUndockButtonClicked())); // AutoHide Button - const auto autoHideEnabled = testConfigFlag(CDockManager::AutoHideFeatureEnabled); - AutoHideButton = new CTitleBarButton(testConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); + const auto autoHideEnabled = testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled); + AutoHideButton = new CTitleBarButton(testAutoHideConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); - AutoHideButton->setCheckable(testConfigFlag(CDockManager::AutoHideButtonCheckable)); + AutoHideButton->setCheckable(testAutoHideConfigFlag(CDockManager::AutoHideButtonCheckable)); AutoHideButton->setChecked(false); Layout->addWidget(AutoHideButton, 0); _this->connect(AutoHideButton, SIGNAL(clicked()), SLOT(onAutoHideButtonClicked())); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index c6d5523d7..5035237c6 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1176,7 +1176,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) const auto area = dockContainer()->calculateSideTabBarArea(this); - if (dockManager()->testConfigFlag(CDockManager::AutoHideButtonTogglesArea)) + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)) { for (const auto DockWidget : openedDockWidgets()) { diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 459b166d7..c50918f01 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1045,7 +1045,7 @@ bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s, Q_UNUSED(CreatedWidget) // Simply ignore side bar auto hide widgets from saved state if // auto hide support is disabled - if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { return true; } @@ -1374,7 +1374,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) { - if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { Q_ASSERT_X(false, "CDockContainerWidget::createAndInitializeDockWidgetOverlayContainer", "Requested area does not exist in config"); @@ -1951,7 +1951,7 @@ void CDockContainerWidget::createRootSplitter() //============================================================================ void CDockContainerWidget::createSideTabBarWidgets() { - if (!CDockManager::testConfigFlag(CDockManager::AutoHideFeatureEnabled)) + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { return; } diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 5b4aefabe..d07c4ff03 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -1183,7 +1183,7 @@ bool CDockManager::testConfigFlag(eConfigFlag Flag) //=========================================================================== -bool CDockManager::testConfigFlag(eAutoHideFlag Flag) +bool CDockManager::testAutoHideConfigFlag(eAutoHideFlag Flag) { return autoHideConfigFlags().testFlag(Flag); } diff --git a/src/DockManager.h b/src/DockManager.h index 810ebbfba..6af42e5d6 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -307,7 +307,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget /** * Returns true if the given overlay config flag is set */ - static bool testConfigFlag(eAutoHideFlag Flag); + static bool testAutoHideConfigFlag(eAutoHideFlag Flag); /** * Returns the global icon provider. diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index e82ae77a4..30c5135c0 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -343,10 +343,6 @@ CDockWidgetTab::CDockWidgetTab(CDockWidget* DockWidget, QWidget *parent) : d->DockWidget = DockWidget; d->createLayout(); setFocusPolicy(Qt::NoFocus); - /*if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting)) - { - setFocusPolicy(Qt::ClickFocus); - }*/ } //============================================================================ From 08714ddc3f6d3b5a869179866600e3be77fed23c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 16:11:45 +0100 Subject: [PATCH 181/236] Properly evaluate pinnable flag --- src/DockAreaTitleBar.cpp | 5 +---- src/DockAreaWidget.cpp | 3 ++- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 1ca898ee3..f6e79a7bf 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -493,10 +493,7 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - if (d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)) - { - d->DockArea->toggleAutoHideArea(!d->DockArea->isAutoHide()); - } + d->DockArea->toggleAutoHideArea(!d->DockArea->isAutoHide()); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 5035237c6..8b7dc24a4 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1176,7 +1176,8 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) const auto area = dockContainer()->calculateSideTabBarArea(this); - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)) + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea) + && features().testFlag(CDockWidget::DockWidgetPinnable)) { for (const auto DockWidget : openedDockWidgets()) { From 28745fa2f88bd6efbdb147d1ceef54cc96c2ab1a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 17:17:58 +0100 Subject: [PATCH 182/236] Some small improvements and execute auto hide code only if config is enabled --- src/AutoHideDockContainer.cpp | 2 -- src/DockAreaWidget.cpp | 27 +++++++++++++++++++-------- src/DockAreaWidget.h | 20 ++++++++++---------- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6256b78e8..d84d605cc 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -190,8 +190,6 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockManager* DockManager, SideBa d->DockArea = new CDockAreaWidget(DockManager, parent); d->DockArea->setObjectName("autoHideDockArea"); d->DockArea->setAutoHideDockContainer(this); - d->DockArea->updateAutoHideButtonCheckState(); - d->DockArea->updateTitleBarButtonToolTip(); setObjectName("autoHideDockContainer"); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 8b7dc24a4..5f43698b9 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -455,6 +455,8 @@ bool CDockAreaWidget::isAutoHide() const void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer) { d->AutoHideDockContainer = AutoHideDockContainer; + updateAutoHideButtonCheckState(); + updateTitleBarButtonToolTip(); } @@ -812,16 +814,24 @@ void CDockAreaWidget::updateTitleBarVisibility() return; } - if (d->TitleBar) + if (!d->TitleBar) + { + return; + } + + bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() + || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); + Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); + bool IsAutoHide = isAutoHide(); + Hidden &= !IsAutoHide; // Titlebar must always be visible when auto hidden so it can be dragged + d->TitleBar->setVisible(!Hidden); + + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { - 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(isAutoHide()); // Always show when auto hidden, never otherwise - updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); + tabBar->setVisible(!IsAutoHide); // Never show tab bar when auto hidden + d->TitleBar->autoHideTitleLabel()->setVisible(IsAutoHide); // Always show when auto hidden, never otherwise + updateTitleBarButtonVisibility(Container->topLevelDockArea() == this); } } @@ -849,6 +859,7 @@ void CDockAreaWidget::updateAutoHideButtonCheckState() //============================================================================ void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const { + qDebug() << "CDockAreaWidget::updateTitleBarButtonVisibility IsTopLevel " << IsTopLevel; d->updateTitleBarButtonVisibility(IsTopLevel); } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 4059a8321..d177fb875 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -79,6 +79,16 @@ private Q_SLOTS: */ void reorderDockWidget(int fromIndex, int toIndex); + /* + * Update the auto hide button checked state based on if it's contained in an auto hide container or not + */ + void updateAutoHideButtonCheckState(); + + /* + * Update the title bar button tooltips + */ + void updateTitleBarButtonToolTip(); + protected: #ifdef Q_OS_WIN @@ -152,21 +162,11 @@ private Q_SLOTS: */ void markTitleBarMenuOutdated(); - /* - * Update the auto hide button checked state based on if it's contained in an auto hide container or not - */ - void updateAutoHideButtonCheckState(); - /* * Update the title bar button visibility based on if it's top level or not */ void updateTitleBarButtonVisibility(bool IsTopLevel) const; - /* - * Update the title bar button tooltips - */ - void updateTitleBarButtonToolTip(); - protected Q_SLOTS: void toggleView(bool Open); From fbd25a83f1b67499de6d9055219ad77afd522517 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 17:31:47 +0100 Subject: [PATCH 183/236] Improved auto hide config flags --- src/DockManager.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/DockManager.h b/src/DockManager.h index 6af42e5d6..008acebf4 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -236,12 +236,13 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget { AutoHideFeatureEnabled = 0x01, //!< enables / disables auto hide feature DockAreaHasAutoHideButton = 0x02, //!< If the flag is set each dock area has a auto hide menu button - LeftSideBarIconOnly = 0x04, //!< If the flag is set left side bar will show only icon if a the dock widget has an icon assigned - RightSideBarIconOnly = 0x08, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned - BottomSideBarIconOnly = 0x10,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned - TopSideBarIconOnly = 0x20, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned - AutoHideButtonTogglesArea = 0x40, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled - AutoHideButtonCheckable = 0x80, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. + AutoHideButtonTogglesArea = 0x04, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled + AutoHideButtonCheckable = 0x08, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. + LeftSideBarIconOnly = 0x10, //!< If the flag is set left side bar will show only icon if a the dock widget has an icon assigned + RightSideBarIconOnly = 0x20, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned + BottomSideBarIconOnly = 0x40,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned + TopSideBarIconOnly = 0x80, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned + AutoHideSideBarIconOnly = LeftSideBarIconOnly | RightSideBarIconOnly | BottomSideBarIconOnly | TopSideBarIconOnly, DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars From 0d7830371331ca6da6eb74769bcac5f21f6c7fdc Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 17:41:47 +0100 Subject: [PATCH 184/236] Fixed typo --- src/DockManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DockManager.h b/src/DockManager.h index 008acebf4..47262465f 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -242,7 +242,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget RightSideBarIconOnly = 0x20, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned BottomSideBarIconOnly = 0x40,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned TopSideBarIconOnly = 0x80, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned - AutoHideSideBarIconOnly = LeftSideBarIconOnly | RightSideBarIconOnly | BottomSideBarIconOnly | TopSideBarIconOnly, + AutoHideSideBarsIconOnly = LeftSideBarIconOnly | RightSideBarIconOnly | BottomSideBarIconOnly | TopSideBarIconOnly, DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars From fda5887d506752f4cb09c6198142ad93e6d947be Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 20:42:52 +0100 Subject: [PATCH 185/236] Removed AutoHideInsertOrder enum - new side tabs are always appended. --- demo/MainWindow.cpp | 2 +- examples/autohide/mainwindow.cpp | 4 ++-- src/DockAreaTitleBar.cpp | 2 +- src/DockAreaWidget.cpp | 6 +++--- src/DockAreaWidget.h | 2 +- src/DockContainerWidget.cpp | 6 +++--- src/DockContainerWidget.h | 3 +-- src/DockManager.cpp | 9 ++++----- src/DockManager.h | 5 ++--- src/DockWidget.cpp | 13 ------------- src/DockWidget.h | 33 -------------------------------- 11 files changed, 18 insertions(+), 67 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index f0bf1fef5..84ebb8835 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -647,7 +647,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line if you want a central widget in the main dock container (the dock manager) without a titlebar // If you enable this code, you can test it in the demo with the Calendar 0 // dock widget. - // CDockManager::setConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar, true); + //CDockManager::setConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar, true); // uncomment the following line to enable focus highlighting of the dock // widget that has the focus diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 4ae68be55..56b6eaaf4 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,7 +46,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setWidget(table); TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->setMinimumSize(200,150); - const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); + const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget); autoHideContainer->setSize(480); ui->menuView->addAction(TableDockWidget->toggleViewAction()); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget, CDockWidget::Last); + DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index f6e79a7bf..fdaacd32f 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -493,7 +493,7 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - d->DockArea->toggleAutoHideArea(!d->DockArea->isAutoHide()); + d->DockArea->toggleAutoHide(!d->DockArea->isAutoHide()); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 5f43698b9..fc2f70fad 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1177,7 +1177,7 @@ void CDockAreaWidget::closeArea() } //============================================================================ -void CDockAreaWidget::toggleAutoHideArea(bool Enable) +void CDockAreaWidget::toggleAutoHide(bool Enable) { if (!Enable) { @@ -1197,7 +1197,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) continue; } - dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); + dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); } } else @@ -1207,7 +1207,7 @@ void CDockAreaWidget::toggleAutoHideArea(bool Enable) { return; } - dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, DockWidget->autoHideInsertOrder()); + dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); } } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index d177fb875..eb9179ac5 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -387,7 +387,7 @@ public Q_SLOTS: /** * Toggles the Auto hides behaviour of the dock area and all dock widgets in this area */ - void toggleAutoHideArea(bool Enable); + void toggleAutoHide(bool Enable); /** * This function closes all other areas except of this area diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index c50918f01..af31f2f8b 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1372,7 +1372,7 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW //============================================================================ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( - SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder) + SideBarLocation area, CDockWidget* DockWidget) { if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { @@ -1385,7 +1385,7 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( DockWidget->setDockManager(d->DockManager); // Auto hide Dock Container needs a valid dock manager } - return sideTabBar(area)->insertDockWidget(insertOrder == CDockWidget::First ? 0 : -1, DockWidget); + return sideTabBar(area)->insertDockWidget(-1, DockWidget); } @@ -1714,7 +1714,7 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi auto autoHideWidgets = FloatingWidget->dockContainer()->autoHideWidgets(); for (const auto autohideWidget : autoHideWidgets) { - createAndSetupAutoHideContainer(autohideWidget->sideBarLocation(), autohideWidget->dockWidget(), autohideWidget->dockWidget()->autoHideInsertOrder()); + createAndSetupAutoHideContainer(autohideWidget->sideBarLocation(), autohideWidget->dockWidget()); } if (DockArea) diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index e8737e823..0f3d3eaf8 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -100,8 +100,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame * Initializing inserts the tabs into the side tab widget and hides it * Returns nullptr if you try and insert into an area where the configuration is not enabled */ - CAutoHideDockContainer* createAndSetupAutoHideContainer( - SideBarLocation area, CDockWidget* DockWidget, CDockWidget::eAutoHideInsertOrder insertOrder); + CAutoHideDockContainer* createAndSetupAutoHideContainer(SideBarLocation area, CDockWidget* DockWidget); /** * Helper function for creation of the root splitter diff --git a/src/DockManager.cpp b/src/DockManager.cpp index d07c4ff03..268dafcd9 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -867,18 +867,17 @@ CDockAreaWidget* CDockManager::addDockWidgetToContainer(DockWidgetArea area, } //============================================================================ -CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget, - CDockWidget::eAutoHideInsertOrder insertOrder) +CAutoHideDockContainer* CDockManager::addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget) { - return addAutoHideDockWidgetToContainer(area, Dockwidget, this, insertOrder); + return addAutoHideDockWidgetToContainer(area, Dockwidget, this); } //============================================================================ CAutoHideDockContainer* CDockManager::addAutoHideDockWidgetToContainer(SideBarLocation area, CDockWidget* Dockwidget, - CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder insertOrder) + CDockContainerWidget* DockContainerWidget) { d->DockWidgetsMap.insert(Dockwidget->objectName(), Dockwidget); - auto container = DockContainerWidget->createAndSetupAutoHideContainer(area, Dockwidget, insertOrder); + auto container = DockContainerWidget->createAndSetupAutoHideContainer(area, Dockwidget); container->collapseView(true); Q_EMIT dockWidgetAdded(Dockwidget); diff --git a/src/DockManager.h b/src/DockManager.h index 47262465f..ed6d2cf28 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -347,8 +347,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * An overlay widget is used for auto hide functionality * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget, - CDockWidget::eAutoHideInsertOrder insertOrder = CDockWidget::Last); + CAutoHideDockContainer* addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget); /** * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. @@ -356,7 +355,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ CAutoHideDockContainer* addAutoHideDockWidgetToContainer(SideBarLocation area, - CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget, CDockWidget::eAutoHideInsertOrder = CDockWidget::Last); + CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); /** * This function will add the given Dockwidget to the given dock area as diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index be44c37db..ca3f55b44 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -94,7 +94,6 @@ struct DockWidgetPrivate QList TitleBarActions; CDockWidget::eMinimumSizeHintMode MinimumSizeHintMode = CDockWidget::MinimumSizeHintFromDockWidget; WidgetFactory* Factory = nullptr; - CDockWidget::eAutoHideInsertOrder AutoHideInsertOrder = CDockWidget::Last; QPointer SideTabWidget; /** @@ -1139,18 +1138,6 @@ bool CDockWidget::isCurrentTab() const } -//============================================================================ -void CDockWidget::setAutoHideInsertOrder(eAutoHideInsertOrder insertOrder) -{ - d->AutoHideInsertOrder = insertOrder; -} - -CDockWidget::eAutoHideInsertOrder CDockWidget::autoHideInsertOrder() const -{ - return d->AutoHideInsertOrder; -} - - //============================================================================ void CDockWidget::raise() { diff --git a/src/DockWidget.h b/src/DockWidget.h index 76f2dce4f..b0d9f546d 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -231,17 +231,6 @@ private Q_SLOTS: ActionModeShow //!< ActionModeShow }; - /** - * This mode configures the order of pinning and unpinning auto hide widgets - * First will add it to the top of the SideTabBar, while Last will append it to the end - */ - enum eAutoHideInsertOrder - { - First, - Last - }; - - /** * This constructor creates a dock widget with the given title. @@ -537,28 +526,6 @@ private Q_SLOTS: */ bool isCurrentTab() const; - /* - * Set default dock proportion when auto hiding - * see *DefaultAutoHideDockProportion() - */ - void setDefaultAutoHideDockProportion(float Proportion); - - /* - * Set default dock proportion when auto hiding - * 0.25 is a quarter of the size, 0.5 is half the size, 1 is the entire size - */ - float DefaultAutoHideDockProportion() const; - - /* - * Set auto hide insertion mode - */ - void setAutoHideInsertOrder(eAutoHideInsertOrder insertOrder); - - /* - * Get auto hide insertion mode - */ - eAutoHideInsertOrder autoHideInsertOrder() const; - public: // reimplements QFrame ----------------------------------------------- /** * Emits titleChanged signal if title change event occurs From 540961b8dd7f486575bd9946c23b5179b2df7f5d Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 1 Nov 2022 21:31:27 +0100 Subject: [PATCH 186/236] Renamed toggleAutoHide to setAutoHide and added toggleAutoHide function --- src/DockAreaTitleBar.cpp | 2 +- src/DockAreaWidget.cpp | 40 ++++++++++++++++++++++++++++++++++--- src/DockAreaWidget.h | 18 ++++++++++++++--- src/DockContainerWidget.cpp | 2 +- src/DockContainerWidget.h | 2 +- 5 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index fdaacd32f..efa93fddc 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -493,7 +493,7 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - d->DockArea->toggleAutoHide(!d->DockArea->isAutoHide()); + d->DockArea->setAutoHide(!d->DockArea->isAutoHide()); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index fc2f70fad..ae7c159f6 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -61,6 +61,15 @@ namespace ads static const char* const INDEX_PROPERTY = "index"; static const char* const ACTION_PROPERTY = "action"; +/** + * Check, if auto hide is enabled + */ +static bool isAutoHideFeatureEnabled() +{ + return CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled); +} + + /** * Internal dock area layout mimics stack layout but only inserts the current * widget into the internal QLayout object. @@ -826,7 +835,7 @@ void CDockAreaWidget::updateTitleBarVisibility() Hidden &= !IsAutoHide; // Titlebar must always be visible when auto hidden so it can be dragged d->TitleBar->setVisible(!Hidden); - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + if (isAutoHideFeatureEnabled()) { auto tabBar = d->TitleBar->tabBar(); tabBar->setVisible(!IsAutoHide); // Never show tab bar when auto hidden @@ -1176,16 +1185,29 @@ void CDockAreaWidget::closeArea() } } + //============================================================================ -void CDockAreaWidget::toggleAutoHide(bool Enable) +SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const { + return dockContainer()->calculateSideTabBarArea(this); +} + + +//============================================================================ +void CDockAreaWidget::setAutoHide(bool Enable) +{ + if (!isAutoHideFeatureEnabled()) + { + return; + } + if (!Enable) { autoHideDockContainer()->moveContentsToParent(); return; } - const auto area = dockContainer()->calculateSideTabBarArea(this); + const auto area = calculateSideTabBarArea(); if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea) && features().testFlag(CDockWidget::DockWidgetPinnable)) @@ -1212,6 +1234,18 @@ void CDockAreaWidget::toggleAutoHide(bool Enable) } +//============================================================================ +void CDockAreaWidget::toggleAutoHide() +{ + if (!isAutoHideFeatureEnabled()) + { + return; + } + + setAutoHide(!isAutoHide()); +} + + //============================================================================ void CDockAreaWidget::closeOtherAreas() { diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index eb9179ac5..65d73deaf 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -89,6 +89,12 @@ private Q_SLOTS: */ void updateTitleBarButtonToolTip(); + /** + * Calculate the auto hide side bar location depending on the dock area + * widget position in the container + */ + SideBarLocation calculateSideTabBarArea() const; + protected: #ifdef Q_OS_WIN @@ -211,7 +217,7 @@ protected Q_SLOTS: CAutoHideDockContainer* autoHideDockContainer() const; /** - * Returns true if the dock area exists in an auto hide dock container + * Returns true if the dock area is in an auto hide container */ bool isAutoHide() const; @@ -385,9 +391,15 @@ public Q_SLOTS: void closeArea(); /** - * Toggles the Auto hides behaviour of the dock area and all dock widgets in this area + * Sets the dock area into auto hide mode or into normal mode + */ + void setAutoHide(bool Enable); + + /** + * Switches the dock area to auto hide mode or vice versa depending on its + * current state. */ - void toggleAutoHide(bool Enable); + void toggleAutoHide(); /** * This function closes all other areas except of this area diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index af31f2f8b..6bd0df634 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1411,7 +1411,7 @@ enum eBorderLocation //============================================================================ -SideBarLocation CDockContainerWidget::calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget) +SideBarLocation CDockContainerWidget::calculateSideTabBarArea(const CDockAreaWidget* DockAreaWidget) const { auto ContentRect = this->contentRect(); diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 0f3d3eaf8..b37494bf9 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -220,7 +220,7 @@ class ADS_EXPORT CDockContainerWidget : public QFrame /** * Get's the auto hide dock side tab bar area based on the dock area widget position */ - SideBarLocation calculateSideTabBarArea(CDockAreaWidget* DockAreaWidget); + SideBarLocation calculateSideTabBarArea(const CDockAreaWidget* DockAreaWidget) const; /** * Removes dockwidget From 07355fa5b290723300d7f6cd351fc8867ec613c9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 2 Nov 2022 12:40:45 +0800 Subject: [PATCH 187/236] change fix for crash on currentIndex invalid --- src/AutoHideDockContainer.cpp | 3 ++- src/DockContainerWidget.cpp | 5 ----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6256b78e8..4f91149f0 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -311,7 +311,8 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; d->SideTab->setDockWidget(DockWidget); CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); - if (OldDockArea) + // Don't remove dock widgets while restoring state, the current index pointer may be invalid + if (!DockWidget->dockManager()->isRestoringState() && OldDockArea) { OldDockArea->removeDockWidget(DockWidget); } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index ee71d2194..459b166d7 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1089,11 +1089,6 @@ bool DockContainerWidgetPrivate::restoreSideBar(CDockingStateReader& s, { continue; } - const auto oldDockArea = DockWidget->dockAreaWidget(); - if (oldDockArea) - { - oldDockArea->removeDockWidget(DockWidget); - } auto SideBar = _this->sideTabBar(Area); auto AutoHideContainer = SideBar->insertDockWidget(-1, DockWidget); From ea499c7deac6af5d6659640029b3f86345f0d0ad Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 2 Nov 2022 14:10:41 +0800 Subject: [PATCH 188/236] setSideTabWidget on dockwidget --- src/AutoHideTab.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index b0b447105..afe41cf61 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -215,6 +215,7 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; setText(DockWidget->windowTitle()); setIcon(d->DockWidget->icon()); + DockWidget->setSideTabWidget(this); } } From 1f6938219adbe97c8ee3897489f3abb43a626a8e Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Wed, 2 Nov 2022 14:10:55 +0800 Subject: [PATCH 189/236] small cleanup --- src/AutoHideDockContainer.h | 2 -- src/DockManager.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 9823ac071..c00f114a3 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -45,7 +45,6 @@ class CDockContainerWidget; class CAutoHideSideBar; class CDockAreaWidget; class CDockingStateReader; -struct SideTabBarPrivate; /** * Auto hide container for hosting an auto hide dock widget @@ -58,7 +57,6 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame AutoHideDockContainerPrivate* d; ///< private data (pimpl) friend struct AutoHideDockContainerPrivate; friend CAutoHideSideBar; - friend SideTabBarPrivate; protected: bool eventFilter(QObject* watched, QEvent* event) override; diff --git a/src/DockManager.h b/src/DockManager.h index 810ebbfba..d9912be03 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -244,7 +244,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget AutoHideButtonCheckable = 0x80, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. DefaultAutoHideConfig = AutoHideFeatureEnabled - | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars + | DockAreaHasAutoHideButton ///< the default configuration for the auto hide feature }; Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) From 983afc4d1e9e337fa45edbdaabd77bbd738ab374 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 07:29:45 +0100 Subject: [PATCH 190/236] Fixed wrong size calculation in CAutoHideDockContainer updateSize() function --- src/AutoHideDockContainer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index d84d605cc..52e9f09d3 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -228,7 +228,7 @@ void CAutoHideDockContainer::updateSize() switch (sideBarLocation()) { case SideBarLocation::Top: - resize(rect.width(), qMin(rect.height(), d->Size.height() - ResizeMargin)); + resize(rect.width(), qMin(rect.height() - ResizeMargin, d->Size.height())); move(rect.topLeft()); break; @@ -248,7 +248,7 @@ void CAutoHideDockContainer::updateSize() case SideBarLocation::Bottom: { - resize(rect.width(), qMin(rect.height(), d->Size.height() - ResizeMargin)); + resize(rect.width(), qMin(rect.height() - ResizeMargin, d->Size.height())); QPoint p = rect.bottomLeft(); p.ry() -= (height() - 1); move(p); From 7d79ea27706471701301757ac2a8bd147f4ad6b2 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 07:46:02 +0100 Subject: [PATCH 191/236] Fixed crash by access to invalid dock parent container in CAutoHideDockContainer::updateSize() function --- src/AutoHideDockContainer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 52e9f09d3..11242628e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -223,6 +223,11 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarL void CAutoHideDockContainer::updateSize() { auto dockContainerParent = parentContainer(); + if (!dockContainerParent) + { + return; + } + auto rect = dockContainerParent->contentRect(); switch (sideBarLocation()) From 9f153af5bbf86e5c7ba0e4c54927eff1170753a4 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 08:08:44 +0100 Subject: [PATCH 192/236] Changed MainWindow to enable ActiveX only for non opaque configuration and if AutoHide is disabled --- demo/MainWindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 84ebb8835..71bd13de1 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -495,7 +495,10 @@ void MainWindowPrivate::createContent() #ifdef Q_OS_WIN #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) - if (!ads::CDockManager::testConfigFlag(ads::CDockManager::OpaqueUndocking)) + // ActiveX widget only works without OpaqueUndocking and without + // auto hide feature + if (!ads::CDockManager::testConfigFlag(ads::CDockManager::OpaqueUndocking) + && !ads::CDockManager::testAutoHideConfigFlag(ads::CDockManager::AutoHideFeatureEnabled)) { DockManager->addDockWidget(ads::CenterDockWidgetArea, createActiveXWidget(), RighDockArea); } From 7c1d04f7be90df1d5dcc36cdcb978c488afe9dd6 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 08:16:56 +0100 Subject: [PATCH 193/236] Move calculateSideTabBarArea() function from DockContainerWidget into DockAreaWidget because it is only required there and it depends on dock area position --- src/DockAreaWidget.cpp | 101 +++++++++++++++++++++++++++++++++++- src/DockContainerWidget.cpp | 99 ----------------------------------- src/DockContainerWidget.h | 5 -- 3 files changed, 99 insertions(+), 106 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index ae7c159f6..651b674a2 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1186,10 +1186,104 @@ void CDockAreaWidget::closeArea() } +enum eBorderLocation +{ + BorderNone = 0, + BorderLeft = 0x01, + BorderRight = 0x02, + BorderTop = 0x04, + BorderBottom = 0x08, + BorderVertical = BorderLeft | BorderRight, + BorderHorizontal = BorderTop | BorderBottom, + BorderTopLeft = BorderTop | BorderLeft, + BorderTopRight = BorderTop | BorderRight, + BorderBottomLeft = BorderBottom | BorderLeft, + BorderBottomRight = BorderBottom | BorderRight, + BorderVerticalBottom = BorderVertical | BorderBottom, + BorderVerticalTop = BorderVertical | BorderTop, + BorderHorizontalLeft = BorderHorizontal | BorderLeft, + BorderHorizontalRight = BorderHorizontal | BorderRight, + BorderAll = BorderVertical | BorderHorizontal +}; + + //============================================================================ SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const { - return dockContainer()->calculateSideTabBarArea(this); + auto Container = dockContainer(); + auto ContentRect = Container->contentRect(); + + int borders = BorderNone; // contains all borders that are touched by the dock ware + auto DockAreaTopLeft = mapTo(Container, rect().topLeft()); + auto DockAreaRect = rect(); + DockAreaRect.moveTo(DockAreaTopLeft); + const qreal aspectRatio = DockAreaRect.width() / (qMax(1, DockAreaRect.height()) * 1.0); + const qreal sizeRatio = (qreal)ContentRect.width() / DockAreaRect.width(); + static const int MinBorderDistance = 16; + bool HorizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0); + + // measure border distances - a distance less than 16 px means we touch the + // border + int BorderDistance[4]; + + int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y()); + BorderDistance[SideBarLocation::Top] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Top]) + { + borders |= BorderTop; + } + + Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y()); + BorderDistance[SideBarLocation::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Bottom]) + { + borders |= BorderBottom; + } + + Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x()); + BorderDistance[SideBarLocation::Left] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Left]) + { + borders |= BorderLeft; + } + + Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x()); + BorderDistance[SideBarLocation::Right] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::Right]) + { + borders |= BorderRight; + } + + auto SideTab = SideBarLocation::Right; + switch (borders) + { + // 1. It's touching all borders + case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; + + // 2. It's touching 3 borders + case BorderVerticalBottom : SideTab = SideBarLocation::Bottom; break; + case BorderVerticalTop : SideTab = SideBarLocation::Top; break; + case BorderHorizontalLeft: SideTab = SideBarLocation::Left; break; + case BorderHorizontalRight: SideTab = SideBarLocation::Right; break; + + // 3. Its touching horizontal or vertical borders + case BorderVertical : SideTab = SideBarLocation::Bottom; break; + case BorderHorizontal: SideTab = SideBarLocation::Right; break; + + // 4. Its in a corner + case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Left; break; + case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Right; break; + case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Left; break; + case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; + + // 5 Ists touching only one border + case BorderLeft: SideTab = SideBarLocation::Left; break; + case BorderRight: SideTab = SideBarLocation::Right; break; + case BorderTop: SideTab = SideBarLocation::Top; break; + case BorderBottom: SideTab = SideBarLocation::Bottom; break; + } + + return SideTab; } @@ -1203,7 +1297,10 @@ void CDockAreaWidget::setAutoHide(bool Enable) if (!Enable) { - autoHideDockContainer()->moveContentsToParent(); + if (isAutoHide()) + { + autoHideDockContainer()->moveContentsToParent(); + } return; } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 6bd0df634..ee7381709 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1389,105 +1389,6 @@ CAutoHideDockContainer* CDockContainerWidget::createAndSetupAutoHideContainer( } -enum eBorderLocation -{ - BorderNone = 0, - BorderLeft = 0x01, - BorderRight = 0x02, - BorderTop = 0x04, - BorderBottom = 0x08, - BorderVertical = BorderLeft | BorderRight, - BorderHorizontal = BorderTop | BorderBottom, - BorderTopLeft = BorderTop | BorderLeft, - BorderTopRight = BorderTop | BorderRight, - BorderBottomLeft = BorderBottom | BorderLeft, - BorderBottomRight = BorderBottom | BorderRight, - BorderVerticalBottom = BorderVertical | BorderBottom, - BorderVerticalTop = BorderVertical | BorderTop, - BorderHorizontalLeft = BorderHorizontal | BorderLeft, - BorderHorizontalRight = BorderHorizontal | BorderRight, - BorderAll = BorderVertical | BorderHorizontal -}; - - -//============================================================================ -SideBarLocation CDockContainerWidget::calculateSideTabBarArea(const CDockAreaWidget* DockAreaWidget) const -{ - - auto ContentRect = this->contentRect(); - int borders = BorderNone; // contains all borders that are touched by the dock ware - auto DockAreaTopLeft = DockAreaWidget->mapTo(this, DockAreaWidget->rect().topLeft()); - auto DockAreaRect = DockAreaWidget->rect(); - DockAreaRect.moveTo(DockAreaTopLeft); - const qreal aspectRatio = DockAreaRect.width() / (qMax(1, DockAreaRect.height()) * 1.0); - const qreal sizeRatio = (qreal)ContentRect.width() / DockAreaRect.width(); - static const int MinBorderDistance = 16; - bool HorizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0); - - // measure border distances - a distance less than 16 px means we touch the - // border - int BorderDistance[4]; - - int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y()); - BorderDistance[SideBarLocation::Top] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Top]) - { - borders |= BorderTop; - } - - Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y()); - BorderDistance[SideBarLocation::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Bottom]) - { - borders |= BorderBottom; - } - - Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x()); - BorderDistance[SideBarLocation::Left] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Left]) - { - borders |= BorderLeft; - } - - Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x()); - BorderDistance[SideBarLocation::Right] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Right]) - { - borders |= BorderRight; - } - - auto SideTab = SideBarLocation::Right; - switch (borders) - { - // 1. It's touching all borders - case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; - - // 2. It's touching 3 borders - case BorderVerticalBottom : SideTab = SideBarLocation::Bottom; break; - case BorderVerticalTop : SideTab = SideBarLocation::Top; break; - case BorderHorizontalLeft: SideTab = SideBarLocation::Left; break; - case BorderHorizontalRight: SideTab = SideBarLocation::Right; break; - - // 3. Its touching horizontal or vertical borders - case BorderVertical : SideTab = SideBarLocation::Bottom; break; - case BorderHorizontal: SideTab = SideBarLocation::Right; break; - - // 4. Its in a corner - case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Left; break; - case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Right; break; - case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Left; break; - case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; - - // 5 Ists touching only one border - case BorderLeft: SideTab = SideBarLocation::Left; break; - case BorderRight: SideTab = SideBarLocation::Right; break; - case BorderTop: SideTab = SideBarLocation::Top; break; - case BorderBottom: SideTab = SideBarLocation::Bottom; break; - } - - return SideTab; -} - //============================================================================ void CDockContainerWidget::removeDockWidget(CDockWidget* Dockwidget) { diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index b37494bf9..421939beb 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -217,11 +217,6 @@ class ADS_EXPORT CDockContainerWidget : public QFrame CDockAreaWidget* addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget = nullptr); - /** - * Get's the auto hide dock side tab bar area based on the dock area widget position - */ - SideBarLocation calculateSideTabBarArea(const CDockAreaWidget* DockAreaWidget) const; - /** * Removes dockwidget */ From 9c14c62637d275fd6ddfb3b758752e3af3616ea8 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 08:27:23 +0100 Subject: [PATCH 194/236] Added setAutoHide() and toggleAutoHide() function to CDockWidget --- src/DockAreaWidget.cpp | 10 ++-------- src/DockWidget.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/DockWidget.h | 12 ++++++++++++ 3 files changed, 53 insertions(+), 8 deletions(-) diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 651b674a2..8ec5e0e05 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1304,11 +1304,10 @@ void CDockAreaWidget::setAutoHide(bool Enable) return; } - const auto area = calculateSideTabBarArea(); - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea) && features().testFlag(CDockWidget::DockWidgetPinnable)) { + auto area = calculateSideTabBarArea(); for (const auto DockWidget : openedDockWidgets()) { if (Enable == isAutoHide()) @@ -1321,12 +1320,7 @@ void CDockAreaWidget::setAutoHide(bool Enable) } else { - const auto DockWidget = currentDockWidget(); - if (Enable == isAutoHide()) - { - return; - } - dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); + currentDockWidget()->setAutoHide(true); } } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index ca3f55b44..31f3cb979 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1156,6 +1156,45 @@ void CDockWidget::raise() } +//============================================================================ +void CDockWidget::setAutoHide(bool Enable) +{ + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + return; + } + + // Do nothing if nothing changes + if (Enable == isAutoHide()) + { + return; + } + + auto DockArea = dockAreaWidget(); + if (!Enable) + { + DockArea->setAutoHide(false); + } + else + { + auto area = DockArea->calculateSideTabBarArea(); + dockContainer()->createAndSetupAutoHideContainer(area, this); + } +} + + +//============================================================================ +void CDockWidget::toggleAutoHide() +{ + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + return; + } + + setAutoHide(!isAutoHide()); +} + + } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockWidget.h b/src/DockWidget.h index b0d9f546d..115c02c75 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -592,6 +592,18 @@ public Q_SLOTS: */ void showNormal(); + /** + * Sets the dock widget into auto hide mode if this feature is enabled + * via CDockManager::setAutoHideFlags(CDockManager::AutoHideFeatureEnabled) + */ + void setAutoHide(bool Enable); + + /** + * Switches the dock widget to auto hide mode or vice versa depending on its + * current state. + */ + void toggleAutoHide(); + Q_SIGNALS: /** From b5a179555a8576af03d21d447582ca6436d00475 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 12:45:45 +0100 Subject: [PATCH 195/236] Added context menu actions for titleBar and dock widget tab auto hide --- src/DockAreaTitleBar.cpp | 36 +++++++++++++++++++++++++++++------- src/DockAreaTitleBar.h | 1 + src/DockAreaWidget.cpp | 23 ++++++++++------------- src/DockAreaWidget.h | 4 +++- src/DockWidgetTab.cpp | 12 ++++++++++++ src/DockWidgetTab.h | 1 + 6 files changed, 56 insertions(+), 21 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index efa93fddc..30314b549 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -27,7 +27,6 @@ //============================================================================ // INCLUDES //============================================================================ -#include #include "DockAreaTitleBar.h" #include @@ -53,6 +52,7 @@ #include "DockComponentsFactory.h" #include "DockFocusController.h" #include "ElidingLabel.h" +#include "AutoHideDockContainer.h" #include @@ -137,7 +137,6 @@ struct DockAreaTitleBarPrivate return this->DragState == dragState; } - /** * Starts floating */ @@ -493,7 +492,21 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - d->DockArea->setAutoHide(!d->DockArea->isAutoHide()); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)) + { + d->DockArea->toggleAutoHide(); + } + else + { + d->DockArea->currentDockWidget()->toggleAutoHide(); + } +} + + +//============================================================================ +void CDockAreaTitleBar::onAutoHideDockAreaClicked() +{ + d->DockArea->toggleAutoHide(); } @@ -538,7 +551,6 @@ void CDockAreaTitleBar::mousePressEvent(QMouseEvent* ev) if (CDockManager::testConfigFlag(CDockManager::FocusHighlighting)) { - //d->TabBar->currentTab()->setFocus(Qt::OtherFocusReason); d->dockManager()->dockFocusController()->setDockWidgetTabFocused(d->TabBar->currentTab()); } return; @@ -652,13 +664,23 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) return; } + bool IsAutoHide = d->DockArea->isAutoHide(); QMenu Menu(this); - auto Action = Menu.addAction(tr("Detach Group"), this, SLOT(onUndockButtonClicked())); + auto Action = Menu.addAction(IsAutoHide ? tr("Detach") : tr("Detach Group"), + this, SLOT(onUndockButtonClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaClicked())); + Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)); + } Menu.addSeparator(); - Action = Menu.addAction(tr("Close Group"), this, SLOT(onCloseButtonClicked())); + Action = Menu.addAction(IsAutoHide ? tr("Close") : tr("Close Group"), this, SLOT(onCloseButtonClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable)); - Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas())); + if (!IsAutoHide) + { + Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas())); + } Menu.exec(ev->globalPos()); } diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 5ccdc4a35..88e4fddb1 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -62,6 +62,7 @@ private Q_SLOTS: void onTabsMenuActionTriggered(QAction* Action); void onCurrentTabChanged(int Index); void onAutoHideButtonClicked(); + void onAutoHideDockAreaClicked(); protected: /** diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 8ec5e0e05..4cfb7ac4b 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1304,23 +1304,20 @@ void CDockAreaWidget::setAutoHide(bool Enable) return; } - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea) - && features().testFlag(CDockWidget::DockWidgetPinnable)) + auto area = calculateSideTabBarArea(); + for (const auto DockWidget : openedDockWidgets()) { - auto area = calculateSideTabBarArea(); - for (const auto DockWidget : openedDockWidgets()) + if (Enable == isAutoHide()) { - if (Enable == isAutoHide()) - { - continue; - } + continue; + } - dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); + if (!DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable)) + { + continue; } - } - else - { - currentDockWidget()->setAutoHide(true); + + dockContainer()->createAndSetupAutoHideContainer(area, DockWidget); } } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 65d73deaf..8e8a0aa42 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -391,7 +391,9 @@ public Q_SLOTS: void closeArea(); /** - * Sets the dock area into auto hide mode or into normal mode + * Sets the dock area into auto hide mode or into normal mode. + * If the dock area is switched to auto hide mode, then all dock widgets + * that are pinable will be added to the sidebar */ void setAutoHide(bool Enable); diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index 30c5135c0..aa904c778 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -515,6 +515,11 @@ void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev) auto Action = Menu.addAction(tr("Detach"), this, SLOT(detachDockWidget())); Action->setEnabled(isDetachable); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + Action = Menu.addAction(tr("Auto Hide"), this, SLOT(autoHideDockWidget())); + Action->setEnabled(d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable)); + } Menu.addSeparator(); Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested())); Action->setEnabled(isClosable()); @@ -700,6 +705,13 @@ void CDockWidgetTab::detachDockWidget() } +//=========================================================================== +void CDockWidgetTab::autoHideDockWidget() +{ + d->DockWidget->setAutoHide(true); +} + + //============================================================================ bool CDockWidgetTab::event(QEvent *e) { diff --git a/src/DockWidgetTab.h b/src/DockWidgetTab.h index d186c460c..df32ef03a 100644 --- a/src/DockWidgetTab.h +++ b/src/DockWidgetTab.h @@ -63,6 +63,7 @@ class ADS_EXPORT CDockWidgetTab : public QFrame private Q_SLOTS: void detachDockWidget(); + void autoHideDockWidget(); protected: virtual void mousePressEvent(QMouseEvent* ev) override; From d2c08aca701710c2ee2e3cfe111becd38c551197 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 13:06:42 +0100 Subject: [PATCH 196/236] Improved context menu of DockAreaWidget --- src/DockAreaTitleBar.cpp | 26 ++++++++++++++++---------- src/DockAreaWidget.cpp | 13 +++++++++++++ src/DockAreaWidget.h | 6 ++++++ src/DockContainerWidget.h | 3 ++- 4 files changed, 37 insertions(+), 11 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 30314b549..87d3c511c 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -665,21 +665,27 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) } bool IsAutoHide = d->DockArea->isAutoHide(); + bool IsTopLevelArea = d->DockArea->isTopLevelArea(); + QAction* Action; QMenu Menu(this); - auto Action = Menu.addAction(IsAutoHide ? tr("Detach") : tr("Detach Group"), - this, SLOT(onUndockButtonClicked())); - Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) - { - Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaClicked())); - Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)); - } - Menu.addSeparator(); + if (!IsTopLevelArea) + { + Action = Menu.addAction(IsAutoHide ? tr("Detach") : tr("Detach Group"), + this, SLOT(onUndockButtonClicked())); + Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaClicked())); + Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)); + } + Menu.addSeparator(); + } Action = Menu.addAction(IsAutoHide ? tr("Close") : tr("Close Group"), this, SLOT(onCloseButtonClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable)); if (!IsAutoHide) { - Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas())); + Action = Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas())); + Action->setEnabled(!IsTopLevelArea); } Menu.exec(ev->globalPos()); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 4cfb7ac4b..fc90cc771 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1405,6 +1405,19 @@ void CDockAreaWidget::onDockWidgetFeaturesChanged() } +//============================================================================ +bool CDockAreaWidget::isTopLevelArea() const +{ + auto Container = dockContainer(); + if (!Container) + { + return false; + } + + return (Container->topLevelDockArea() == this); +} + + #ifdef Q_OS_WIN //============================================================================ bool CDockAreaWidget::event(QEvent *e) diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index 8e8a0aa42..b79107cc6 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -376,6 +376,12 @@ protected Q_SLOTS: */ bool containsCentralWidget() const; + /** + * If this dock area is the one and only visible area in a container, then + * this function returns true + */ + bool isTopLevelArea() const; + public Q_SLOTS: /** diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 421939beb..6153cd77e 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -163,7 +163,8 @@ class ADS_EXPORT CDockContainerWidget : public QFrame CDockWidget* topLevelDockWidget() const; /** - * Returns the top level dock area. + * If the container has only one single visible dock area, then this + * functions returns this top level dock area */ CDockAreaWidget* topLevelDockArea() const; From 159579fb48f51bc59ef36afd6f31d2bf6483e386 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 14:29:23 +0100 Subject: [PATCH 197/236] Fixed some auto hide specific bugs --- src/AutoHideDockContainer.cpp | 1 + src/AutoHideSideBar.cpp | 1 + src/DockAreaTitleBar.cpp | 5 +++-- src/DockAreaTitleBar.h | 2 +- src/DockAreaWidget.cpp | 18 ++++++++++++++++-- src/DockContainerWidget.cpp | 1 + src/DockManager.cpp | 1 - 7 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 11242628e..1f0f1aa56 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -265,6 +265,7 @@ void CAutoHideDockContainer::updateSize() //============================================================================ CAutoHideDockContainer::~CAutoHideDockContainer() { + qDebug() << "~CAutoHideDockContainer()" ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index 9fd7709f7..17d25c888 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -143,6 +143,7 @@ CAutoHideDockContainer* CAutoHideSideBar::insertDockWidget(int Index, CDockWidge auto AutoHideContainer = new CAutoHideDockContainer(DockWidget, d->SideTabArea, d->ContainerWidget); DockWidget->dockManager()->dockFocusController()->clearDockWidgetFocus(DockWidget); auto Tab = AutoHideContainer->autoHideTab(); + DockWidget->setSideTabWidget(Tab); insertTab(Index, Tab); return AutoHideContainer; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 87d3c511c..94781b1c0 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -498,13 +498,14 @@ void CDockAreaTitleBar::onAutoHideButtonClicked() } else { + qDebug() << "d->DockArea->currentDockWidget()->toggleAutoHide()"; d->DockArea->currentDockWidget()->toggleAutoHide(); } } //============================================================================ -void CDockAreaTitleBar::onAutoHideDockAreaClicked() +void CDockAreaTitleBar::onAutoHideDockAreaActionClicked() { d->DockArea->toggleAutoHide(); } @@ -675,7 +676,7 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { - Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaClicked())); + Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaActionClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)); } Menu.addSeparator(); diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 88e4fddb1..b2c81e8cc 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -62,7 +62,7 @@ private Q_SLOTS: void onTabsMenuActionTriggered(QAction* Action); void onCurrentTabChanged(int Index); void onAutoHideButtonClicked(); - void onAutoHideDockAreaClicked(); + void onAutoHideDockAreaActionClicked(); protected: /** diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index fc90cc771..06424c26a 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -514,6 +514,15 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { ADS_PRINT("CDockAreaWidget::removeDockWidget"); + + // If this dock area is in a auto hide container, then we can delete + // the auto hide container now + if (isAutoHide()) + { + autoHideDockContainer()->cleanupAndDelete(); + return; + } + auto CurrentDockWidget = currentDockWidget(); auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr; @@ -528,7 +537,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { 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 + else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1) // 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); @@ -868,7 +877,6 @@ void CDockAreaWidget::updateAutoHideButtonCheckState() //============================================================================ void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const { - qDebug() << "CDockAreaWidget::updateTitleBarButtonVisibility IsTopLevel " << IsTopLevel; d->updateTitleBarButtonVisibility(IsTopLevel); } @@ -970,9 +978,15 @@ bool CDockAreaWidget::restoreState(CDockingStateReader& s, CDockAreaWidget*& Cre } ADS_PRINT("Dock Widget found - parent " << DockWidget->parent()); + if (DockWidget->autoHideDockContainer()) + { + DockWidget->autoHideDockContainer()->cleanupAndDelete(); + } + // We hide the DockArea here to prevent the short display (the flashing) // of the dock areas during application startup DockArea->hide(); + qDebug() << "DockArea->addDockWidget " << DockWidget->windowTitle(); DockArea->addDockWidget(DockWidget); DockWidget->setToggleViewActionChecked(!Closed); DockWidget->setClosedState(Closed); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index ee7381709..b156c2f3c 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1440,6 +1440,7 @@ void CDockContainerWidget::deleteAutoHideWidgets() d->AutoHideWidgets.clear(); } + //============================================================================ QList CDockContainerWidget::autoHideWidgets() const { diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 268dafcd9..08b7a9c30 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -437,7 +437,6 @@ bool DockManagerPrivate::restoreState(const QByteArray& State, int version) // Hide updates of floating widgets from use hideFloatingWidgets(); markDockWidgetsDirty(); - _this->deleteAutoHideWidgets(); if (!restoreStateFromXml(state, version)) { From 716207f600da07874d183df5120d778fc9416485 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 2 Nov 2022 14:41:41 +0100 Subject: [PATCH 198/236] Removed superfluous deleteAutoHideWidgets() function from CDockContainerWidget --- demo/MainWindow.cpp | 2 +- src/DockContainerWidget.cpp | 17 ----------------- src/DockContainerWidget.h | 6 ------ 3 files changed, 1 insertion(+), 24 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 71bd13de1..e0394c4f7 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -752,7 +752,7 @@ void CMainWindow::onViewToggled(bool Open) return; } - qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; + //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index b156c2f3c..a90f99073 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1338,12 +1338,6 @@ CDockContainerWidget::~CDockContainerWidget() d->DockManager->removeDockContainer(this); } - auto AutoHideWidgets = d->AutoHideWidgets; - for (auto AutohideWidget : AutoHideWidgets) - { - delete AutohideWidget; - } - delete d; } @@ -1430,17 +1424,6 @@ bool CDockContainerWidget::event(QEvent *e) } -//============================================================================ -void CDockContainerWidget::deleteAutoHideWidgets() -{ - for (auto AutohideWidget : d->AutoHideWidgets) - { - AutohideWidget->cleanupAndDelete(); - } - d->AutoHideWidgets.clear(); -} - - //============================================================================ QList CDockContainerWidget::autoHideWidgets() const { diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 6153cd77e..247c698b8 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -84,12 +84,6 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ virtual bool event(QEvent *e) override; - /* - * Delete function for resetting the auto hide widget list - * Used during restore - */ - void deleteAutoHideWidgets(); - /** * Access function for the internal root splitter */ From 736c096bc008716fd0e413727f4d5fbec7a08408 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 3 Nov 2022 11:50:41 +0800 Subject: [PATCH 199/236] make a copy before deleting --- src/DockContainerWidget.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 459b166d7..91316cb81 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1532,7 +1532,8 @@ bool CDockContainerWidget::event(QEvent *e) //============================================================================ void CDockContainerWidget::deleteAutoHideWidgets() { - for (auto AutohideWidget : d->AutoHideWidgets) + const auto autoHideWidgets = d->AutoHideWidgets; + for (auto AutohideWidget : autoHideWidgets) { AutohideWidget->cleanupAndDelete(); } From 246dd04279da22d38fd162cb0613bcf9e9091a37 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 3 Nov 2022 12:42:02 +0800 Subject: [PATCH 200/236] fix crash --- src/AutoHideDockContainer.cpp | 21 ++++++++++++--------- src/AutoHideDockContainer.h | 4 +++- src/DockContainerWidget.cpp | 4 ++++ src/FloatingDragPreview.cpp | 4 ++-- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 4f91149f0..3c64940ef 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -167,14 +167,8 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( //============================================================================ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const { - if (d->DockArea) - { - return d->DockArea->dockContainer(); - } - else - { - return internal::findParent(this); - } + // Don't rely on the dock area parent container, when dragging or floating the parent container can change + return internal::findParent(this); } @@ -357,7 +351,7 @@ void CAutoHideDockContainer::moveContentsToParent() //============================================================================ -void CAutoHideDockContainer::cleanupAndDelete() +void CAutoHideDockContainer::cleanupAndDelete(bool deleteDockArea) { const auto dockWidget = d->DockWidget; if (dockWidget) @@ -371,6 +365,15 @@ void CAutoHideDockContainer::cleanupAndDelete() hide(); deleteLater(); + + // Schedule deletion of the dock area after the auto hide widget + // Otherwise, there are issues with the windows native event handler + if (deleteDockArea) + { + d->DockArea->setParent(nullptr); + d->DockArea->deleteLater(); + d->DockArea = nullptr; + } } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index c00f114a3..dbd78f89a 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -134,8 +134,10 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Cleanups up the side tab widget and then deletes itself + * deleteDockArea = true is set, this will also delete the dockArea. + * Avoid deleting the dock area floating drag, where the dock area is simply moved into another container */ - void cleanupAndDelete(); + void cleanupAndDelete(bool deleteDockArea = true); /* * Toggles the auto Hide dock container widget diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 91316cb81..a7a0f2d22 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -2073,12 +2073,16 @@ void CDockContainerWidget::registerAutoHideWidget(CAutoHideDockContainer* Autohi d->AutoHideWidgets.append(AutohideWidget); Q_EMIT autoHideWidgetCreated(AutohideWidget); ADS_PRINT("d->AutoHideWidgets.count() " << d->AutoHideWidgets.count()); + qInfo()<< this << "Size after registering: " << d->AutoHideWidgets.size(); } //============================================================================ void CDockContainerWidget::removeAutoHideWidget(CAutoHideDockContainer* AutohideWidget) { + qInfo() << this << "Auto hide widgets: " << d->AutoHideWidgets; + qInfo() << "Size before removing: " << d->AutoHideWidgets.size(); d->AutoHideWidgets.removeAll(AutohideWidget); + qInfo() << "Size after removing: " << d->AutoHideWidgets.size(); } //============================================================================ diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index a48611df6..24be3ead0 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -371,11 +371,11 @@ void CFloatingDragPreview::cleanupAutoHideContainerWidget() auto DroppedArea = qobject_cast(d->Content); if (DroppedDockWidget && DroppedDockWidget->autoHideDockContainer()) { - DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(); + DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(false); } if (DroppedArea && DroppedArea->autoHideDockContainer()) { - DroppedArea->autoHideDockContainer()->cleanupAndDelete(); + DroppedArea->autoHideDockContainer()->cleanupAndDelete(false); } } From d255292714409f19c5d066bd17add38ca29249a9 Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 3 Nov 2022 15:01:21 +0800 Subject: [PATCH 201/236] Revert "fix crash" This reverts commit 246dd04279da22d38fd162cb0613bcf9e9091a37. --- src/AutoHideDockContainer.cpp | 21 +++++++++------------ src/AutoHideDockContainer.h | 4 +--- src/DockContainerWidget.cpp | 4 ---- src/FloatingDragPreview.cpp | 4 ++-- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index ce28688dd..2cb2f3463 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -167,8 +167,14 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( //============================================================================ CDockContainerWidget* CAutoHideDockContainer::parentContainer() const { - // Don't rely on the dock area parent container, when dragging or floating the parent container can change - return internal::findParent(this); + if (d->DockArea) + { + return d->DockArea->dockContainer(); + } + else + { + return internal::findParent(this); + } } @@ -355,7 +361,7 @@ void CAutoHideDockContainer::moveContentsToParent() //============================================================================ -void CAutoHideDockContainer::cleanupAndDelete(bool deleteDockArea) +void CAutoHideDockContainer::cleanupAndDelete() { const auto dockWidget = d->DockWidget; if (dockWidget) @@ -369,15 +375,6 @@ void CAutoHideDockContainer::cleanupAndDelete(bool deleteDockArea) hide(); deleteLater(); - - // Schedule deletion of the dock area after the auto hide widget - // Otherwise, there are issues with the windows native event handler - if (deleteDockArea) - { - d->DockArea->setParent(nullptr); - d->DockArea->deleteLater(); - d->DockArea = nullptr; - } } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index dbd78f89a..c00f114a3 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -134,10 +134,8 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Cleanups up the side tab widget and then deletes itself - * deleteDockArea = true is set, this will also delete the dockArea. - * Avoid deleting the dock area floating drag, where the dock area is simply moved into another container */ - void cleanupAndDelete(bool deleteDockArea = true); + void cleanupAndDelete(); /* * Toggles the auto Hide dock container widget diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 648c9e8ce..a90f99073 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1957,16 +1957,12 @@ void CDockContainerWidget::registerAutoHideWidget(CAutoHideDockContainer* Autohi d->AutoHideWidgets.append(AutohideWidget); Q_EMIT autoHideWidgetCreated(AutohideWidget); ADS_PRINT("d->AutoHideWidgets.count() " << d->AutoHideWidgets.count()); - qInfo()<< this << "Size after registering: " << d->AutoHideWidgets.size(); } //============================================================================ void CDockContainerWidget::removeAutoHideWidget(CAutoHideDockContainer* AutohideWidget) { - qInfo() << this << "Auto hide widgets: " << d->AutoHideWidgets; - qInfo() << "Size before removing: " << d->AutoHideWidgets.size(); d->AutoHideWidgets.removeAll(AutohideWidget); - qInfo() << "Size after removing: " << d->AutoHideWidgets.size(); } //============================================================================ diff --git a/src/FloatingDragPreview.cpp b/src/FloatingDragPreview.cpp index 24be3ead0..a48611df6 100644 --- a/src/FloatingDragPreview.cpp +++ b/src/FloatingDragPreview.cpp @@ -371,11 +371,11 @@ void CFloatingDragPreview::cleanupAutoHideContainerWidget() auto DroppedArea = qobject_cast(d->Content); if (DroppedDockWidget && DroppedDockWidget->autoHideDockContainer()) { - DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(false); + DroppedDockWidget->autoHideDockContainer()->cleanupAndDelete(); } if (DroppedArea && DroppedArea->autoHideDockContainer()) { - DroppedArea->autoHideDockContainer()->cleanupAndDelete(false); + DroppedArea->autoHideDockContainer()->cleanupAndDelete(); } } From bcf8e8a42138ce15d77a6d95e4ca1a5860a16feb Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 3 Nov 2022 15:04:00 +0800 Subject: [PATCH 202/236] Revert "setSideTabWidget on dockwidget" This reverts commit ea499c7deac6af5d6659640029b3f86345f0d0ad. --- src/AutoHideTab.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index b045d88d3..461085d9e 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -215,7 +215,6 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; setText(DockWidget->windowTitle()); setIcon(d->DockWidget->icon()); - DockWidget->setSideTabWidget(this); } } From 986077c76599ca87e29f4635ab13467a3ea6025d Mon Sep 17 00:00:00 2001 From: Syarif Fakhri Date: Thu, 3 Nov 2022 15:27:18 +0800 Subject: [PATCH 203/236] revert not removing old dock widgets when restoring state --- src/AutoHideDockContainer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 2cb2f3463..952c1ef57 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -315,8 +315,7 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; d->SideTab->setDockWidget(DockWidget); CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); - // Don't remove dock widgets while restoring state, the current index pointer may be invalid - if (!DockWidget->dockManager()->isRestoringState() && OldDockArea) + if (OldDockArea) { OldDockArea->removeDockWidget(DockWidget); } From 3b97fdc2ceff71d814847e9f72df6183ec87cc0b Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 3 Nov 2022 11:34:04 +0100 Subject: [PATCH 204/236] Improved AutoHideSidebar to provide better resize behavior if parent widget is resized --- demo/MainWindow.cpp | 3 +- src/AutoHideSideBar.cpp | 184 ++++++++++++++++++------- src/AutoHideSideBar.h | 36 ++++- src/AutoHideTab.cpp | 8 ++ src/stylesheets/default.css | 25 ++-- src/stylesheets/focus_highlighting.css | 30 ++-- 6 files changed, 204 insertions(+), 82 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index e0394c4f7..e46bd7c49 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -746,13 +746,14 @@ void CMainWindow::savePerspective() //============================================================================ void CMainWindow::onViewToggled(bool Open) { + Q_UNUSED(Open); auto DockWidget = qobject_cast(sender()); if (!DockWidget) { return; } - //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; + qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; } diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index 17d25c888..23babbace 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -45,6 +45,8 @@ namespace ads { +class CTabsWidget; + /** * Private data class of CSideTabBar class (pimpl) */ @@ -57,6 +59,7 @@ struct AutoHideSideBarPrivate CAutoHideSideBar* _this; CDockContainerWidget* ContainerWidget; + CTabsWidget* TabsContainerWidget; QBoxLayout* TabsLayout; Qt::Orientation Orientation; SideBarLocation SideTabArea = SideBarLocation::Left; @@ -68,8 +71,43 @@ struct AutoHideSideBarPrivate { return Qt::Horizontal == Orientation; } + + /** + * Called from viewport to forward event handling to this + */ + void handleViewportEvent(QEvent* e); }; // struct AutoHideSideBarPrivate + +/** + * This widget stores the tab buttons + */ +class CTabsWidget : public QWidget +{ +public: + using QWidget::QWidget; + using Super = QWidget; + AutoHideSideBarPrivate* EventHandler; + + /** + * Returns the size hint as minimum size hint + */ + virtual QSize minimumSizeHint() const override + { + return Super::sizeHint(); + } + + /** + * Forward event handling to EventHandler + */ + /*virtual bool event(QEvent* e) override + { + EventHandler->handleViewportEvent(e); + return Super::event(e); + }*/ +}; + + //============================================================================ AutoHideSideBarPrivate::AutoHideSideBarPrivate(CAutoHideSideBar* _public) : _this(_public) @@ -77,6 +115,45 @@ AutoHideSideBarPrivate::AutoHideSideBarPrivate(CAutoHideSideBar* _public) : } +//============================================================================ +void AutoHideSideBarPrivate::handleViewportEvent(QEvent* e) +{ + switch (e->type()) + { + case QEvent::ChildRemoved: + if (TabsLayout->isEmpty()) + { + _this->hide(); + } + break; + + case QEvent::Resize: + if (_this->tabCount()) + { + auto ev = static_cast(e); + auto Tab = _this->tabAt(0); + int Size = isHorizontal() ? ev->size().height() : ev->size().width(); + int TabSize = isHorizontal() ? Tab->size().height() : Tab->size().width(); + // If the size of the side bar is less than the size of the first tab + // then there are no visible tabs in this side bar. This check will + // fail if someone will force a very big border via CSS!! + if (Size < TabSize) + { + _this->hide(); + } + } + else + { + _this->hide(); + } + break; + + default: + break; + } +} + + //============================================================================ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation area) : Super(parent), @@ -87,16 +164,24 @@ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation d->Orientation = (area == SideBarLocation::Bottom || area == SideBarLocation::Top) ? Qt::Horizontal : Qt::Vertical; - auto mainLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); + setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + setFrameStyle(QFrame::NoFrame); + setWidgetResizable(true); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + d->TabsContainerWidget = new CTabsWidget(); + d->TabsContainerWidget->EventHandler = d; + d->TabsContainerWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + d->TabsContainerWidget->setObjectName("sideTabsContainerWidget"); + d->TabsLayout = new QBoxLayout(d->Orientation == Qt::Vertical ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); d->TabsLayout->setContentsMargins(0, 0, 0, 0); - d->TabsLayout->setSpacing(0); - mainLayout->addLayout(d->TabsLayout); - mainLayout->setContentsMargins(0, 0, 0, 0); - mainLayout->setSpacing(0); - mainLayout->addStretch(1); - setLayout(mainLayout); + d->TabsLayout->setSpacing(12); + d->TabsLayout->addStretch(1); + d->TabsContainerWidget->setLayout(d->TabsLayout); + setWidget(d->TabsContainerWidget); setFocusPolicy(Qt::NoFocus); if (d->isHorizontal()) @@ -108,6 +193,8 @@ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); } + qDebug() << "d->TabsLayout->count " << d->TabsLayout->count(); + hide(); } @@ -130,9 +217,16 @@ CAutoHideSideBar::~CAutoHideSideBar() //============================================================================ void CAutoHideSideBar::insertTab(int Index, CAutoHideTab* SideTab) { - SideTab->installEventFilter(this); SideTab->setSideBar(this); - d->TabsLayout->insertWidget(Index, SideTab); + SideTab->installEventFilter(this); + if (Index < 0) + { + d->TabsLayout->insertWidget(d->TabsLayout->count() - 1, SideTab); + } + else + { + d->TabsLayout->insertWidget(Index, SideTab); + } show(); } @@ -161,46 +255,6 @@ void CAutoHideSideBar::removeTab(CAutoHideTab* SideTab) } -//============================================================================ -bool CAutoHideSideBar::event(QEvent* e) -{ - switch (e->type()) - { - case QEvent::ChildRemoved: - if (d->TabsLayout->isEmpty()) - { - hide(); - } - break; - - case QEvent::Resize: - if (d->TabsLayout->count()) - { - auto ev = static_cast(e); - auto Tab = tabAt(0); - int Size = d->isHorizontal() ? ev->size().height() : ev->size().width(); - int TabSize = d->isHorizontal() ? Tab->size().height() : Tab->size().width(); - // If the size of the side bar is less than the size of the first tab - // then there are no visible tabs in this side bar. This check will - // fail if someone will force a very big border via CSS!! - if (Size < TabSize) - { - hide(); - } - } - else - { - hide(); - } - break; - - default: - break; - } - return Super::event(e); -} - - //============================================================================ bool CAutoHideSideBar::eventFilter(QObject *watched, QEvent *event) { @@ -209,7 +263,7 @@ bool CAutoHideSideBar::eventFilter(QObject *watched, QEvent *event) return false; } - // As soon as on tab is shhown, we need to show the side tab bar + // As soon as on tab is shown, we need to show the side tab bar auto Tab = qobject_cast(watched); if (Tab) { @@ -235,7 +289,7 @@ CAutoHideTab* CAutoHideSideBar::tabAt(int index) const //============================================================================ int CAutoHideSideBar::tabCount() const { - return d->TabsLayout->count(); + return d->TabsLayout->count() - 1; } @@ -272,5 +326,33 @@ void CAutoHideSideBar::saveState(QXmlStreamWriter& s) const s.writeEndElement(); } +//=========================================================================== +QSize CAutoHideSideBar::minimumSizeHint() const +{ + QSize Size = sizeHint(); + Size.setWidth(10); + return Size; +} + + +//=========================================================================== +QSize CAutoHideSideBar::sizeHint() const +{ + return d->TabsContainerWidget->sizeHint(); +} + + +//=========================================================================== +int CAutoHideSideBar::spacing() const +{ + return d->TabsLayout->spacing(); +} + +//=========================================================================== +void CAutoHideSideBar::setSpacing(int Spacing) +{ + d->TabsLayout->setSpacing(Spacing); +} } // namespace ads + diff --git a/src/AutoHideSideBar.h b/src/AutoHideSideBar.h index 11f734586..3e57e2b25 100644 --- a/src/AutoHideSideBar.h +++ b/src/AutoHideSideBar.h @@ -29,7 +29,7 @@ //============================================================================ // INCLUDES //============================================================================ -#include +#include #include "ads_globals.h" #include "AutoHideTab.h" @@ -50,12 +50,16 @@ class CDockingStateReader; * it contains visible tabs. If it is empty or all tabs are hidden, then the * side bar is also hidden. As soon as one single tab becomes visible, this * tab bar will be shown. + * The CAutoHideSideBar uses a QScrollArea here, to enable proper resizing. + * If the side bar contains many tabs, then the tabs are simply clipped - this + * is the same like in visual studio */ -class ADS_EXPORT CAutoHideSideBar : public QFrame +class ADS_EXPORT CAutoHideSideBar : public QScrollArea { Q_OBJECT Q_PROPERTY(int sideBarLocation READ sideBarLocation) Q_PROPERTY(Qt::Orientation orientation READ orientation) + Q_PROPERTY(int spacing READ spacing WRITE setSpacing) private: AutoHideSideBarPrivate* d; ///< private data (pimpl) @@ -64,7 +68,6 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame friend DockContainerWidgetPrivate; protected: - virtual bool event(QEvent* e) override; virtual bool eventFilter(QObject *watched, QEvent *event) override; /** @@ -79,7 +82,7 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame void insertTab(int Index, CAutoHideTab* SideTab); public: - using Super = QFrame; + using Super = QScrollArea; /** * Default Constructor @@ -123,6 +126,31 @@ class ADS_EXPORT CAutoHideSideBar : public QFrame */ SideBarLocation sideBarLocation() const; + /** + * Overrides the minimumSizeHint() function of QScrollArea + * The minimumSizeHint() is bigger than the sizeHint () for the scroll + * area because even if the scrollbars are invisible, the required speace + * is reserved in the minimumSizeHint(). This override simply returns + * sizeHint(); + */ + virtual QSize minimumSizeHint() const override; + + /** + * The function provides a sizeHint that matches the height of the + * internal viewport. + */ + virtual QSize sizeHint() const override; + + /** + * Getter for spacing property - returns the spacing of the tabs + */ + int spacing() const; + + /** + * Setter for spacing property - sets the spacing + */ + void setSpacing(int Spacing); + Q_SIGNALS: void sideTabAutoHideToggleRequested(); }; diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 461085d9e..9377980a1 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -173,6 +173,14 @@ SideBarLocation CAutoHideTab::sideBarLocation() const void CAutoHideTab::setOrientation(Qt::Orientation Orientation) { d->Orientation = Orientation; + if (orientation() == Qt::Horizontal) + { + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); + } + else + { + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + } CPushButton::setButtonOrientation((Qt::Horizontal == Orientation) ? CPushButton::Horizontal : CPushButton::VerticalTopToBottom); updateStyle(); diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 155de9ea0..718b48260 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -131,53 +131,52 @@ QScrollArea#dockWidgetScrollArea { * CAutoHideTab *****************************************************************************/ ads--CAutoHideTab { - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ background: none; border: none; padding-left: 2px; padding-right: 0px; text-align: center; - margin-right: 6px; - min-height: 20; + min-height: 20px; + padding-bottom: 2px; } ads--CAutoHideTab[sideBarLocation="0"], ads--CAutoHideTab[sideBarLocation="2"] { - border-top: 5px solid rgba(0, 0, 0, 48); - + border-top: 6px solid rgba(0, 0, 0, 48); } ads--CAutoHideTab[sideBarLocation="1"], ads--CAutoHideTab[sideBarLocation="3"] { - border-bottom: 5px solid rgba(0, 0, 0, 48); + border-bottom: 6px solid rgba(0, 0, 0, 48); } ads--CAutoHideTab:hover[sideBarLocation="0"], ads--CAutoHideTab:hover[sideBarLocation="2"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); color: palette(highlight); } ads--CAutoHideTab:hover[sideBarLocation="1"], ads--CAutoHideTab:hover[sideBarLocation="3"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); color: palette(highlight); } ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); } ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); } @@ -186,6 +185,12 @@ ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { *****************************************************************************/ ads--CAutoHideSideBar{ background: palette(window); + border: none; + qproperty-spacing: 12; +} + +#sideTabsContainerWidget { + background: transparent; } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 1e09c4308..105776928 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -168,59 +168,52 @@ QScrollArea#dockWidgetScrollArea { * CAutoHideTab *****************************************************************************/ ads--CAutoHideTab { - /*background: palette(window);*/ qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - - -ads--CAutoHideTab { background: none; border: none; padding-left: 2px; padding-right: 0px; text-align: center; + min-height: 20px; + padding-bottom: 2px; } ads--CAutoHideTab[sideBarLocation="0"], ads--CAutoHideTab[sideBarLocation="2"] { - border-top: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; + border-top: 6px solid rgba(0, 0, 0, 48); } ads--CAutoHideTab[sideBarLocation="1"], ads--CAutoHideTab[sideBarLocation="3"] { - border-bottom: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; + border-bottom: 6px solid rgba(0, 0, 0, 48); } ads--CAutoHideTab:hover[sideBarLocation="0"], ads--CAutoHideTab:hover[sideBarLocation="2"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); color: palette(highlight); } ads--CAutoHideTab:hover[sideBarLocation="1"], ads--CAutoHideTab:hover[sideBarLocation="3"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); color: palette(highlight); } ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); } ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); } @@ -229,6 +222,12 @@ ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { *****************************************************************************/ ads--CAutoHideSideBar{ background: palette(window); + border: none; + qproperty-spacing: 12; +} + +#sideTabsContainerWidget { + background: transparent; } @@ -336,4 +335,3 @@ ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { border-top: 1px solid palette(dark); } - From 1922395b4b2f175c92546a22f045d7b497fae1bd Mon Sep 17 00:00:00 2001 From: Uwe Date: Thu, 3 Nov 2022 12:00:52 +0100 Subject: [PATCH 205/236] Improved linux auto hide specific css code --- src/stylesheets/default_linux.css | 57 +++++++++++-------- src/stylesheets/focus_highlighting_linux.css | 58 ++++++++++++-------- 2 files changed, 69 insertions(+), 46 deletions(-) diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index 28d2b5a24..fbfc3050e 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -167,49 +167,52 @@ ads--CFloatingWidgetTitleBar { * CAutoHideTab *****************************************************************************/ ads--CAutoHideTab { - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ - padding-left: 2px; - padding-right: 0px; - text-align: center; - margin-right: 6px; - min-height: 20; - border: none; -} - -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { - border-bottom: 5px solid rgba(0, 0, 0, 48); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; + min-height: 20px; + padding-bottom: 2px; } ads--CAutoHideTab[sideBarLocation="0"], ads--CAutoHideTab[sideBarLocation="2"] { - border-top: 5px solid rgba(0, 0, 0, 48); + border-top: 6px solid rgba(0, 0, 0, 48); } +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + + ads--CAutoHideTab:hover[sideBarLocation="0"], ads--CAutoHideTab:hover[sideBarLocation="2"] { - border-top: 5px solid palette(highlight); - color: palette(highlight); + border-top: 6px solid palette(highlight); + color: palette(highlight); } ads--CAutoHideTab:hover[sideBarLocation="1"], ads--CAutoHideTab:hover[sideBarLocation="3"] { - border-bottom: 5px solid palette(highlight); - color: palette(highlight); + border-bottom: 6px solid palette(highlight); + color: palette(highlight); } ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); } ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); } @@ -218,23 +221,29 @@ ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { *****************************************************************************/ ads--CAutoHideSideBar{ background: palette(window); + border: none; + qproperty-spacing: 12; +} + +#sideTabsContainerWidget { + background: transparent; } ads--CAutoHideSideBar[sideBarLocation="0"] { - border-bottom: 1px solid palette(dark); + border-bottom: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="1"] { - border-right: 1px solid palette(dark); + border-right: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="2"] { - border-left: 1px solid palette(dark); + border-left: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="3"] { - border-top: 1px solid palette(dark); + border-top: 1px solid palette(dark); } @@ -291,10 +300,12 @@ ads--CAutoHideDockContainer #dockAreaCloseButton{ ads--CAutoHideDockContainer ads--CTitleBarButton:hover { background: rgba(255, 255, 255, 48); + border: none; } ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { background: rgba(255, 255, 255, 96); + border: none; } /***************************************************************************** diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 3a78cef14..45a878497 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -243,74 +243,84 @@ ads--CFloatingDockContainer[isActiveWindow="true"] #floatingTitleMaximizeButton: * CAutoHideTab *****************************************************************************/ ads--CAutoHideTab { - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ - padding-left: 2px; - padding-right: 0px; - text-align: center; - margin-right: 6px; - min-height: 20; - border: none; -} - -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { - border-bottom: 5px solid rgba(0, 0, 0, 48); + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; + min-height: 20px; + padding-bottom: 2px; } ads--CAutoHideTab[sideBarLocation="0"], ads--CAutoHideTab[sideBarLocation="2"] { - border-top: 5px solid rgba(0, 0, 0, 48); + border-top: 6px solid rgba(0, 0, 0, 48); +} + + +ads--CAutoHideTab[sideBarLocation="1"], +ads--CAutoHideTab[sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); } + ads--CAutoHideTab:hover[sideBarLocation="0"], ads--CAutoHideTab:hover[sideBarLocation="2"] { - border-top: 5px solid palette(highlight); - color: palette(highlight); + border-top: 6px solid palette(highlight); + color: palette(highlight); } ads--CAutoHideTab:hover[sideBarLocation="1"], ads--CAutoHideTab:hover[sideBarLocation="3"] { - border-bottom: 5px solid palette(highlight); - color: palette(highlight); + border-bottom: 6px solid palette(highlight); + color: palette(highlight); } ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { - border-top: 5px solid palette(highlight); + border-top: 6px solid palette(highlight); } ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { - border-bottom: 5px solid palette(highlight); + border-bottom: 6px solid palette(highlight); } + /***************************************************************************** * CAutoHideSideBar *****************************************************************************/ ads--CAutoHideSideBar{ background: palette(window); + border: none; + qproperty-spacing: 12; +} + +#sideTabsContainerWidget { + background: transparent; } ads--CAutoHideSideBar[sideBarLocation="0"] { - border-bottom: 1px solid palette(dark); + border-bottom: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="1"] { - border-right: 1px solid palette(dark); + border-right: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="2"] { - border-left: 1px solid palette(dark); + border-left: 1px solid palette(dark); } ads--CAutoHideSideBar[sideBarLocation="3"] { - border-top: 1px solid palette(dark); + border-top: 1px solid palette(dark); } @@ -367,10 +377,12 @@ ads--CAutoHideDockContainer #dockAreaCloseButton{ ads--CAutoHideDockContainer ads--CTitleBarButton:hover { background: rgba(255, 255, 255, 48); + border: none; } ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { background: rgba(255, 255, 255, 96); + border: none; } /***************************************************************************** From 04ea1c68a71d706e3719e3bfb78f2eed9f43a573 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 3 Nov 2022 15:28:01 +0100 Subject: [PATCH 206/236] Added option to auto hide a DockWidget or a DockArea to a specific sidebar location --- examples/autohide/mainwindow.cpp | 4 +-- src/AutoHideDockContainer.cpp | 56 +++++++++++++++++++------------- src/AutoHideSideBar.cpp | 4 +-- src/AutoHideTab.cpp | 17 ++++++---- src/DockAreaTitleBar.cpp | 37 ++++++++++++++++++++- src/DockAreaTitleBar.h | 1 + src/DockAreaWidget.cpp | 56 ++++++++++++++++---------------- src/DockAreaWidget.h | 4 +-- src/DockContainerWidget.cpp | 8 ++--- src/DockWidget.cpp | 8 ++--- src/DockWidget.h | 4 +-- src/DockWidgetTab.cpp | 32 ++++++++++++++++-- src/DockWidgetTab.h | 1 + src/ads_globals.h | 9 ++--- 14 files changed, 161 insertions(+), 80 deletions(-) diff --git a/examples/autohide/mainwindow.cpp b/examples/autohide/mainwindow.cpp index 56b6eaaf4..d70b51ce7 100644 --- a/examples/autohide/mainwindow.cpp +++ b/examples/autohide/mainwindow.cpp @@ -46,7 +46,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setWidget(table); TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->setMinimumSize(200,150); - const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget); + const auto autoHideContainer = DockManager->addAutoHideDockWidget(SideBarLocation::SideBarLeft, TableDockWidget); autoHideContainer->setSize(480); ui->menuView->addAction(TableDockWidget->toggleViewAction()); @@ -58,7 +58,7 @@ CMainWindow::CMainWindow(QWidget *parent) TableDockWidget->setMinimumSizeHintMode(CDockWidget::MinimumSizeHintFromDockWidget); TableDockWidget->resize(250, 150); TableDockWidget->setMinimumSize(200,150); - DockManager->addAutoHideDockWidget(SideBarLocation::Left, TableDockWidget); + DockManager->addAutoHideDockWidget(SideBarLocation::SideBarLeft, TableDockWidget); ui->menuView->addAction(TableDockWidget->toggleViewAction()); QTableWidget* propertiesTable = new QTableWidget(); diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 1f0f1aa56..60335963a 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -57,10 +57,12 @@ bool static isHorizontalArea(SideBarLocation Area) { switch (Area) { - case SideBarLocation::Top: - case SideBarLocation::Bottom: return true; - case SideBarLocation::Left: - case SideBarLocation::Right: return false; + case SideBarLocation::SideBarTop: + case SideBarLocation::SideBarBottom: return true; + case SideBarLocation::SideBarLeft: + case SideBarLocation::SideBarRight: return false; + default: + return true; } return true; @@ -72,10 +74,12 @@ Qt::Edge static edgeFromSideTabBarArea(SideBarLocation Area) { switch (Area) { - case SideBarLocation::Top: return Qt::BottomEdge; - case SideBarLocation::Bottom: return Qt::TopEdge; - case SideBarLocation::Left: return Qt::RightEdge; - case SideBarLocation::Right: return Qt::LeftEdge; + case SideBarLocation::SideBarTop: return Qt::BottomEdge; + case SideBarLocation::SideBarBottom: return Qt::TopEdge; + case SideBarLocation::SideBarLeft: return Qt::RightEdge; + case SideBarLocation::SideBarRight: return Qt::LeftEdge; + default: + return Qt::LeftEdge; } return Qt::LeftEdge; @@ -87,11 +91,14 @@ int resizeHandleLayoutPosition(SideBarLocation Area) { switch (Area) { - case SideBarLocation::Bottom: - case SideBarLocation::Right: return 0; + case SideBarLocation::SideBarBottom: + case SideBarLocation::SideBarRight: return 0; - case SideBarLocation::Top: - case SideBarLocation::Left: return 1; + case SideBarLocation::SideBarTop: + case SideBarLocation::SideBarLeft: return 1; + + default: + return 0; } return 0; @@ -106,8 +113,8 @@ struct AutoHideDockContainerPrivate CAutoHideDockContainer* _this; CDockAreaWidget* DockArea{nullptr}; CDockWidget* DockWidget{nullptr}; - SideBarLocation SideTabBarArea; - QBoxLayout* Layout; + SideBarLocation SideTabBarArea = SideBarNone; + QBoxLayout* Layout = nullptr; CResizeHandle* ResizeHandle = nullptr; QSize Size; // creates invalid size QPointer SideTab; @@ -124,10 +131,12 @@ struct AutoHideDockContainerPrivate { switch (area) { - case SideBarLocation::Left: return LeftDockWidgetArea; - case SideBarLocation::Right: return RightDockWidgetArea; - case SideBarLocation::Bottom: return BottomDockWidgetArea; - case SideBarLocation::Top: return TopDockWidgetArea; + case SideBarLocation::SideBarLeft: return LeftDockWidgetArea; + case SideBarLocation::SideBarRight: return RightDockWidgetArea; + case SideBarLocation::SideBarBottom: return BottomDockWidgetArea; + case SideBarLocation::SideBarTop: return TopDockWidgetArea; + default: + return LeftDockWidgetArea; } return LeftDockWidgetArea; @@ -232,17 +241,17 @@ void CAutoHideDockContainer::updateSize() switch (sideBarLocation()) { - case SideBarLocation::Top: + case SideBarLocation::SideBarTop: resize(rect.width(), qMin(rect.height() - ResizeMargin, d->Size.height())); move(rect.topLeft()); break; - case SideBarLocation::Left: + case SideBarLocation::SideBarLeft: resize(qMin(d->Size.width(), rect.width() - ResizeMargin), rect.height()); move(rect.topLeft()); break; - case SideBarLocation::Right: + case SideBarLocation::SideBarRight: { resize(qMin(d->Size.width(), rect.width() - ResizeMargin), rect.height()); QPoint p = rect.topRight(); @@ -251,7 +260,7 @@ void CAutoHideDockContainer::updateSize() } break; - case SideBarLocation::Bottom: + case SideBarLocation::SideBarBottom: { resize(rect.width(), qMin(rect.height() - ResizeMargin, d->Size.height())); QPoint p = rect.bottomLeft(); @@ -259,6 +268,9 @@ void CAutoHideDockContainer::updateSize() move(p); } break; + + default: + break; } } diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index 23babbace..fdb98ed29 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -62,7 +62,7 @@ struct AutoHideSideBarPrivate CTabsWidget* TabsContainerWidget; QBoxLayout* TabsLayout; Qt::Orientation Orientation; - SideBarLocation SideTabArea = SideBarLocation::Left; + SideBarLocation SideTabArea = SideBarLocation::SideBarLeft; /** * Convenience function to check if this is a horizontal side bar @@ -161,7 +161,7 @@ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation { d->SideTabArea = area; d->ContainerWidget = parent; - d->Orientation = (area == SideBarLocation::Bottom || area == SideBarLocation::Top) + d->Orientation = (area == SideBarLocation::SideBarBottom || area == SideBarLocation::SideBarTop) ? Qt::Horizontal : Qt::Vertical; setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 9377980a1..b8fbb2c5d 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -74,7 +74,7 @@ AutoHideTabPrivate::AutoHideTabPrivate(CAutoHideTab* _public) : void AutoHideTabPrivate::updateOrientation() { auto area = SideBar->sideBarLocation(); - _this->setOrientation((area == Bottom || area == Top) ? Qt::Horizontal : Qt::Vertical); + _this->setOrientation((area == SideBarBottom || area == SideBarTop) ? Qt::Horizontal : Qt::Vertical); if (_this->icon().isNull()) { @@ -84,21 +84,24 @@ void AutoHideTabPrivate::updateOrientation() bool IconOnly = false; switch (area) { - case SideBarLocation::Left: + case SideBarLocation::SideBarLeft: IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::LeftSideBarIconOnly); break; - case SideBarLocation::Right: + case SideBarLocation::SideBarRight: IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::RightSideBarIconOnly); break; - case SideBarLocation::Top: + case SideBarLocation::SideBarTop: IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::BottomSideBarIconOnly); break; - case SideBarLocation::Bottom: + case SideBarLocation::SideBarBottom: IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::TopSideBarIconOnly); break; + + default: + break; } if (IconOnly) @@ -133,7 +136,7 @@ void CAutoHideTab::removeFromSideBar() //============================================================================ CAutoHideTab::CAutoHideTab(QWidget* parent) : - Super(parent), + CPushButton(parent), d(new AutoHideTabPrivate(this)) { setAttribute(Qt::WA_NoMousePropagation); @@ -165,7 +168,7 @@ SideBarLocation CAutoHideTab::sideBarLocation() const return d->SideBar->sideBarLocation(); } - return Left; + return SideBarLeft; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 94781b1c0..951a42e81 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -53,11 +53,13 @@ #include "DockFocusController.h" #include "ElidingLabel.h" #include "AutoHideDockContainer.h" +#include "IconProvider.h" #include namespace ads { +static const char* const LocationProperty = "Location"; /** * Private data class of CDockAreaTitleBar class (pimpl) @@ -146,6 +148,19 @@ struct DockAreaTitleBarPrivate * Makes the dock area floating */ IFloatingWidget* makeAreaFloating(const QPoint& Offset, eDragState DragState); + + /** + * Helper function to create and initialize the menu entries for + * the "Auto Hide Group To..." menu + */ + QAction* createAutoHideToAction(const QString& Title, SideBarLocation Location, + QMenu* Menu) + { + auto Action = Menu->addAction(Title); + Action->setProperty("Location", Location); + QObject::connect(Action, &QAction::triggered, _this, &CDockAreaTitleBar::onAutoHideToActionClicked); + return Action; + } };// struct DockAreaTitleBarPrivate //============================================================================ @@ -511,6 +526,15 @@ void CDockAreaTitleBar::onAutoHideDockAreaActionClicked() } +//============================================================================ +void CDockAreaTitleBar::onAutoHideToActionClicked() +{ + qDebug() << "CDockAreaTitleBar::onAutoHideToActionClicked()"; + int Location = sender()->property(LocationProperty).toInt(); + d->DockArea->toggleAutoHide((SideBarLocation)Location); +} + + //============================================================================ QAbstractButton* CDockAreaTitleBar::button(TitleBarButton which) const { @@ -677,7 +701,18 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaActionClicked())); - Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable)); + auto AreaIsPinnable = d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable); + Action->setEnabled(AreaIsPinnable); + + if (!IsAutoHide) + { + auto menu = Menu.addMenu(tr("Auto Hide Group To...")); + menu->setEnabled(AreaIsPinnable); + d->createAutoHideToAction(tr("Top"), SideBarTop, menu); + d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); + d->createAutoHideToAction(tr("Right"), SideBarRight, menu); + d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu); + } } Menu.addSeparator(); } diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index b2c81e8cc..6cc8e50ca 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -63,6 +63,7 @@ private Q_SLOTS: void onCurrentTabChanged(int Index); void onAutoHideButtonClicked(); void onAutoHideDockAreaActionClicked(); + void onAutoHideToActionClicked(); protected: /** diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 06424c26a..4054ec1ab 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -1241,60 +1241,60 @@ SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const int BorderDistance[4]; int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y()); - BorderDistance[SideBarLocation::Top] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Top]) + BorderDistance[SideBarLocation::SideBarTop] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::SideBarTop]) { borders |= BorderTop; } Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y()); - BorderDistance[SideBarLocation::Bottom] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Bottom]) + BorderDistance[SideBarLocation::SideBarBottom] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::SideBarBottom]) { borders |= BorderBottom; } Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x()); - BorderDistance[SideBarLocation::Left] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Left]) + BorderDistance[SideBarLocation::SideBarLeft] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::SideBarLeft]) { borders |= BorderLeft; } Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x()); - BorderDistance[SideBarLocation::Right] = (Distance < MinBorderDistance) ? 0 : Distance; - if (!BorderDistance[SideBarLocation::Right]) + BorderDistance[SideBarLocation::SideBarRight] = (Distance < MinBorderDistance) ? 0 : Distance; + if (!BorderDistance[SideBarLocation::SideBarRight]) { borders |= BorderRight; } - auto SideTab = SideBarLocation::Right; + auto SideTab = SideBarLocation::SideBarRight; switch (borders) { // 1. It's touching all borders - case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; + case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarRight; break; // 2. It's touching 3 borders - case BorderVerticalBottom : SideTab = SideBarLocation::Bottom; break; - case BorderVerticalTop : SideTab = SideBarLocation::Top; break; - case BorderHorizontalLeft: SideTab = SideBarLocation::Left; break; - case BorderHorizontalRight: SideTab = SideBarLocation::Right; break; + case BorderVerticalBottom : SideTab = SideBarLocation::SideBarBottom; break; + case BorderVerticalTop : SideTab = SideBarLocation::SideBarTop; break; + case BorderHorizontalLeft: SideTab = SideBarLocation::SideBarLeft; break; + case BorderHorizontalRight: SideTab = SideBarLocation::SideBarRight; break; // 3. Its touching horizontal or vertical borders - case BorderVertical : SideTab = SideBarLocation::Bottom; break; - case BorderHorizontal: SideTab = SideBarLocation::Right; break; + case BorderVertical : SideTab = SideBarLocation::SideBarBottom; break; + case BorderHorizontal: SideTab = SideBarLocation::SideBarRight; break; // 4. Its in a corner - case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Left; break; - case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::Top : SideBarLocation::Right; break; - case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Left; break; - case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::Bottom : SideBarLocation::Right; break; + case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::SideBarTop : SideBarLocation::SideBarLeft; break; + case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::SideBarTop : SideBarLocation::SideBarRight; break; + case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarLeft; break; + case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarRight; break; // 5 Ists touching only one border - case BorderLeft: SideTab = SideBarLocation::Left; break; - case BorderRight: SideTab = SideBarLocation::Right; break; - case BorderTop: SideTab = SideBarLocation::Top; break; - case BorderBottom: SideTab = SideBarLocation::Bottom; break; + case BorderLeft: SideTab = SideBarLocation::SideBarLeft; break; + case BorderRight: SideTab = SideBarLocation::SideBarRight; break; + case BorderTop: SideTab = SideBarLocation::SideBarTop; break; + case BorderBottom: SideTab = SideBarLocation::SideBarBottom; break; } return SideTab; @@ -1302,7 +1302,7 @@ SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const //============================================================================ -void CDockAreaWidget::setAutoHide(bool Enable) +void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location) { if (!isAutoHideFeatureEnabled()) { @@ -1318,7 +1318,7 @@ void CDockAreaWidget::setAutoHide(bool Enable) return; } - auto area = calculateSideTabBarArea(); + auto area = (SideBarNone == Location) ? calculateSideTabBarArea() : Location; for (const auto DockWidget : openedDockWidgets()) { if (Enable == isAutoHide()) @@ -1337,14 +1337,14 @@ void CDockAreaWidget::setAutoHide(bool Enable) //============================================================================ -void CDockAreaWidget::toggleAutoHide() +void CDockAreaWidget::toggleAutoHide(SideBarLocation Location) { if (!isAutoHideFeatureEnabled()) { return; } - setAutoHide(!isAutoHide()); + setAutoHide(!isAutoHide(), Location); } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index b79107cc6..fface9928 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -401,13 +401,13 @@ public Q_SLOTS: * If the dock area is switched to auto hide mode, then all dock widgets * that are pinable will be added to the sidebar */ - void setAutoHide(bool Enable); + void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone); /** * Switches the dock area to auto hide mode or vice versa depending on its * current state. */ - void toggleAutoHide(); + void toggleAutoHide(SideBarLocation Location = SideBarNone); /** * This function closes all other areas except of this area diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index a90f99073..43b059473 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1842,25 +1842,25 @@ void CDockContainerWidget::createSideTabBarWidgets() } { - auto Area = SideBarLocation::Left; + auto Area = SideBarLocation::SideBarLeft; d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 0); } { - auto Area = SideBarLocation::Right; + auto Area = SideBarLocation::SideBarRight; d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 1, 2); } { - auto Area = SideBarLocation::Bottom; + auto Area = SideBarLocation::SideBarBottom; d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 2, 1); } { - auto Area = SideBarLocation::Top; + auto Area = SideBarLocation::SideBarTop; d->SideTabBarWidgets[Area] = new CAutoHideSideBar(this, Area); d->Layout->addWidget(d->SideTabBarWidgets[Area], 0, 1); } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index 31f3cb979..e519880f0 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -1157,7 +1157,7 @@ void CDockWidget::raise() //============================================================================ -void CDockWidget::setAutoHide(bool Enable) +void CDockWidget::setAutoHide(bool Enable, SideBarLocation Location) { if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { @@ -1177,21 +1177,21 @@ void CDockWidget::setAutoHide(bool Enable) } else { - auto area = DockArea->calculateSideTabBarArea(); + auto area = (SideBarNone == Location) ? DockArea->calculateSideTabBarArea() : Location; dockContainer()->createAndSetupAutoHideContainer(area, this); } } //============================================================================ -void CDockWidget::toggleAutoHide() +void CDockWidget::toggleAutoHide(SideBarLocation Location) { if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { return; } - setAutoHide(!isAutoHide()); + setAutoHide(!isAutoHide(), Location); } diff --git a/src/DockWidget.h b/src/DockWidget.h index 115c02c75..c0d0d91df 100644 --- a/src/DockWidget.h +++ b/src/DockWidget.h @@ -596,13 +596,13 @@ public Q_SLOTS: * Sets the dock widget into auto hide mode if this feature is enabled * via CDockManager::setAutoHideFlags(CDockManager::AutoHideFeatureEnabled) */ - void setAutoHide(bool Enable); + void setAutoHide(bool Enable, SideBarLocation Location = SideBarNone); /** * Switches the dock widget to auto hide mode or vice versa depending on its * current state. */ - void toggleAutoHide(); + void toggleAutoHide(SideBarLocation Location = SideBarNone); Q_SIGNALS: diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index aa904c778..844a9fbd1 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -56,7 +56,7 @@ namespace ads { - +static const char* const LocationProperty = "Location"; using tTabLabel = CElidingLabel; /** @@ -217,6 +217,18 @@ struct DockWidgetTabPrivate return DockWidget->dockManager()->dockFocusController(); } + /** + * Helper function to create and initialize the menu entries for + * the "Auto Hide Group To..." menu + */ + QAction* createAutoHideToAction(const QString& Title, SideBarLocation Location, + QMenu* Menu) + { + auto Action = Menu->addAction(Title); + Action->setProperty("Location", Location); + QObject::connect(Action, &QAction::triggered, _this, &CDockWidgetTab::onAutoHideToActionClicked); + return Action; + } }; // struct DockWidgetTabPrivate @@ -518,7 +530,15 @@ void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev) if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { Action = Menu.addAction(tr("Auto Hide"), this, SLOT(autoHideDockWidget())); - Action->setEnabled(d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable)); + auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable); + Action->setEnabled(IsPinnable); + + auto menu = Menu.addMenu(tr("Auto Hide To...")); + menu->setEnabled(IsPinnable); + d->createAutoHideToAction(tr("Top"), SideBarTop, menu); + d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); + d->createAutoHideToAction(tr("Right"), SideBarRight, menu); + d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu); } Menu.addSeparator(); Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested())); @@ -712,6 +732,14 @@ void CDockWidgetTab::autoHideDockWidget() } +//=========================================================================== +void CDockWidgetTab::onAutoHideToActionClicked() +{ + int Location = sender()->property(LocationProperty).toInt(); + d->DockWidget->toggleAutoHide((SideBarLocation)Location); +} + + //============================================================================ bool CDockWidgetTab::event(QEvent *e) { diff --git a/src/DockWidgetTab.h b/src/DockWidgetTab.h index df32ef03a..11d0ba512 100644 --- a/src/DockWidgetTab.h +++ b/src/DockWidgetTab.h @@ -64,6 +64,7 @@ class ADS_EXPORT CDockWidgetTab : public QFrame private Q_SLOTS: void detachDockWidget(); void autoHideDockWidget(); + void onAutoHideToActionClicked(); protected: virtual void mousePressEvent(QMouseEvent* ev) override; diff --git a/src/ads_globals.h b/src/ads_globals.h index 3260f87f4..1b86b012d 100644 --- a/src/ads_globals.h +++ b/src/ads_globals.h @@ -136,10 +136,11 @@ enum eBitwiseOperator */ enum SideBarLocation { - Top, - Left, - Right, - Bottom + SideBarTop, + SideBarLeft, + SideBarRight, + SideBarBottom, + SideBarNone }; Q_ENUMS(SideBarLocation); From 409d4489ccaadfaa11555bea0b5d41fce22bf418 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 3 Nov 2022 16:44:40 +0100 Subject: [PATCH 207/236] Added support for auto hiding a dock area / widget to a specific border via context menu --- demo/MainWindow.cpp | 1 + src/AutoHideSideBar.h | 3 --- src/DockAreaTitleBar.cpp | 17 ++++++++--------- src/DockAreaWidget.cpp | 22 ++++++++++------------ src/DockWidgetTab.cpp | 40 ++++++++++++++++++++++++---------------- 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index e46bd7c49..f980b8470 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -655,6 +655,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); + CDockManager::setConfigFlag(CDockManager::AlwaysShowTabs, true); // uncomment if you would like to enable dock widget auto hiding CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); diff --git a/src/AutoHideSideBar.h b/src/AutoHideSideBar.h index 3e57e2b25..b452ee023 100644 --- a/src/AutoHideSideBar.h +++ b/src/AutoHideSideBar.h @@ -150,9 +150,6 @@ class ADS_EXPORT CAutoHideSideBar : public QScrollArea * Setter for spacing property - sets the spacing */ void setSpacing(int Spacing); - -Q_SIGNALS: - void sideTabAutoHideToggleRequested(); }; } // namespace ads //----------------------------------------------------------------------------- diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 951a42e81..ed06c1832 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -689,22 +689,22 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) return; } - bool IsAutoHide = d->DockArea->isAutoHide(); - bool IsTopLevelArea = d->DockArea->isTopLevelArea(); + const bool isAutoHide = d->DockArea->isAutoHide(); + const bool isTopLevelArea = d->DockArea->isTopLevelArea(); QAction* Action; QMenu Menu(this); - if (!IsTopLevelArea) + if (!isTopLevelArea) { - Action = Menu.addAction(IsAutoHide ? tr("Detach") : tr("Detach Group"), + Action = Menu.addAction(isAutoHide ? tr("Detach") : tr("Detach Group"), this, SLOT(onUndockButtonClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { - Action = Menu.addAction(IsAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaActionClicked())); + Action = Menu.addAction(isAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaActionClicked())); auto AreaIsPinnable = d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable); Action->setEnabled(AreaIsPinnable); - if (!IsAutoHide) + if (!isAutoHide) { auto menu = Menu.addMenu(tr("Auto Hide Group To...")); menu->setEnabled(AreaIsPinnable); @@ -716,12 +716,11 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) } Menu.addSeparator(); } - Action = Menu.addAction(IsAutoHide ? tr("Close") : tr("Close Group"), this, SLOT(onCloseButtonClicked())); + Action = Menu.addAction(isAutoHide ? tr("Close") : tr("Close Group"), this, SLOT(onCloseButtonClicked())); Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetClosable)); - if (!IsAutoHide) + if (!isAutoHide && !isTopLevelArea) { Action = Menu.addAction(tr("Close Other Groups"), d->DockArea, SLOT(closeOtherAreas())); - Action->setEnabled(!IsTopLevelArea); } Menu.exec(ev->globalPos()); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 4054ec1ab..1697ad601 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -537,7 +537,7 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { setCurrentDockWidget(NextOpenDockWidget); } - else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1) // Don't remove empty dock areas that are auto hidden, they'll be deleted by the auto hide dock + else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1) { ADS_PRINT("Dock Area empty"); DockContainer->removeDockArea(this); @@ -827,22 +827,20 @@ void CDockAreaWidget::updateTitleBarVisibility() return; } - if (CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs)) - { - return; - } - if (!d->TitleBar) { return; } - bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() - || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); - Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); - bool IsAutoHide = isAutoHide(); - Hidden &= !IsAutoHide; // Titlebar must always be visible when auto hidden so it can be dragged - d->TitleBar->setVisible(!Hidden); + bool IsAutoHide = isAutoHide(); + if (!CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs)) + { + bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating() + || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar)); + Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1); + Hidden &= !IsAutoHide; // Titlebar must always be visible when auto hidden so it can be dragged + d->TitleBar->setVisible(!Hidden); + } if (isAutoHideFeatureEnabled()) { diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index 844a9fbd1..5d1ce0445 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -518,32 +518,40 @@ void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev) } d->saveDragStartMousePosition(ev->globalPos()); - QMenu Menu(this); const bool isFloatable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetFloatable); const bool isNotOnlyTabInContainer = !d->DockArea->dockContainer()->hasTopLevelDockWidget(); - + const bool isTopLevelArea = d->DockArea->isTopLevelArea(); const bool isDetachable = isFloatable && isNotOnlyTabInContainer; + QAction* Action; + QMenu Menu(this); - auto Action = Menu.addAction(tr("Detach"), this, SLOT(detachDockWidget())); - Action->setEnabled(isDetachable); - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + if (!isTopLevelArea) { - Action = Menu.addAction(tr("Auto Hide"), this, SLOT(autoHideDockWidget())); - auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable); - Action->setEnabled(IsPinnable); - - auto menu = Menu.addMenu(tr("Auto Hide To...")); - menu->setEnabled(IsPinnable); - d->createAutoHideToAction(tr("Top"), SideBarTop, menu); - d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); - d->createAutoHideToAction(tr("Right"), SideBarRight, menu); - d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu); + Action = Menu.addAction(tr("Detach"), this, SLOT(detachDockWidget())); + Action->setEnabled(isDetachable); + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) + { + Action = Menu.addAction(tr("Auto Hide"), this, SLOT(autoHideDockWidget())); + auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable); + Action->setEnabled(IsPinnable); + + auto menu = Menu.addMenu(tr("Auto Hide To...")); + menu->setEnabled(IsPinnable); + d->createAutoHideToAction(tr("Top"), SideBarTop, menu); + d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); + d->createAutoHideToAction(tr("Right"), SideBarRight, menu); + d->createAutoHideToAction(tr("Bottom"), SideBarBottom, menu); + } } + Menu.addSeparator(); Action = Menu.addAction(tr("Close"), this, SIGNAL(closeRequested())); Action->setEnabled(isClosable()); - Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested())); + if (d->DockArea->openDockWidgetsCount() > 1) + { + Action = Menu.addAction(tr("Close Others"), this, SIGNAL(closeOtherTabsRequested())); + } Menu.exec(ev->globalPos()); } From 5e59a6dc3a44be277892da0186eaea068262c873 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 3 Nov 2022 16:49:20 +0100 Subject: [PATCH 208/236] Removed debug output --- src/AutoHideDockContainer.cpp | 1 - src/AutoHideSideBar.cpp | 4 +--- src/AutoHideTab.cpp | 2 +- src/DockAreaTitleBar.cpp | 2 -- src/DockAreaWidget.cpp | 1 - src/FloatingDockContainer.cpp | 1 - 6 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 60335963a..f38c2f924 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -277,7 +277,6 @@ void CAutoHideDockContainer::updateSize() //============================================================================ CAutoHideDockContainer::~CAutoHideDockContainer() { - qDebug() << "~CAutoHideDockContainer()" ADS_PRINT("~CAutoHideDockContainer"); // Remove event filter in case there are any queued messages diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index fdb98ed29..066c06016 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -193,8 +193,6 @@ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); } - qDebug() << "d->TabsLayout->count " << d->TabsLayout->count(); - hide(); } @@ -202,7 +200,7 @@ CAutoHideSideBar::CAutoHideSideBar(CDockContainerWidget* parent, SideBarLocation //============================================================================ CAutoHideSideBar::~CAutoHideSideBar() { - qDebug() << "~CSideTabBar() "; + ADS_PRINT("~CSideTabBar()"); // The SideTabeBar is not the owner of the tabs and to prevent deletion // we set the parent here to nullptr to remove it from the children auto Tabs = findChildren(QString(), Qt::FindDirectChildrenOnly); diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index b8fbb2c5d..85a17f8dc 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -147,7 +147,7 @@ CAutoHideTab::CAutoHideTab(QWidget* parent) : //============================================================================ CAutoHideTab::~CAutoHideTab() { - qDebug() << "~CDockWidgetSideTab()"; + ADS_PRINT("~CDockWidgetSideTab()"); delete d; } diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index ed06c1832..91737c2e7 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -513,7 +513,6 @@ void CDockAreaTitleBar::onAutoHideButtonClicked() } else { - qDebug() << "d->DockArea->currentDockWidget()->toggleAutoHide()"; d->DockArea->currentDockWidget()->toggleAutoHide(); } } @@ -529,7 +528,6 @@ void CDockAreaTitleBar::onAutoHideDockAreaActionClicked() //============================================================================ void CDockAreaTitleBar::onAutoHideToActionClicked() { - qDebug() << "CDockAreaTitleBar::onAutoHideToActionClicked()"; int Location = sender()->property(LocationProperty).toInt(); d->DockArea->toggleAutoHide((SideBarLocation)Location); } diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 1697ad601..5d7df44d2 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -984,7 +984,6 @@ bool CDockAreaWidget::restoreState(CDockingStateReader& s, CDockAreaWidget*& Cre // We hide the DockArea here to prevent the short display (the flashing) // of the dock areas during application startup DockArea->hide(); - qDebug() << "DockArea->addDockWidget " << DockWidget->windowTitle(); DockArea->addDockWidget(DockWidget); DockWidget->setToggleViewActionChecked(!Closed); DockWidget->setClosedState(Closed); diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 571c5f12f..2152b6b1d 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -721,7 +721,6 @@ CFloatingDockContainer::CFloatingDockContainer(CDockWidget *DockWidget) : //============================================================================ CFloatingDockContainer::~CFloatingDockContainer() { - qDebug() << "~CFloatingDockContainer " << windowTitle(); ADS_PRINT("~CFloatingDockContainer"); if (d->DockManager) { From 27d71eecac0f993eeeed4548da65c9545990ec74 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Thu, 3 Nov 2022 20:00:03 +0100 Subject: [PATCH 209/236] Fixed restoreDockWidgetsOpenState() function to delete legacy auto hide widgets --- src/DockManager.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 08b7a9c30..27fcf09b9 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -156,7 +156,7 @@ struct DockManagerPrivate { for (auto DockWidget : DockWidgetsMap) { - DockWidget->setProperty("dirty", true); + DockWidget->setProperty(internal::DirtyProperty, true); } } @@ -349,6 +349,12 @@ void DockManagerPrivate::restoreDockWidgetsOpenState() { if (DockWidget->property(internal::DirtyProperty).toBool()) { + // If the DockWidget is an auto hide widget that is not assigned yet, + // then we need to delete the auto hide container now + if (DockWidget->isAutoHide()) + { + DockWidget->autoHideDockContainer()->cleanupAndDelete(); + } DockWidget->flagAsUnassigned(); Q_EMIT DockWidget->viewToggled(false); } From c0247fc02a0ebcda4088c5a14ff8922948895d57 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 08:51:17 +0100 Subject: [PATCH 210/236] Added option ShowAutoHideOnMouseOver that enables showing of auto hide widgets by hovering over auto hide tab --- src/AutoHideDockContainer.cpp | 52 +++++++++++++++++--- src/AutoHideDockContainer.h | 10 ++-- src/AutoHideTab.cpp | 45 +++++++++++++++++ src/AutoHideTab.h | 3 ++ src/DockContainerWidget.cpp | 93 +++++++++++++++++++++++++++++++++-- src/DockContainerWidget.h | 13 ++++- src/DockManager.h | 1 + 7 files changed, 202 insertions(+), 15 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index f38c2f924..7ddec6fe8 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -147,7 +147,7 @@ struct AutoHideDockContainerPrivate */ void updateResizeHandleSizeLimitMax() { - auto Rect = _this->parentContainer()->contentRect(); + auto Rect = _this->dockContainer()->contentRect(); const auto maxResizeHandleSize = ResizeHandle->orientation() == Qt::Horizontal ? Rect.width() : Rect.height(); ResizeHandle->setMaxResizeSize(maxResizeHandleSize - ResizeMargin); @@ -161,6 +161,18 @@ struct AutoHideDockContainerPrivate return isHorizontalArea(SideTabBarArea); } + /** + * Forward this event to the dock container + */ + void forwardEventToDockContainer(QEvent* event) + { + auto DockContainer = _this->dockContainer(); + if (DockContainer) + { + DockContainer->handleAutoHideWidgetEvent(event, _this); + } + } + }; // struct AutoHideDockContainerPrivate @@ -174,7 +186,7 @@ AutoHideDockContainerPrivate::AutoHideDockContainerPrivate( //============================================================================ -CDockContainerWidget* CAutoHideDockContainer::parentContainer() const +CDockContainerWidget* CAutoHideDockContainer::dockContainer() const { if (d->DockArea) { @@ -231,7 +243,7 @@ CAutoHideDockContainer::CAutoHideDockContainer(CDockWidget* DockWidget, SideBarL //============================================================================ void CAutoHideDockContainer::updateSize() { - auto dockContainerParent = parentContainer(); + auto dockContainerParent = dockContainer(); if (!dockContainerParent) { return; @@ -281,9 +293,9 @@ CAutoHideDockContainer::~CAutoHideDockContainer() // Remove event filter in case there are any queued messages qApp->removeEventFilter(this); - if (parentContainer()) + if (dockContainer()) { - parentContainer()->removeAutoHideWidget(this); + dockContainer()->removeAutoHideWidget(this); } if (d->SideTab) @@ -297,7 +309,7 @@ CAutoHideDockContainer::~CAutoHideDockContainer() //============================================================================ CAutoHideSideBar* CAutoHideDockContainer::sideBar() const { - return parentContainer()->sideTabBar(d->SideTabBarArea); + return dockContainer()->sideTabBar(d->SideTabBarArea); } @@ -366,7 +378,7 @@ void CAutoHideDockContainer::moveContentsToParent() // location like it had as a auto hide widget. This brings the least surprise // to the user and he does not have to search where the widget was inserted. d->DockWidget->setDockArea(nullptr); - parentContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); + dockContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); } @@ -479,7 +491,7 @@ bool CAutoHideDockContainer::eventFilter(QObject* watched, QEvent* event) } else if (event->type() == QEvent::MouseButtonPress) { - auto Container = parentContainer(); + auto Container = dockContainer(); // First we check, if the mouse button press is inside the container // widget. If it is not, i.e. if someone resizes the main window or // clicks into the application menu or toolbar, then we ignore the @@ -543,5 +555,29 @@ void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) } } + +//============================================================================ +void CAutoHideDockContainer::leaveEvent(QEvent *event) +{ + d->forwardEventToDockContainer(event); + Super::leaveEvent(event); +} + + +//============================================================================ +void CAutoHideDockContainer::enterEvent(QEvent *event) +{ + d->forwardEventToDockContainer(event); + Super::enterEvent(event); +} + + +//============================================================================ +void CAutoHideDockContainer::hideEvent(QHideEvent *event) +{ + d->forwardEventToDockContainer(event); + Super::hideEvent(event); +} + } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 9823ac071..7c222f43b 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -61,8 +61,12 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame friend SideTabBarPrivate; protected: - bool eventFilter(QObject* watched, QEvent* event) override; - void resizeEvent(QResizeEvent* event) override; + virtual bool eventFilter(QObject* watched, QEvent* event) override; + virtual void resizeEvent(QResizeEvent* event) override; + virtual void leaveEvent(QEvent *event) override; + virtual void enterEvent(QEvent *event) override; + virtual void hideEvent(QHideEvent *event) override; + /** * Updates the size considering the size limits and the resize margins @@ -126,7 +130,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame /** * Returns the parent container that hosts this auto hide container */ - CDockContainerWidget* parentContainer() const; + CDockContainerWidget* dockContainer() const; /** * Moves the contents to the parent container widget diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 85a17f8dc..9a812604a 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -30,6 +30,7 @@ #include "AutoHideTab.h" #include +#include #include "AutoHideDockContainer.h" #include "AutoHideSideBar.h" @@ -59,6 +60,26 @@ struct AutoHideTabPrivate * the side bar */ void updateOrientation(); + + /** + * Convenience function to ease dock container access + */ + CDockContainerWidget* dockContainer() const + { + return DockWidget ? DockWidget->dockContainer() : nullptr; + } + + /** + * Forward this event to the dock container + */ + void forwardEventToDockContainer(QEvent* event) + { + auto DockContainer = dockContainer(); + if (DockContainer) + { + DockContainer->handleAutoHideWidgetEvent(event, _this); + } + } }; // struct DockWidgetTabPrivate @@ -228,4 +249,28 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) setIcon(d->DockWidget->icon()); } + +//============================================================================ +void CAutoHideTab::enterEvent(QEvent *event) +{ + d->forwardEventToDockContainer(event); + Super::enterEvent(event); +} + + +//============================================================================ +void CAutoHideTab::leaveEvent(QEvent *event) +{ + d->forwardEventToDockContainer(event); + Super::leaveEvent(event); +} + + +//============================================================================ +void CAutoHideTab::mousePressEvent(QMouseEvent* event) +{ + d->forwardEventToDockContainer(event); + Super::mousePressEvent(event); +} + } diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index d3783b9fc..2a942b42e 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -67,6 +67,9 @@ class ADS_EXPORT CAutoHideTab : public CPushButton void setSideBar(CAutoHideSideBar *SideTabBar); void removeFromSideBar(); + virtual void enterEvent(QEvent *event) override; + virtual void leaveEvent(QEvent *event) override; + virtual void mousePressEvent(QMouseEvent* event) override; public: using Super = CPushButton; diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 43b059473..141debc09 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -28,9 +28,6 @@ //============================================================================ // INCLUDES //============================================================================ -#include -#include -#include #include "DockContainerWidget.h" #include @@ -42,6 +39,10 @@ #include #include #include +#include +#include +#include +#include #include "DockManager.h" #include "DockAreaWidget.h" @@ -54,6 +55,9 @@ #include "DockWidgetTab.h" #include "DockAreaTitleBar.h" #include "DockFocusController.h" +#include "AutoHideDockContainer.h" +#include "AutoHideSideBar.h" +#include "AutoHideTab.h" #include #include @@ -146,6 +150,9 @@ class DockContainerWidgetPrivate CDockAreaWidget* LastAddedAreaCache[5]; int VisibleDockAreaCount = -1; CDockAreaWidget* TopLevelDockArea = nullptr; + QTimer DelayedAutoHideTimer; + CAutoHideTab* DelayedAutoHideTab; + bool DelayedAutoHideShow = false; /** * Private data constructor @@ -371,6 +378,14 @@ DockContainerWidgetPrivate::DockContainerWidgetPrivate(CDockContainerWidget* _pu _this(_public) { std::fill(std::begin(LastAddedAreaCache),std::end(LastAddedAreaCache), nullptr); + DelayedAutoHideTimer.setSingleShot(true); + DelayedAutoHideTimer.setInterval(500); + QObject::connect(&DelayedAutoHideTimer, &QTimer::timeout, [this](){ + qDebug() << "DelayedAutoHideTimer timeout"; + auto GlobalPos = DelayedAutoHideTab->mapToGlobal(QPoint(0, 0)); + qApp->sendEvent(DelayedAutoHideTab, new QMouseEvent(QEvent::MouseButtonPress, + QPoint(0, 0), GlobalPos, Qt::LeftButton, {Qt::LeftButton}, Qt::NoModifier)); + }); } @@ -2045,6 +2060,78 @@ CDockManager* CDockContainerWidget::dockManager() const { return d->DockManager; } + + +//=========================================================================== +void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w) +{ + if (!CDockManager::testAutoHideConfigFlag(CDockManager::ShowAutoHideOnMouseOver)) + { + return; + } + + if (dockManager()->isRestoringState()) + { + return; + } + + auto AutoHideTab = qobject_cast(w); + if (AutoHideTab) + { + qDebug() << "Event AutoHideTab " << e; + switch (e->type()) + { + case QEvent::Enter: + if (!AutoHideTab->dockWidget()->isVisible()) + { + d->DelayedAutoHideTab = AutoHideTab; + d->DelayedAutoHideShow = true; + d->DelayedAutoHideTimer.start(); + } + else + { + d->DelayedAutoHideTimer.stop(); + } + break; + + case QEvent::Leave: + case QEvent::MouseButtonPress: + d->DelayedAutoHideTimer.stop(); + break; + + default: + break; + } + return; + } + + auto AutoHideContainer = qobject_cast(w); + if (AutoHideContainer) + { + qDebug() << "Event AutoHideContainer " << e; + switch (e->type()) + { + case QEvent::Enter: + case QEvent::Hide: + d->DelayedAutoHideTimer.stop(); + break; + + case QEvent::Leave: + if (AutoHideContainer->isVisible()) + { + d->DelayedAutoHideTab = AutoHideContainer->autoHideTab(); + d->DelayedAutoHideShow = false; + d->DelayedAutoHideTimer.start(); + } + break; + + default: + break; + } + return; + return; + } +} } // namespace ads //--------------------------------------------------------------------------- diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 247c698b8..dd73e504b 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -52,6 +52,9 @@ class CFloatingDragPreview; struct FloatingDragPreviewPrivate; class CDockingStateReader; class CAutoHideSideBar; +class CAutoHideTab; +struct AutoHideTabPrivate; +struct AutoHideDockContainerPrivate; /** @@ -76,7 +79,10 @@ class ADS_EXPORT CDockContainerWidget : public QFrame friend class CDockWidget; friend class CFloatingDragPreview; friend struct FloatingDragPreviewPrivate; - friend class CAutoHideDockContainer; + friend CAutoHideDockContainer; + friend CAutoHideTab; + friend AutoHideTabPrivate; + friend AutoHideDockContainerPrivate; protected: /** @@ -190,6 +196,11 @@ class ADS_EXPORT CDockContainerWidget : public QFrame */ void removeAutoHideWidget(CAutoHideDockContainer* AutoHideWidget); + /** + * Handles widget events of auto hide widgets to trigger delayed show + * or hide actions for auto hide container on auto hide tab mouse over + */ + void handleAutoHideWidgetEvent(QEvent* e, QWidget* w); public: /** diff --git a/src/DockManager.h b/src/DockManager.h index ed6d2cf28..ceb16f339 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -243,6 +243,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget BottomSideBarIconOnly = 0x40,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned TopSideBarIconOnly = 0x80, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned AutoHideSideBarsIconOnly = LeftSideBarIconOnly | RightSideBarIconOnly | BottomSideBarIconOnly | TopSideBarIconOnly, + ShowAutoHideOnMouseOver = 0x100, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars From 279a9d7df9800a59977223deaed5c15e946da9e9 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 09:41:00 +0100 Subject: [PATCH 211/236] Fixed delayed hiding of CAutoHideDockContainer on mouse leave when resizing --- src/AutoHideDockContainer.cpp | 10 ++++++- src/AutoHideTab.cpp | 40 ++++++-------------------- src/DockContainerWidget.cpp | 17 ++++++++--- src/DockManager.h | 8 ++---- src/stylesheets/focus_highlighting.css | 9 ++++-- 5 files changed, 39 insertions(+), 45 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7ddec6fe8..7dae89670 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include "DockManager.h" #include "DockWidgetTab.h" @@ -559,7 +560,14 @@ void CAutoHideDockContainer::resizeEvent(QResizeEvent* event) //============================================================================ void CAutoHideDockContainer::leaveEvent(QEvent *event) { - d->forwardEventToDockContainer(event); + // Resizing of the dock container via the resize handle in non opaque mode + // mays cause a leave event that is not really a leave event. Therefore + // we check here, if we are really outside of our rect. + auto pos = mapFromGlobal(QCursor::pos()); + if (!rect().contains(pos)) + { + d->forwardEventToDockContainer(event); + } Super::leaveEvent(event); } diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 9a812604a..3d7e3fafa 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -94,41 +94,17 @@ AutoHideTabPrivate::AutoHideTabPrivate(CAutoHideTab* _public) : //============================================================================ void AutoHideTabPrivate::updateOrientation() { - auto area = SideBar->sideBarLocation(); - _this->setOrientation((area == SideBarBottom || area == SideBarTop) ? Qt::Horizontal : Qt::Vertical); - - if (_this->icon().isNull()) - { - return; - } - - bool IconOnly = false; - switch (area) - { - case SideBarLocation::SideBarLeft: - IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::LeftSideBarIconOnly); - break; - - case SideBarLocation::SideBarRight: - IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::RightSideBarIconOnly); - break; - - case SideBarLocation::SideBarTop: - IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::BottomSideBarIconOnly); - break; - - case SideBarLocation::SideBarBottom: - IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::TopSideBarIconOnly); - break; - - default: - break; - } - - if (IconOnly) + bool IconOnly = CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideSideBarsIconOnly); + if (IconOnly && !_this->icon().isNull()) { _this->setText(""); _this->setOrientation(Qt::Horizontal); + _this->updateStyle(); + } + else + { + auto area = SideBar->sideBarLocation(); + _this->setOrientation((area == SideBarBottom || area == SideBarTop) ? Qt::Horizontal : Qt::Vertical); } } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 141debc09..2ddb1ab84 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -381,7 +381,6 @@ DockContainerWidgetPrivate::DockContainerWidgetPrivate(CDockContainerWidget* _pu DelayedAutoHideTimer.setSingleShot(true); DelayedAutoHideTimer.setInterval(500); QObject::connect(&DelayedAutoHideTimer, &QTimer::timeout, [this](){ - qDebug() << "DelayedAutoHideTimer timeout"; auto GlobalPos = DelayedAutoHideTab->mapToGlobal(QPoint(0, 0)); qApp->sendEvent(DelayedAutoHideTab, new QMouseEvent(QEvent::MouseButtonPress, QPoint(0, 0), GlobalPos, Qt::LeftButton, {Qt::LeftButton}, Qt::NoModifier)); @@ -2078,7 +2077,6 @@ void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w) auto AutoHideTab = qobject_cast(w); if (AutoHideTab) { - qDebug() << "Event AutoHideTab " << e; switch (e->type()) { case QEvent::Enter: @@ -2094,11 +2092,23 @@ void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w) } break; - case QEvent::Leave: case QEvent::MouseButtonPress: d->DelayedAutoHideTimer.stop(); break; + case QEvent::Leave: + if (AutoHideTab->dockWidget()->isVisible()) + { + d->DelayedAutoHideTab = AutoHideTab; + d->DelayedAutoHideShow = false; + d->DelayedAutoHideTimer.start(); + } + else + { + d->DelayedAutoHideTimer.stop(); + } + break; + default: break; } @@ -2108,7 +2118,6 @@ void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w) auto AutoHideContainer = qobject_cast(w); if (AutoHideContainer) { - qDebug() << "Event AutoHideContainer " << e; switch (e->type()) { case QEvent::Enter: diff --git a/src/DockManager.h b/src/DockManager.h index ceb16f339..4fb3c8d4c 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -238,12 +238,8 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget DockAreaHasAutoHideButton = 0x02, //!< If the flag is set each dock area has a auto hide menu button AutoHideButtonTogglesArea = 0x04, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled AutoHideButtonCheckable = 0x08, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. - LeftSideBarIconOnly = 0x10, //!< If the flag is set left side bar will show only icon if a the dock widget has an icon assigned - RightSideBarIconOnly = 0x20, //!< If the flag is set right side bar will show only icon if a the dock widget has an icon assigned - BottomSideBarIconOnly = 0x40,//!< If the flag is set bottom side show only icon if a the dock widget has an icon assigned - TopSideBarIconOnly = 0x80, //!< If the flag is set top side bar show only icon if a the dock widget has an icon assigned - AutoHideSideBarsIconOnly = LeftSideBarIconOnly | RightSideBarIconOnly | BottomSideBarIconOnly | TopSideBarIconOnly, - ShowAutoHideOnMouseOver = 0x100, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container + AutoHideSideBarsIconOnly = 0x10,///< show only icons in auto hide side tab - if a tab has no icon, then the text will be shown + ShowAutoHideOnMouseOver = 0x20, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 105776928..3b014521e 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -179,6 +179,12 @@ ads--CAutoHideTab { } +ads--CAutoHideTab:hover +{ + color: palette(highlight); +} + + ads--CAutoHideTab[sideBarLocation="0"], ads--CAutoHideTab[sideBarLocation="2"] { border-top: 6px solid rgba(0, 0, 0, 48); @@ -195,14 +201,12 @@ ads--CAutoHideTab[sideBarLocation="3"] { ads--CAutoHideTab:hover[sideBarLocation="0"], ads--CAutoHideTab:hover[sideBarLocation="2"] { border-top: 6px solid palette(highlight); - color: palette(highlight); } ads--CAutoHideTab:hover[sideBarLocation="1"], ads--CAutoHideTab:hover[sideBarLocation="3"] { border-bottom: 6px solid palette(highlight); - color: palette(highlight); } ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], @@ -217,6 +221,7 @@ ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { } + /***************************************************************************** * CAutoHideSideBar *****************************************************************************/ From 6f5e33a2add5bf6d64a303ce273bac3d4628e9af Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 10:22:10 +0100 Subject: [PATCH 212/236] Added CSS styling for AutoHideTab that is iconOnly --- src/AutoHideTab.cpp | 8 ++- src/AutoHideTab.h | 7 +++ src/stylesheets/default.css | 69 ++++++++++++++++++++------ src/stylesheets/focus_highlighting.css | 65 +++++++++++++++++++----- 4 files changed, 122 insertions(+), 27 deletions(-) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 3d7e3fafa..5f69c456d 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -99,7 +99,6 @@ void AutoHideTabPrivate::updateOrientation() { _this->setText(""); _this->setOrientation(Qt::Horizontal); - _this->updateStyle(); } else { @@ -249,4 +248,11 @@ void CAutoHideTab::mousePressEvent(QMouseEvent* event) Super::mousePressEvent(event); } + +//============================================================================ +bool CAutoHideTab::iconOnly() const +{ + return CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideSideBarsIconOnly) && !icon().isNull(); +} + } diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index 2a942b42e..58ec66507 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -53,6 +53,7 @@ class ADS_EXPORT CAutoHideTab : public CPushButton Q_PROPERTY(int sideBarLocation READ sideBarLocation) Q_PROPERTY(Qt::Orientation orientation READ orientation) Q_PROPERTY(bool activeTab READ isActiveTab) + Q_PROPERTY(bool iconOnly READ iconOnly) private: AutoHideTabPrivate* d; ///< private data (pimpl) @@ -121,6 +122,12 @@ class ADS_EXPORT CAutoHideTab : public CPushButton * Sets the dock widget that is controlled by this tab */ void setDockWidget(CDockWidget* DockWidget); + + /** + * Returns true if the auto hide config flag AutoHideSideBarsIconOnly + * is set and if the tab has an icon - that means the icon is not null + */ + bool iconOnly() const; }; // class AutoHideTab } // namespace ads diff --git a/src/stylesheets/default.css b/src/stylesheets/default.css index 718b48260..83d1e32ac 100644 --- a/src/stylesheets/default.css +++ b/src/stylesheets/default.css @@ -142,40 +142,81 @@ ads--CAutoHideTab { } -ads--CAutoHideTab[sideBarLocation="0"], -ads--CAutoHideTab[sideBarLocation="2"] { +ads--CAutoHideTab:hover +{ + color: palette(highlight); +} + + +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] { border-top: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] { border-bottom: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideBarLocation="0"], -ads--CAutoHideTab:hover[sideBarLocation="2"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] { border-top: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab:hover[sideBarLocation="1"], -ads--CAutoHideTab:hover[sideBarLocation="3"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { + +/** + * Auto hide tabs with icon only + */ +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] { + border-left: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] { + border-right: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + +/** + * Auto hide tabs with icon only hover + */ +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] { border-top: 6px solid palette(highlight); } +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] { + border-left: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] { + border-right: 6px solid palette(highlight); +} -ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); } diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index 3b014521e..f615929c1 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -185,43 +185,84 @@ ads--CAutoHideTab:hover } -ads--CAutoHideTab[sideBarLocation="0"], -ads--CAutoHideTab[sideBarLocation="2"] { +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] { border-top: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] { border-bottom: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideBarLocation="0"], -ads--CAutoHideTab:hover[sideBarLocation="2"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] { border-top: 6px solid palette(highlight); } -ads--CAutoHideTab:hover[sideBarLocation="1"], -ads--CAutoHideTab:hover[sideBarLocation="3"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); } -ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { + +/** + * Auto hide tabs with icon only + */ +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] { + border-left: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] { + border-right: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + +/** + * Auto hide tabs with icon only hover + */ +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] { border-top: 6px solid palette(highlight); } +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] { + border-left: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] { + border-right: 6px solid palette(highlight); +} -ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); } + + + + /***************************************************************************** * CAutoHideSideBar *****************************************************************************/ From 32eaf936927cf66e7cd053fa0e4598a9b41c0c1f Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 10:23:40 +0100 Subject: [PATCH 213/236] Removed some whitespace from focus_highlighting.css --- src/stylesheets/focus_highlighting.css | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/stylesheets/focus_highlighting.css b/src/stylesheets/focus_highlighting.css index f615929c1..0fd9f183a 100644 --- a/src/stylesheets/focus_highlighting.css +++ b/src/stylesheets/focus_highlighting.css @@ -259,10 +259,6 @@ ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { - - - - /***************************************************************************** * CAutoHideSideBar *****************************************************************************/ From 35f212a788084e3ccc9445f6afda8fc7a46c0aec Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 10:45:09 +0100 Subject: [PATCH 214/236] Fixed Qt6 build --- src/AutoHideDockContainer.cpp | 20 +++++++++++--------- src/AutoHideDockContainer.h | 3 +-- src/AutoHideTab.cpp | 33 +++++++++++++-------------------- src/AutoHideTab.h | 4 +--- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 7dae89670..f4deed397 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -573,18 +573,20 @@ void CAutoHideDockContainer::leaveEvent(QEvent *event) //============================================================================ -void CAutoHideDockContainer::enterEvent(QEvent *event) +bool CAutoHideDockContainer::event(QEvent* event) { - d->forwardEventToDockContainer(event); - Super::enterEvent(event); -} + switch (event->type()) + { + case QEvent::Enter: + case QEvent::Hide: + d->forwardEventToDockContainer(event); + break; + default: + break; + } -//============================================================================ -void CAutoHideDockContainer::hideEvent(QHideEvent *event) -{ - d->forwardEventToDockContainer(event); - Super::hideEvent(event); + return Super::event(event); } } diff --git a/src/AutoHideDockContainer.h b/src/AutoHideDockContainer.h index 7c222f43b..0e1a3f64b 100644 --- a/src/AutoHideDockContainer.h +++ b/src/AutoHideDockContainer.h @@ -64,8 +64,7 @@ class ADS_EXPORT CAutoHideDockContainer : public QFrame virtual bool eventFilter(QObject* watched, QEvent* event) override; virtual void resizeEvent(QResizeEvent* event) override; virtual void leaveEvent(QEvent *event) override; - virtual void enterEvent(QEvent *event) override; - virtual void hideEvent(QHideEvent *event) override; + virtual bool event(QEvent* event) override; /** diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 5f69c456d..38090ab59 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -226,29 +226,22 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) //============================================================================ -void CAutoHideTab::enterEvent(QEvent *event) +bool CAutoHideTab::event(QEvent* event) { - d->forwardEventToDockContainer(event); - Super::enterEvent(event); -} - - -//============================================================================ -void CAutoHideTab::leaveEvent(QEvent *event) -{ - d->forwardEventToDockContainer(event); - Super::leaveEvent(event); -} - - -//============================================================================ -void CAutoHideTab::mousePressEvent(QMouseEvent* event) -{ - d->forwardEventToDockContainer(event); - Super::mousePressEvent(event); + switch (event->type()) + { + case QEvent::Enter: + case QEvent::Leave: + case QEvent::MouseButtonPress: + d->forwardEventToDockContainer(event); + break; + + default: + break; + } + return Super::event(event); } - //============================================================================ bool CAutoHideTab::iconOnly() const { diff --git a/src/AutoHideTab.h b/src/AutoHideTab.h index 58ec66507..fec49cd00 100644 --- a/src/AutoHideTab.h +++ b/src/AutoHideTab.h @@ -68,9 +68,7 @@ class ADS_EXPORT CAutoHideTab : public CPushButton void setSideBar(CAutoHideSideBar *SideTabBar); void removeFromSideBar(); - virtual void enterEvent(QEvent *event) override; - virtual void leaveEvent(QEvent *event) override; - virtual void mousePressEvent(QMouseEvent* event) override; + virtual bool event(QEvent* event) override; public: using Super = CPushButton; From 99854f686e58ab12d0090063da7591577a2df396 Mon Sep 17 00:00:00 2001 From: Uwe Date: Fri, 4 Nov 2022 11:24:15 +0100 Subject: [PATCH 215/236] Update linux stylesheet files to support icon only auto hide sidebars --- src/stylesheets/default_linux.css | 69 ++++++++++++++++---- src/stylesheets/focus_highlighting_linux.css | 69 ++++++++++++++++---- 2 files changed, 110 insertions(+), 28 deletions(-) diff --git a/src/stylesheets/default_linux.css b/src/stylesheets/default_linux.css index fbfc3050e..573d7dfe6 100644 --- a/src/stylesheets/default_linux.css +++ b/src/stylesheets/default_linux.css @@ -178,40 +178,81 @@ ads--CAutoHideTab { } -ads--CAutoHideTab[sideBarLocation="0"], -ads--CAutoHideTab[sideBarLocation="2"] { +ads--CAutoHideTab:hover +{ + color: palette(highlight); +} + + +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] { border-top: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] { border-bottom: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideBarLocation="0"], -ads--CAutoHideTab:hover[sideBarLocation="2"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] { border-top: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab:hover[sideBarLocation="1"], -ads--CAutoHideTab:hover[sideBarLocation="3"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { + +/** + * Auto hide tabs with icon only + */ +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] { + border-left: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] { + border-right: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + +/** + * Auto hide tabs with icon only hover + */ +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] { border-top: 6px solid palette(highlight); } +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] { + border-left: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] { + border-right: 6px solid palette(highlight); +} -ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); } diff --git a/src/stylesheets/focus_highlighting_linux.css b/src/stylesheets/focus_highlighting_linux.css index 45a878497..f21b137a4 100644 --- a/src/stylesheets/focus_highlighting_linux.css +++ b/src/stylesheets/focus_highlighting_linux.css @@ -254,40 +254,81 @@ ads--CAutoHideTab { } -ads--CAutoHideTab[sideBarLocation="0"], -ads--CAutoHideTab[sideBarLocation="2"] { +ads--CAutoHideTab:hover +{ + color: palette(highlight); +} + + +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] { border-top: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] { +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] { border-bottom: 6px solid rgba(0, 0, 0, 48); } -ads--CAutoHideTab:hover[sideBarLocation="0"], -ads--CAutoHideTab:hover[sideBarLocation="2"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] { border-top: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab:hover[sideBarLocation="1"], -ads--CAutoHideTab:hover[sideBarLocation="3"] { +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); - color: palette(highlight); } -ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] { + +/** + * Auto hide tabs with icon only + */ +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] { + border-left: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] { + border-right: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + +/** + * Auto hide tabs with icon only hover + */ +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] { border-top: 6px solid palette(highlight); } +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] { + border-left: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] { + border-right: 6px solid palette(highlight); +} -ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] { +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { border-bottom: 6px solid palette(highlight); } From 3f11f74324a76b8f0dfed15103ead0d6f5ebb1a8 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 12:10:52 +0100 Subject: [PATCH 216/236] Some cleanup --- demo/MainWindow.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index f980b8470..38dc8bd7b 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -620,7 +620,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line if you want to use opaque undocking and // opaque splitter resizing - //CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); + // CDockManager::setConfigFlags(CDockManager::DefaultOpaqueConfig); // uncomment the following line if you want a fixed tab width that does // not change if the visibility of the close button changes @@ -655,7 +655,6 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment the following line to enable focus highlighting of the dock // widget that has the focus CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); - CDockManager::setConfigFlag(CDockManager::AlwaysShowTabs, true); // uncomment if you would like to enable dock widget auto hiding CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); @@ -754,7 +753,7 @@ void CMainWindow::onViewToggled(bool Open) return; } - qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; + //qDebug() << DockWidget->objectName() << " viewToggled(" << Open << ")"; } From a79abbdb4838ea2a7380519328b388203eb9d70d Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 13:43:59 +0100 Subject: [PATCH 217/236] Fixed hiding of sidebar if Auto Hide Tab is closed --- src/AutoHideSideBar.cpp | 4 +- src/ads.qrc | 1 - src/stylesheets/visual_studio_light.css | 287 ------------------------ 3 files changed, 2 insertions(+), 290 deletions(-) delete mode 100644 src/stylesheets/visual_studio_light.css diff --git a/src/AutoHideSideBar.cpp b/src/AutoHideSideBar.cpp index 066c06016..aa1ad1a9a 100644 --- a/src/AutoHideSideBar.cpp +++ b/src/AutoHideSideBar.cpp @@ -100,11 +100,11 @@ class CTabsWidget : public QWidget /** * Forward event handling to EventHandler */ - /*virtual bool event(QEvent* e) override + virtual bool event(QEvent* e) override { EventHandler->handleViewportEvent(e); return Super::event(e); - }*/ + } }; diff --git a/src/ads.qrc b/src/ads.qrc index 3348820fd..019f871f3 100644 --- a/src/ads.qrc +++ b/src/ads.qrc @@ -17,7 +17,6 @@ images/restore-button-focused.svg images/vs-pin-button.svg images/vs-pin-button-pinned.svg - stylesheets/visual_studio_light.css images/vs-pin-button-pinned-focused.svg diff --git a/src/stylesheets/visual_studio_light.css b/src/stylesheets/visual_studio_light.css deleted file mode 100644 index 845c3d674..000000000 --- a/src/stylesheets/visual_studio_light.css +++ /dev/null @@ -1,287 +0,0 @@ - -/* - * Default style sheet on Windows Platforms with focus highlighting flag enabled - */ -ads--CDockManager -{ - background: palette(window); -} - - -ads--CDockContainerWidget { - background: palette(window); - padding: 2px; -} - - -/*ads--CDockContainerWidget > QSplitter{ - padding: 1 0 1 0; -}*/ - -ads--CDockAreaWidget { - background: palette(window); - /*border: 1px solid palette(dark);*/ -} - - -ads--CDockWidgetTab { - background: palette(window); - border: none; - padding: 0 0px; - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - -ads--CDockWidgetTab[activeTab="true"] { - background: rgb(204, 204, 204); -} - -ads--CDockWidgetTab QLabel { - color: palette(foreground); -} - -ads--CDockWidgetTab[activeTab="true"] QLabel { - color: palette(foreground); -} - -ads--CDockWidget { - background: palette(light); - /*border-color: palette(dark); - border-style: solid; - border-width: 1px 0 0 0;*/ - border: 1px solid rgb(204, 204, 204); - border-top: none; -} - -ads--CTitleBarButton { - padding: 0px 0px; - background: transparent; - border: none; -} - -ads--CTitleBarButton:hover { - background: rgba(0, 0, 0, 24); -} - -ads--CTitleBarButton:pressed { - background: rgba(0, 0, 0, 48); -} - -QScrollArea#dockWidgetScrollArea { - padding: 0px; - border: none; -} - -#tabsMenuButton::menu-indicator { - image: none; -} - -#tabCloseButton { - margin-top: 2px; - background: none; - border: none; - padding: 0px -2px; - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#tabCloseButton:hover { - /*border: 1px solid rgba(0, 0, 0, 32);*/ - background: rgba(0, 0, 0, 24); -} - -#tabCloseButton:pressed { - background: rgba(0, 0, 0, 48); -} - -#dockAreaCloseButton { - qproperty-icon: url(:/ads/images/close-button.svg), - url(:/ads/images/close-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -#detachGroupButton { - qproperty-icon: url(:/ads/images/detach-button.svg), - url(:/ads/images/detach-button-disabled.svg) disabled; - qproperty-iconSize: 16px; -} - -ads--CDockSplitter::handle { - /*background-color: palette(dark);*/ - /* uncomment the following line if you would like to change the size of - the splitter handles */ - /* height: 1px; */ -} - -/* Focus related styling */ -ads--CDockWidgetTab[focused="true"] { - background: palette(highlight); - border-color: palette(highlight); -} - -ads--CDockWidgetTab[focused="true"] > #tabCloseButton { - qproperty-icon: url(:/ads/images/close-button-focused.svg) -} - -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover { - background: rgba(255, 255, 255, 48); -} - -ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed { - background: rgba(255, 255, 255, 92); -} - -ads--CDockWidgetTab[focused="true"] QLabel { - color: palette(light); -} - -ads--CDockAreaTitleBar { - background: transparent; - border-bottom: 2px solid rgb(204, 204, 204); - padding-bottom: 0px; -} - -ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { - border-bottom: 2px solid palette(highlight); -} - -/*----------------------------------------------------------------------------- - * Styling of auto hide functionality - *---------------------------------------------------------------------------- - */ -ads--CAutoHideTab { - /*background: palette(window);*/ - qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ -} - - -ads--CAutoHideTab -{ - background: none; - border: none; - padding-left: 2px; - padding-right: 0px; - text-align: center; -} - -ads--CAutoHideTab[sideBarLocation="0"], -ads--CAutoHideTab[sideBarLocation="2"] -{ - border-top: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; -} - - -ads--CAutoHideTab[sideBarLocation="1"], -ads--CAutoHideTab[sideBarLocation="3"] -{ - border-bottom: 5px solid rgba(0, 0, 0, 48); - margin-right: 6px; - min-height: 20; -} - - - -ads--CAutoHideTab:hover[sideBarLocation="0"], -ads--CAutoHideTab:hover[sideBarLocation="2"] -{ - border-top: 5px solid palette(highlight); - color: palette(highlight); -} - - -ads--CAutoHideTab:hover[sideBarLocation="1"], -ads--CAutoHideTab:hover[sideBarLocation="3"] -{ - border-bottom: 5px solid palette(highlight); - color: palette(highlight); -} - -ads--CAutoHideTab[sideBarLocation="0"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="2"][activeTab="true"] -{ - border-top: 5px solid palette(highlight); -} - - -ads--CAutoHideTab[sideBarLocation="1"][activeTab="true"], -ads--CAutoHideTab[sideBarLocation="3"][activeTab="true"] -{ - border-bottom: 5px solid palette(highlight); -} - - -/* -ads--CAutoHideDockContainer::handle { - background: palette(dark); -} - -ads--CAutoHideDockContainer::handle:vertical { - height: 4px; -} - - -ads--CAutoHideDockContainer::handle:horizontal { - width: 4px; -} -*/ - -/*ads--CAutoHideDockContainer[sideBarLocation="0"]:handle { - border: 1px solid palette(dark); - background: white; -}*/ - - -#dockAreaAutoHideButton { - qproperty-icon: url(:/ads/images/vs-pin-button.svg); - qproperty-iconSize: 16px; -} - -ads--CAutoHideDockContainer #dockAreaAutoHideButton -{ - qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); - qproperty-iconSize: 16px; -} - -#autoHideTitleLabel -{ - padding-left: 4px; - color: palette(light); -} - -ads--CResizeHandle -{ - /*background: red; - border: 1px solid green;*/ -} - - -ads--CAutoHideDockContainer -{ - background: palette(window); -} - - -ads--CAutoHideDockContainer ads--CDockAreaTitleBar -{ - background: palette(highlight); - border: none; - padding: 0px; -} - -ads--CAutoHideDockContainer #dockAreaCloseButton -{ - qproperty-icon: url(:/ads/images/close-button-focused.svg) -} - - -ads--CAutoHideDockContainer ads--CTitleBarButton:hover -{ - background: rgba(255, 255, 255, 48); -} - -ads--CAutoHideDockContainer ads--CTitleBarButton:pressed -{ - background: rgba(255, 255, 255, 96); -} From 1bf698478d72d8eda20a0336cfb614995230f128 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 13:44:30 +0100 Subject: [PATCH 218/236] Added feature to apply a Visual Studio like light theme via ToolBar --- demo/MainWindow.cpp | 17 ++ demo/MainWindow.h | 1 + demo/demo.qrc | 2 + demo/images/color_lens.svg | 6 + demo/res/visual_studio_light.css | 379 +++++++++++++++++++++++++++++++ 5 files changed, 405 insertions(+) create mode 100644 demo/images/color_lens.svg create mode 100644 demo/res/visual_studio_light.css diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 38dc8bd7b..0daed57cd 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -561,6 +561,11 @@ void MainWindowPrivate::createActions() a = ui.menuTests->addAction("Toggle Label 0 Window Title"); _this->connect(a, SIGNAL(triggered()), SLOT(toggleDockWidgetWindowTitle())); ui.menuTests->addSeparator(); + + a = ui.toolBar->addAction("Apply VS Style"); + a->setToolTip("Applies a Visual Studio light style (visual_studio_light.css)." ); + a->setIcon(svgIcon(":/adsdemo/images/color_lens.svg")); + QObject::connect(a, &QAction::triggered, _this, &CMainWindow::applyVsStyle); } @@ -864,3 +869,15 @@ void CMainWindow::toggleDockWidgetWindowTitle() d->WindowTitleTestDockWidget->setWindowTitle(Title); } + +//============================================================================ +void CMainWindow::applyVsStyle() +{ + QFile StyleSheetFile(":adsdemo/res/visual_studio_light.css"); + StyleSheetFile.open(QIODevice::ReadOnly); + QTextStream StyleSheetStream(&StyleSheetFile); + auto Stylesheet = StyleSheetStream.readAll(); + StyleSheetFile.close(); + d->DockManager->setStyleSheet(Stylesheet); +} + diff --git a/demo/MainWindow.h b/demo/MainWindow.h index cd0eca6b0..a4d78a888 100644 --- a/demo/MainWindow.h +++ b/demo/MainWindow.h @@ -65,6 +65,7 @@ private slots: void onEditorCloseRequested(); void showStatusDialog(); void toggleDockWidgetWindowTitle(); + void applyVsStyle(); }; #endif // MAINWINDOW_H diff --git a/demo/demo.qrc b/demo/demo.qrc index cabf10958..7dc097ba3 100644 --- a/demo/demo.qrc +++ b/demo/demo.qrc @@ -17,5 +17,7 @@ images/create_floating_editor.svg images/create_floating_table.svg images/docked_editor.svg + res/visual_studio_light.css + images/color_lens.svg diff --git a/demo/images/color_lens.svg b/demo/images/color_lens.svg new file mode 100644 index 000000000..456049712 --- /dev/null +++ b/demo/images/color_lens.svg @@ -0,0 +1,6 @@ + + color_lens icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/res/visual_studio_light.css b/demo/res/visual_studio_light.css new file mode 100644 index 000000000..056163add --- /dev/null +++ b/demo/res/visual_studio_light.css @@ -0,0 +1,379 @@ + +/* + * Visual Studio like light theme + */ + +/***************************************************************************** + * CDockManager + *****************************************************************************/ +ads--CDockManager +{ + background: palette(window); +} + + + +/***************************************************************************** + * CDockContainerWidget + *****************************************************************************/ +ads--CDockContainerWidget { + background: palette(window); + padding: 2px; +} + + +/***************************************************************************** + * CDockAreaWidget + *****************************************************************************/ +ads--CDockAreaWidget { + background: palette(window); + /*border: 1px solid palette(dark);*/ +} + + +ads--CDockAreaTitleBar { + background: transparent; + border-bottom: 2px solid rgb(204, 204, 204); + padding-bottom: 0px; +} + + +ads--CTitleBarButton { + padding: 0px 0px; + background: transparent; + border: none; +} + +ads--CTitleBarButton:hover { + background: rgba(0, 0, 0, 24); +} + +ads--CTitleBarButton:pressed { + background: rgba(0, 0, 0, 48); +} + +QScrollArea#dockWidgetScrollArea { + padding: 0px; + border: none; +} + +#tabsMenuButton::menu-indicator { + image: none; +} + + +#dockAreaCloseButton { + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#detachGroupButton { + qproperty-icon: url(:/ads/images/detach-button.svg), + url(:/ads/images/detach-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + + +ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + border-bottom: 2px solid palette(highlight); +} + + +/***************************************************************************** + * CDockWidgetTab + *****************************************************************************/ +ads--CDockWidgetTab { + background: palette(window); + border: none; + padding: 0 0px; + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ +} + +ads--CDockWidgetTab[activeTab="true"] { + background: rgb(204, 204, 204); +} + +ads--CDockWidgetTab QLabel { + color: palette(foreground); +} + +ads--CDockWidgetTab[activeTab="true"] QLabel { + color: palette(foreground); +} + + +#tabCloseButton { + margin-top: 2px; + background: none; + border: none; + padding: 0px -2px; + qproperty-icon: url(:/ads/images/close-button.svg), + url(:/ads/images/close-button-disabled.svg) disabled; + qproperty-iconSize: 16px; +} + +#tabCloseButton:hover { + /*border: 1px solid rgba(0, 0, 0, 32);*/ + background: rgba(0, 0, 0, 24); +} + +#tabCloseButton:pressed { + background: rgba(0, 0, 0, 48); +} + + +/* Focus related styling */ +ads--CDockWidgetTab[focused="true"] { + background: palette(highlight); + border-color: palette(highlight); +} + +ads--CDockWidgetTab[focused="true"] > #tabCloseButton { + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + +ads--CDockWidgetTab[focused="true"]>#tabCloseButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CDockWidgetTab[focused="true"]>#tabCloseButton:pressed { + background: rgba(255, 255, 255, 92); +} + +ads--CDockWidgetTab[focused="true"] QLabel { + color: palette(light); +} + + +/***************************************************************************** + * CDockWidget + *****************************************************************************/ +ads--CDockWidget { + background: palette(light); + border: 1px solid rgb(204, 204, 204); + border-top: none; +} + + + +/***************************************************************************** + * + * Styling of auto hide functionality + * + *****************************************************************************/ + + +/***************************************************************************** + * CAutoHideTab + *****************************************************************************/ +ads--CAutoHideTab { + qproperty-iconSize: 16px 16px;/* this is optional in case you would like to change icon size*/ + background: none; + border: none; + padding-left: 2px; + padding-right: 0px; + text-align: center; + min-height: 20px; + padding-bottom: 2px; +} + + +ads--CAutoHideTab:hover +{ + color: palette(highlight); +} + + +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + + +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + + +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="0"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="0"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="2"][activeTab="true"] { + border-top: 6px solid palette(highlight); +} + + +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="1"], +ads--CAutoHideTab:hover[iconOnly="false"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="1"][activeTab="true"], +ads--CAutoHideTab[iconOnly="false"][sideBarLocation="3"][activeTab="true"] { + border-bottom: 6px solid palette(highlight); +} + + +/** + * Auto hide tabs with icon only + */ +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"] { + border-top: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"] { + border-left: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"] { + border-right: 6px solid rgba(0, 0, 0, 48); +} + +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"] { + border-bottom: 6px solid rgba(0, 0, 0, 48); +} + + +/** + * Auto hide tabs with icon only hover + */ +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="0"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="0"][activeTab="true"] { + border-top: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="1"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="1"][activeTab="true"] { + border-left: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="2"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="2"][activeTab="true"] { + border-right: 6px solid palette(highlight); +} + +ads--CAutoHideTab:hover[iconOnly="true"][sideBarLocation="3"], +ads--CAutoHideTab[iconOnly="true"][sideBarLocation="3"][activeTab="true"] { + border-bottom: 6px solid palette(highlight); +} + + + +/***************************************************************************** + * CAutoHideSideBar + *****************************************************************************/ +ads--CAutoHideSideBar{ + background: palette(window); + border: none; + qproperty-spacing: 12; +} + +#sideTabsContainerWidget { + background: transparent; +} + + +ads--CAutoHideSideBar[sideBarLocation="0"] { + border-bottom: 1px solid palette(dark); +} + +ads--CAutoHideSideBar[sideBarLocation="1"] { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideSideBar[sideBarLocation="2"] { + border-left: 1px solid palette(dark); +} + +ads--CAutoHideSideBar[sideBarLocation="3"] { + border-top: 1px solid palette(dark); +} + + +/***************************************************************************** + * CAutoHideDockContainer + *****************************************************************************/ +ads--CAutoHideDockContainer { + background: palette(window); +} + + +ads--CAutoHideDockContainer ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +/* + * This is required because the ads--CDockAreaWidget[focused="true"] will + * overwrite the ads--CAutoHideDockContainer ads--CDockAreaTitleBar rule + */ +ads--CAutoHideDockContainer ads--CDockAreaWidget[focused="true"] ads--CDockAreaTitleBar { + background: palette(highlight); + padding: 0px; + border: none; +} + + +#autoHideTitleLabel { + padding-left: 4px; + color: palette(light); +} + + +/***************************************************************************** + * CAutoHideDockContainer titlebar buttons + *****************************************************************************/ +#dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button.svg); + qproperty-iconSize: 16px; +} + +ads--CAutoHideDockContainer #dockAreaAutoHideButton { + qproperty-icon: url(:/ads/images/vs-pin-button-pinned-focused.svg); + qproperty-iconSize: 16px; +} + + +ads--CAutoHideDockContainer #dockAreaCloseButton{ + qproperty-icon: url(:/ads/images/close-button-focused.svg) +} + + +ads--CAutoHideDockContainer ads--CTitleBarButton:hover { + background: rgba(255, 255, 255, 48); +} + +ads--CAutoHideDockContainer ads--CTitleBarButton:pressed { + background: rgba(255, 255, 255, 96); +} + +/***************************************************************************** + * CAutoHideDockContainer Titlebar and Buttons + *****************************************************************************/ + + +/***************************************************************************** + * CResizeHandle + *****************************************************************************/ +ads--CResizeHandle { + background: palette(window); +} + + +ads--CAutoHideDockContainer[sideBarLocation="0"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideBarLocation="1"] ads--CResizeHandle { + border-left: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideBarLocation="2"] ads--CResizeHandle { + border-right: 1px solid palette(dark); +} + +ads--CAutoHideDockContainer[sideBarLocation="3"] ads--CResizeHandle { + border-top: 1px solid palette(dark); +} From 9c537340c5f2e3314a5fee96c72f0f5cd562ed37 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Fri, 4 Nov 2022 20:14:04 +0100 Subject: [PATCH 219/236] Added a small image viewer to the demo application --- demo/ImageViewer.cpp | 281 +++++++++++++++++++++++++++++++++++ demo/ImageViewer.h | 88 +++++++++++ demo/MainWindow.cpp | 21 +++ demo/RenderWidget.h | 111 ++++++++++++++ demo/demo.pro | 17 ++- demo/demo.qrc | 7 + demo/images/ads_icon.svg | 77 ++++++++++ demo/images/ads_logo.svg | 88 +++++++++++ demo/images/find_in_page.svg | 6 + demo/images/perm_media.svg | 6 + demo/images/zoom_in.svg | 6 + demo/images/zoom_out.svg | 6 + demo/images/zoom_out_map.svg | 6 + 13 files changed, 714 insertions(+), 6 deletions(-) create mode 100644 demo/ImageViewer.cpp create mode 100644 demo/ImageViewer.h create mode 100644 demo/RenderWidget.h create mode 100644 demo/images/ads_icon.svg create mode 100644 demo/images/ads_logo.svg create mode 100644 demo/images/find_in_page.svg create mode 100644 demo/images/perm_media.svg create mode 100644 demo/images/zoom_in.svg create mode 100644 demo/images/zoom_out.svg create mode 100644 demo/images/zoom_out_map.svg diff --git a/demo/ImageViewer.cpp b/demo/ImageViewer.cpp new file mode 100644 index 000000000..43c7d151b --- /dev/null +++ b/demo/ImageViewer.cpp @@ -0,0 +1,281 @@ +//============================================================================ +/// \file ImageViewer.cpp +/// \author Uwe Kindler +/// \date 04.11.2022 +/// \brief Implementation of CImageViewer +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include "ImageViewer.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "RenderWidget.h" + +/** + * Private image viewer data + */ +struct ImageViewerPrivate +{ + CImageViewer* _this; + CRenderWidget* RenderWidget;///< renders the image to screen + bool AutoFit;///< automatically fit image to window size on resize events + QSize ImageSize;///< stores the image size to detect image size changes + QPoint MouseMoveStartPos;///< for calculation of mouse move vector + QLabel* ScalingLabel;///< label displays scaling factor + QList OverlayTools;///< list of tool widget to overlay + + ImageViewerPrivate(CImageViewer* _public) : _this(_public) {} +}; + + + +//============================================================================ +CImageViewer::CImageViewer(QWidget *parent) + : Super(parent), + d(new ImageViewerPrivate(this)) +{ + d->AutoFit = true; + d->RenderWidget = new CRenderWidget(this); + + this->setBackgroundRole(QPalette::Light); + this->setAlignment(Qt::AlignCenter); + this->setWidget(d->RenderWidget); + this->createActions(); + this->setMouseTracking(false); // only produce mouse move events if mouse button pressed +} + + +//============================================================================ +CImageViewer::~CImageViewer() +{ + delete d; +} + + +//============================================================================ +bool CImageViewer::loadFile(const QString& fileName) +{ + QImageReader reader(fileName); + reader.setAutoTransform(true); + const QImage newImage = reader.read(); + if (newImage.isNull()) + { + QMessageBox::information(this, QGuiApplication::applicationDisplayName(), + tr("Cannot load %1: %2") + .arg(QDir::toNativeSeparators(fileName), reader.errorString())); + return false; + } + + setImage(newImage); + setWindowFilePath(fileName); + return true; +} + + +//=========================================================================== +void CImageViewer::setImage(const QImage &newImage) +{ + d->RenderWidget->showImage(newImage); + this->adjustDisplaySize(newImage); +} + + +//============================================================================ +void CImageViewer::adjustDisplaySize(const QImage& Image) +{ + if (d->ImageSize == Image.size()) + { + return; + } + d->ImageSize = Image.size(); + if (d->AutoFit) + { + this->fitToWindow(); + } +} + + +//=========================================================================== +static void initializeImageFileDialog(QFileDialog &dialog, QFileDialog::AcceptMode acceptMode) +{ + static bool firstDialog = true; + + if (firstDialog) { + firstDialog = false; + const QStringList picturesLocations = QStandardPaths::standardLocations(QStandardPaths::PicturesLocation); + dialog.setDirectory(picturesLocations.isEmpty() ? QDir::currentPath() : picturesLocations.last()); + } + + QStringList mimeTypeFilters; + const QByteArrayList supportedMimeTypes = acceptMode == QFileDialog::AcceptOpen + ? QImageReader::supportedMimeTypes() : QImageWriter::supportedMimeTypes(); + for (const QByteArray &mimeTypeName : supportedMimeTypes) + mimeTypeFilters.append(mimeTypeName); + mimeTypeFilters.sort(); + dialog.setMimeTypeFilters(mimeTypeFilters); + dialog.selectMimeTypeFilter("image/jpeg"); + if (acceptMode == QFileDialog::AcceptSave) + dialog.setDefaultSuffix("jpg"); +} + + +//=========================================================================== +void CImageViewer::open() +{ + QFileDialog dialog(this, tr("Open File")); + initializeImageFileDialog(dialog, QFileDialog::AcceptOpen); + + while (dialog.exec() == QDialog::Accepted && !loadFile(dialog.selectedFiles().first())) {} +} + + +//=========================================================================== +void CImageViewer::createActions() +{ + QAction* a; + a = new QAction(tr("&Open...")); + a->setIcon(QIcon(":/adsdemo/images/perm_media.svg")); + connect(a, &QAction::triggered, this, &CImageViewer::open); + a->setShortcut(QKeySequence::Open);; + this->addAction(a); + + a = new QAction(tr("Fit on Screen")); + a->setIcon(QIcon(":/adsdemo/images/zoom_out_map.svg")); + connect(a, &QAction::triggered, this, &CImageViewer::fitToWindow); + this->addAction(a); + + a = new QAction(tr("Actual Pixels")); + a->setIcon(QIcon(":/adsdemo/images/find_in_page.svg")); + connect(a, &QAction::triggered, this, &CImageViewer::normalSize); + this->addAction(a); + + a = new QAction(this); + a->setSeparator(true); + this->addAction(a); + + a = new QAction(tr("Zoom In (25%)")); + a->setIcon(QIcon(":/adsdemo/images/zoom_in.svg")); + connect(a, &QAction::triggered, this, &CImageViewer::zoomIn); + this->addAction(a); + + a = new QAction(tr("Zoom Out (25%)")); + a->setIcon(QIcon(":/adsdemo/images/zoom_out.svg")); + connect(a, &QAction::triggered, this, &CImageViewer::zoomOut); + this->addAction(a); + + this->setContextMenuPolicy(Qt::ActionsContextMenu); +} + + +//=========================================================================== +void CImageViewer::zoomIn() +{ + d->AutoFit = false; + d->RenderWidget->zoomIn(); +} + + +//=========================================================================== +void CImageViewer::zoomOut() +{ + d->AutoFit = false; + d->RenderWidget->zoomOut(); +} + + +//=========================================================================== +void CImageViewer::normalSize() +{ + d->AutoFit = false; + d->RenderWidget->normalSize(); +} + + +//=========================================================================== +void CImageViewer::fitToWindow() +{ + d->AutoFit = true; + d->RenderWidget->scaleToSize(this->maximumViewportSize()); +} + + +//============================================================================ +void CImageViewer::resizeEvent(QResizeEvent* ResizeEvent) +{ + Super::resizeEvent(ResizeEvent); + if (d->AutoFit) + { + this->fitToWindow(); + } +} + + +//============================================================================ +void CImageViewer::mousePressEvent(QMouseEvent* Event) +{ + d->RenderWidget->setCursor(Qt::ClosedHandCursor); + d->MouseMoveStartPos = Event->pos(); + Super::mousePressEvent(Event); +} + + +//============================================================================ +void CImageViewer::mouseReleaseEvent(QMouseEvent* Event) +{ + d->RenderWidget->setCursor(Qt::OpenHandCursor); + Super::mouseReleaseEvent(Event); +} + + +//============================================================================ +void CImageViewer::mouseMoveEvent(QMouseEvent* Event) +{ + QPoint MoveVector = Event->pos() - d->MouseMoveStartPos; + d->MouseMoveStartPos = Event->pos(); + horizontalScrollBar()->setValue(horizontalScrollBar()->value() + - MoveVector.x()); + verticalScrollBar()->setValue(verticalScrollBar()->value() - MoveVector.y()); +} + + +//============================================================================ +void CImageViewer::wheelEvent(QWheelEvent* Event) +{ + double numDegrees = Event->delta() / 8; + double numSteps = numDegrees / 15; + d->AutoFit = false; + double Zoom; + if (numSteps < 0) + { + Zoom = pow(0.9, 0 - numSteps); + } + else + { + Zoom = pow(1.10, numSteps); + } + d->RenderWidget->zoomByValue(Zoom); +} + +#include "moc_ImageViewer.cpp" +//--------------------------------------------------------------------------- +// EOF ImageViewer.cpp diff --git a/demo/ImageViewer.h b/demo/ImageViewer.h new file mode 100644 index 000000000..37bc8cba7 --- /dev/null +++ b/demo/ImageViewer.h @@ -0,0 +1,88 @@ +#ifndef ImageViewerH +#define ImageViewerH +//============================================================================ +/// \file ImageViewer.h +/// \author Uwe Kindler +/// \date 04.11.2022 +/// \brief Declaration of CImageViewer +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include + +QT_BEGIN_NAMESPACE +class QLabel; +QT_END_NAMESPACE + + +struct ImageViewerPrivate; + +/** + * Tiny simple image viewer for showing images in demo + */ +class CImageViewer : public QScrollArea +{ + Q_OBJECT +public: + using Super = QScrollArea; + + explicit CImageViewer(QWidget *parent = nullptr); + virtual ~CImageViewer(); + + bool loadFile(const QString& Filename); + void setImage(const QImage &newImage); + +public Q_SLOTS: + void open(); + void zoomIn(); + void zoomOut(); + void normalSize(); + void fitToWindow(); + +protected: + /** + * @brief Reimplemented from QScrollArea to adjust image scaling if m_AutoFit is + * true. + */ + virtual void resizeEvent(QResizeEvent* ResizeEvent); + + /** + * @brief Handle mouse press events. + */ + virtual void mousePressEvent(QMouseEvent* Event); + + /** + * @brief Handles mouse release events. + */ + virtual void mouseReleaseEvent(QMouseEvent* Event); + + /** + * @brief Handle mouse move events. + */ + virtual void mouseMoveEvent(QMouseEvent* Event); + + /** + * @brief Use mouse wheel to change scaling of the image. + */ + virtual void wheelEvent(QWheelEvent* Event); + +private: + /** + * @brief Create the wiget actions. + */ + void createActions(); + + /** + * @brief Adjust size of render widget in case of image size change. + * @param[in] Image The new image that may have a different image size. + */ + void adjustDisplaySize(const QImage& Image); + + ImageViewerPrivate* d; + friend ImageViewerPrivate; +}; + +//--------------------------------------------------------------------------- +#endif // ImageViewerH diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 0daed57cd..bf8a133fd 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -80,6 +80,7 @@ #include "DockComponentsFactory.h" #include "StatusDialog.h" #include "DockSplitter.h" +#include "ImageViewer.h" /** @@ -317,6 +318,22 @@ struct MainWindowPrivate return DockWidget; } + /** + * Creates a simply image viewr + */ + ads::CDockWidget* createImageViewer() + { + static int ImageViewerCount = 0; + auto w = new CImageViewer(); + auto Result = w->loadFile(":adsdemo/images/ads_logo.svg"); + qDebug() << "loadFile result: " << Result; + ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Image Viewer %1").arg(ImageViewerCount++)); + DockWidget->setWidget(w,ads:: CDockWidget::ForceNoScrollArea); + auto ToolBar = DockWidget->createDefaultToolBar(); + ToolBar->addActions(w->actions()); + return DockWidget; + } + /** * Create a table widget */ @@ -510,6 +527,10 @@ void MainWindowPrivate::createContent() _this->connect(DockWidget, SIGNAL(viewToggled(bool)), SLOT(onViewToggled(bool))); _this->connect(DockWidget, SIGNAL(visibilityChanged(bool)), SLOT(onViewVisibilityChanged(bool))); } + + // Create image viewer + DockWidget = createImageViewer(); + DockManager->addDockWidget(ads::LeftDockWidgetArea, DockWidget); } diff --git a/demo/RenderWidget.h b/demo/RenderWidget.h new file mode 100644 index 000000000..81fedf145 --- /dev/null +++ b/demo/RenderWidget.h @@ -0,0 +1,111 @@ +#ifndef RenderWidgetH +#define RenderWidgetH +//============================================================================ +/// \file RenderWidget.h +/// \author Uwe Kindler +/// \date 04.11.2022 +/// \brief Declaration of CRenderWidget +//============================================================================ + +//============================================================================ +// INCLUDES +//============================================================================ +#include +#include + +//============================================================================ +// FORWARD DECLARATIONS +//============================================================================ +class QImage; + + +/** + * @brief Widget for fast display of images (i.e. for video capture devices) + */ +class CRenderWidget : public QWidget +{ + Q_OBJECT +private: + QPixmap m_Image; + double m_ScaleFactor; + +protected: + /** + * @brief Reimplemented paint event method showing actual image. + */ + void paintEvent(QPaintEvent* PaintEvent); + + /** + * @brief Change scale factor + */ + void scaleImage(double ScaleFactor); + + /** + * @brief Adjust widget size to size of image. + */ + void adjustWidgetSize(); + +public: + /** + * Constructor + * @param[in] Parent Parent widget. + */ + CRenderWidget(QWidget* Parent); + + /** + * Destructor + */ + virtual ~CRenderWidget(); + +signals: + /** + * @brief Signalize change of captured image size. + * @param ImageSize New image size. + */ + void imageSizeChanged(const QSize& ImageSize); + +public slots: + /** + * @brief Show new image in render widget. + */ + void showImage(const QImage& Image); + + /** + * @brief Zoom into the scene. + * This function decreases the scaling factor by setting it to the previous + * value in internal scaling list. + * @brief Steps The number of steps to zoom in. One step is 25%. + */ + void zoomIn(); + + /** + * @brief Zoom out of the scene. + * This function decreases the scaling factor by setting it to the next + * value in internal scaling list. + * @brief Steps The number of steps to zoom out. One step is 25%. + */ + void zoomOut(); + + /** + * @brief Change zoom by zoom value. + * @param[in] ZoomValue This is the zoom value to apply. A value of 1 + * means no change a value > 1 increases the image (i.e. 1.25 would increase + * the image by 25%) and a value of < 1 decreases the image size (i.e. + * a value of 0.8 would decrease the image size by 25%). + */ + void zoomByValue(double ZoomValue); + + /** + * @brief Resets the actual scaling to 1 and display the image with its + * actual pixel size. + */ + void normalSize(); + + /** + * @brief Scales the wiget and its content image to the given TargetSize + */ + void scaleToSize(const QSize& TargetSize); +}; // class CRenderWidget + +//--------------------------------------------------------------------------- +#endif // RenderWidgetH diff --git a/demo/demo.pro b/demo/demo.pro index 80ad86672..b330fd923 100644 --- a/demo/demo.pro +++ b/demo/demo.pro @@ -2,7 +2,7 @@ ADS_OUT_ROOT = $${OUT_PWD}/.. TARGET = AdvancedDockingSystemDemo DESTDIR = $${ADS_OUT_ROOT}/lib -QT += core gui widgets +QT += core gui widgets svg include(../ads.pri) @@ -20,14 +20,19 @@ adsBuildStatic { DEFINES += ADS_STATIC } -SOURCES += \ - main.cpp \ - MainWindow.cpp \ - StatusDialog.cpp HEADERS += \ MainWindow.h \ - StatusDialog.h + StatusDialog.h \ + ImageViewer.h \ + RenderWidget.h + +SOURCES += \ + main.cpp \ + MainWindow.cpp \ + StatusDialog.cpp \ + ImageViewer.cpp \ + RenderWidget.cpp FORMS += \ mainwindow.ui \ diff --git a/demo/demo.qrc b/demo/demo.qrc index 7dc097ba3..3139b20b7 100644 --- a/demo/demo.qrc +++ b/demo/demo.qrc @@ -19,5 +19,12 @@ images/docked_editor.svg res/visual_studio_light.css images/color_lens.svg + images/ads_icon.svg + images/ads_logo.svg + images/find_in_page.svg + images/perm_media.svg + images/zoom_in.svg + images/zoom_out.svg + images/zoom_out_map.svg diff --git a/demo/images/ads_icon.svg b/demo/images/ads_icon.svg new file mode 100644 index 000000000..4231be6c4 --- /dev/null +++ b/demo/images/ads_icon.svg @@ -0,0 +1,77 @@ + + + + + electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH + + + + + + + + + diff --git a/demo/images/ads_logo.svg b/demo/images/ads_logo.svg new file mode 100644 index 000000000..107254086 --- /dev/null +++ b/demo/images/ads_logo.svg @@ -0,0 +1,88 @@ + + + + + electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH + + Qt Advanced Docking + + + + + + + + diff --git a/demo/images/find_in_page.svg b/demo/images/find_in_page.svg new file mode 100644 index 000000000..ff4e34667 --- /dev/null +++ b/demo/images/find_in_page.svg @@ -0,0 +1,6 @@ + + find_in_page icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/perm_media.svg b/demo/images/perm_media.svg new file mode 100644 index 000000000..2dac12f97 --- /dev/null +++ b/demo/images/perm_media.svg @@ -0,0 +1,6 @@ + + perm_media icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/zoom_in.svg b/demo/images/zoom_in.svg new file mode 100644 index 000000000..b65ca3c4f --- /dev/null +++ b/demo/images/zoom_in.svg @@ -0,0 +1,6 @@ + + zoom_in icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/zoom_out.svg b/demo/images/zoom_out.svg new file mode 100644 index 000000000..d2912384d --- /dev/null +++ b/demo/images/zoom_out.svg @@ -0,0 +1,6 @@ + + zoom_out icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/zoom_out_map.svg b/demo/images/zoom_out_map.svg new file mode 100644 index 000000000..dedc2d5f7 --- /dev/null +++ b/demo/images/zoom_out_map.svg @@ -0,0 +1,6 @@ + + zoom_out_map icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file From bd0b2ad483f9369d8d08a907fecddfa567fee714 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sat, 5 Nov 2022 10:11:09 +0100 Subject: [PATCH 220/236] Improved title bar button tooltips and made naming consistend with context menu --- src/DockAreaTitleBar.cpp | 58 ++++++++++++++++++++++++++++++---------- src/DockAreaTitleBar.h | 2 +- src/DockAreaWidget.cpp | 9 ++++--- src/DockAreaWidget.h | 2 +- src/DockWidgetTab.cpp | 4 +-- 5 files changed, 54 insertions(+), 21 deletions(-) diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index 91737c2e7..02796afd8 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include "DockAreaTitleBar_p.h" #include "ads_globals.h" @@ -209,7 +210,7 @@ void DockAreaTitleBarPrivate::createButtons() AutoHideButton = new CTitleBarButton(testAutoHideConfigFlag(CDockManager::DockAreaHasAutoHideButton) && autoHideEnabled); AutoHideButton->setObjectName("dockAreaAutoHideButton"); AutoHideButton->setAutoRaise(true); - internal::setToolTip(AutoHideButton, QObject::tr("Toggle Auto Hide")); + internal::setToolTip(AutoHideButton, _this->titleBarButtonToolTip(TitleBarButtonAutoHide)); internal::setButtonIcon(AutoHideButton, QStyle::SP_DialogOkButton, ads::AutoHideIcon); AutoHideButton->setSizePolicy(ButtonSizePolicy); AutoHideButton->setCheckable(testAutoHideConfigFlag(CDockManager::AutoHideButtonCheckable)); @@ -222,7 +223,7 @@ void DockAreaTitleBarPrivate::createButtons() CloseButton->setObjectName("dockAreaCloseButton"); CloseButton->setAutoRaise(true); internal::setButtonIcon(CloseButton, QStyle::SP_TitleBarCloseButton, ads::DockAreaCloseIcon); - internal::setToolTip(CloseButton, _this->closeGroupToolTip()); + internal::setToolTip(CloseButton, _this->titleBarButtonToolTip(TitleBarButtonClose)); CloseButton->setSizePolicy(ButtonSizePolicy); CloseButton->setIconSize(QSize(16, 16)); Layout->addWidget(CloseButton, 0); @@ -507,7 +508,8 @@ void CDockAreaTitleBar::onCurrentTabChanged(int Index) //============================================================================ void CDockAreaTitleBar::onAutoHideButtonClicked() { - if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)) + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea) + || qApp->keyboardModifiers().testFlag(Qt::ControlModifier)) { d->DockArea->toggleAutoHide(); } @@ -698,13 +700,13 @@ void CDockAreaTitleBar::contextMenuEvent(QContextMenuEvent* ev) Action->setEnabled(d->DockArea->features().testFlag(CDockWidget::DockWidgetFloatable)); if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { - Action = Menu.addAction(isAutoHide ? tr("Dock") : tr("Auto Hide Group"), this, SLOT(onAutoHideDockAreaActionClicked())); + Action = Menu.addAction(isAutoHide ? tr("Unpin (Dock)") : tr("Pin Group"), this, SLOT(onAutoHideDockAreaActionClicked())); auto AreaIsPinnable = d->DockArea->features().testFlag(CDockWidget::DockWidgetPinnable); Action->setEnabled(AreaIsPinnable); if (!isAutoHide) { - auto menu = Menu.addMenu(tr("Auto Hide Group To...")); + auto menu = Menu.addMenu(tr("Pin Group To...")); menu->setEnabled(AreaIsPinnable); d->createAutoHideToAction(tr("Top"), SideBarTop, menu); d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); @@ -738,19 +740,47 @@ int CDockAreaTitleBar::indexOf(QWidget *widget) const } //============================================================================ -QString CDockAreaTitleBar::closeGroupToolTip() const +QString CDockAreaTitleBar::titleBarButtonToolTip(TitleBarButton Button) const { - if (d->DockArea->isAutoHide()) + switch (Button) { - return QObject::tr("Close Overlay"); - - } - if (CDockManager::testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) - { - return QObject::tr("Close Active Tab"); + case TitleBarButtonAutoHide: + if (d->DockArea->isAutoHide()) + { + return tr("Unpin (Dock)"); + } + + if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideButtonTogglesArea)) + { + return tr("Pin Group"); + } + else + { + return tr("Pin Active Tab (Press Ctrl to Pin Group)"); + } + break; + + case TitleBarButtonClose: + if (d->DockArea->isAutoHide()) + { + return tr("Close"); + } + + if (CDockManager::testConfigFlag(CDockManager::DockAreaCloseButtonClosesTab)) + { + return tr("Close Active Tab"); + } + else + { + return tr("Close Group"); + } + break; + + default: + break; } - return QObject::tr("Close Group") ; + return QString(); } //============================================================================ diff --git a/src/DockAreaTitleBar.h b/src/DockAreaTitleBar.h index 6cc8e50ca..a31464034 100644 --- a/src/DockAreaTitleBar.h +++ b/src/DockAreaTitleBar.h @@ -161,7 +161,7 @@ public Q_SLOTS: * Close group tool tip based on the current state * Auto hide widgets can only have one dock widget so it does not make sense for the tooltip to show close group */ - QString closeGroupToolTip() const; + QString titleBarButtonToolTip(TitleBarButton Button) const; Q_SIGNALS: /** diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 5d7df44d2..93c816b56 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -465,7 +465,7 @@ void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideD { d->AutoHideDockContainer = AutoHideDockContainer; updateAutoHideButtonCheckState(); - updateTitleBarButtonToolTip(); + updateTitleBarButtonsToolTips(); } @@ -880,9 +880,12 @@ void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const //============================================================================ -void CDockAreaWidget::updateTitleBarButtonToolTip() +void CDockAreaWidget::updateTitleBarButtonsToolTips() { - internal::setToolTip(titleBarButton(TitleBarButtonClose), titleBar()->closeGroupToolTip()); + internal::setToolTip(titleBarButton(TitleBarButtonClose), + titleBar()->titleBarButtonToolTip(TitleBarButtonClose)); + internal::setToolTip(titleBarButton(TitleBarButtonAutoHide), + titleBar()->titleBarButtonToolTip(TitleBarButtonAutoHide)); } diff --git a/src/DockAreaWidget.h b/src/DockAreaWidget.h index fface9928..a3ef76c29 100644 --- a/src/DockAreaWidget.h +++ b/src/DockAreaWidget.h @@ -87,7 +87,7 @@ private Q_SLOTS: /* * Update the title bar button tooltips */ - void updateTitleBarButtonToolTip(); + void updateTitleBarButtonsToolTips(); /** * Calculate the auto hide side bar location depending on the dock area diff --git a/src/DockWidgetTab.cpp b/src/DockWidgetTab.cpp index 5d1ce0445..7a8194262 100644 --- a/src/DockWidgetTab.cpp +++ b/src/DockWidgetTab.cpp @@ -532,11 +532,11 @@ void CDockWidgetTab::contextMenuEvent(QContextMenuEvent* ev) Action->setEnabled(isDetachable); if (CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled)) { - Action = Menu.addAction(tr("Auto Hide"), this, SLOT(autoHideDockWidget())); + Action = Menu.addAction(tr("Pin"), this, SLOT(autoHideDockWidget())); auto IsPinnable = d->DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable); Action->setEnabled(IsPinnable); - auto menu = Menu.addMenu(tr("Auto Hide To...")); + auto menu = Menu.addMenu(tr("Pin To...")); menu->setEnabled(IsPinnable); d->createAutoHideToAction(tr("Top"), SideBarTop, menu); d->createAutoHideToAction(tr("Left"), SideBarLeft, menu); From 1b2b90396a231cd81de66778274cdf46dc778bb3 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sat, 5 Nov 2022 10:14:01 +0100 Subject: [PATCH 221/236] Auto Hide Tab now shows text as tooltip - for icon only buttons to help the user --- src/AutoHideTab.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 38090ab59..2b5b10d27 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -222,6 +222,7 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; setText(DockWidget->windowTitle()); setIcon(d->DockWidget->icon()); + setToolTip(DockWidget->windowTitle()); } From e1368be6455f608a99bbb15cf9a15f4a7c4c5d63 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Sat, 5 Nov 2022 10:14:40 +0100 Subject: [PATCH 222/236] Added missing render widget to demo application --- demo/RenderWidget.cpp | 114 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 demo/RenderWidget.cpp diff --git a/demo/RenderWidget.cpp b/demo/RenderWidget.cpp new file mode 100644 index 000000000..41e302472 --- /dev/null +++ b/demo/RenderWidget.cpp @@ -0,0 +1,114 @@ +//============================================================================ +/// \file RenderWidget.cpp +/// \author Uwe Kindler +/// \date 04.11.2022 +/// \brief Implementation of CRenderWidget +//============================================================================ + + +//============================================================================ +// INCLUDES +//============================================================================ +#include "RenderWidget.h" + +#include +#include + + +//=========================================================================== +CRenderWidget::CRenderWidget(QWidget* Parent) : + QWidget(Parent), m_ScaleFactor(1) +{ + // + // OpaquePaintEvent indicates that we do not need an auto-filled + // background. It is used for widgets filling the whole paint area + // with its own opaque colors and need to draw its contents quickly. + // This applies for a capture widget. + // + this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); + this->setCursor(Qt::OpenHandCursor); +} + +//=========================================================================== +CRenderWidget::~CRenderWidget() +{ + +} + +//=========================================================================== +void CRenderWidget::showImage(const QImage& Image) +{ + m_Image = QPixmap::fromImage(Image); + this->adjustWidgetSize(); + this->repaint(); +} + +//=========================================================================== +void CRenderWidget::paintEvent(QPaintEvent* Event) +{ + Q_UNUSED(Event); + QPainter Painter(this); + Painter.setRenderHint(QPainter::SmoothPixmapTransform, true); + Painter.setRenderHint(QPainter::Antialiasing, true); + Painter.scale(m_ScaleFactor, m_ScaleFactor); + Painter.drawPixmap(QPoint(0, 0), m_Image); +} + +//============================================================================ +void CRenderWidget::zoomIn() +{ + scaleImage(1.25); +} + +//============================================================================ +void CRenderWidget::zoomOut() +{ + scaleImage(0.8); +} + +//============================================================================ +void CRenderWidget::zoomByValue(double ZoomValue) +{ + scaleImage(ZoomValue); +} + +//============================================================================ +void CRenderWidget::normalSize() +{ + m_ScaleFactor = 1; + this->adjustWidgetSize(); +} + +//============================================================================ +void CRenderWidget::scaleImage(double ScaleFactor) +{ + m_ScaleFactor *= ScaleFactor; + this->adjustWidgetSize(); +} + +//============================================================================ +void CRenderWidget::adjustWidgetSize() +{ + QSize ScaledImageSize = m_Image.size() * m_ScaleFactor; + if (ScaledImageSize != this->size()) + { + this->setFixedSize(ScaledImageSize); + } +} + +//============================================================================ +void CRenderWidget::scaleToSize(const QSize& TargetSize) +{ + if (m_Image.isNull()) + { + return; + } + double ScaleFactorH = (double) TargetSize.width() / m_Image.size().width(); + double ScaleFactorV = (double) TargetSize.height() + / m_Image.size().height(); + m_ScaleFactor = (ScaleFactorH < ScaleFactorV) ? ScaleFactorH : ScaleFactorV; + this->adjustWidgetSize(); +} + +//--------------------------------------------------------------------------- +// EOF RenderWidget.cpp From 44a5873415d614c93d5f2d2e6490d5b89e30a39a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 08:11:00 +0100 Subject: [PATCH 223/236] Fixed emission of missing top level event when redocking a auto hide widget --- src/AutoHideDockContainer.cpp | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index f4deed397..b83d689bf 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -379,7 +379,17 @@ void CAutoHideDockContainer::moveContentsToParent() // location like it had as a auto hide widget. This brings the least surprise // to the user and he does not have to search where the widget was inserted. d->DockWidget->setDockArea(nullptr); - dockContainer()->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); + auto DockContainer = dockContainer(); + + // If the container contained only one visible dock widget, the we need + // to emit a top level event for this widget because it is not the one and + // only visible docked widget anymore + auto TopLevelDockWidget = DockContainer->topLevelDockWidget(); + DockContainer->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); + if (TopLevelDockWidget) + { + CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, false); + } } From eda610409afaa51863a67228a43e2e5d89a8cf2c Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 08:11:50 +0100 Subject: [PATCH 224/236] Added actions to demo applications to create floating, docked and auto hide image viewers --- demo/MainWindow.cpp | 48 +++++++++ demo/MainWindow.h | 1 + demo/RenderWidget.cpp | 6 -- demo/demo.qrc | 7 ++ demo/images/ads_icon.svg | 86 ++-------------- demo/images/ads_icon2.svg | 13 +++ demo/images/ads_logo.svg | 98 +++---------------- demo/images/ads_tile_blue.svg | 33 +++++++ demo/images/ads_tile_blue_light.svg | 147 ++++++++++++++++++++++++++++ demo/images/ads_tile_green.svg | 33 +++++++ demo/images/ads_tile_orange.svg | 33 +++++++ demo/images/crop_original.svg | 6 ++ demo/images/panorama.svg | 6 ++ demo/images/photo.svg | 6 ++ 14 files changed, 354 insertions(+), 169 deletions(-) create mode 100644 demo/images/ads_icon2.svg create mode 100644 demo/images/ads_tile_blue.svg create mode 100644 demo/images/ads_tile_blue_light.svg create mode 100644 demo/images/ads_tile_green.svg create mode 100644 demo/images/ads_tile_orange.svg create mode 100644 demo/images/crop_original.svg create mode 100644 demo/images/panorama.svg create mode 100644 demo/images/photo.svg diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index bf8a133fd..1325404ed 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -575,6 +575,22 @@ void MainWindowPrivate::createActions() _this->connect(a, SIGNAL(triggered()), SLOT(createTable())); ui.menuTests->addAction(a); + a = ui.toolBar->addAction("Create Image Viewer"); + auto ToolButton = qobject_cast(ui.toolBar->widgetForAction(a)); + ToolButton->setPopupMode(QToolButton::InstantPopup); + a->setToolTip("Creates floating, docked or pinned image viewer"); + a->setIcon(svgIcon(":/adsdemo/images/panorama.svg")); + ui.menuTests->addAction(a); + auto Menu = new QMenu(); + ToolButton->setMenu(Menu); + a = Menu->addAction("Floating Image Viewer"); + _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer())); + a = Menu->addAction("Docked Image Viewer"); + _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer())); + a = Menu->addAction("Pinned Image Viewer"); + _this->connect(a, SIGNAL(triggered()), SLOT(createImageViewer())); + + ui.menuTests->addSeparator(); a = ui.menuTests->addAction("Show Status Dialog"); _this->connect(a, SIGNAL(triggered()), SLOT(showStatusDialog())); @@ -587,6 +603,7 @@ void MainWindowPrivate::createActions() a->setToolTip("Applies a Visual Studio light style (visual_studio_light.css)." ); a->setIcon(svgIcon(":/adsdemo/images/color_lens.svg")); QObject::connect(a, &QAction::triggered, _this, &CMainWindow::applyVsStyle); + ui.menuTests->addAction(a); } @@ -902,3 +919,34 @@ void CMainWindow::applyVsStyle() d->DockManager->setStyleSheet(Stylesheet); } + +//============================================================================ +void CMainWindow::createImageViewer() +{ + QAction* a = qobject_cast(sender()); + qDebug() << "createImageViewer " << a->text(); + + auto DockWidget = d->createImageViewer(); + DockWidget->setFeature(ads::CDockWidget::DockWidgetDeleteOnClose, true); + DockWidget->setFeature(ads::CDockWidget::DockWidgetForceCloseWithArea, true); + DockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true); + DockWidget->resize(QSize(640, 480)); + connect(DockWidget, &ads::CDockWidget::closeRequested, [this](){ + qDebug() << "ImageViewer close requested"; + }); + + if (a->text().startsWith("Floating")) + { + auto FloatingWidget = d->DockManager->addDockWidgetFloating(DockWidget); + FloatingWidget->move(QPoint(20, 20)); + } + else if (a->text().startsWith("Docked")) + { + d->DockManager->addDockWidget(ads::RightDockWidgetArea, DockWidget); + } + else if (a->text().startsWith("Pinned")) + { + d->DockManager->addAutoHideDockWidget(ads::SideBarLeft, DockWidget); + } +} + diff --git a/demo/MainWindow.h b/demo/MainWindow.h index a4d78a888..0eeb52512 100644 --- a/demo/MainWindow.h +++ b/demo/MainWindow.h @@ -66,6 +66,7 @@ private slots: void showStatusDialog(); void toggleDockWidgetWindowTitle(); void applyVsStyle(); + void createImageViewer(); }; #endif // MAINWINDOW_H diff --git a/demo/RenderWidget.cpp b/demo/RenderWidget.cpp index 41e302472..c168e963a 100644 --- a/demo/RenderWidget.cpp +++ b/demo/RenderWidget.cpp @@ -19,12 +19,6 @@ CRenderWidget::CRenderWidget(QWidget* Parent) : QWidget(Parent), m_ScaleFactor(1) { - // - // OpaquePaintEvent indicates that we do not need an auto-filled - // background. It is used for widgets filling the whole paint area - // with its own opaque colors and need to draw its contents quickly. - // This applies for a capture widget. - // this->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); this->setCursor(Qt::OpenHandCursor); } diff --git a/demo/demo.qrc b/demo/demo.qrc index 3139b20b7..e6f2f40e5 100644 --- a/demo/demo.qrc +++ b/demo/demo.qrc @@ -26,5 +26,12 @@ images/zoom_in.svg images/zoom_out.svg images/zoom_out_map.svg + images/ads_tile_blue.svg + images/ads_tile_blue_light.svg + images/ads_tile_green.svg + images/ads_tile_orange.svg + images/photo.svg + images/crop_original.svg + images/panorama.svg diff --git a/demo/images/ads_icon.svg b/demo/images/ads_icon.svg index 4231be6c4..ee0ac56cc 100644 --- a/demo/images/ads_icon.svg +++ b/demo/images/ads_icon.svg @@ -1,77 +1,11 @@ - - - - - electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH - - - - - - - - + + + + + + + + + + diff --git a/demo/images/ads_icon2.svg b/demo/images/ads_icon2.svg new file mode 100644 index 000000000..91a0b02c8 --- /dev/null +++ b/demo/images/ads_icon2.svg @@ -0,0 +1,13 @@ + + + electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH + + + + + + + + + + diff --git a/demo/images/ads_logo.svg b/demo/images/ads_logo.svg index 107254086..da1b3b4de 100644 --- a/demo/images/ads_logo.svg +++ b/demo/images/ads_logo.svg @@ -1,88 +1,12 @@ - - - - - electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH - - Qt Advanced Docking - - - - - - - + + + + Qt Advanced Docking + + + + + + + diff --git a/demo/images/ads_tile_blue.svg b/demo/images/ads_tile_blue.svg new file mode 100644 index 000000000..91ec6dc1b --- /dev/null +++ b/demo/images/ads_tile_blue.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/images/ads_tile_blue_light.svg b/demo/images/ads_tile_blue_light.svg new file mode 100644 index 000000000..aa9bb833b --- /dev/null +++ b/demo/images/ads_tile_blue_light.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/images/ads_tile_green.svg b/demo/images/ads_tile_green.svg new file mode 100644 index 000000000..ce8075af4 --- /dev/null +++ b/demo/images/ads_tile_green.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/images/ads_tile_orange.svg b/demo/images/ads_tile_orange.svg new file mode 100644 index 000000000..bb343dddf --- /dev/null +++ b/demo/images/ads_tile_orange.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demo/images/crop_original.svg b/demo/images/crop_original.svg new file mode 100644 index 000000000..a4a6513a5 --- /dev/null +++ b/demo/images/crop_original.svg @@ -0,0 +1,6 @@ + + crop_original icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/panorama.svg b/demo/images/panorama.svg new file mode 100644 index 000000000..5716c3dfe --- /dev/null +++ b/demo/images/panorama.svg @@ -0,0 +1,6 @@ + + panorama icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/images/photo.svg b/demo/images/photo.svg new file mode 100644 index 000000000..6da023429 --- /dev/null +++ b/demo/images/photo.svg @@ -0,0 +1,6 @@ + + photo icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file From be86a772ce4e631fb6ba36f550befd1b5396a126 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 08:19:00 +0100 Subject: [PATCH 225/236] Implemented custom close handling for dynamically created image viewers --- demo/MainWindow.cpp | 19 ++++++++++++++++--- demo/MainWindow.h | 1 + 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 1325404ed..1509b4bda 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -873,6 +873,20 @@ void CMainWindow::onEditorCloseRequested() } +//============================================================================ +void CMainWindow::onImageViewerCloseRequested() +{ + auto DockWidget = qobject_cast(sender()); + int Result = QMessageBox::question(this, "Close Image Viewer", QString("%1 " + "contains unsaved changes? Would you like to close it?") + .arg(DockWidget->windowTitle())); + if (QMessageBox::Yes == Result) + { + DockWidget->closeDockWidget(); + } +} + + //============================================================================ void CMainWindow::createTable() { @@ -931,9 +945,8 @@ void CMainWindow::createImageViewer() DockWidget->setFeature(ads::CDockWidget::DockWidgetForceCloseWithArea, true); DockWidget->setFeature(ads::CDockWidget::CustomCloseHandling, true); DockWidget->resize(QSize(640, 480)); - connect(DockWidget, &ads::CDockWidget::closeRequested, [this](){ - qDebug() << "ImageViewer close requested"; - }); + connect(DockWidget, &ads::CDockWidget::closeRequested, this, + &CMainWindow::onImageViewerCloseRequested); if (a->text().startsWith("Floating")) { diff --git a/demo/MainWindow.h b/demo/MainWindow.h index 0eeb52512..4afee1483 100644 --- a/demo/MainWindow.h +++ b/demo/MainWindow.h @@ -63,6 +63,7 @@ private slots: void createEditor(); void createTable(); void onEditorCloseRequested(); + void onImageViewerCloseRequested(); void showStatusDialog(); void toggleDockWidgetWindowTitle(); void applyVsStyle(); From 2569e0aa0554328fb667fb43808dd2c295ee71b3 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 09:50:28 +0100 Subject: [PATCH 226/236] Dynamically created image viewer now loads random image in demo --- demo/MainWindow.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 1509b4bda..5e38d3c85 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #ifdef Q_OS_WIN @@ -325,7 +326,19 @@ struct MainWindowPrivate { static int ImageViewerCount = 0; auto w = new CImageViewer(); - auto Result = w->loadFile(":adsdemo/images/ads_logo.svg"); + auto ImageIndex = QRandomGenerator::global()->bounded(4); + auto FileName = ":adsdemo/images/ads_logo.svg"; + + // Pick a random image from a number of images + switch (ImageIndex) + { + case 0: FileName = ":adsdemo/images/ads_tile_blue.svg"; break; + case 1: FileName = ":adsdemo/images/ads_tile_light_blue.svg"; break; + case 2: FileName = ":adsdemo/images/ads_tile_green.svg"; break; + case 3: FileName = ":adsdemo/images/ads_tile_orange.svg"; break; + } + + auto Result = w->loadFile(FileName); qDebug() << "loadFile result: " << Result; ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Image Viewer %1").arg(ImageViewerCount++)); DockWidget->setWidget(w,ads:: CDockWidget::ForceNoScrollArea); @@ -701,6 +714,7 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment if you would like to enable dock widget auto hiding CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); + CDockManager::setAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver, true); // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets From 95b627e83e0d29dc21ac0ab8e20e391285d4436a Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 10:15:14 +0100 Subject: [PATCH 227/236] Prevent accidental hiding collapsing of an auto hide widget by a mouse click shortly after a mouse over collapse event --- src/AutoHideTab.cpp | 24 +++++++++++++++++++++++- src/DockContainerWidget.cpp | 2 +- src/DockManager.h | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/AutoHideTab.cpp b/src/AutoHideTab.cpp index 2b5b10d27..72bbf0c22 100644 --- a/src/AutoHideTab.cpp +++ b/src/AutoHideTab.cpp @@ -31,6 +31,7 @@ #include #include +#include #include "AutoHideDockContainer.h" #include "AutoHideSideBar.h" @@ -49,6 +50,7 @@ struct AutoHideTabPrivate CDockWidget* DockWidget = nullptr; CAutoHideSideBar* SideBar = nullptr; Qt::Orientation Orientation{Qt::Vertical}; + QElapsedTimer TimeSinceHoverMousePress; /** * Private data constructor @@ -229,14 +231,34 @@ void CAutoHideTab::setDockWidget(CDockWidget* DockWidget) //============================================================================ bool CAutoHideTab::event(QEvent* event) { + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver)) + { + return Super::event(event); + } + switch (event->type()) { case QEvent::Enter: case QEvent::Leave: - case QEvent::MouseButtonPress: d->forwardEventToDockContainer(event); break; + case QEvent::MouseButtonPress: + // If AutoHideShowOnMouseOver is active, then the showing is triggered + // by a MousePressEvent sent to this tab. To prevent accidental hiding + // of the tab by a mouse click, we wait at least 500 ms before we accept + // the mouse click + if (!event->spontaneous()) + { + d->TimeSinceHoverMousePress.restart(); + d->forwardEventToDockContainer(event); + } + else if (d->TimeSinceHoverMousePress.hasExpired(500)) + { + d->forwardEventToDockContainer(event); + } + break; + default: break; } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 2ddb1ab84..bf0943602 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -2064,7 +2064,7 @@ CDockManager* CDockContainerWidget::dockManager() const //=========================================================================== void CDockContainerWidget::handleAutoHideWidgetEvent(QEvent* e, QWidget* w) { - if (!CDockManager::testAutoHideConfigFlag(CDockManager::ShowAutoHideOnMouseOver)) + if (!CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver)) { return; } diff --git a/src/DockManager.h b/src/DockManager.h index 4fb3c8d4c..c29ec4a04 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -239,7 +239,7 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget AutoHideButtonTogglesArea = 0x04, //!< If the flag is set, the auto hide button enables auto hiding for all dock widgets in an area, if disabled, only the current dock widget will be toggled AutoHideButtonCheckable = 0x08, //!< If the flag is set, the auto hide button will be checked and unchecked depending on the auto hide state. Mainly for styling purposes. AutoHideSideBarsIconOnly = 0x10,///< show only icons in auto hide side tab - if a tab has no icon, then the text will be shown - ShowAutoHideOnMouseOver = 0x20, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container + AutoHideShowOnMouseOver = 0x20, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton ///< the default configuration for left and right side bars From 6cdea82a40b2cbc368a72c0b94a1a176ea834d4b Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 10:15:39 +0100 Subject: [PATCH 228/236] Fixed wrong image filename in demo application --- demo/MainWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index 5e38d3c85..f549ba370 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -333,7 +333,7 @@ struct MainWindowPrivate switch (ImageIndex) { case 0: FileName = ":adsdemo/images/ads_tile_blue.svg"; break; - case 1: FileName = ":adsdemo/images/ads_tile_light_blue.svg"; break; + case 1: FileName = ":adsdemo/images/ads_tile_blue_light.svg"; break; case 2: FileName = ":adsdemo/images/ads_tile_green.svg"; break; case 3: FileName = ":adsdemo/images/ads_tile_orange.svg"; break; } From 00738704807a96db74819fcb5bc2f85568d68b34 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 14:36:19 +0100 Subject: [PATCH 229/236] Added documentation for Auto-Hide feature --- demo/MainWindow.cpp | 3 + demo/demo.pro | 1 + demo/demo.qrc | 2 + demo/images/ads_icon2.svg | 14 +- demo/images/font_download.svg | 6 + demo/main.cpp | 1 + doc/AutoHide_PinTo.png | Bin 0 -> 27071 bytes ...fg_flag_AutoHideSideBarsIconOnly_false.png | Bin 0 -> 33505 bytes ...cfg_flag_AutoHideSideBarsIconOnly_true.png | Bin 0 -> 15947 bytes doc/cfg_flag_DockAreaHasAutoHideButton.png | Bin 0 -> 17921 bytes doc/user-guide.md | 149 ++++++++++++++---- src/DockManager.h | 12 +- 12 files changed, 143 insertions(+), 45 deletions(-) create mode 100644 demo/images/font_download.svg create mode 100644 doc/AutoHide_PinTo.png create mode 100644 doc/cfg_flag_AutoHideSideBarsIconOnly_false.png create mode 100644 doc/cfg_flag_AutoHideSideBarsIconOnly_true.png create mode 100644 doc/cfg_flag_DockAreaHasAutoHideButton.png diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index f549ba370..b0cb8e461 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -222,6 +222,7 @@ struct MainWindowPrivate ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Filesystem %1") .arg(FileSystemCount++)); DockWidget->setWidget(w); + DockWidget->setIcon(svgIcon(":/adsdemo/images/folder_open.svg")); ui.menuView->addAction(DockWidget->toggleViewAction()); // We disable focus to test focus highlighting if the dock widget content // does not support focus @@ -282,6 +283,7 @@ struct MainWindowPrivate ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Label %1").arg(LabelCount++)); DockWidget->setWidget(l); + DockWidget->setIcon(svgIcon(":/adsdemo/images/font_download.svg")); ui.menuView->addAction(DockWidget->toggleViewAction()); return DockWidget; } @@ -341,6 +343,7 @@ struct MainWindowPrivate auto Result = w->loadFile(FileName); qDebug() << "loadFile result: " << Result; ads::CDockWidget* DockWidget = new ads::CDockWidget(QString("Image Viewer %1").arg(ImageViewerCount++)); + DockWidget->setIcon(svgIcon(":/adsdemo/images/photo.svg")); DockWidget->setWidget(w,ads:: CDockWidget::ForceNoScrollArea); auto ToolBar = DockWidget->createDefaultToolBar(); ToolBar->addActions(w->actions()); diff --git a/demo/demo.pro b/demo/demo.pro index b330fd923..a94b5d12a 100644 --- a/demo/demo.pro +++ b/demo/demo.pro @@ -15,6 +15,7 @@ lessThan(QT_MAJOR_VERSION, 6) { CONFIG += c++14 CONFIG += debug_and_release DEFINES += QT_DEPRECATED_WARNINGS +RC_FILE += app.rc adsBuildStatic { DEFINES += ADS_STATIC diff --git a/demo/demo.qrc b/demo/demo.qrc index e6f2f40e5..a182763a3 100644 --- a/demo/demo.qrc +++ b/demo/demo.qrc @@ -33,5 +33,7 @@ images/photo.svg images/crop_original.svg images/panorama.svg + images/ads_icon2.svg + images/font_download.svg diff --git a/demo/images/ads_icon2.svg b/demo/images/ads_icon2.svg index 91a0b02c8..8ed092a33 100644 --- a/demo/images/ads_icon2.svg +++ b/demo/images/ads_icon2.svg @@ -1,13 +1,11 @@ electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH - - - - - - - - + + + + + + diff --git a/demo/images/font_download.svg b/demo/images/font_download.svg new file mode 100644 index 000000000..ecf5582e4 --- /dev/null +++ b/demo/images/font_download.svg @@ -0,0 +1,6 @@ + + font_download icon - Licensed under Apache License v2.0 (http://www.apache.org/licenses/LICENSE-2.0) - Created with Iconfu.com - Derivative work of Material icons (Copyright Google Inc.) + + + + \ No newline at end of file diff --git a/demo/main.cpp b/demo/main.cpp index 2b7e636af..750c983f0 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -45,6 +45,7 @@ int main(int argc, char *argv[]) QApplication a(argc, argv); a.setApplicationName("Advanced Docking System Demo"); a.setQuitOnLastWindowClosed(true); + a.setWindowIcon(QIcon(":/adsdemo/images/ads_icon2.svg")); qInstallMessageHandler(myMessageOutput); qDebug() << "Message handler test"; diff --git a/doc/AutoHide_PinTo.png b/doc/AutoHide_PinTo.png new file mode 100644 index 0000000000000000000000000000000000000000..5f653e564175946b7f789c4716a70438a2f1cf55 GIT binary patch literal 27071 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�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 literal 0 HcmV?d00001 diff --git a/doc/cfg_flag_DockAreaHasAutoHideButton.png b/doc/cfg_flag_DockAreaHasAutoHideButton.png new file mode 100644 index 0000000000000000000000000000000000000000..0ca1013d331173afd160d6e094acfb61f3e381d2 GIT binary patch literal 17921 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 zUF_aDockManager = new CDockManager(this); +``` + +If you set the Auto-Hide flags, you can set individual flags using the +function `CDockManager::setAutoHideConfigFlag` or you can set all flags using +the function `CDockManager::setAutoHideConfigFlags`. Instead of settings all +flags individually, it is better to pick a predefined set of configuration +flags and then modify individual flags. The following predefined +configurations are available + +- `DefaultAutoHideConfig` - default auto hide config + +Pick one of those predefined configurations and then modify the following +configurations flags to adjust the docking system to your needs. + +### `AutoHideFeatureEnabled` + +Enables / disables the Auto-Hide functionality. Only if this flag is enabled, +the other Auto-Hide flags will be evaluated. + +### `DockAreaHasAutoHideButton` + +If this flag is set (default), then each dock area has a pin button in the title +bar to toggle Auto-Hide state. + +![DockAreaHasAutoHideButton true](cfg_flag_DockAreaHasAutoHideButton.png) + +### `AutoHideButtonTogglesArea` + +If set, the the pin button in the dock area title bar toggles the complete area. +If not set (default), then the pin button toggles the current active tab / dock +widget and pressing the **Ctrl** key while clicking the pin button toggles the +complete ara. + +### `AutoHideButtonCheckable` + +Normally the pin button in the dock area title bar is not checkable. If this +flag is set, then the button is checkable. That means, if button is checked, +the dock widget is pinned. + +### `AutoHideSideBarsIconOnly` + +Normally the Auto-Hide tabs show the icon and title of the dock widget: + +![AutoHideSideBarsIconOnly false](cfg_flag_AutoHideSideBarsIconOnly_false.png) + +You can set this flag, if you would like to have only icons in the Auto-Hide +tabs instead of icon and dock widget title. If this is set, the Auto-Hide tab +needs less space. The tooltip of each tab still shows the dock widget title. + +![AutoHideSideBarsIconOnly true](cfg_flag_AutoHideSideBarsIconOnly_true.png) + +### `AutoHideShowOnMouseOver` + +Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and +hidden by clicking the Auto-Hide tab again or by clicking into any other +dock widget in the same container. If this flag is set, the Auto-Hide widget +is shown, if the user hovers over the Auto-Hide tab or if the users moves the +mouse outside of the Auto-Hide widget. Showing and hiding my mouse click still +works if this feature is enabled. + ## DockWidget Feature Flags ### `DockWidgetClosable` @@ -613,51 +703,48 @@ When an entire area is closed, the default behavior is to hide the dock widgets ## Auto Hide Dock Widgets -Enabling this feature adds a pin icon to each dock area that will pin the dock widgets in the area to the left, right or bottom edge of the window as a side tab. The dock widget is then normally hidden, but showing the view by clicking the tab would overlay the dock widget on top of all the other widgets. +The Advanced Docking System supports "Auto-Hide" functionality for **all** dock containers. The "Auto Hide" feature allows to display more information using less screen space by hiding or showing windows pinned to one of the four dock container borders. -![Auto hide demo](autohide-feature-demo.png) +Enabling this feature adds a button with a pin icon to each dock area. -The area dock widgets are added to are based on the distance to the left, right and bottom edge. +![DockAreaHasAutoHideButton true](cfg_flag_DockAreaHasAutoHideButton.png) -Note: Overlay, Pin, and Auto Hide here all refer to the same functionality. +By clicking this button, the current dock widget (or the complete area - depending on the +configuration flags) will be pinned to a certain border. The border is choosen +depending on the location of the dock area. If you click the pin button while +holding down the **Ctrl** key, the whole dock area will be pinned to a certain +border. -### Setting Configuration Flags +### Pinning Auto-Hide Widgets to a certain border -Setting and enabling the overlay feature is similar to setting config flags, but do be aware that it uses a different eOverlayFlag enum and not the eConfigFlag enum. This is only relevant if you call `CDockManager::setConfigFlags` for the `ConfigFlags`, as it would mean you have to call `CDockManager::setConfigFlags` a second time for the `AutoHideFlags`. +If you would like to pin a dock widget or a dock area to a certain border, +then you can right-click into the dock widget tab or into the dock area title bar +to show the context menu. Then you can select the location via the **Pin to** menu: -```c++ -CDockManager::setConfigFlags(CDockManager::DefaultAutoHideConfig); -CDockManager::setConfigFlag(CDockManager::LeftSideBarPrioritizeIconOnly, true); -... -d->DockManager = new CDockManager(this); -``` +![Pin to](AutoHide_PinTo.png) + +### Show / Hide Auto-Hide Widgets via Mouse Over + +Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and hidden by +clicking the Auto-Hide tab again or by clicking into any other dock widget in +the same container. If the Auto-Hide config flag `AutoHideShowOnMouseOver` is set, +the Auto-Hide widget is shown, if the user hovers over the Auto-Hide tab and is +collapsed if the mouse cursor leaves the Auto-Hide widget. Showing and hiding +my mouse click still works if this feature is enabled. ### Adding Auto Hide Widgets -Adding an auto hide widget is similar to adding a dock widget, simply call `dockManager->addAutoHideDockWidget`. +Adding an auto hide widget is similar to adding a dock widget, simply call +`dockManager->addAutoHideDockWidget()`. ```c++ +CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); d->DockManager = new CDockManager(this); CDockWidget* TableDockWidget = new CDockWidget("Table 1"); -TableDockWidget->setDefaultOverlayDockProportion(0.5); // Default size in proportion to the window size when adding the overlay widget -DockManager->addOverlayDockWidget(CDockWidgetSideTab::SideTabBarArea::LeftTop, TableDockWidget, CDockWidget::Last); +DockManager->addAutoHideDockWidget(SideBarLeft, TableDockWidget); ``` -See `autohide` example to learn how it works. - -### Configuration Flags For Auto Hide Widgets - -- `DockContainerHasTopSideBar`,`DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar` -> Enabling each of these enables the side bar at each location. Disabling any of them would mean that the widget cannot be added at that location, so it would be added at the next available location. E.g. If you only enable `DockContainerHasRightSideBar` and `DockContainerHasBottomSideBar` then it will be added to the bottom side bar or right side bar respectively. If none of these are enabled, the auto hide button will not be added, as at least one of them must be enabled to work. -- `DockAreaHasAutoHideButton` -> Adds the auto hide button to the title bar of the dock area -- `TopSideBarPrioritizeIconOnly`, `LeftSideBarPrioritizeIconOnly`, `RightSideBarPrioritizeIconOnly`, `BottomSideBarPrioritizeIconOnly` -> If this is set, the side bar this is enabled with will prioritize showing an icon only, as opposed to an icon and text. This is set per side bar, so if you only enable `LeftSideBarPrioritizeIconOnly`, the right and bottom side bars will still show the icon and the text. This is only relevant if an icon is set, otherwise it will only show text as usual. -- `AutoHideDockAreaHasTitle` -> Adds the title of the dock window where the title bar would be. -- `DefaultAutoHideConfig` -> Enables `DockContainerHasTopSideBar`, `DockContainerHasLeftSideBar`, `DockContainerHasRightSideBar`, `DockContainerHasBottomSideBar`, `DockAreaHasAutoHideButton`, `AutoHideDockAreaHasTitle` - -### Limitations - -- Currently the `LeftBottom` and `RightBottom` areas can only be added programatically, and not through the pin icon. These are used if you'd like to add a new dock widget separated from the normal dock areas. - -- Adding a `DockWidget` (e.g. via `addDockWidget`) to an `DockArea` in an Auto Hide Widget that already has a dockwidget is undefined behavior. An overlayed dock area does not have tabs and does not support more than one `DockWidget` in it's area. If you want to add a `DockWidget` to a `DockArea` that *could* be in an auto hidden widget, check first if it's auto hidden via `CDockArea::isAutoHide` and handle it accordingly (typically by adding the overlay dock widget as a side tab instead of to the area). +See `autohide` example or the demo application to learn how it works. ## Styling diff --git a/src/DockManager.h b/src/DockManager.h index c29ec4a04..7a2bfc37b 100644 --- a/src/DockManager.h +++ b/src/DockManager.h @@ -340,18 +340,18 @@ class ADS_EXPORT CDockManager : public CDockContainerWidget CDockContainerWidget* DockContainerWidget); /** - * Adds a dock widget overlayed into the dock manager container based on the side tab bar area. - * An overlay widget is used for auto hide functionality + * Adds an Auto-Hide widget to the dock manager container pinned to + * the given side bar location. * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addAutoHideDockWidget(SideBarLocation area, CDockWidget* Dockwidget); + CAutoHideDockContainer* addAutoHideDockWidget(SideBarLocation Location, CDockWidget* Dockwidget); /** - * Adds dock widget overlayed into the given container based on the CDockWidgetSideTab::SideTabBarArea. - * An overlay widget is used for auto hide functionality + * Adds an Auto-Hide widget to the given DockContainerWidget pinned to + * the given side bar location in this container. * \return Returns the CAutoHideDockContainer that contains the new DockWidget */ - CAutoHideDockContainer* addAutoHideDockWidgetToContainer(SideBarLocation area, + CAutoHideDockContainer* addAutoHideDockWidgetToContainer(SideBarLocation Location, CDockWidget* Dockwidget, CDockContainerWidget* DockContainerWidget); /** From 5a9f23a9adbe3233fa9c2aaf68cc054790b880b9 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Mon, 7 Nov 2022 16:28:27 +0100 Subject: [PATCH 230/236] Fixed emission of top level event in DockContainerWidget --- demo/MainWindow.cpp | 1 - doc/user-guide.md | 111 +++++++++++++++++----------------- src/AutoHideDockContainer.cpp | 9 --- src/DockContainerWidget.cpp | 19 +++++- 4 files changed, 72 insertions(+), 68 deletions(-) diff --git a/demo/MainWindow.cpp b/demo/MainWindow.cpp index b0cb8e461..07dea017f 100644 --- a/demo/MainWindow.cpp +++ b/demo/MainWindow.cpp @@ -717,7 +717,6 @@ CMainWindow::CMainWindow(QWidget *parent) : // uncomment if you would like to enable dock widget auto hiding CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); - CDockManager::setAutoHideConfigFlag(CDockManager::AutoHideShowOnMouseOver, true); // uncomment if you would like to enable an equal distribution of the // available size of a splitter to all contained dock widgets diff --git a/doc/user-guide.md b/doc/user-guide.md index e8d882f27..45fd7f5dd 100644 --- a/doc/user-guide.md +++ b/doc/user-guide.md @@ -29,6 +29,10 @@ - [`FloatingContainerForceQWidgetTitleBar` (Linux only)](#floatingcontainerforceqwidgettitlebar-linux-only) - [`MiddleMouseButtonClosesTab`](#middlemousebuttonclosestab) - [Auto-Hide Configuration Flags](#auto-hide-configuration-flags) + - [Auto Hide Dock Widgets](#auto-hide-dock-widgets) + - [Pinning Auto-Hide Widgets to a certain border](#pinning-auto-hide-widgets-to-a-certain-border) + - [Show / Hide Auto-Hide Widgets via Mouse Over](#show--hide-auto-hide-widgets-via-mouse-over) + - [Adding Auto Hide Widgets](#adding-auto-hide-widgets) - [Setting Auto-Hide Flags](#setting-auto-hide-flags) - [`AutoHideFeatureEnabled`](#autohidefeatureenabled) - [`DockAreaHasAutoHideButton`](#dockareahasautohidebutton) @@ -49,10 +53,6 @@ - [Central Widget](#central-widget) - [Empty Dock Area](#empty-dock-area) - [Custom Close Handling](#custom-close-handling) -- [Auto Hide Dock Widgets](#auto-hide-dock-widgets) - - [Pinning Auto-Hide Widgets to a certain border](#pinning-auto-hide-widgets-to-a-certain-border) - - [Show / Hide Auto-Hide Widgets via Mouse Over](#show--hide-auto-hide-widgets-via-mouse-over) - - [Adding Auto Hide Widgets](#adding-auto-hide-widgets) - [Styling](#styling) - [Disabling the Internal Style Sheet](#disabling-the-internal-style-sheet) @@ -500,16 +500,60 @@ possible in various web browsers. ## Auto-Hide Configuration Flags -The Advanced Docking System has a number of global configuration options to -configure the Auto-Hide functionality. The "Auto Hide" feature allows to display -more information using less screen space by hiding or showing windows pinned to -one of the four dock container borders. +### Auto Hide Dock Widgets + +The Advanced Docking System supports "Auto-Hide" functionality for **all** +dock containers. The "Auto Hide" feature allows to display more information +using less screen space by hiding or showing windows pinned to one of the +four dock container borders. + +Enabling this feature adds a button with a pin icon to each dock area. + +![DockAreaHasAutoHideButton true](cfg_flag_DockAreaHasAutoHideButton.png) + +By clicking this button, the current dock widget (or the complete area - depending on the +configuration flags) will be pinned to a certain border. The border is choosen +depending on the location of the dock area. If you click the pin button while +holding down the **Ctrl** key, the whole dock area will be pinned to a certain +border. + +### Pinning Auto-Hide Widgets to a certain border + +If you would like to pin a dock widget or a dock area to a certain border, +then you can right-click into the dock widget tab or into the dock area title bar +to show the context menu. Then you can select the location via the **Pin to** menu: + +![Pin to](AutoHide_PinTo.png) + +### Show / Hide Auto-Hide Widgets via Mouse Over + +Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and hidden by +clicking the Auto-Hide tab again or by clicking into any other dock widget in +the same container. If the Auto-Hide config flag `AutoHideShowOnMouseOver` is set, +the Auto-Hide widget is shown, if the user hovers over the Auto-Hide tab and is +collapsed if the mouse cursor leaves the Auto-Hide widget. Showing and hiding +by mouse click still works if this feature is enabled. + +### Adding Auto Hide Widgets + +Adding an auto hide widget is similar to adding a dock widget, simply call +`dockManager->addAutoHideDockWidget()`. + +```c++ +CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); +d->DockManager = new CDockManager(this); +CDockWidget* TableDockWidget = new CDockWidget("Table 1"); +DockManager->addAutoHideDockWidget(SideBarLeft, TableDockWidget); +``` + +See `autohide` example or the demo application to learn how it works. ### Setting Auto-Hide Flags -You should set the Auto-Hide flags before creating the dock manager -instance. That means, you should set the Auto-Hide flags after setting the -configuration flags. +The Advanced Docking System has a number of global configuration flags to +configure the Auto-Hide functionality. You should set the Auto-Hide flags before +creating the dock manager instance. That means, you should set the Auto-Hide +flags after setting the configuration flags. ```c++ CDockManager::setConfigFlag(CDockManager::FocusHighlighting, true); @@ -701,51 +745,6 @@ Normally clicking the close button of a dock widget will just hide the widget an When an entire area is closed, the default behavior is to hide the dock widgets it contains regardless of the `DockWidgetDeleteOnClose` flag except if there is only one dock widget. In this special case, the `DockWidgetDeleteOnClose` flag is followed. This behavior can be changed by setting the `DockWidgetForceCloseWithArea` flag to all the dock widgets that needs to be closed with their area. -## Auto Hide Dock Widgets - -The Advanced Docking System supports "Auto-Hide" functionality for **all** dock containers. The "Auto Hide" feature allows to display more information using less screen space by hiding or showing windows pinned to one of the four dock container borders. - -Enabling this feature adds a button with a pin icon to each dock area. - -![DockAreaHasAutoHideButton true](cfg_flag_DockAreaHasAutoHideButton.png) - -By clicking this button, the current dock widget (or the complete area - depending on the -configuration flags) will be pinned to a certain border. The border is choosen -depending on the location of the dock area. If you click the pin button while -holding down the **Ctrl** key, the whole dock area will be pinned to a certain -border. - -### Pinning Auto-Hide Widgets to a certain border - -If you would like to pin a dock widget or a dock area to a certain border, -then you can right-click into the dock widget tab or into the dock area title bar -to show the context menu. Then you can select the location via the **Pin to** menu: - -![Pin to](AutoHide_PinTo.png) - -### Show / Hide Auto-Hide Widgets via Mouse Over - -Normally Auto-Hide widgets are shown by clicking the Auto-Hide tab and hidden by -clicking the Auto-Hide tab again or by clicking into any other dock widget in -the same container. If the Auto-Hide config flag `AutoHideShowOnMouseOver` is set, -the Auto-Hide widget is shown, if the user hovers over the Auto-Hide tab and is -collapsed if the mouse cursor leaves the Auto-Hide widget. Showing and hiding -my mouse click still works if this feature is enabled. - -### Adding Auto Hide Widgets - -Adding an auto hide widget is similar to adding a dock widget, simply call -`dockManager->addAutoHideDockWidget()`. - -```c++ -CDockManager::setAutoHideConfigFlags(CDockManager::DefaultAutoHideConfig); -d->DockManager = new CDockManager(this); -CDockWidget* TableDockWidget = new CDockWidget("Table 1"); -DockManager->addAutoHideDockWidget(SideBarLeft, TableDockWidget); -``` - -See `autohide` example or the demo application to learn how it works. - ## Styling The Advanced Docking System supports styling via [Qt Style Sheets](https://doc.qt.io/qt-5/stylesheet.html). All components like splitters, tabs, buttons, titlebar and diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index b83d689bf..6a09fdb18 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -380,16 +380,7 @@ void CAutoHideDockContainer::moveContentsToParent() // to the user and he does not have to search where the widget was inserted. d->DockWidget->setDockArea(nullptr); auto DockContainer = dockContainer(); - - // If the container contained only one visible dock widget, the we need - // to emit a top level event for this widget because it is not the one and - // only visible docked widget anymore - auto TopLevelDockWidget = DockContainer->topLevelDockWidget(); DockContainer->addDockWidget(d->getDockWidgetArea(d->SideTabBarArea), d->DockWidget); - if (TopLevelDockWidget) - { - CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, false); - } } diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index bf0943602..c8d5d697a 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -1360,6 +1360,7 @@ CDockContainerWidget::~CDockContainerWidget() CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockWidget* Dockwidget, CDockAreaWidget* DockAreaWidget) { + auto TopLevelDockWidget = topLevelDockWidget(); CDockAreaWidget* OldDockArea = Dockwidget->dockAreaWidget(); if (OldDockArea) { @@ -1367,14 +1368,28 @@ CDockAreaWidget* CDockContainerWidget::addDockWidget(DockWidgetArea area, CDockW } Dockwidget->setDockManager(d->DockManager); + CDockAreaWidget* DockArea; if (DockAreaWidget) { - return d->addDockWidgetToDockArea(area, Dockwidget, DockAreaWidget); + DockArea = d->addDockWidgetToDockArea(area, Dockwidget, DockAreaWidget); } else { - return d->addDockWidgetToContainer(area, Dockwidget); + DockArea = d->addDockWidgetToContainer(area, Dockwidget); } + + if (TopLevelDockWidget) + { + auto NewTopLevelDockWidget = topLevelDockWidget(); + // If the container contained only one visible dock widget, the we need + // to emit a top level event for this widget because it is not the one and + // only visible docked widget anymore + if (!NewTopLevelDockWidget) + { + CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, false); + } + } + return DockArea; } From 64bd9021d98520dcf47f4d93c7a71831e0517c1e Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 8 Nov 2022 16:32:35 +0100 Subject: [PATCH 231/236] Fixed bug in dropIntoSection() caused by the addition of AutoHideSideBars to dock container --- src/DockContainerWidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index c8d5d697a..9e0aab569 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -566,8 +566,8 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin TargetAreaSplitter = Splitter; } int AreaIndex = TargetAreaSplitter->indexOf(TargetArea); - auto Widget = FloatingWidget->dockContainer()->findChild(QString(), Qt::FindDirectChildrenOnly); - auto FloatingSplitter = qobject_cast(Widget); + auto FloatingSplitter = FloatingWidget->dockContainer()->findChild( + QString(), Qt::FindDirectChildrenOnly); if (TargetAreaSplitter->orientation() == InsertParam.orientation()) { @@ -576,7 +576,7 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin bool AdjustSplitterSizes = true; if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1) { - TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), Widget); + TargetAreaSplitter->insertWidget(AreaIndex + InsertParam.insertOffset(), FloatingSplitter); updateSplitterHandles(TargetAreaSplitter); } else @@ -606,7 +606,7 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin bool AdjustSplitterSizes = true; if ((FloatingSplitter->orientation() != InsertParam.orientation()) && FloatingSplitter->count() > 1) { - NewSplitter->addWidget(Widget); + NewSplitter->addWidget(FloatingSplitter); updateSplitterHandles(NewSplitter); } else From 89cca4c36a41f1f1c419d3264889ab2d96538470 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 8 Nov 2022 16:33:13 +0100 Subject: [PATCH 232/236] Reverted file version change for saved state data because the file is backward compatible --- src/DockManager.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 27fcf09b9..febd4952a 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -88,8 +88,7 @@ enum eStateFileVersion { InitialVersion = 0, //!< InitialVersion Version1 = 1, //!< Version1 - Version2 = 2, //!< Version2 - Version bump due to addition of Autohide functionality - CurrentVersion = Version2//!< CurrentVersion + CurrentVersion = Version1//!< CurrentVersion }; static CDockManager::ConfigFlags StaticConfigFlags = CDockManager::DefaultNonOpaqueConfig; From 208c804db1ab8719fd5513e79c5b76cab1d424b7 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 8 Nov 2022 20:37:48 +0100 Subject: [PATCH 233/236] User rootSplitter() function instead of searching for child widget --- src/DockContainerWidget.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index 9e0aab569..3876ff5ab 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -552,8 +552,9 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin return; } + CDockContainerWidget* FloatingContainer = FloatingWidget->dockContainer(); auto InsertParam = internal::dockAreaInsertParameters(area); - auto NewDockAreas = FloatingWidget->dockContainer()->findChildren( + auto NewDockAreas = FloatingContainer->findChildren( QString(), Qt::FindChildrenRecursively); QSplitter* TargetAreaSplitter = internal::findParent(TargetArea); @@ -566,9 +567,7 @@ void DockContainerWidgetPrivate::dropIntoSection(CFloatingDockContainer* Floatin TargetAreaSplitter = Splitter; } int AreaIndex = TargetAreaSplitter->indexOf(TargetArea); - auto FloatingSplitter = FloatingWidget->dockContainer()->findChild( - QString(), Qt::FindDirectChildrenOnly); - + auto FloatingSplitter = FloatingContainer->rootSplitter(); if (TargetAreaSplitter->orientation() == InsertParam.orientation()) { auto Sizes = TargetAreaSplitter->sizes(); From f13225549224b6d301a1ab1cbf4d0b8da662a589 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 8 Nov 2022 20:38:51 +0100 Subject: [PATCH 234/236] Added app icon for demo app --- demo/app.ico | Bin 0 -> 105914 bytes demo/app.rc | 1 + 2 files changed, 1 insertion(+) create mode 100644 demo/app.ico create mode 100644 demo/app.rc diff --git a/demo/app.ico b/demo/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..3a57c647dcfe7437b80a66f2828a7826512335c1 GIT binary patch literal 105914 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 RxEe*q-^`s6HO=a${|6umt4{y` literal 0 HcmV?d00001 diff --git a/demo/app.rc b/demo/app.rc new file mode 100644 index 000000000..b8bb54af7 --- /dev/null +++ b/demo/app.rc @@ -0,0 +1 @@ +IDI_ICON1 ICON DISCARDABLE "app.ico" From c646d13b142a9e9e358aa5933fba6ed42f60db58 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Tue, 8 Nov 2022 21:12:56 +0100 Subject: [PATCH 235/236] Updated ads_logo.svg to fix size for mobile page --- README.md | 2 +- doc/ads_logo.svg | 117 +++++++++++---------------------------- doc/ads_logo_ukraine.jpg | Bin 0 -> 174876 bytes 3 files changed, 32 insertions(+), 87 deletions(-) create mode 100644 doc/ads_logo_ukraine.jpg diff --git a/README.md b/README.md index 27e86b196..62b3f783a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![ukraine](doc/taiwan_ukraine.jpg) +![ukraine](doc/ukraine.jpg) ![logo](doc/ads_logo.svg) diff --git a/doc/ads_logo.svg b/doc/ads_logo.svg index 107254086..13edf85cd 100644 --- a/doc/ads_logo.svg +++ b/doc/ads_logo.svg @@ -1,88 +1,33 @@ - - - - - electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH - - Qt Advanced Docking - - - - - - + + + electric_iron icon - Licensed under Iconfu Standard License v1.0 (https://www.iconfu.com/iconfu_standard_license) - Incors GmbH + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/ads_logo_ukraine.jpg b/doc/ads_logo_ukraine.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bf36a026785e7c1bf9d15a9ffc7e1c29e19af571 GIT binary patch literal 174876 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 d&}Y@-+zDR(RX?+HpgvXv}9y3Y?4M=n4!I$ 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 LX(Vv=e=q(IFwhu; literal 0 HcmV?d00001 From 8e7b7f536e93953c42cca03d2ee2b044e8a06260 Mon Sep 17 00:00:00 2001 From: Uwe Kindler Date: Wed, 9 Nov 2022 11:15:42 +0100 Subject: [PATCH 236/236] Fixed CAutoHideDockContainer::addDockWidget to prevent OldDockArea->removeDockWidget(DockWidget) call when restoring state --- src/AutoHideDockContainer.cpp | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/AutoHideDockContainer.cpp b/src/AutoHideDockContainer.cpp index 6a09fdb18..208ee075e 100644 --- a/src/AutoHideDockContainer.cpp +++ b/src/AutoHideDockContainer.cpp @@ -339,22 +339,16 @@ void CAutoHideDockContainer::addDockWidget(CDockWidget* DockWidget) d->DockWidget = DockWidget; d->SideTab->setDockWidget(DockWidget); CDockAreaWidget* OldDockArea = DockWidget->dockAreaWidget(); - if (OldDockArea) + auto IsRestoringState = DockWidget->dockManager()->isRestoringState(); + if (OldDockArea && !IsRestoringState) { - OldDockArea->removeDockWidget(DockWidget); - } - d->DockArea->addDockWidget(DockWidget); - - // Prevent overriding of d->Size parameter when this function is called during - // state restoring - if (!DockWidget->dockManager()->isRestoringState() && OldDockArea) - { // The initial size should be a little bit bigger than the original dock // area size to prevent that the resize handle of this auto hid dock area // is near of the splitter of the old dock area. d->Size = OldDockArea->size() + QSize(16, 16); - } - + OldDockArea->removeDockWidget(DockWidget); + } + d->DockArea->addDockWidget(DockWidget); updateSize(); }