diff --git a/core/ModuleView.cpp b/core/ModuleView.cpp --- a/core/ModuleView.cpp +++ b/core/ModuleView.cpp @@ -30,8 +30,11 @@ #include #include #include +#include #include #include +#include +#include #include #include @@ -48,6 +51,60 @@ #include "MenuItem.h" +class BreadcrumbButton : public QToolButton { + Q_OBJECT +public: + BreadcrumbButton(QWidget *parent = 0) + : QToolButton(parent) + { + QFont font = QToolButton::font(); + font.setPointSize(14); + setFont(font); + setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + setAutoRaise(true); + setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); + setGraphicsEffect(new QGraphicsOpacityEffect(this)); + } + + void setLevel(uint level) + { + m_level = level; + if (level > 0) { + setArrowType(Qt::RightArrow); + } else { + setArrowType(Qt::NoArrow); + } + } + + void setCurrent(bool current) + { + if (current) { + //1.0 doesn't work on old Qt releases, see https://bugreports.qt.io/browse/QTBUG-66803 + static_cast(graphicsEffect())->setOpacity(0.99); + } else { + static_cast(graphicsEffect())->setOpacity(0.6); + } + } + + void paintEvent(QPaintEvent *) + { + QStylePainter p(this); + QStyleOptionToolButton opt; + initStyleOption(&opt); + opt.palette.setColor(QPalette::WindowText, opt.palette.color(QPalette::Normal, QPalette::WindowText)); + p.drawComplexControl(QStyle::CC_ToolButton, opt); + } + + QSize sizeHint() const + { + QFontMetrics fm(font()); + return QSize(fm.tightBoundingRect(text()).width() + (m_level > 0 ? KIconLoader::SizeSmall : 0), QToolButton::sizeHint().height()); + } + +private: + uint m_level = 0; +}; + class ModuleView::Private { public: Private() {} @@ -175,13 +232,21 @@ } // Create the scroller + QWidget *mainWidget = new QWidget( this ); + QVBoxLayout *layout = new QVBoxLayout( mainWidget ); + QHBoxLayout *titleLayout = new QHBoxLayout; + titleLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum)); + titleLayout->setSpacing(0); + layout->addLayout(titleLayout); + QScrollArea * moduleScroll = new QScrollArea( this ); + layout->addWidget(moduleScroll); // Prepare the scroll area moduleScroll->setWidgetResizable( true ); moduleScroll->setFrameStyle( QFrame::NoFrame ); moduleScroll->viewport()->setAutoFillBackground( false ); // Create the page - KPageWidgetItem *page = new KPageWidgetItem( moduleScroll, module->moduleName() ); + KPageWidgetItem *page = new KPageWidgetItem( mainWidget, module->moduleName() ); // Provide information to the users if( module->service()->hasServiceType(QStringLiteral("SystemSettingsExternalApp")) || // Is it an external app? @@ -194,6 +259,43 @@ moduleProxy->setAutoFillBackground( false ); connect( moduleProxy, SIGNAL(changed(bool)), this, SLOT(stateChanged())); d->mPages.insert( page, moduleProxy ); + + const auto createBreadCrumb = [this, mainWidget, moduleProxy, titleLayout](const QString &title) { + BreadcrumbButton *crumbPart = new BreadcrumbButton(mainWidget); + crumbPart->setText(title); + + const int level = titleLayout->count() - 1; + crumbPart->setLevel(level); + titleLayout->insertWidget(level, crumbPart); + if (titleLayout->count() == 2) { + crumbPart->setEnabled(false); + } else { + titleLayout->itemAt(0)->widget()->setEnabled(true); + } + connect(crumbPart, &QToolButton::clicked, this, [this, moduleProxy, level]() { + moduleProxy->realModule()->setCurrentLevel(level); + }); + //connected to crumbPart so the connection goes away at its deletion + connect(moduleProxy->realModule(), &KCModule::currentLevelChanged, crumbPart, [this, crumbPart, level](int newLevel) { + crumbPart->setCurrent(level == newLevel); + }); + static_cast(crumbPart->graphicsEffect())->setOpacity(0.99); + }; + + for (const auto &title : moduleProxy->realModule()->levelTitles()) { + createBreadCrumb(title); + } + + connect(moduleProxy->realModule(), &KCModule::levelPushed, + this, createBreadCrumb); + connect(moduleProxy->realModule(), &KCModule::levelRemoved, this, + [this, titleLayout]() { + if (titleLayout->count() == 3) { + titleLayout->itemAt(0)->widget()->setEnabled(false); + } + titleLayout->itemAt(titleLayout->count() - 2)->widget()->deleteLater(); + } + ); } d->mModules.insert( page, module ); @@ -203,7 +305,9 @@ } void ModuleView::updatePageIconHeader( KPageWidgetItem * page, bool light ) -{ +{page->setHeader(QString()); + page->setName(QString()); + return; if( !page ) { // Page is invalid. Probably means we have a race condition during closure of everyone so do nothing return; @@ -437,3 +541,4 @@ return d->mPageWidget->faceType(); } +#include "ModuleView.moc"