diff --git a/src/app/PanelHeader.cpp b/src/app/PanelHeader.cpp index 30c342d..5e4a6e3 100644 --- a/src/app/PanelHeader.cpp +++ b/src/app/PanelHeader.cpp @@ -81,7 +81,7 @@ QWidget* buildPanelHeader(Glyph icon, const QString& title, const QVector
setObjectName(QStringLiteral("panelHeader")); header->setFixedHeight(kHeaderHeight); - header->setStyleSheet(headerQss()); + geopro::app::applyThemedStyleSheet(header, headerQss()); auto* lay = new QHBoxLayout(header); lay->setContentsMargins(12, 0, 8, 0); @@ -114,7 +114,7 @@ TabbedPanel buildTabbedPanel(const QVector& tabs, const QVector
setObjectName(QStringLiteral("panelHeader")); header->setFixedHeight(kHeaderHeight); - header->setStyleSheet(headerQss()); + geopro::app::applyThemedStyleSheet(header, headerQss()); auto* hlay = new QHBoxLayout(header); hlay->setContentsMargins(10, 0, 8, 0); hlay->setSpacing(2); diff --git a/src/app/Theme.cpp b/src/app/Theme.cpp index 078920d..d9bc575 100644 --- a/src/app/Theme.cpp +++ b/src/app/Theme.cpp @@ -3,8 +3,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -407,6 +409,10 @@ const RoleMap kRoleMap[] = { {"#E6EBF3", ElaThemeType::BasicDisable}, // 进度条底 {"#EAF1FB", ElaThemeType::BasicHover}, // 工具按钮选中底 {"#C0392B", ElaThemeType::StatusDanger}, // 危险 + // 内联 chrome(TopBar/PanelHeader)额外用到的令牌: + {"#EEF1F5", ElaThemeType::BasicBorder}, // 菜单栏底边线 + {"#E6EAF1", ElaThemeType::BasicBorder}, // 面板表头底边线 + {"#EAEEF5", ElaThemeType::BasicBaseDeep}, // 面板徽标底 }; QColor roleColor(bool dark, ElaThemeType::ThemeColor role) @@ -414,15 +420,21 @@ QColor roleColor(bool dark, ElaThemeType::ThemeColor role) return eTheme->getThemeColor(dark ? ElaThemeType::Dark : ElaThemeType::Light, role); } -// 当前模式的全局 QSS:按 kRoleMap 把设计稿色令牌换成 ElaTheme 真实颜色(明/暗同源于外壳)。 -QString styleSheetForMode(bool dark) +// 把一段设计稿 QSS 按 ElaTheme 当前模式着色(浅色令牌→真实角色色)。供全局与内联样式共用。 +QString themedQss(const QString& designQss, bool dark) { - QString s = QString::fromUtf8(kStyleSheet); + QString s = designQss; for (const auto& rm : kRoleMap) s.replace(QLatin1String(rm.token), roleColor(dark, rm.role).name()); return s; } +// 当前模式的全局 QSS。 +QString styleSheetForMode(bool dark) +{ + return themedQss(QString::fromUtf8(kStyleSheet), dark); +} + // 调色板同样取自 ElaTheme,让无 QSS 覆盖处的标准控件也与外壳一致。 QPalette buildPalette(bool dark) { @@ -482,4 +494,19 @@ void applyTheme(QApplication& app) applyThemeMode(app, false); } +bool isDarkTheme() +{ + return eTheme->getThemeMode() == ElaThemeType::Dark; +} + +void applyThemedStyleSheet(QWidget* w, const QString& designQss) +{ + if (!w) return; + w->setStyleSheet(themedQss(designQss, isDarkTheme())); + QObject::connect(eTheme, &ElaTheme::themeModeChanged, w, + [w, designQss](ElaThemeType::ThemeMode m) { + w->setStyleSheet(themedQss(designQss, m == ElaThemeType::Dark)); + }); +} + } // namespace geopro::app diff --git a/src/app/Theme.hpp b/src/app/Theme.hpp index 385b005..295b7d0 100644 --- a/src/app/Theme.hpp +++ b/src/app/Theme.hpp @@ -9,7 +9,10 @@ // 文字 #1F2A3D 次要文字 #5A6B85 边框 #D5DBE5 强边框 #C2CCDA // 危险 #C0392B +#include + class QApplication; +class QWidget; namespace geopro::app { @@ -87,4 +90,12 @@ void applyThemeMode(QApplication& app, bool dark); // 浅色主题快捷入口(= applyThemeMode(app,false))。经典壳启动调用一次。 void applyTheme(QApplication& app); +// 当前 ElaTheme 是否暗色(供内联样式判断)。 +bool isDarkTheme(); + +// 把一段「浅色设计稿 QSS」按当前 ElaTheme 配色着色应用到 widget,并随明/暗切换自动重着色。 +// 用于 TopBar/PanelHeader/浮层 等带内联 setStyleSheet 的自定义 chrome——让它们也跟随主题 +// (设计稿里用浅色令牌 #1F2A3D/#FFFFFF/#2D6CB5… 书写即可,与全局 QSS 同一套角色映射)。 +void applyThemedStyleSheet(QWidget* w, const QString& designQss); + } // namespace geopro::app diff --git a/src/app/TopBar.cpp b/src/app/TopBar.cpp index 3a9824f..77811c9 100644 --- a/src/app/TopBar.cpp +++ b/src/app/TopBar.cpp @@ -116,12 +116,13 @@ QWidget* buildMenuBar(QWidget* parent) auto* mb = new QMenuBar(parent); mb->setObjectName(QStringLiteral("appMenuBar")); // 自带样式(覆盖全局),加大字号/内边距,专业观感。 - mb->setStyleSheet(QStringLiteral( - "#appMenuBar { background:#FFFFFF; border-bottom:1px solid #EEF1F5; padding:2px 8px; }" - "#appMenuBar::item { padding:7px 14px; border-radius:6px; font-size:%1px; color:#1F2A3D; }" - "#appMenuBar::item:selected { background:#EAF1FB; color:#2D6CB5; }" - "#appMenuBar::item:pressed { background:#DCE6F4; }") - .arg(type::kBody)); + geopro::app::applyThemedStyleSheet( + mb, QStringLiteral( + "#appMenuBar { background:#FFFFFF; border-bottom:1px solid #EEF1F5; padding:2px 8px; }" + "#appMenuBar::item { padding:7px 14px; border-radius:6px; font-size:%1px; color:#1F2A3D; }" + "#appMenuBar::item:selected { background:#EAF1FB; color:#2D6CB5; }" + "#appMenuBar::item:pressed { background:#DCE6F4; }") + .arg(type::kBody)); mb->addMenu(buildViewMenu(mb)); mb->addMenu(buildProjectMenu(mb)); mb->addMenu(buildToolsMenu(mb)); @@ -134,25 +135,26 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) { setFixedHeight(56); // 字号引用 Theme 排版令牌:工作空间切换器=title(15)、头像/用户名=body·label(13)、 // 角色名=caption(12)。原 11px 角色名上调到 12,去掉只差 1px 的糊层级。 - setStyleSheet(QStringLiteral( - "#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }" - "#topDivider { color:#E1E6EE; }" - "#wsSwitcher { color:#1F2A3D; border:none; border-radius:8px; padding:8px 12px;" - " font-size:%1px; font-weight:%5; }" - "#wsSwitcher:hover { background:#EEF3FB; }" - "QToolButton#iconBtn { border:none; border-radius:8px; padding:8px; }" - "QToolButton#iconBtn:hover { background:#EEF3FB; }" - "QToolButton::menu-indicator { image:none; }" - "#avatar { background:#2D6CB5; color:#FFFFFF; border-radius:17px; font-weight:%6;" - " font-size:%2px; }" - "#userName { color:#1F2A3D; font-size:%3px; font-weight:%5; }" - "#userRole { color:#8A93A3; font-size:%4px; }") - .arg(type::kTitle) - .arg(type::kBody) - .arg(type::kLabel) - .arg(type::kCaption) - .arg(type::kWeightSemibold) - .arg(type::kWeightBold)); + geopro::app::applyThemedStyleSheet( + this, QStringLiteral( + "#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }" + "#topDivider { color:#E1E6EE; }" + "#wsSwitcher { color:#1F2A3D; border:none; border-radius:8px; padding:8px 12px;" + " font-size:%1px; font-weight:%5; }" + "#wsSwitcher:hover { background:#EEF3FB; }" + "QToolButton#iconBtn { border:none; border-radius:8px; padding:8px; }" + "QToolButton#iconBtn:hover { background:#EEF3FB; }" + "QToolButton::menu-indicator { image:none; }" + "#avatar { background:#2D6CB5; color:#FFFFFF; border-radius:17px; font-weight:%6;" + " font-size:%2px; }" + "#userName { color:#1F2A3D; font-size:%3px; font-weight:%5; }" + "#userRole { color:#8A93A3; font-size:%4px; }") + .arg(type::kTitle) + .arg(type::kBody) + .arg(type::kLabel) + .arg(type::kCaption) + .arg(type::kWeightSemibold) + .arg(type::kWeightBold)); auto* lay = new QHBoxLayout(this); lay->setContentsMargins(14, 0, 14, 0); diff --git a/src/app/main.cpp b/src/app/main.cpp index 59f137e..786d983 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -331,9 +331,10 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re // 仅三维视图显示;含 帘面 / 体素 勾选(体素=两交叉测线散点配准 IDW 的派生层,正确归宿)。 auto* layerPanel = new QFrame(centerWidget); layerPanel->setFrameShape(QFrame::StyledPanel); - layerPanel->setStyleSheet( - QStringLiteral("QFrame{background:rgba(255,255,255,0.96);border:1px solid #D5DBE5;" - "border-radius:8px;} QCheckBox{padding:2px 1px;color:#1F2A3D;}" + geopro::app::applyThemedStyleSheet( + layerPanel, + QStringLiteral("QFrame{background:#FFFFFF;border:1px solid #D5DBE5;border-radius:8px;}" + "QCheckBox{padding:2px 1px;color:#1F2A3D;}" "QCheckBox:disabled{color:#9AA6B6;}")); auto* layerLayout = new QVBoxLayout(layerPanel); // 浮层内边距取间距令牌:左右 lg(12)、上下 ml(10),对称(原 13/10/15/11 是手调奇数)。 @@ -341,11 +342,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re geopro::app::space::kLg, geopro::app::space::kMl); layerLayout->setSpacing(geopro::app::space::kSm); auto* layerTitle = new QLabel(QStringLiteral("视图详情")); - layerTitle->setStyleSheet(QStringLiteral( - "font-weight:%1;color:#2D6CB5;border:none;background:transparent;" - "padding-bottom:3px;font-size:%2px;") - .arg(geopro::app::type::kWeightSemibold) - .arg(geopro::app::type::kTitle)); + geopro::app::applyThemedStyleSheet( + layerTitle, QStringLiteral("font-weight:%1;color:#2D6CB5;border:none;background:transparent;" + "padding-bottom:3px;font-size:%2px;") + .arg(geopro::app::type::kWeightSemibold) + .arg(geopro::app::type::kTitle)); auto* chkCurtain = new QCheckBox(QStringLiteral("帘面(断面墙)")); chkCurtain->setChecked(true); auto* chkVoxel = new QCheckBox(QStringLiteral("体素(dd_voxel)"));