162 lines
5.5 KiB
C++
162 lines
5.5 KiB
C++
#include "PanelHeader.hpp"
|
||
|
||
#include "Theme.hpp"
|
||
|
||
#include <ElaIconButton.h>
|
||
#include <ElaToolButton.h>
|
||
|
||
#include <QButtonGroup>
|
||
#include <QColor>
|
||
#include <QHBoxLayout>
|
||
#include <QLabel>
|
||
#include <QSize>
|
||
#include <QStackedWidget>
|
||
#include <QToolButton>
|
||
#include <QVBoxLayout>
|
||
#include <QWidget>
|
||
|
||
namespace geopro::app {
|
||
|
||
namespace {
|
||
|
||
// ── 专业图标/字号尺寸(统一放大)──
|
||
constexpr int kHeaderHeight = 42;
|
||
constexpr int kTitleIcon = 20; // 表头标题图标
|
||
constexpr int kActionIcon = 19; // 表头操作按钮图标
|
||
constexpr int kTabIcon = 19; // Tab 图标
|
||
|
||
// 表头统一样式(标准表头 + Tab 表头共用)。字号/字重引用 Theme 排版令牌:
|
||
// 面板标题=title(15)、徽标=caption(12)、Tab 文本=body(13),加粗统一 semibold。
|
||
// #panelBadge 为中性计数徽标;#panelBadgeWarn 为“需注意”变体(语义 warning 色),
|
||
// 供异常计数等承载“待复查”含义的徽标使用(调用方改 objectName 即切换)。
|
||
// 表头底/标题/徽标样式。Tab(ElaToolButton)与操作按钮(ElaIconButton)自绘 Fluent,
|
||
// 不再写它们的 QSS(选中态由 Ela 的 checked 高亮表达,而非自定义下划线)。
|
||
QString headerQss()
|
||
{
|
||
return QStringLiteral(
|
||
"#panelHeader { background:#FFFFFF; border-bottom:1px solid #E6EAF1; }"
|
||
"#panelTitle { color:#1F2A3D; font-size:%1px; font-weight:%3; }"
|
||
"#panelBadge { background:#EAEEF5; color:#5A6B85; border-radius:9px;"
|
||
" padding:1px 7px; font-size:%2px; font-weight:%3; }"
|
||
"#panelBadgeWarn { background:%4; color:%5; border-radius:9px;"
|
||
" padding:1px 7px; font-size:%2px; font-weight:%3; }")
|
||
.arg(type::kTitle)
|
||
.arg(type::kCaption)
|
||
.arg(type::kWeightSemibold)
|
||
.arg(QString::fromUtf8(semantic::kWarningFill))
|
||
.arg(QString::fromUtf8(semantic::kWarning));
|
||
}
|
||
|
||
// 数量徽标(默认隐藏,调用方 setText+setVisible 显示)。
|
||
QLabel* makeBadge(QWidget* parent)
|
||
{
|
||
auto* badge = new QLabel(parent);
|
||
badge->setObjectName(QStringLiteral("panelBadge"));
|
||
badge->setAlignment(Qt::AlignCenter);
|
||
badge->setMinimumWidth(16);
|
||
badge->setVisible(false);
|
||
return badge;
|
||
}
|
||
|
||
// 表头操作按钮(Fluent ElaIconButton;图标沿用项目 glyph 像素图)。
|
||
QWidget* makeActionButton(QWidget* parent, const HeaderAction& a)
|
||
{
|
||
auto* btn = new ElaIconButton(
|
||
makeGlyph(a.first, QColor("#5A6B85"), kActionIcon).pixmap(kActionIcon, kActionIcon), parent);
|
||
btn->setFixedSize(30, 30); // QPixmap 构造不设尺寸,显式固定防变形
|
||
btn->setCursor(Qt::PointingHandCursor);
|
||
btn->setToolTip(a.second + QStringLiteral("(占位)"));
|
||
return btn;
|
||
}
|
||
|
||
} // namespace
|
||
|
||
QWidget* buildPanelHeader(Glyph icon, const QString& title, const QVector<HeaderAction>& actions)
|
||
{
|
||
auto* header = new QWidget();
|
||
header->setObjectName(QStringLiteral("panelHeader"));
|
||
header->setFixedHeight(kHeaderHeight);
|
||
geopro::app::applyThemedStyleSheet(header, headerQss());
|
||
|
||
auto* lay = new QHBoxLayout(header);
|
||
lay->setContentsMargins(12, 0, 8, 0);
|
||
lay->setSpacing(8);
|
||
|
||
auto* iconLbl = new QLabel(header);
|
||
iconLbl->setPixmap(makeGlyph(icon, QColor("#44546B"), kTitleIcon).pixmap(kTitleIcon, kTitleIcon));
|
||
lay->addWidget(iconLbl);
|
||
|
||
auto* titleLbl = new QLabel(title, header);
|
||
titleLbl->setObjectName(QStringLiteral("panelTitle"));
|
||
lay->addWidget(titleLbl);
|
||
|
||
lay->addWidget(makeBadge(header)); // 默认隐藏,调用方可经 findChild 更新
|
||
|
||
lay->addStretch();
|
||
|
||
for (const auto& a : actions) lay->addWidget(makeActionButton(header, a));
|
||
|
||
return header;
|
||
}
|
||
|
||
TabbedPanel buildTabbedPanel(const QVector<PanelTab>& tabs, const QVector<HeaderAction>& actions)
|
||
{
|
||
auto* box = new QWidget();
|
||
auto* v = new QVBoxLayout(box);
|
||
v->setContentsMargins(0, 0, 0, 0);
|
||
v->setSpacing(0);
|
||
|
||
auto* header = new QWidget(box);
|
||
header->setObjectName(QStringLiteral("panelHeader"));
|
||
header->setFixedHeight(kHeaderHeight);
|
||
geopro::app::applyThemedStyleSheet(header, headerQss());
|
||
auto* hlay = new QHBoxLayout(header);
|
||
hlay->setContentsMargins(10, 0, 8, 0);
|
||
hlay->setSpacing(2);
|
||
|
||
auto* stack = new QStackedWidget(box);
|
||
auto* group = new QButtonGroup(box);
|
||
group->setExclusive(true);
|
||
|
||
TabbedPanel result;
|
||
result.container = box;
|
||
|
||
for (int i = 0; i < tabs.size(); ++i) {
|
||
const PanelTab& t = tabs[i];
|
||
auto* btn = new ElaToolButton(header); // Fluent tab(选中态由 Ela checked 高亮)
|
||
btn->setObjectName(QStringLiteral("tabBtn"));
|
||
btn->setText(t.title);
|
||
btn->setIcon(makeGlyph(t.icon, QColor("#5A6B85"), kTabIcon));
|
||
btn->setIconSize(QSize(kTabIcon, kTabIcon));
|
||
btn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||
btn->setCheckable(true);
|
||
btn->setCursor(Qt::PointingHandCursor);
|
||
group->addButton(btn, i);
|
||
hlay->addWidget(btn);
|
||
|
||
QLabel* badge = nullptr;
|
||
if (t.hasBadge) {
|
||
badge = makeBadge(header);
|
||
hlay->addWidget(badge);
|
||
}
|
||
result.badges.append(badge);
|
||
|
||
stack->addWidget(t.content);
|
||
hlay->addSpacing(10);
|
||
}
|
||
|
||
hlay->addStretch();
|
||
for (const auto& a : actions) hlay->addWidget(makeActionButton(header, a));
|
||
|
||
QObject::connect(group, &QButtonGroup::idClicked, stack, &QStackedWidget::setCurrentIndex);
|
||
if (auto* first = group->button(0)) first->setChecked(true);
|
||
stack->setCurrentIndex(0);
|
||
|
||
v->addWidget(header);
|
||
v->addWidget(stack, 1);
|
||
|
||
return result;
|
||
}
|
||
|
||
} // namespace geopro::app
|