refactor/pure-qt-ui #3

Merged
gaozheng merged 56 commits from refactor/pure-qt-ui into main 2026-06-10 18:41:53 +08:00
5 changed files with 79 additions and 38 deletions
Showing only changes of commit 4a785ede88 - Show all commits

View File

@ -81,7 +81,7 @@ QWidget* buildPanelHeader(Glyph icon, const QString& title, const QVector<Header
auto* header = new QWidget(); auto* header = new QWidget();
header->setObjectName(QStringLiteral("panelHeader")); header->setObjectName(QStringLiteral("panelHeader"));
header->setFixedHeight(kHeaderHeight); header->setFixedHeight(kHeaderHeight);
header->setStyleSheet(headerQss()); geopro::app::applyThemedStyleSheet(header, headerQss());
auto* lay = new QHBoxLayout(header); auto* lay = new QHBoxLayout(header);
lay->setContentsMargins(12, 0, 8, 0); lay->setContentsMargins(12, 0, 8, 0);
@ -114,7 +114,7 @@ TabbedPanel buildTabbedPanel(const QVector<PanelTab>& tabs, const QVector<Header
auto* header = new QWidget(box); auto* header = new QWidget(box);
header->setObjectName(QStringLiteral("panelHeader")); header->setObjectName(QStringLiteral("panelHeader"));
header->setFixedHeight(kHeaderHeight); header->setFixedHeight(kHeaderHeight);
header->setStyleSheet(headerQss()); geopro::app::applyThemedStyleSheet(header, headerQss());
auto* hlay = new QHBoxLayout(header); auto* hlay = new QHBoxLayout(header);
hlay->setContentsMargins(10, 0, 8, 0); hlay->setContentsMargins(10, 0, 8, 0);
hlay->setSpacing(2); hlay->setSpacing(2);

View File

@ -3,8 +3,10 @@
#include <QApplication> #include <QApplication>
#include <QColor> #include <QColor>
#include <QFont> #include <QFont>
#include <QObject>
#include <QPalette> #include <QPalette>
#include <QStyleFactory> #include <QStyleFactory>
#include <QWidget>
#include <ElaDef.h> #include <ElaDef.h>
#include <ElaTheme.h> #include <ElaTheme.h>
@ -407,6 +409,10 @@ const RoleMap kRoleMap[] = {
{"#E6EBF3", ElaThemeType::BasicDisable}, // 进度条底 {"#E6EBF3", ElaThemeType::BasicDisable}, // 进度条底
{"#EAF1FB", ElaThemeType::BasicHover}, // 工具按钮选中底 {"#EAF1FB", ElaThemeType::BasicHover}, // 工具按钮选中底
{"#C0392B", ElaThemeType::StatusDanger}, // 危险 {"#C0392B", ElaThemeType::StatusDanger}, // 危险
// 内联 chromeTopBar/PanelHeader额外用到的令牌
{"#EEF1F5", ElaThemeType::BasicBorder}, // 菜单栏底边线
{"#E6EAF1", ElaThemeType::BasicBorder}, // 面板表头底边线
{"#EAEEF5", ElaThemeType::BasicBaseDeep}, // 面板徽标底
}; };
QColor roleColor(bool dark, ElaThemeType::ThemeColor role) 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); return eTheme->getThemeColor(dark ? ElaThemeType::Dark : ElaThemeType::Light, role);
} }
// 当前模式的全局 QSS按 kRoleMap 把设计稿色令牌换成 ElaTheme 真实颜色(明/暗同源于外壳) // 把一段设计稿 QSS 按 ElaTheme 当前模式着色(浅色令牌→真实角色色)。供全局与内联样式共用
QString styleSheetForMode(bool dark) QString themedQss(const QString& designQss, bool dark)
{ {
QString s = QString::fromUtf8(kStyleSheet); QString s = designQss;
for (const auto& rm : kRoleMap) for (const auto& rm : kRoleMap)
s.replace(QLatin1String(rm.token), roleColor(dark, rm.role).name()); s.replace(QLatin1String(rm.token), roleColor(dark, rm.role).name());
return s; return s;
} }
// 当前模式的全局 QSS。
QString styleSheetForMode(bool dark)
{
return themedQss(QString::fromUtf8(kStyleSheet), dark);
}
// 调色板同样取自 ElaTheme让无 QSS 覆盖处的标准控件也与外壳一致。 // 调色板同样取自 ElaTheme让无 QSS 覆盖处的标准控件也与外壳一致。
QPalette buildPalette(bool dark) QPalette buildPalette(bool dark)
{ {
@ -482,4 +494,19 @@ void applyTheme(QApplication& app)
applyThemeMode(app, false); 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 } // namespace geopro::app

View File

@ -9,7 +9,10 @@
// 文字 #1F2A3D 次要文字 #5A6B85 边框 #D5DBE5 强边框 #C2CCDA // 文字 #1F2A3D 次要文字 #5A6B85 边框 #D5DBE5 强边框 #C2CCDA
// 危险 #C0392B // 危险 #C0392B
#include <QString>
class QApplication; class QApplication;
class QWidget;
namespace geopro::app { namespace geopro::app {
@ -87,4 +90,12 @@ void applyThemeMode(QApplication& app, bool dark);
// 浅色主题快捷入口(= applyThemeMode(app,false))。经典壳启动调用一次。 // 浅色主题快捷入口(= applyThemeMode(app,false))。经典壳启动调用一次。
void applyTheme(QApplication& app); 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 } // namespace geopro::app

View File

@ -116,12 +116,13 @@ QWidget* buildMenuBar(QWidget* parent)
auto* mb = new QMenuBar(parent); auto* mb = new QMenuBar(parent);
mb->setObjectName(QStringLiteral("appMenuBar")); mb->setObjectName(QStringLiteral("appMenuBar"));
// 自带样式(覆盖全局),加大字号/内边距,专业观感。 // 自带样式(覆盖全局),加大字号/内边距,专业观感。
mb->setStyleSheet(QStringLiteral( geopro::app::applyThemedStyleSheet(
"#appMenuBar { background:#FFFFFF; border-bottom:1px solid #EEF1F5; padding:2px 8px; }" mb, QStringLiteral(
"#appMenuBar::item { padding:7px 14px; border-radius:6px; font-size:%1px; color:#1F2A3D; }" "#appMenuBar { background:#FFFFFF; border-bottom:1px solid #EEF1F5; padding:2px 8px; }"
"#appMenuBar::item:selected { background:#EAF1FB; color:#2D6CB5; }" "#appMenuBar::item { padding:7px 14px; border-radius:6px; font-size:%1px; color:#1F2A3D; }"
"#appMenuBar::item:pressed { background:#DCE6F4; }") "#appMenuBar::item:selected { background:#EAF1FB; color:#2D6CB5; }"
.arg(type::kBody)); "#appMenuBar::item:pressed { background:#DCE6F4; }")
.arg(type::kBody));
mb->addMenu(buildViewMenu(mb)); mb->addMenu(buildViewMenu(mb));
mb->addMenu(buildProjectMenu(mb)); mb->addMenu(buildProjectMenu(mb));
mb->addMenu(buildToolsMenu(mb)); mb->addMenu(buildToolsMenu(mb));
@ -134,25 +135,26 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
setFixedHeight(56); setFixedHeight(56);
// 字号引用 Theme 排版令牌:工作空间切换器=title(15)、头像/用户名=body·label(13)、 // 字号引用 Theme 排版令牌:工作空间切换器=title(15)、头像/用户名=body·label(13)、
// 角色名=caption(12)。原 11px 角色名上调到 12去掉只差 1px 的糊层级。 // 角色名=caption(12)。原 11px 角色名上调到 12去掉只差 1px 的糊层级。
setStyleSheet(QStringLiteral( geopro::app::applyThemedStyleSheet(
"#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }" this, QStringLiteral(
"#topDivider { color:#E1E6EE; }" "#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }"
"#wsSwitcher { color:#1F2A3D; border:none; border-radius:8px; padding:8px 12px;" "#topDivider { color:#E1E6EE; }"
" font-size:%1px; font-weight:%5; }" "#wsSwitcher { color:#1F2A3D; border:none; border-radius:8px; padding:8px 12px;"
"#wsSwitcher:hover { background:#EEF3FB; }" " font-size:%1px; font-weight:%5; }"
"QToolButton#iconBtn { border:none; border-radius:8px; padding:8px; }" "#wsSwitcher:hover { background:#EEF3FB; }"
"QToolButton#iconBtn:hover { background:#EEF3FB; }" "QToolButton#iconBtn { border:none; border-radius:8px; padding:8px; }"
"QToolButton::menu-indicator { image:none; }" "QToolButton#iconBtn:hover { background:#EEF3FB; }"
"#avatar { background:#2D6CB5; color:#FFFFFF; border-radius:17px; font-weight:%6;" "QToolButton::menu-indicator { image:none; }"
" font-size:%2px; }" "#avatar { background:#2D6CB5; color:#FFFFFF; border-radius:17px; font-weight:%6;"
"#userName { color:#1F2A3D; font-size:%3px; font-weight:%5; }" " font-size:%2px; }"
"#userRole { color:#8A93A3; font-size:%4px; }") "#userName { color:#1F2A3D; font-size:%3px; font-weight:%5; }"
.arg(type::kTitle) "#userRole { color:#8A93A3; font-size:%4px; }")
.arg(type::kBody) .arg(type::kTitle)
.arg(type::kLabel) .arg(type::kBody)
.arg(type::kCaption) .arg(type::kLabel)
.arg(type::kWeightSemibold) .arg(type::kCaption)
.arg(type::kWeightBold)); .arg(type::kWeightSemibold)
.arg(type::kWeightBold));
auto* lay = new QHBoxLayout(this); auto* lay = new QHBoxLayout(this);
lay->setContentsMargins(14, 0, 14, 0); lay->setContentsMargins(14, 0, 14, 0);

View File

@ -331,9 +331,10 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
// 仅三维视图显示;含 帘面 / 体素 勾选(体素=两交叉测线散点配准 IDW 的派生层,正确归宿)。 // 仅三维视图显示;含 帘面 / 体素 勾选(体素=两交叉测线散点配准 IDW 的派生层,正确归宿)。
auto* layerPanel = new QFrame(centerWidget); auto* layerPanel = new QFrame(centerWidget);
layerPanel->setFrameShape(QFrame::StyledPanel); layerPanel->setFrameShape(QFrame::StyledPanel);
layerPanel->setStyleSheet( geopro::app::applyThemedStyleSheet(
QStringLiteral("QFrame{background:rgba(255,255,255,0.96);border:1px solid #D5DBE5;" layerPanel,
"border-radius:8px;} QCheckBox{padding:2px 1px;color:#1F2A3D;}" QStringLiteral("QFrame{background:#FFFFFF;border:1px solid #D5DBE5;border-radius:8px;}"
"QCheckBox{padding:2px 1px;color:#1F2A3D;}"
"QCheckBox:disabled{color:#9AA6B6;}")); "QCheckBox:disabled{color:#9AA6B6;}"));
auto* layerLayout = new QVBoxLayout(layerPanel); auto* layerLayout = new QVBoxLayout(layerPanel);
// 浮层内边距取间距令牌:左右 lg(12)、上下 ml(10),对称(原 13/10/15/11 是手调奇数)。 // 浮层内边距取间距令牌:左右 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); geopro::app::space::kLg, geopro::app::space::kMl);
layerLayout->setSpacing(geopro::app::space::kSm); layerLayout->setSpacing(geopro::app::space::kSm);
auto* layerTitle = new QLabel(QStringLiteral("视图详情")); auto* layerTitle = new QLabel(QStringLiteral("视图详情"));
layerTitle->setStyleSheet(QStringLiteral( geopro::app::applyThemedStyleSheet(
"font-weight:%1;color:#2D6CB5;border:none;background:transparent;" layerTitle, QStringLiteral("font-weight:%1;color:#2D6CB5;border:none;background:transparent;"
"padding-bottom:3px;font-size:%2px;") "padding-bottom:3px;font-size:%2px;")
.arg(geopro::app::type::kWeightSemibold) .arg(geopro::app::type::kWeightSemibold)
.arg(geopro::app::type::kTitle)); .arg(geopro::app::type::kTitle));
auto* chkCurtain = new QCheckBox(QStringLiteral("帘面(断面墙)")); auto* chkCurtain = new QCheckBox(QStringLiteral("帘面(断面墙)"));
chkCurtain->setChecked(true); chkCurtain->setChecked(true);
auto* chkVoxel = new QCheckBox(QStringLiteral("体素dd_voxel")); auto* chkVoxel = new QCheckBox(QStringLiteral("体素dd_voxel"));