#include "ElaNavigationBar.h" #include "ElaBaseListView.h" #include "ElaFooterDelegate.h" #include "ElaFooterModel.h" #include "ElaIconButton.h" #include "ElaInteractiveCard.h" #include "ElaMenu.h" #include "ElaNavigationModel.h" #include "ElaNavigationNode.h" #include "ElaNavigationView.h" #include "ElaSuggestBox.h" #include "ElaTheme.h" #include "ElaToolButton.h" #include "private/ElaNavigationBarPrivate.h" #include "private/ElaSuggestBoxPrivate.h" #include #include #include #include #include #include #include Q_PROPERTY_CREATE_Q_CPP(ElaNavigationBar, bool, IsTransparent) Q_PROPERTY_CREATE_Q_CPP(ElaNavigationBar, bool, IsAllowPageOpenInNewWindow) ElaNavigationBar::ElaNavigationBar(QWidget *parent) : QWidget{parent}, d_ptr(new ElaNavigationBarPrivate()) { Q_D(ElaNavigationBar); d->q_ptr = this; d->_pIsAllowPageOpenInNewWindow = true; d->_pNavigationBarWidth = 300; setFixedWidth(300); d->_pIsTransparent = true; // 用户卡片 d->_userCard = new ElaInteractiveCard(this); d->_userCard->setMinimumWidth(0); d->_userCard->setCardPixmap(QPixmap(":/include/Image/Cirno.jpg")); d->_userCard->setTitle("Ela Tool"); d->_userCard->setSubTitle("Liniyous@gmail.com"); connect(d->_userCard, &ElaInteractiveCard::clicked, this, &ElaNavigationBar::userInfoCardClicked); d->_userButton = new ElaIconButton(QPixmap(":/include/Image/Cirno.jpg"), this); d->_userButton->setFixedSize(36, 36); d->_userButton->setVisible(false); d->_userButton->setBorderRadius(8); d->_userButtonLayout = new QVBoxLayout(); d->_userButtonLayout->setAlignment(Qt::AlignLeft); d->_userButtonLayout->setContentsMargins(0, 0, 0, 6); d->_userButtonLayout->setSpacing(0); d->_userButtonLayout->addWidget(d->_userButton); connect(d->_userButton, &ElaIconButton::clicked, this, &ElaNavigationBar::userInfoCardClicked); QHBoxLayout *userCardLayout = new QHBoxLayout(); userCardLayout->setContentsMargins(0, 0, 0, 0); userCardLayout->addSpacing(3); userCardLayout->addLayout(d->_userButtonLayout); userCardLayout->addWidget(d->_userCard); // 搜索栏和按钮组 d->_navigationButton = new ElaToolButton(this); d->_navigationButton->setFixedSize(40, 38); d->_navigationButton->setElaIcon(ElaIconType::Bars); d->_navigationButton->setBorderRadius(8); connect(d->_navigationButton, &ElaToolButton::clicked, d, &ElaNavigationBarPrivate::onNavigationButtonClicked); d->_searchButton = new ElaToolButton(this); d->_searchButton->setFixedSize(40, 38); d->_searchButton->setElaIcon(ElaIconType::MagnifyingGlass); d->_searchButton->setBorderRadius(8); connect(d->_searchButton, &ElaToolButton::clicked, d, &ElaNavigationBarPrivate::onNavigationButtonClicked); d->_searchButton->setVisible(false); d->_navigationSuggestBox = new ElaSuggestBox(this); d->_navigationSuggestBox->setMinimumWidth(0); d->_navigationButtonLayout = new QVBoxLayout(); d->_navigationButtonLayout->setContentsMargins(0, 0, 0, 0); d->_navigationButtonLayout->setSpacing(0); d->_navigationButtonLayout->addWidget(d->_navigationButton); d->_navigationButtonLayout->addWidget(d->_searchButton); d->_navigationSuggestLayout = new QHBoxLayout(); d->_navigationSuggestLayout->setContentsMargins(0, 0, 10, 0); d->_navigationSuggestLayout->setSpacing(6); d->_navigationSuggestLayout->addLayout(d->_navigationButtonLayout); d->_navigationSuggestLayout->addWidget(d->_navigationSuggestBox); // 搜索跳转 connect(d->_navigationSuggestBox, &ElaSuggestBox::suggestionClicked, this, [=](QString suggestText, QVariantMap suggestData) { ElaNavigationNode *node = nullptr; if (suggestData.value("ElaNodeType").toString() == "Stacked") { node = d->_navigationModel->getNavigationNode(suggestData.value("ElaPageKey").toString()); if (node) { d->onTreeViewClicked(node->getModelIndex()); } } else { node = d->_footerModel->getNavigationNode(suggestData.value("ElaPageKey").toString()); if (node) { d->onFooterViewClicked(node->getModelIndex()); } } }); // 导航模型 d->_navigationModel = new ElaNavigationModel(this); d->_navigationView = new ElaNavigationView(this); d->_navigationView->setNavigationBarPrivate(d); d->_navigationView->setModel(d->_navigationModel); connect(d->_navigationView, &ElaNavigationView::navigationClicked, this, [=](const QModelIndex &index) { d->onTreeViewClicked(index); }); connect(d->_navigationView, &ElaNavigationView::navigationOpenNewWindow, d, &ElaNavigationBarPrivate::onNavigationOpenNewWindow); // 页脚 d->_footerView = new ElaBaseListView(this); d->_footerView->setFixedHeight(0); d->_footerModel = new ElaFooterModel(this); d->_footerView->setModel(d->_footerModel); d->_footerDelegate = new ElaFooterDelegate(this); d->_footerDelegate->setElaListView(d->_footerView); d->_footerView->setItemDelegate(d->_footerDelegate); connect(d->_footerView, &ElaBaseListView::mousePress, this, [=](const QModelIndex &index) { d->_footerDelegate->setPressIndex(index); d->_footerView->viewport()->update(); }); connect(d->_footerView, &ElaBaseListView::mouseDoubleClick, this, [=](const QModelIndex &index) { d->_footerDelegate->setPressIndex(index); d->_footerView->viewport()->update(); }); connect(d->_footerView, &ElaBaseListView::mouseRelease, this, [=](const QModelIndex &index) { d->_footerDelegate->setPressIndex(QModelIndex()); d->_footerView->viewport()->update(); }); connect(d->_footerView, &ElaBaseListView::clicked, this, [=](const QModelIndex &index) { d->onFooterViewClicked(index); }); QVBoxLayout *mainLayout = new QVBoxLayout(this); mainLayout->setAlignment(Qt::AlignLeft); mainLayout->setSpacing(0); mainLayout->setContentsMargins(0, 10, 5, 0); mainLayout->addLayout(userCardLayout); mainLayout->addSpacing(4); mainLayout->addLayout(d->_navigationSuggestLayout); mainLayout->addSpacing(4); mainLayout->addWidget(d->_navigationView); mainLayout->addWidget(d->_footerView); // 主题设置 d->_themeMode = eTheme->getThemeMode(); connect(eTheme, &ElaTheme::themeModeChanged, this, [=](ElaThemeType::ThemeMode themeMode) { d->_themeMode = themeMode; }); } ElaNavigationBar::~ElaNavigationBar() {} void ElaNavigationBar::setNavigationBarWidth(int navigationBarWidth) { Q_D(ElaNavigationBar); if (navigationBarWidth < 180) { navigationBarWidth = 180; } if (d->_currentDisplayMode == ElaNavigationType::NavigationDisplayMode::Maximal) { setFixedWidth(navigationBarWidth); } d->_pNavigationBarWidth = navigationBarWidth; Q_EMIT pNavigationBarWidthChanged(); } int ElaNavigationBar::getNavigationBarWidth() const { Q_D(const ElaNavigationBar); return d->_pNavigationBarWidth; } void ElaNavigationBar::setUserInfoCardVisible(bool isVisible) { Q_D(ElaNavigationBar); d->_isShowUserCard = isVisible; d->_userCard->setVisible(isVisible); if (!isVisible) { d->_userButton->setVisible(false); } } void ElaNavigationBar::setUserInfoCardPixmap(QPixmap pix) { Q_D(ElaNavigationBar); d->_userCard->setCardPixmap(pix); d->_userButton->setPixmap(pix); } void ElaNavigationBar::setUserInfoCardTitle(QString title) { Q_D(ElaNavigationBar); d->_userCard->setTitle(title); } void ElaNavigationBar::setUserInfoCardSubTitle(QString subTitle) { Q_D(ElaNavigationBar); d->_userCard->setSubTitle(subTitle); } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addExpanderNode(QString expanderTitle, QString &expanderKey, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); ElaNavigationType::NodeOperateReturnType returnType = d_ptr->_navigationModel->addExpanderNode(expanderTitle, expanderKey, awesome); if (returnType == ElaNavigationType::Success) { d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addExpanderNode(QString expanderTitle, QString &expanderKey, QString targetExpanderKey, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); ElaNavigationType::NodeOperateReturnType returnType = d->_navigationModel->addExpanderNode(expanderTitle, expanderKey, targetExpanderKey, awesome); if (returnType == ElaNavigationType::Success) { d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addPageNode(QString pageTitle, QWidget *page, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); if (!page) { return ElaNavigationType::PageInvalid; } QString pageKey; ElaNavigationType::NodeOperateReturnType returnType = d_ptr->_navigationModel->addPageNode(pageTitle, pageKey, awesome); if (returnType == ElaNavigationType::Success) { d->_pageMetaMap.insert(pageKey, page->metaObject()); d->_pageNewWindowCountMap.insert(pageKey, 0); d->_addStackedPage(page, pageKey); d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addPageNode(QString pageTitle, QWidget *page, QString targetExpanderKey, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); if (!page) { return ElaNavigationType::PageInvalid; } if (targetExpanderKey.isEmpty()) { return ElaNavigationType::TargetNodeInvalid; } QString pageKey; ElaNavigationType::NodeOperateReturnType returnType = d->_navigationModel->addPageNode(pageTitle, pageKey, targetExpanderKey, awesome); if (returnType == ElaNavigationType::NodeOperateReturnType::Success) { d->_pageMetaMap.insert(pageKey, page->metaObject()); d->_pageNewWindowCountMap.insert(pageKey, 0); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(pageKey); ElaNavigationNode *originalNode = node->getOriginalNode(); if (d->_compactMenuMap.contains(originalNode)) { ElaMenu *menu = d->_compactMenuMap.value(originalNode); QAction *action = menu->addElaIconAction(node->getAwesome(), node->getNodeTitle()); connect(action, &QAction::triggered, this, [=]() { d->onTreeViewClicked(node->getModelIndex()); }); } else { ElaMenu *menu = new ElaMenu(const_cast(this)); QAction *action = menu->addElaIconAction(node->getAwesome(), node->getNodeTitle()); connect(action, &QAction::triggered, this, [=]() { d_ptr->onTreeViewClicked(node->getModelIndex()); }); d_ptr->_compactMenuMap.insert(originalNode, menu); } d_ptr->_addStackedPage(page, pageKey); d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addPageNode(QString pageTitle, QWidget *page, int keyPoints, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); if (!page) { return ElaNavigationType::PageInvalid; } QString pageKey; ElaNavigationType::NodeOperateReturnType returnType = d_ptr->_navigationModel->addPageNode(pageTitle, pageKey, keyPoints, awesome); if (returnType == ElaNavigationType::Success) { d->_pageMetaMap.insert(pageKey, page->metaObject()); d->_pageNewWindowCountMap.insert(pageKey, 0); d->_addStackedPage(page, pageKey); d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addPageNode(QString pageTitle, QWidget *page, QString targetExpanderKey, int keyPoints, ElaIconType::IconName awesome) { Q_D(ElaNavigationBar); if (!page) { return ElaNavigationType::PageInvalid; } if (targetExpanderKey.isEmpty()) { return ElaNavigationType::TargetNodeInvalid; } QString pageKey; ElaNavigationType::NodeOperateReturnType returnType = d_ptr->_navigationModel->addPageNode(pageTitle, pageKey, targetExpanderKey, keyPoints, awesome); if (returnType == ElaNavigationType::Success) { d->_pageMetaMap.insert(pageKey, page->metaObject()); d->_pageNewWindowCountMap.insert(pageKey, 0); ElaNavigationNode *node = d_ptr->_navigationModel->getNavigationNode(pageKey); ElaNavigationNode *originalNode = node->getOriginalNode(); if (d_ptr->_compactMenuMap.contains(originalNode)) { ElaMenu *menu = d_ptr->_compactMenuMap.value(originalNode); QAction *action = menu->addElaIconAction(node->getAwesome(), node->getNodeTitle()); connect(action, &QAction::triggered, this, [=]() { d_ptr->onTreeViewClicked(node->getModelIndex()); }); } else { ElaMenu *menu = new ElaMenu(const_cast(this)); QAction *action = menu->addElaIconAction(node->getAwesome(), node->getNodeTitle()); connect(action, &QAction::triggered, this, [=]() { d_ptr->onTreeViewClicked(node->getModelIndex()); }); d_ptr->_compactMenuMap.insert(originalNode, menu); } d_ptr->_addStackedPage(page, pageKey); d->_initNodeModelIndex(QModelIndex()); d->_resetNodeSelected(); } return returnType; } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addFooterNode(QString footerTitle, QString &footerKey, int keyPoints, ElaIconType::IconName awesome) { return addFooterNode(footerTitle, nullptr, footerKey, keyPoints, awesome); } ElaNavigationType::NodeOperateReturnType ElaNavigationBar::addFooterNode(QString footerTitle, QWidget *page, QString &footerKey, int keyPoints, ElaIconType::IconName awesome) { ElaNavigationType::NodeOperateReturnType returnType = d_ptr->_footerModel->addFooterNode(footerTitle, footerKey, page ? true : false, keyPoints, awesome); if (returnType == ElaNavigationType::Success) { d_ptr->_addFooterPage(page, footerKey); } return returnType; } bool ElaNavigationBar::getNavigationNodeIsExpanded(QString expanderKey) const { Q_D(const ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(expanderKey); if (!node || !node->getIsExpanderNode()) { return false; } return d->_navigationView->isExpanded(node->getModelIndex()); } void ElaNavigationBar::expandNavigationNode(QString expanderKey) { Q_D(ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(expanderKey); if (!node || !node->getIsExpanderNode()) { return; } d->_expandOrCollpaseExpanderNode(node, true); d->_resetNodeSelected(); } void ElaNavigationBar::collpaseNavigationNode(QString expanderKey) { Q_D(ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(expanderKey); if (!node || !node->getIsExpanderNode()) { return; } d->_expandOrCollpaseExpanderNode(node, false); d->_resetNodeSelected(); } void ElaNavigationBar::removeNavigationNode(QString nodeKey) { Q_D(ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(nodeKey); if (!node) { node = d->_footerModel->getNavigationNode(nodeKey); } if (!node) { return; } if (node->getIsFooterNode()) { Q_EMIT navigationNodeRemoved(ElaNavigationType::FooterNode, nodeKey); d->_footerModel->removeNavigationNode(nodeKey); d->_footerView->setFixedHeight(40 * d->_footerModel->getFooterNodeCount()); } else { QStringList removeKeyList = d->_navigationModel->removeNavigationNode(nodeKey); d->_initNodeModelIndex(QModelIndex()); for (const auto &removeKey : removeKeyList) { d->_pageMetaMap.remove(removeKey); d->_pageNewWindowCountMap.remove(removeKey); Q_EMIT navigationNodeRemoved(ElaNavigationType::PageNode, removeKey); } } d->_navigationSuggestBox->removeSuggestion(d->_suggestKeyMap.value(nodeKey)); } void ElaNavigationBar::setNodeKeyPoints(QString nodeKey, int keyPoints) { Q_D(ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(nodeKey); if (!node) { node = d->_footerModel->getNavigationNode(nodeKey); } else if (node->getIsExpanderNode() || keyPoints < 0) { return; } if (!node) { return; } node->setKeyPoints(keyPoints); if (node->getIsFooterNode()) { d->_footerView->viewport()->update(); } else { d->_navigationView->viewport()->update(); } } int ElaNavigationBar::getNodeKeyPoints(QString nodeKey) const { Q_D(const ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(nodeKey); if (!node) { node = d->_footerModel->getNavigationNode(nodeKey); } else if (node->getIsExpanderNode()) { return -1; } if (!node) { return -1; } return node->getKeyPoints(); } void ElaNavigationBar::navigation(QString pageKey, bool isLogClicked, bool isRouteBack) { Q_D(ElaNavigationBar); ElaNavigationNode *node = d->_navigationModel->getNavigationNode(pageKey); if (!node) { node = d->_footerModel->getNavigationNode(pageKey); } if (node) { if (node->getIsFooterNode()) { d->onFooterViewClicked(node->getModelIndex(), isLogClicked, isRouteBack); } else { if (!node->getIsExpanderNode()) { d->onTreeViewClicked(node->getModelIndex(), isLogClicked, isRouteBack); } } } } void ElaNavigationBar::setDisplayMode(ElaNavigationType::NavigationDisplayMode displayMode, bool isAnimation) { Q_D(ElaNavigationBar); if (d->_currentDisplayMode == displayMode || displayMode == ElaNavigationType::Auto) { return; } d->_doComponentAnimation(displayMode, isAnimation); d->_raiseNavigationBar(); } int ElaNavigationBar::getPageOpenInNewWindowCount(QString nodeKey) const { Q_D(const ElaNavigationBar); if (!d->_pageNewWindowCountMap.contains(nodeKey)) { return 0; } return d->_pageNewWindowCountMap[nodeKey]; } void ElaNavigationBar::paintEvent(QPaintEvent *event) { Q_D(ElaNavigationBar); if (!d->_pIsTransparent) { QPainter painter(this); painter.save(); painter.setPen(ElaThemeColor(d->_themeMode, PopupBorder)); painter.setBrush(ElaThemeColor(d->_themeMode, PopupBase)); QRect baseRect = this->rect(); baseRect.adjust(-1, 0, -1, 0); QPainterPath path; path.moveTo(baseRect.topLeft()); path.lineTo(QPoint(baseRect.right() - 8, baseRect.y())); path.arcTo(QRectF(baseRect.right() - 16, baseRect.y(), 16, 16), 90, -90); path.lineTo(QPoint(baseRect.right(), baseRect.bottom() - 8)); path.arcTo(QRectF(baseRect.right() - 16, baseRect.bottom() - 16, 16, 16), 0, -90); path.lineTo(baseRect.bottomLeft()); path.closeSubpath(); painter.drawPath(path); painter.restore(); } QWidget::paintEvent(event); }