feat(theme): 全局 QSS 模板化 + palette 从令牌,标准控件对齐规范色值(§1/§3/§6/§7)

This commit is contained in:
gaozheng 2026-06-10 15:29:07 +08:00
parent 425e17e6af
commit b242240df6
1 changed files with 110 additions and 109 deletions

View File

@ -88,57 +88,57 @@ QString tokenHex(const char* name, bool dark)
// 全局样式表(浅色专业)。只描述外观,不含任何交互逻辑。
// 注意:刻意不重写 QCheckBox::indicator —— Fusion 一旦检测到 indicator 子控件被改写,
// 就需要自带勾选 image否则勾选态会变成空白方块。这里交给 Fusion 原生绘制,
// 它会自动采用调色板的 Highlight(#2D6CB5) 作勾选色,省去打包图片资源。
// 它会自动采用调色板的 Highlight(accent/primary) 作勾选色,省去打包图片资源。
const char* kStyleSheet = R"QSS(
/* ── 基础 ───────────────────────────────────────────────── */
QWidget {
color: #1F2A3D;
color: {{text/primary}};
}
QMainWindow, QDialog {
background: #F4F6FA;
background: {{bg/app}};
}
/* QToolTip 不写 QSS用系统原生工具提示自定义 QSS 会让弹窗圆角露直角、且不像原生)。 */
/* ── 视图内工具条2D/3D、数据详情白底分段控件柔和不刺眼 ── */
QToolBar {
background: #FFFFFF;
background: {{bg/panel}};
border: none;
border-bottom: 1px solid #EAEEF4;
border-bottom: 1px solid {{divider}};
padding: 6px 8px;
spacing: 4px;
}
QToolBar QToolButton {
background: transparent;
color: #5A6B85;
color: {{text/secondary}};
border: none;
border-radius: 8px;
padding: 6px 14px;
font-weight: 500;
}
QToolBar QToolButton:hover {
background: #EEF3FB;
color: #1F2A3D;
background: {{bg/hover}};
color: {{text/primary}};
}
QToolBar QToolButton:pressed {
background: #DCE9F8;
background: {{bg/selected}};
}
QToolBar QToolButton:checked {
background: #EAF1FB;
color: #2D6CB5;
background: {{bg/hover}};
color: {{accent/primary}};
font-weight: 600;
}
QToolBar QToolButton:checked:hover {
background: #DCE9F8;
background: {{bg/selected}};
}
QToolBar::separator {
background: #EAEEF4;
background: {{divider}};
width: 1px;
margin: 6px 8px;
}
/* ── 树 / 列表:无边框(靠面板与留白分隔,去掉线框感)+ 充足行距 ── */
QTreeWidget, QListWidget, QTreeView, QListView {
background: #FFFFFF;
background: {{bg/panel}};
border: none;
padding: 6px;
outline: none;
@ -148,22 +148,22 @@ QTreeWidget::item, QListWidget::item, QTreeView::item, QListView::item {
}
QTreeWidget::item:hover, QListWidget::item:hover,
QTreeView::item:hover, QListView::item:hover {
background: #EEF3FB;
background: {{bg/hover}};
}
QTreeWidget::item:selected, QListWidget::item:selected,
QTreeView::item:selected, QListView::item:selected {
background: #DCE9F8;
color: #1B3D67;
background: {{bg/selected}};
color: {{text/primary}};
}
/* 注意:不要给 QTreeView::branch 设 background——一旦改写 branchQt 会停止绘制
/ indicator */
/* 表头(对象显示栏) */
QHeaderView::section {
background: #EDF1F7;
color: #3A475C;
background: {{bg/hover}};
color: {{text/secondary}};
border: none;
border-bottom: 1px solid #D5DBE5;
border-bottom: 1px solid {{border/default}};
padding: 6px 8px;
font-weight: 600;
}
@ -171,82 +171,82 @@ QHeaderView::section {
/* ── 标签页(数据 / 文件):现代下划线 tab无边框盒子 ──────── */
QTabWidget::pane {
border: none;
border-top: 1px solid #EAEEF4;
border-top: 1px solid {{divider}};
top: 0;
background: #FFFFFF;
background: {{bg/panel}};
}
QTabBar {
background: transparent;
}
QTabBar::tab {
background: transparent;
color: #5A6B85;
color: {{text/secondary}};
border: none;
border-bottom: 2px solid transparent;
padding: 8px 16px;
margin-right: 4px;
}
QTabBar::tab:selected {
color: #2D6CB5;
border-bottom: 2px solid #2D6CB5;
color: {{accent/primary}};
border-bottom: 2px solid {{accent/primary}};
font-weight: 600;
}
QTabBar::tab:hover:!selected {
color: #1F2A3D;
color: {{text/primary}};
}
/* ── 复选框(仅调间距/字色indicator 交给 Fusion 原生)──── */
QCheckBox {
spacing: 7px;
color: #1F2A3D;
color: {{text/primary}};
}
QCheckBox:disabled {
color: #9AA6B6;
color: {{text/disabled}};
}
/* ── 通用按钮 / 输入(登录窗内部各自再覆盖)────────────────── */
QPushButton {
background: #FFFFFF;
color: #1F2A3D;
border: 1px solid #C2CCDA;
background: {{bg/panel}};
color: {{text/primary}};
border: 1px solid {{border/strong}};
border-radius: 6px;
padding: 6px 14px;
}
QPushButton:hover {
background: #EEF3FB;
border-color: #2D6CB5;
background: {{bg/hover}};
border-color: {{accent/primary}};
}
QPushButton:pressed {
background: #DCE9F8;
background: {{bg/selected}};
}
QPushButton:default {
background: #2D6CB5;
color: #FFFFFF;
border-color: #2D6CB5;
background: {{accent/primary}};
color: {{text/on-primary}};
border-color: {{accent/primary}};
}
QPushButton:default:hover {
background: #2862A6;
background: {{accent/primary-hover}};
}
QPushButton:disabled {
background: #F0F2F6;
color: #9AA6B6;
border-color: #DCE0E7;
background: {{bg/app}};
color: {{text/disabled}};
border-color: {{border/default}};
}
QLineEdit {
background: #FFFFFF;
color: #1F2A3D;
border: 1px solid #C7D2E0;
background: {{bg/panel}};
color: {{text/primary}};
border: 1px solid {{border/strong}};
border-radius: 6px;
padding: 6px 8px;
selection-background-color: #2D6CB5;
selection-color: #FFFFFF;
selection-background-color: {{accent/primary}};
selection-color: {{text/on-primary}};
}
QLineEdit:focus {
border: 1px solid #2D6CB5;
border: 1px solid {{accent/primary}};
}
QLineEdit:disabled {
background: #F0F2F6;
color: #8A93A3;
background: {{bg/app}};
color: {{text/disabled}};
}
/* ── 滚动条:纤细现代(无需图片资源)───────────────────────── */
@ -256,12 +256,12 @@ QScrollBar:vertical {
margin: 2px;
}
QScrollBar::handle:vertical {
background: #C2CCDA;
background: {{scrollbar/thumb}};
border-radius: 6px;
min-height: 28px;
}
QScrollBar::handle:vertical:hover {
background: #A7B4C7;
background: {{scrollbar/thumb-hover}};
}
QScrollBar:horizontal {
background: transparent;
@ -269,12 +269,12 @@ QScrollBar:horizontal {
margin: 2px;
}
QScrollBar::handle:horizontal {
background: #C2CCDA;
background: {{scrollbar/thumb}};
border-radius: 6px;
min-width: 28px;
}
QScrollBar::handle:horizontal:hover {
background: #A7B4C7;
background: {{scrollbar/thumb-hover}};
}
QScrollBar::add-line, QScrollBar::sub-line {
width: 0;
@ -286,38 +286,38 @@ QScrollBar::add-page, QScrollBar::sub-page {
/* ── 分隔条:默认近乎隐形,悬停时才显淡色(去掉灰硬条)──────── */
QSplitter::handle {
background: #EAEEF4;
background: {{divider}};
}
QSplitter::handle:hover {
background: #C7D2E0;
background: {{accent/primary}};
}
ads--CDockSplitter::handle {
background: #EAEEF4;
background: {{divider}};
}
ads--CDockSplitter::handle:hover {
background: #C7D2E0;
background: {{accent/primary}};
}
/* ── 状态栏:底部信息条(坐标系 / 状态指示,常驻可见)──────── */
QStatusBar {
background: #FFFFFF;
color: #5A6B85;
border-top: 1px solid #EAEEF4;
background: {{bg/panel}};
color: {{text/secondary}};
border-top: 1px solid {{divider}};
}
QStatusBar::item {
border: none;
}
QStatusBar QLabel {
color: #5A6B85;
color: {{text/secondary}};
padding: 0 4px;
}
/* ── 菜单栏 / 菜单(标准 QMenuBar/QMenu刻意不设 border-radius——弹窗圆角靠系统(Win11
)QSS // */
QMenuBar {
background: #FFFFFF;
color: #1F2A3D;
border-bottom: 1px solid #EEF1F5;
background: {{bg/panel}};
color: {{text/primary}};
border-bottom: 1px solid {{divider}};
padding: 2px 6px;
}
QMenuBar::item {
@ -326,16 +326,16 @@ QMenuBar::item {
border-radius: 6px;
}
QMenuBar::item:selected {
background: #EAF1FB;
color: #2D6CB5;
background: {{bg/hover}};
color: {{accent/primary}};
}
QMenuBar::item:pressed {
background: #DCE6F4;
background: {{bg/selected}};
}
QMenu {
background: #FFFFFF;
color: #1F2A3D;
border: 1px solid #D5DBE5;
background: {{bg/panel}};
color: {{text/primary}};
border: 1px solid {{border/default}};
padding: 4px;
}
QMenu::item {
@ -343,37 +343,37 @@ QMenu::item {
border-radius: 6px;
}
QMenu::item:selected {
background: #EAF1FB;
color: #2D6CB5;
background: {{bg/hover}};
color: {{accent/primary}};
}
QMenu::separator {
height: 1px;
background: #E1E6EE;
background: {{divider}};
margin: 4px 8px;
}
/* ── 下拉框(按需出现时也与主题一致)──────────────────────── */
QComboBox {
background: #FFFFFF;
color: #1F2A3D;
border: 1px solid #C2CCDA;
background: {{bg/panel}};
color: {{text/primary}};
border: 1px solid {{border/strong}};
border-radius: 6px;
padding: 6px 10px;
min-height: 18px;
}
QComboBox:hover {
border-color: #2D6CB5;
border-color: {{accent/primary}};
}
QComboBox:focus {
border-color: #2D6CB5;
border-color: {{accent/primary}};
}
QComboBox::drop-down {
border: none;
width: 22px;
}
QComboBox QAbstractItemView {
background: #FFFFFF;
border: 1px solid #D5DBE5;
background: {{bg/panel}};
border: 1px solid {{border/default}};
outline: none;
padding: 2px;
}
@ -381,16 +381,16 @@ QComboBox QAbstractItemView::item {
border: none;
padding: 6px 10px;
min-height: 20px;
color: #1F2A3D;
color: {{text/primary}};
}
QComboBox QAbstractItemView::item:selected {
background: #EAF1FB;
color: #2D6CB5;
background: {{bg/hover}};
color: {{accent/primary}};
}
/* ── 分组框(按需出现时也与主题一致)──────────────────────── */
QGroupBox {
border: 1px solid #D5DBE5;
border: 1px solid {{border/default}};
border-radius: 8px;
margin-top: 10px;
padding-top: 6px;
@ -400,20 +400,20 @@ QGroupBox::title {
subcontrol-origin: margin;
left: 12px;
padding: 0 4px;
color: #3A475C;
color: {{text/secondary}};
}
/* ── 进度条(长任务反馈,遵循 Doherty 阈值)──────────────────── */
QProgressBar {
background: #E6EBF3;
background: {{divider}};
border: none;
border-radius: 6px;
height: 8px;
text-align: center;
color: #5A6B85;
color: {{text/secondary}};
}
QProgressBar::chunk {
background: #2D6CB5;
background: {{accent/primary}};
border-radius: 6px;
}
@ -421,30 +421,30 @@ QProgressBar::chunk {
(//) +
线 + */
ads--CDockAreaWidget {
background: #F4F6FA;
background: {{bg/app}};
}
ads--CDockAreaTitleBar {
background: #EDF1F7;
border-bottom: 1px solid #D5DBE5;
background: {{bg/hover}};
border-bottom: 1px solid {{border/default}};
padding: 0;
}
ads--CDockWidgetTab {
background: #EDF1F7;
background: {{bg/hover}};
border: none;
border-bottom: 2px solid transparent;
padding: 7px 12px;
min-height: 22px;
}
ads--CDockWidgetTab[activeTab="true"] {
background: #EDF1F7;
border-bottom: 2px solid #2D6CB5;
background: {{bg/hover}};
border-bottom: 2px solid {{accent/primary}};
}
ads--CDockWidgetTab QLabel {
color: #5A6B85;
color: {{text/secondary}};
font-weight: 600;
}
ads--CDockWidgetTab[activeTab="true"] QLabel {
color: #1F2A3D;
color: {{text/primary}};
font-weight: 600;
}
)QSS";
@ -504,34 +504,35 @@ QString themedQss(const QString& designQss, bool dark)
}
// 当前模式的全局 QSS。
QString styleSheetForMode(bool dark)
QString styleSheetForMode(bool /*dark*/)
{
return themedQss(QString::fromUtf8(kStyleSheet), dark);
return fillTokens(QString::fromUtf8(kStyleSheet));
}
// 调色板同样取自 ElaTheme让无 QSS 覆盖处的标准控件也与外壳一致。
QPalette buildPalette(bool dark)
{
QPalette p;
const QColor shell = roleColor(dark, "#F4F6FA");
const QColor panel = roleColor(dark, "#FFFFFF");
const QColor text = roleColor(dark, "#1F2A3D");
const QColor muted = roleColor(dark, "#5A6B85");
const QColor accent = roleColor(dark, "#2D6CB5");
const QColor border = roleColor(dark, "#D5DBE5");
const QColor disabled = roleColor(dark, "#9AA6B6");
const QColor shell = QColor(tokenHex("bg/app", dark));
const QColor panel = QColor(tokenHex("bg/panel", dark));
const QColor text = QColor(tokenHex("text/primary", dark));
const QColor muted = QColor(tokenHex("text/secondary", dark));
const QColor accent = QColor(tokenHex("accent/primary", dark));
const QColor border = QColor(tokenHex("border/default", dark));
const QColor disabled = QColor(tokenHex("text/disabled", dark));
const QColor hoverBg = QColor(tokenHex("bg/hover", dark));
p.setColor(QPalette::Window, shell);
p.setColor(QPalette::WindowText, text);
p.setColor(QPalette::Base, panel);
p.setColor(QPalette::AlternateBase, roleColor(dark, "#EDF1F7"));
p.setColor(QPalette::AlternateBase, QColor(tokenHex("bg/panel-subtle", dark)));
p.setColor(QPalette::Text, text);
p.setColor(QPalette::Button, roleColor(dark, "#EDF1F7"));
p.setColor(QPalette::Button, hoverBg);
p.setColor(QPalette::ButtonText, text);
p.setColor(QPalette::ToolTipBase, text);
p.setColor(QPalette::ToolTipText, shell);
p.setColor(QPalette::ToolTipText, panel);
p.setColor(QPalette::Highlight, accent);
p.setColor(QPalette::HighlightedText, panel);
p.setColor(QPalette::HighlightedText, QColor(tokenHex("text/on-primary", dark)));
p.setColor(QPalette::PlaceholderText, muted);
p.setColor(QPalette::Link, accent);
// Fusion 的明暗 3D 角色统一压成边框色,立体效果塌成平面(去斜角/凹槽)。