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
2 changed files with 35 additions and 47 deletions
Showing only changes of commit b6e0142d06 - Show all commits

View File

@ -2,6 +2,9 @@
#include "Theme.hpp" #include "Theme.hpp"
#include <ElaIconButton.h>
#include <ElaToolButton.h>
#include <QButtonGroup> #include <QButtonGroup>
#include <QColor> #include <QColor>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -26,25 +29,19 @@ constexpr int kTabIcon = 19; // Tab 图标
// 面板标题=title(15)、徽标=caption(12)、Tab 文本=body(13),加粗统一 semibold。 // 面板标题=title(15)、徽标=caption(12)、Tab 文本=body(13),加粗统一 semibold。
// #panelBadge 为中性计数徽标;#panelBadgeWarn 为“需注意”变体(语义 warning 色), // #panelBadge 为中性计数徽标;#panelBadgeWarn 为“需注意”变体(语义 warning 色),
// 供异常计数等承载“待复查”含义的徽标使用(调用方改 objectName 即切换)。 // 供异常计数等承载“待复查”含义的徽标使用(调用方改 objectName 即切换)。
// 表头底/标题/徽标样式。Tab(ElaToolButton)与操作按钮(ElaIconButton)自绘 Fluent
// 不再写它们的 QSS选中态由 Ela 的 checked 高亮表达,而非自定义下划线)。
QString headerQss() QString headerQss()
{ {
return QStringLiteral( return QStringLiteral(
"#panelHeader { background:#FFFFFF; border-bottom:1px solid #E6EAF1; }" "#panelHeader { background:#FFFFFF; border-bottom:1px solid #E6EAF1; }"
"#panelTitle { color:#1F2A3D; font-size:%1px; font-weight:%4; }" "#panelTitle { color:#1F2A3D; font-size:%1px; font-weight:%3; }"
"#panelBadge { background:#EAEEF5; color:#5A6B85; border-radius:9px;" "#panelBadge { background:#EAEEF5; color:#5A6B85; border-radius:9px;"
" padding:1px 7px; font-size:%2px; font-weight:%4; }" " padding:1px 7px; font-size:%2px; font-weight:%3; }"
"#panelBadgeWarn { background:%5; color:%6; border-radius:9px;" "#panelBadgeWarn { background:%4; color:%5; border-radius:9px;"
" padding:1px 7px; font-size:%2px; font-weight:%4; }" " padding:1px 7px; font-size:%2px; font-weight:%3; }")
"QToolButton#panelAction { border:none; border-radius:7px; padding:5px; }"
"QToolButton#panelAction:hover { background:#EEF3FB; }"
"QToolButton#tabBtn { border:none; border-bottom:2px solid transparent; color:#5A6B85;"
" padding:8px 4px; font-size:%3px; }"
"QToolButton#tabBtn:hover { color:#1F2A3D; }"
"QToolButton#tabBtn:checked { color:#1F2A3D; font-weight:%4;"
" border-bottom:2px solid #2D6CB5; }")
.arg(type::kTitle) .arg(type::kTitle)
.arg(type::kCaption) .arg(type::kCaption)
.arg(type::kBody)
.arg(type::kWeightSemibold) .arg(type::kWeightSemibold)
.arg(QString::fromUtf8(semantic::kWarningFill)) .arg(QString::fromUtf8(semantic::kWarningFill))
.arg(QString::fromUtf8(semantic::kWarning)); .arg(QString::fromUtf8(semantic::kWarning));
@ -61,16 +58,13 @@ QLabel* makeBadge(QWidget* parent)
return badge; return badge;
} }
// 表头操作按钮(静态占位)。 // 表头操作按钮(Fluent ElaIconButton图标沿用项目 glyph 像素图)。
QToolButton* makeActionButton(QWidget* parent, const HeaderAction& a) QWidget* makeActionButton(QWidget* parent, const HeaderAction& a)
{ {
auto* btn = new QToolButton(parent); auto* btn = new ElaIconButton(
btn->setObjectName(QStringLiteral("panelAction")); makeGlyph(a.first, QColor("#5A6B85"), kActionIcon).pixmap(kActionIcon, kActionIcon), parent);
btn->setIcon(makeGlyph(a.first, QColor("#5A6B85"), kActionIcon));
btn->setIconSize(QSize(kActionIcon, kActionIcon));
btn->setCursor(Qt::PointingHandCursor); btn->setCursor(Qt::PointingHandCursor);
btn->setToolTip(a.second + QStringLiteral("(占位)")); btn->setToolTip(a.second + QStringLiteral("(占位)"));
btn->setAutoRaise(true);
return btn; return btn;
} }
@ -128,7 +122,7 @@ TabbedPanel buildTabbedPanel(const QVector<PanelTab>& tabs, const QVector<Header
for (int i = 0; i < tabs.size(); ++i) { for (int i = 0; i < tabs.size(); ++i) {
const PanelTab& t = tabs[i]; const PanelTab& t = tabs[i];
auto* btn = new QToolButton(header); auto* btn = new ElaToolButton(header); // Fluent tab(选中态由 Ela checked 高亮)
btn->setObjectName(QStringLiteral("tabBtn")); btn->setObjectName(QStringLiteral("tabBtn"));
btn->setText(t.title); btn->setText(t.title);
btn->setIcon(makeGlyph(t.icon, QColor("#5A6B85"), kTabIcon)); btn->setIcon(makeGlyph(t.icon, QColor("#5A6B85"), kTabIcon));
@ -136,7 +130,6 @@ TabbedPanel buildTabbedPanel(const QVector<PanelTab>& tabs, const QVector<Header
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
btn->setCheckable(true); btn->setCheckable(true);
btn->setCursor(Qt::PointingHandCursor); btn->setCursor(Qt::PointingHandCursor);
btn->setAutoRaise(true);
group->addButton(btn, i); group->addButton(btn, i);
hlay->addWidget(btn); hlay->addWidget(btn);

View File

@ -16,8 +16,11 @@
#include "Glyphs.hpp" #include "Glyphs.hpp"
#include "Theme.hpp" #include "Theme.hpp"
#include <ElaDef.h>
#include <ElaIconButton.h>
#include <ElaMenu.h> #include <ElaMenu.h>
#include <ElaMenuBar.h> #include <ElaMenuBar.h>
#include <ElaToolButton.h>
namespace geopro::app { namespace geopro::app {
@ -38,16 +41,12 @@ QFrame* makeDivider(QWidget* parent)
return line; return line;
} }
// 右侧图标按钮(仅图标,悬停显示文本)。 // 右侧图标按钮(Fluent ElaIconButton自带图标字体 + 悬停 + 随主题着色)。
QToolButton* makeIconButton(QWidget* parent, Glyph g, const QString& tip) QWidget* makeIconButton(QWidget* parent, ElaIconType::IconName icon, const QString& tip)
{ {
auto* btn = new QToolButton(parent); auto* btn = new ElaIconButton(icon, kToolIcon, parent);
btn->setObjectName(QStringLiteral("iconBtn"));
btn->setIcon(makeGlyph(g, QColor("#5A6B85"), kToolIcon));
btn->setIconSize(QSize(kToolIcon, kToolIcon));
btn->setToolTip(tip); btn->setToolTip(tip);
btn->setCursor(Qt::PointingHandCursor); btn->setCursor(Qt::PointingHandCursor);
btn->setAutoRaise(true);
return btn; return btn;
} }
@ -131,33 +130,29 @@ 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 的糊层级。
// 切换器(ElaToolButton)/图标(ElaIconButton) 自绘 Fluent不再写它们的 QSS。
// 仅保留:工具条底/分隔线、头像(圆形自定义)、用户名/角色。头像白字用 white 关键字(恒白)。
geopro::app::applyThemedStyleSheet( geopro::app::applyThemedStyleSheet(
this, QStringLiteral( this, QStringLiteral(
"#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }" "#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }"
"#topDivider { color:#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; }" "QToolButton::menu-indicator { image:none; }"
"#avatar { background:#2D6CB5; color:#FFFFFF; border-radius:17px; font-weight:%6;" "#avatar { background:#2D6CB5; color:white; border-radius:17px; font-weight:%2;"
" font-size:%2px; }" " font-size:%1px; }"
"#userName { color:#1F2A3D; font-size:%3px; font-weight:%5; }" "#userName { color:#1F2A3D; font-size:%3px; font-weight:%4; }"
"#userRole { color:#8A93A3; font-size:%4px; }") "#userRole { color:#8A93A3; font-size:%5px; }")
.arg(type::kTitle)
.arg(type::kBody) .arg(type::kBody)
.arg(type::kWeightBold)
.arg(type::kLabel) .arg(type::kLabel)
.arg(type::kCaption)
.arg(type::kWeightSemibold) .arg(type::kWeightSemibold)
.arg(type::kWeightBold)); .arg(type::kCaption));
auto* lay = new QHBoxLayout(this); auto* lay = new QHBoxLayout(this);
lay->setContentsMargins(14, 0, 14, 0); lay->setContentsMargins(14, 0, 14, 0);
lay->setSpacing(0); lay->setSpacing(0);
// 工作空间切换器(数据驱动;初始占位文本,待 setWorkspaces 填充)。 // 工作空间切换器(Fluent ElaToolButton数据驱动初始占位文本待 setWorkspaces 填充)。
wsBtn_ = new QToolButton(this); wsBtn_ = new ElaToolButton(this);
wsBtn_->setObjectName(QStringLiteral("wsSwitcher")); wsBtn_->setObjectName(QStringLiteral("wsSwitcher"));
wsBtn_->setIcon(makeGlyph(Glyph::Workspace, QColor("#2D6CB5"), kWorkspaceIcon)); wsBtn_->setIcon(makeGlyph(Glyph::Workspace, QColor("#2D6CB5"), kWorkspaceIcon));
wsBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon)); wsBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
@ -172,8 +167,8 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
lay->addWidget(makeDivider(this)); lay->addWidget(makeDivider(this));
lay->addSpacing(10); lay->addSpacing(10);
// 项目切换器(数据驱动)。 // 项目切换器(Fluent ElaToolButton数据驱动)。
projBtn_ = new QToolButton(this); projBtn_ = new ElaToolButton(this);
projBtn_->setObjectName(QStringLiteral("wsSwitcher")); projBtn_->setObjectName(QStringLiteral("wsSwitcher"));
projBtn_->setIcon(makeGlyph(Glyph::Folder, QColor("#2D6CB5"), kWorkspaceIcon)); projBtn_->setIcon(makeGlyph(Glyph::Folder, QColor("#2D6CB5"), kWorkspaceIcon));
projBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon)); projBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
@ -186,9 +181,9 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
lay->addStretch(); lay->addStretch();
lay->addWidget(makeIconButton(this, Glyph::Help, QStringLiteral("帮助"))); lay->addWidget(makeIconButton(this, ElaIconType::CircleQuestion, QStringLiteral("帮助")));
lay->addWidget(makeIconButton(this, Glyph::Bell, QStringLiteral("通知"))); lay->addWidget(makeIconButton(this, ElaIconType::Bell, QStringLiteral("通知")));
lay->addWidget(makeIconButton(this, Glyph::Gear, QStringLiteral("设置"))); lay->addWidget(makeIconButton(this, ElaIconType::Gear, QStringLiteral("设置")));
lay->addSpacing(10); lay->addSpacing(10);
lay->addWidget(makeDivider(this)); lay->addWidget(makeDivider(this));
lay->addSpacing(12); lay->addSpacing(12);