#include "SARibbonMainWindow.h" #include "SARibbonBar.h" #include "SARibbonElementManager.h" #include "SARibbonTabBar.h" #include #include #include #include #include #include #include "SARibbonSystemButtonBar.h" #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER #include #include "SARibbonButtonGroupWidget.h" #include "SARibbonQuickAccessBar.h" #include "SARibbonStackedWidget.h" #else #include "SAFramelessHelper.h" #endif /** * @brief The SARibbonMainWindowPrivate class */ class SARibbonMainWindow::PrivateData { SA_RIBBON_DECLARE_PUBLIC(SARibbonMainWindow) public: PrivateData(SARibbonMainWindow* p); void installFrameless(SARibbonMainWindow* p); public: SARibbonTheme mCurrentRibbonTheme { SARibbonTheme::RibbonThemeOffice2021Blue }; SARibbonSystemButtonBar* mWindowButtonGroup { nullptr }; #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER QWK::WidgetWindowAgent* mFramelessHelper { nullptr }; #else SAFramelessHelper* mFramelessHelper { nullptr }; #endif SARibbonMainWindowEventFilter* mEventFilter { nullptr }; }; SARibbonMainWindow::PrivateData::PrivateData(SARibbonMainWindow* p) : q_ptr(p) { } void SARibbonMainWindow::PrivateData::installFrameless(SARibbonMainWindow* p) { #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER mFramelessHelper = new QWK::WidgetWindowAgent(p); mFramelessHelper->setup(p); #else mFramelessHelper = new SAFramelessHelper(p); #endif } //=================================================== // SARibbonMainWindow //=================================================== SARibbonMainWindow::SARibbonMainWindow(QWidget* parent, bool useRibbon, const Qt::WindowFlags flags) : QMainWindow(parent, flags), d_ptr(new SARibbonMainWindow::PrivateData(this)) { connect(qApp, &QApplication::primaryScreenChanged, this, &SARibbonMainWindow::onPrimaryScreenChanged); if (useRibbon) { d_ptr->installFrameless(this); setRibbonBar(createRibbonBar()); setRibbonTheme(ribbonTheme()); } } SARibbonMainWindow::~SARibbonMainWindow() { } /** * @brief 返回ribbonbar,如果不是使用ribbon模式,返回nullptr * @return */ SARibbonBar* SARibbonMainWindow::ribbonBar() const { return qobject_cast< SARibbonBar* >(menuWidget()); } /** * @brief 设置ribbonbar * @param bar */ void SARibbonMainWindow::setRibbonBar(SARibbonBar* ribbon) { QWidget* old = QMainWindow::menuWidget(); if (old) { // 如果之前已经设置了menubar,要把之前的删除 old->deleteLater(); } QMainWindow::setMenuWidget(ribbon); const int th = ribbon->titleBarHeight(); // 设置window按钮 if (nullptr == d_ptr->mWindowButtonGroup) { d_ptr->mWindowButtonGroup = RibbonSubElementFactory->createWindowButtonGroup(this); // SARibbonSystemButtonBar的eventfilter捕获mainwindow的事件 // 通过eventerfilter来处理mainwindow的事件,避免用户错误的继承resizeEvent导致systembar的位置异常 installEventFilter(d_ptr->mWindowButtonGroup); } SARibbonSystemButtonBar* sysBar = d_ptr->mWindowButtonGroup; sysBar->setWindowStates(windowState()); sysBar->setWindowTitleHeight(th); sysBar->raise(); // 确保sysbar在最顶层,避免第二次设置ribbonbar的时候,被ribbonbar覆盖了sysbar sysBar->show(); #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER auto helper = d_ptr->mFramelessHelper; helper->setTitleBar(ribbon); // 以下这些窗口,需要允许点击 helper->setHitTestVisible(sysBar); // IMPORTANT! helper->setHitTestVisible(ribbon->ribbonTabBar()); // IMPORTANT! helper->setHitTestVisible(ribbon->rightButtonGroup()); // IMPORTANT! helper->setHitTestVisible(ribbon->applicationButton()); // IMPORTANT! helper->setHitTestVisible(ribbon->quickAccessBar()); // IMPORTANT! helper->setHitTestVisible(ribbon->ribbonStackedWidget()); // IMPORTANT! #if SARIBBON_ENABLE_SNAP_LAYOUT if (sysBar->closeButton()) { helper->setSystemButton(QWK::WindowAgentBase::Close, sysBar->closeButton()); } if (sysBar->minimizeButton()) { helper->setSystemButton(QWK::WindowAgentBase::Minimize, sysBar->minimizeButton()); } if (sysBar->maximizeButton()) { helper->setSystemButton(QWK::WindowAgentBase::Maximize, sysBar->maximizeButton()); } #endif #else // 捕获ribbonbar的事件 ribbon->installEventFilter(this); // 设置窗体的标题栏高度 d_ptr->mFramelessHelper->setTitleHeight(th); d_ptr->mFramelessHelper->setRubberBandOnResize(false); #endif if (!d_ptr->mEventFilter) { d_ptr->mEventFilter = new SARibbonMainWindowEventFilter(this); installEventFilter(d_ptr->mEventFilter); } // 最后要提升,否则新加入的会被覆盖 if (d_ptr->mWindowButtonGroup) { d_ptr->mWindowButtonGroup->raise(); } } #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER /** * @brief 如果ribbon中有自定义的窗口在标题栏等非点击区域加入后,想能点击,需要调用此接口告知可点击 * @param w * @param visible */ void SARibbonMainWindow::setFramelessHitTestVisible(QWidget* w, bool visible) { auto helper = d_ptr->mFramelessHelper; helper->setHitTestVisible(const_cast(w), visible); } #else SAFramelessHelper* SARibbonMainWindow::framelessHelper() { return (d_ptr->mFramelessHelper); } #endif bool SARibbonMainWindow::eventFilter(QObject* obj, QEvent* e) { #if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER #else // 这个过滤是为了把ribbonBar上的动作传递到mainwindow,再传递到frameless, // 由于ribbonbar会遮挡掉frameless的区域,导致frameless无法捕获这些消息 // 因此必须ribbonBar()->installEventFilter(this); // 20240101发现installEventFilter后,SARibbonMainWindow没有执行这个回调 if (obj == ribbonBar()) { switch (e->type()) { case QEvent::MouseButtonPress: case QEvent::MouseButtonRelease: case QEvent::MouseMove: case QEvent::Leave: case QEvent::HoverMove: case QEvent::MouseButtonDblClick: QApplication::sendEvent(this, e); default: break; } } #endif return (QMainWindow::eventFilter(obj, e)); } /** * @brief 获取系统按钮组,可以在此基础上添加其他按钮 * @return */ SARibbonSystemButtonBar* SARibbonMainWindow::windowButtonBar() const { return d_ptr->mWindowButtonGroup; } /** * @brief 此函数仅用于控制最小最大化和关闭按钮的显示 */ void SARibbonMainWindow::updateWindowFlag(Qt::WindowFlags flags) { if (SARibbonSystemButtonBar* g = d_ptr->mWindowButtonGroup) { g->updateWindowFlag(flags); } } /** * @brief SARibbonMainWindow::setRibbonTheme * * 注意主题在构造函数设置主题会不完全生效,使用QTimer投放到队列最后执行即可 * @code * QTimer::singleShot(0, this, [ this ]() { this->setRibbonTheme(SARibbonMainWindow::RibbonThemeDark); }); * @endcode * @param theme */ void SARibbonMainWindow::setRibbonTheme(SARibbonTheme theme) { sa_set_ribbon_theme(this, theme); d_ptr->mCurrentRibbonTheme = theme; if (SARibbonBar* bar = ribbonBar()) { auto theme = ribbonTheme(); // 尺寸修正 switch (theme) { case SARibbonTheme::RibbonThemeWindows7: case SARibbonTheme::RibbonThemeOffice2013: case SARibbonTheme::RibbonThemeOffice2016Blue: case SARibbonTheme::RibbonThemeDark: case SARibbonTheme::RibbonThemeDark2: { //! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中 //! office2013.qss的margin信息如下设置 //! margin-top: 0px; //! margin-right: 0px; //! margin-left: 5px; //! margin-bottom: 0px; SARibbonTabBar* tab = bar->ribbonTabBar(); if (!tab) { break; } tab->setTabMargin(QMargins(5, 0, 0, 0)); } break; case SARibbonTheme::RibbonThemeOffice2021Blue: { SARibbonTabBar* tab = bar->ribbonTabBar(); if (!tab) { break; } //! 在设置qss后需要针对margin信息重新设置进SARibbonTabBar中 //! office2021.qss的margin信息如下设置 //! margin-top: 0px; //! margin-right: 5px; //! margin-left: 5px; //! margin-bottom: 0px; tab->setTabMargin(QMargins(5, 0, 5, 0)); } default: break; } // 上下文标签颜色设置,以及基线颜色设置 switch (theme) { case SARibbonTheme::RibbonThemeWindows7: case SARibbonTheme::RibbonThemeOffice2013: case SARibbonTheme::RibbonThemeDark: bar->setContextCategoryColorList(QList< QColor >()); //< 设置空颜色列表会重置为默认色系 break; case SARibbonTheme::RibbonThemeOffice2016Blue: bar->setContextCategoryColorList(QList< QColor >() << QColor(18, 64, 120)); //< 设置空颜色列表会重置为默认色系 break; case SARibbonTheme::RibbonThemeOffice2021Blue: bar->setContextCategoryColorList(QList< QColor >() << QColor(209, 207, 209)); //< 设置空颜色列表会重置为默认色系 break; default: break; } // 基线颜色设置 if (SARibbonTheme::RibbonThemeOffice2013 == theme) { bar->setTabBarBaseLineColor(QColor(186, 201, 219)); } else { bar->setTabBarBaseLineColor(QColor()); } } } SARibbonTheme SARibbonMainWindow::ribbonTheme() const { return (d_ptr->mCurrentRibbonTheme); } bool SARibbonMainWindow::isUseRibbon() const { return (nullptr != ribbonBar()); } /** * @brief 创建ribbonbar的工厂函数 * * 用户如果重写了SARibbonBar,可以通过重新此虚函数返回自己的Ribbon实例 * @return */ SARibbonBar* SARibbonMainWindow::createRibbonBar() { SARibbonBar* bar = RibbonSubElementFactory->createRibbonBar(this); bar->setContentsMargins(3, 0, 3, 0); return bar; } /** * @brief 主屏幕切换触发的信号 * @param screen */ void SARibbonMainWindow::onPrimaryScreenChanged(QScreen* screen) { Q_UNUSED(screen); // 主屏幕切换后,从新计算所有尺寸 if (SARibbonBar* bar = ribbonBar()) { qDebug() << "Primary Screen Changed"; bar->updateRibbonGeometry(); } } void sa_set_ribbon_theme(QWidget* w, SARibbonTheme theme) { QFile file; switch (theme) { case SARibbonTheme::RibbonThemeWindows7: file.setFileName(":/theme/resource/theme-win7.qss"); break; case SARibbonTheme::RibbonThemeOffice2013: file.setFileName(":/theme/resource/theme-office2013.qss"); break; case SARibbonTheme::RibbonThemeOffice2016Blue: file.setFileName(":/theme/resource/theme-office2016-blue.qss"); break; case SARibbonTheme::RibbonThemeOffice2021Blue: file.setFileName(":/theme/resource/theme-office2021-blue.qss"); break; case SARibbonTheme::RibbonThemeDark: file.setFileName(":/theme/resource/theme-dark.qss"); break; case SARibbonTheme::RibbonThemeDark2: file.setFileName(":/theme/resource/theme-dark2.qss"); break; default: file.setFileName(":/theme/resource/theme-office2013.qss"); break; } if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { return; } // 有反馈用qstring接住文件内容,再设置进去才能生效(qt5.7版本) QString qss = QString::fromUtf8(file.readAll()); w->setStyleSheet(qss); } //---------------------------------------------------- // SARibbonMainWindowEventFilter //---------------------------------------------------- SARibbonMainWindowEventFilter::SARibbonMainWindowEventFilter(QObject* par) : QObject(par) { } bool SARibbonMainWindowEventFilter::eventFilter(QObject* obj, QEvent* e) { if (e) { if (e->type() == QEvent::Resize) { if (SARibbonMainWindow* m = qobject_cast< SARibbonMainWindow* >(obj)) { if (SARibbonBar* ribbon = m->ribbonBar()) { ribbon->setFixedWidth(m->size().width()); } } } } return QObject::eventFilter(obj, e); }