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
1 changed files with 110 additions and 109 deletions
Showing only changes of commit b242240df6 - Show all commits

View File

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