diff --git a/demo/main.cpp b/demo/main.cpp index 15ef7b7..7e887f6 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -35,6 +37,8 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS int main(int argc, char *argv[]) { + QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); + QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling); std::shared_ptr b; QApplication a(argc, argv); a.setQuitOnLastWindowClosed(true); diff --git a/src/DockAreaTitleBar.cpp b/src/DockAreaTitleBar.cpp index d50d3f6..e967b78 100644 --- a/src/DockAreaTitleBar.cpp +++ b/src/DockAreaTitleBar.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "FloatingDockContainer.h" #include "DockAreaWidget.h" @@ -61,6 +62,8 @@ struct DockAreaTitleBarPrivate * Creates the internal TabBar */ void createTabBar(); + + QPixmap createTransparentPixmap(const QPixmap& Source); };// struct DockAreaTitleBarPrivate @@ -73,6 +76,18 @@ DockAreaTitleBarPrivate::DockAreaTitleBarPrivate(CDockAreaTitleBar* _public) : } +//============================================================================ +QPixmap DockAreaTitleBarPrivate::createTransparentPixmap(const QPixmap& Source) +{ + QPixmap disabledPixmap(Source.size()); + disabledPixmap.fill(Qt::transparent); + QPainter p(&disabledPixmap); + p.setOpacity(0.25); + p.drawPixmap(0, 0, Source); + return disabledPixmap; +} + + //============================================================================ void DockAreaTitleBarPrivate::createButtons() { @@ -94,8 +109,13 @@ void DockAreaTitleBarPrivate::createButtons() CloseButton = new tTileBarButton(); CloseButton->setObjectName("closeButton"); CloseButton->setAutoRaise(true); - QIcon CloseIcon(":/ads/close-button.svg"); - CloseIcon.addFile(":/ads/close-button-disabled.svg", QSize(), QIcon::Disabled); + + // The standard icons do does not look good on high DPI screens + QIcon CloseIcon = _this->style()->standardIcon(QStyle::SP_TitleBarCloseButton); + QPixmap normalPixmap = _this->style()->standardPixmap(QStyle::SP_TitleBarCloseButton, 0, CloseButton); + QPixmap disabledPixmap = createTransparentPixmap(normalPixmap); + CloseIcon.addPixmap(disabledPixmap, QIcon::Disabled); + CloseButton->setIcon(CloseIcon); CloseButton->setToolTip(QObject::tr("Close")); CloseButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); diff --git a/src/DockAreaWidget.cpp b/src/DockAreaWidget.cpp index 079abbd..392f290 100644 --- a/src/DockAreaWidget.cpp +++ b/src/DockAreaWidget.cpp @@ -373,6 +373,7 @@ void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) { qDebug() << "CDockAreaWidget::removeDockWidget"; + std::cout << "CDockAreaWidget::removeDockWidget" << std::endl; auto NextOpenDockWidget = nextOpenDockWidget(DockWidget); d->ContentsLayout->removeWidget(DockWidget); @@ -398,7 +399,11 @@ void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget) } d->updateTabBar(); - DockWidget->setDockArea(nullptr); + auto TopLevelDockWidget = dockContainer()->topLevelDockWidget(); + if (TopLevelDockWidget) + { + TopLevelDockWidget->emitTopLevelChanged(true); + } #if (ADS_DEBUG_LEVEL > 0) CDockContainerWidget* DockContainer = dockContainer(); diff --git a/src/DockContainerWidget.cpp b/src/DockContainerWidget.cpp index ca2ac22..eaf5565 100644 --- a/src/DockContainerWidget.cpp +++ b/src/DockContainerWidget.cpp @@ -759,8 +759,7 @@ CDockContainerWidget::CDockContainerWidget(CDockManager* DockManager, QWidget *p QFrame(parent), d(new DockContainerWidgetPrivate(this)) { - d->isFloating = dynamic_cast(parent) != 0; - + d->isFloating = floatingWidget() != nullptr; d->DockManager = DockManager; if (DockManager != this) { @@ -986,8 +985,9 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi CDockAreaWidget* DockArea = dockAreaAt(TargetPos); auto dropArea = InvalidDockWidgetArea; auto ContainerDropArea = d->DockManager->containerOverlay()->dropAreaUnderCursor(); - CDockWidget* TopLevelDockWidget = FloatingWidget->hasTopLevelDockWidget() ? - FloatingWidget->topLevelDockWidget() : nullptr; + CDockWidget* FloatingTopLevelDockWidget = FloatingWidget->topLevelDockWidget(); + CDockWidget* TopLevelDockWidget = topLevelDockWidget(); + if (DockArea) { auto dropOverlay = d->DockManager->dockAreaOverlay(); @@ -1017,12 +1017,19 @@ void CDockContainerWidget::dropFloatingWidget(CFloatingDockContainer* FloatingWi } } - // If we drop a floating widget with only one single dock widget, then we - // drop a top level widget that changes from floating to docked now + // If there was a top level widget before the drop, then it is not top + // level widget anymore if (TopLevelDockWidget) { TopLevelDockWidget->emitTopLevelChanged(false); } + + // If we drop a floating widget with only one single dock widget, then we + // drop a top level widget that changes from floating to docked now + if (FloatingTopLevelDockWidget) + { + FloatingTopLevelDockWidget->emitTopLevelChanged(false); + } } @@ -1052,7 +1059,7 @@ void CDockContainerWidget::saveState(QXmlStreamWriter& s) const s.writeAttribute("Floating", QString::number(isFloating() ? 1 : 0)); if (isFloating()) { - CFloatingDockContainer* FloatingWidget = internal::findParent(this); + CFloatingDockContainer* FloatingWidget = floatingWidget(); QByteArray Geometry = FloatingWidget->saveGeometry(); s.writeTextElement("Geometry", Geometry.toHex(' ')); } @@ -1091,7 +1098,7 @@ bool CDockContainerWidget::restoreState(QXmlStreamReader& s, bool Testing) if (!Testing) { - CFloatingDockContainer* FloatingWidget = internal::findParent(this); + CFloatingDockContainer* FloatingWidget = floatingWidget(); FloatingWidget->restoreGeometry(Geometry); } } @@ -1118,6 +1125,40 @@ bool CDockContainerWidget::restoreState(QXmlStreamReader& s, bool Testing) d->RootSplitter = dynamic_cast(NewRootSplitter); OldRoot->deleteLater(); + // All dock widgets, that have not been processed in the restore state + // function are invisible to the user now and have no assigned dock area + // They do not belong to any dock container, until the user toggles the + // toggle view action the next time + for (auto DockWidget : dockWidgets()) + { + if (DockWidget->property("dirty").toBool()) + { + DockWidget->flagAsUnassigned(); + } + else + { + DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool()); + } + } + + // Finally we need to send the topLevelChanged() signals for all dock + // widgets if top level changed + CDockWidget* TopLevelDockWidget = topLevelDockWidget(); + if (TopLevelDockWidget) + { + TopLevelDockWidget->emitTopLevelChanged(true); + } + else + { + for (auto DockArea : d->DockAreas) + { + for (auto DockWidget : DockArea->dockWidgets()) + { + DockWidget->emitTopLevelChanged(false); + } + } + } + return true; } @@ -1150,6 +1191,11 @@ CDockAreaWidget* CDockContainerWidget::lastAddedDockAreaWidget(DockWidgetArea ar //============================================================================ bool CDockContainerWidget::hasTopLevelDockWidget() const { + if (!isFloating()) + { + return false; + } + auto DockAreas = openedDockAreas(); if (DockAreas.count() != 1) { @@ -1163,19 +1209,38 @@ bool CDockContainerWidget::hasTopLevelDockWidget() const //============================================================================ CDockWidget* CDockContainerWidget::topLevelDockWidget() const { - auto DockAreas = openedDockAreas(); - if (DockAreas.count() != 1) + auto TopLevelDockArea = topLevelDockArea(); + if (!TopLevelDockArea) { return nullptr; } - auto DockWidgets = DockAreas[0]->openedDockWidgets(); + auto DockWidgets = TopLevelDockArea->openedDockWidgets(); if (DockWidgets.count() != 1) { return nullptr; } return DockWidgets[0]; + +} + + +//============================================================================ +CDockAreaWidget* CDockContainerWidget::topLevelDockArea() const +{ + if (!isFloating()) + { + return nullptr; + } + + auto DockAreas = openedDockAreas(); + if (DockAreas.count() != 1) + { + return nullptr; + } + + return DockAreas[0]; } @@ -1204,6 +1269,14 @@ CDockWidget::DockWidgetFeatures CDockContainerWidget::features() const return Features; } + +//============================================================================ +CFloatingDockContainer* CDockContainerWidget::floatingWidget() const +{ + return internal::findParent(this); +} + + } // namespace ads #include "moc_DockContainerWidget.cpp" diff --git a/src/DockContainerWidget.h b/src/DockContainerWidget.h index 5da5ffe..7d90a3b 100644 --- a/src/DockContainerWidget.h +++ b/src/DockContainerWidget.h @@ -127,6 +127,11 @@ protected: */ CDockWidget* topLevelDockWidget() const; + /** + * Returns the top level dock area. + */ + CDockAreaWidget* topLevelDockArea() const; + /** * This function returns a list of all dock widgets in this floating widget. * It may be possible, depending on the implementation, that dock widgets, @@ -216,6 +221,13 @@ public: */ CDockWidget::DockWidgetFeatures features() const; + /** + * If this dock container is in a floating widget, this function returns + * the floating widget. + * Else, it returns a nullptr. + */ + CFloatingDockContainer* floatingWidget() const; + signals: /** * This signal is emitted if one or multiple dock areas has been added to diff --git a/src/DockManager.cpp b/src/DockManager.cpp index 6d0a7bb..2be9c82 100644 --- a/src/DockManager.cpp +++ b/src/DockManager.cpp @@ -141,16 +141,27 @@ bool DockManagerPrivate::restoreContainer(int Index, QXmlStreamReader& stream, b Index = 0; } + bool Result = false; if (Index >= Containers.count()) { CFloatingDockContainer* FloatingWidget = new CFloatingDockContainer(_this); - return FloatingWidget->restoreState(stream, Testing); + Result = FloatingWidget->restoreState(stream, Testing); } else { qDebug() << "d->Containers[i]->restoreState "; - return Containers[Index]->restoreState(stream, Testing); + auto Container = Containers[Index]; + if (Container->isFloating()) + { + Result = Container->floatingWidget()->restoreState(stream, Testing); + } + else + { + Result = Container->restoreState(stream, Testing); + } } + + return Result; } @@ -242,23 +253,6 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version) return false; } - // All dock widgets, that have not been processed in the restore state - // function are invisible to the user now and have no assigned dock area - // They do not belong to any dock container, until the user toggles the - // toggle view action the next time - for (auto DockWidget : DockWidgetsMap) - { - if (DockWidget->property("dirty").toBool()) - { - DockWidget->flagAsUnassigned(); - } - else - { - DockWidget->toggleViewInternal(!DockWidget->property("closed").toBool()); - } - } - - // Now all dock areas are properly restored and we setup the index of // The dock areas because the previous toggleView() action has changed // the dock area index @@ -281,7 +275,7 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version) // Finally we need to send the topLevelChanged() signals for all dock // widgets if top level changed - for (auto DockContainer : Containers) + /*for (auto DockContainer : Containers) { CDockWidget* TopLevelDockWidget = DockContainer->topLevelDockWidget(); if (TopLevelDockWidget) @@ -299,7 +293,7 @@ bool DockManagerPrivate::restoreState(const QByteArray &state, int version) } } } - } + }*/ return true; } diff --git a/src/DockWidget.cpp b/src/DockWidget.cpp index a2bbb21..ed8016d 100644 --- a/src/DockWidget.cpp +++ b/src/DockWidget.cpp @@ -434,17 +434,11 @@ void CDockWidget::toggleView(bool Open) void CDockWidget::toggleViewInternal(bool Open) { CDockContainerWidget* DockContainer = dockContainer(); - CDockWidget* TopLevelDockWidget = nullptr; - CDockWidget* TopLevelDockWidgetBefore = nullptr; - - if (DockContainer) - { - TopLevelDockWidgetBefore = DockContainer->topLevelDockWidget(); - } + CDockWidget* TopLevelDockWidgetBefore = DockContainer + ? DockContainer->topLevelDockWidget() : nullptr; if (Open) { - TopLevelDockWidget = TopLevelDockWidgetBefore; d->showDockWidget(); } else @@ -460,32 +454,20 @@ void CDockWidget::toggleViewInternal(bool Open) d->DockArea->toggleDockWidgetView(this, Open); } - if (!Open && DockContainer) + if (Open && TopLevelDockWidgetBefore) { - TopLevelDockWidget = DockContainer->topLevelDockWidget(); + CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetBefore, false); } - if (TopLevelDockWidget) + CDockWidget* TopLevelDockWidgetAfter = DockContainer + ? DockContainer->topLevelDockWidget() : nullptr; + CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidgetAfter, true); + CFloatingDockContainer* FloatingContainer = DockContainer->floatingWidget(); + if (FloatingContainer) { - CDockWidget::emitTopLevelEventForWidget(TopLevelDockWidget, !Open); + FloatingContainer->updateWindowTitle(); } - CDockWidget* TopLevelDockWidgetAfter = nullptr; - if (DockContainer) - { - TopLevelDockWidgetAfter = DockContainer->topLevelDockWidget(); - } - - if (TopLevelDockWidgetAfter != TopLevelDockWidgetBefore) - { - CFloatingDockContainer* FloatingContainer = qobject_cast(DockContainer->parentWidget()); - if (FloatingContainer) - { - FloatingContainer->updateWindowTitle(TopLevelDockWidgetAfter ? TopLevelDockWidgetAfter->windowTitle() : ""); - } - } - - if (!Open) { emit closed(); diff --git a/src/FloatingDockContainer.cpp b/src/FloatingDockContainer.cpp index 66fb06a..5ebc921 100644 --- a/src/FloatingDockContainer.cpp +++ b/src/FloatingDockContainer.cpp @@ -466,9 +466,11 @@ bool CFloatingDockContainer::isClosable() const void CFloatingDockContainer::onDockAreasAddedOrRemoved() { qDebug() << "CFloatingDockContainer::onDockAreasAddedOrRemoved()"; - if (d->DockContainer->visibleDockAreaCount() == 1) + std::cout << "CFloatingDockContainer::onDockAreasAddedOrRemoved()" << std::endl; + auto TopLevelDockArea = d->DockContainer->topLevelDockArea(); + if (TopLevelDockArea) { - d->SingleDockArea = d->DockContainer->openedDockAreas()[0]; + d->SingleDockArea = TopLevelDockArea; this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); connect(d->SingleDockArea, SIGNAL(currentChanged(int)), this, SLOT(onDockAreaCurrentChanged(int))); @@ -487,15 +489,16 @@ void CFloatingDockContainer::onDockAreasAddedOrRemoved() //============================================================================ -void CFloatingDockContainer::updateWindowTitle(const QString& Title) +void CFloatingDockContainer::updateWindowTitle() { - if (Title.isEmpty()) + auto TopLevelDockArea = d->DockContainer->topLevelDockArea(); + if (TopLevelDockArea) { - this->setWindowTitle(qApp->applicationDisplayName()); + this->setWindowTitle(TopLevelDockArea->currentDockWidget()->windowTitle()); } else { - this->setWindowTitle(Title); + this->setWindowTitle(qApp->applicationDisplayName()); } } @@ -504,6 +507,8 @@ void CFloatingDockContainer::updateWindowTitle(const QString& Title) void CFloatingDockContainer::onDockAreaCurrentChanged(int Index) { Q_UNUSED(Index); + std::cout << "CFloatingDockContainer::onDockAreaCurrentChanged " + << Index << std::endl; this->setWindowTitle(d->SingleDockArea->currentDockWidget()->windowTitle()); } @@ -515,6 +520,8 @@ bool CFloatingDockContainer::restoreState(QXmlStreamReader& Stream, bool Testing { return false; } + + std::cout << "Dockarea count " << d->DockContainer->dockAreaCount() << std::endl; onDockAreasAddedOrRemoved(); return true; } @@ -533,6 +540,7 @@ CDockWidget* CFloatingDockContainer::topLevelDockWidget() const return d->DockContainer->topLevelDockWidget(); } + //============================================================================ QList CFloatingDockContainer::dockWidgets() const { diff --git a/src/FloatingDockContainer.h b/src/FloatingDockContainer.h index 2729dee..9fb423f 100644 --- a/src/FloatingDockContainer.h +++ b/src/FloatingDockContainer.h @@ -99,7 +99,7 @@ protected: /** * Call this function to update the window title */ - void updateWindowTitle(const QString& Title =""); + void updateWindowTitle(); protected: // reimplements QWidget