379 lines
11 KiB
C++
379 lines
11 KiB
C++
![]() |
#include "SARibbonMainWindow.h"
|
|||
|
#include "SARibbonBar.h"
|
|||
|
#include "SARibbonElementManager.h"
|
|||
|
#include "SARibbonTabBar.h"
|
|||
|
#include <QApplication>
|
|||
|
#include <QDebug>
|
|||
|
#include <QFile>
|
|||
|
#include <QHash>
|
|||
|
#include <QWindowStateChangeEvent>
|
|||
|
#include <QScreen>
|
|||
|
|
|||
|
#include "SARibbonSystemButtonBar.h"
|
|||
|
#if SARIBBON_USE_3RDPARTY_FRAMELESSHELPER
|
|||
|
#include <QWKWidgets/widgetwindowagent.h>
|
|||
|
#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<QWidget*>(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);
|
|||
|
}
|