geopro/src/app/TopBar.cpp

289 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "TopBar.hpp"
#include <QActionGroup>
#include <QColor>
#include <QFrame>
#include <QHBoxLayout>
#include <QLabel>
#include <QMenu>
#include <QMenuBar>
#include <QSize>
#include <QStringList>
#include <QToolButton>
#include <QVBoxLayout>
#include <QWidget>
#include "Glyphs.hpp"
#include "Theme.hpp"
#include <ElaDef.h>
#include <ElaIconButton.h>
#include <ElaMenu.h>
#include <ElaMenuBar.h>
#include <ElaToolButton.h>
namespace geopro::app {
namespace {
// ── 专业图标尺寸(统一放大;菜单栏字号亦同步加大)──
constexpr int kToolIcon = 22; // 工具条右侧图标
constexpr int kWorkspaceIcon = 20; // 工作空间 / 项目图标
// 竖直分隔细线。
QFrame* makeDivider(QWidget* parent)
{
auto* line = new QFrame(parent);
line->setObjectName(QStringLiteral("topDivider"));
line->setFrameShape(QFrame::VLine);
line->setFixedWidth(1);
line->setFixedHeight(24);
return line;
}
// 右侧图标按钮Fluent ElaIconButton自带图标字体 + 悬停 + 随主题着色)。
QWidget* makeIconButton(QWidget* parent, ElaIconType::IconName icon, const QString& tip)
{
auto* btn = new ElaIconButton(icon, kToolIcon, parent);
btn->setToolTip(tip);
btn->setCursor(Qt::PointingHandCursor);
return btn;
}
// ── 四个菜单(结构对齐需求;叶子项当前为静态占位,后续接真实页面)──
QMenu* buildViewMenu(QWidget* p)
{
auto* m = new ElaMenu(QStringLiteral("视图"), p);
m->addAction(QStringLiteral("分析视图"));
m->addAction(QStringLiteral("大屏视图"));
return m;
}
QMenu* buildProjectMenu(QWidget* p)
{
auto* m = new ElaMenu(QStringLiteral("项目管理"), p);
m->addAction(QStringLiteral("数据视图"));
auto* cfg = m->addMenu(QStringLiteral("项目配置"));
cfg->addAction(QStringLiteral("基本信息"));
cfg->addAction(QStringLiteral("项目结构"));
cfg->addAction(QStringLiteral("视图配置"));
m->addAction(QStringLiteral("数据管理"));
auto* biz = m->addMenu(QStringLiteral("业务管理"));
biz->addAction(QStringLiteral("异常管理"));
biz->addAction(QStringLiteral("异常体管理"));
auto* mon = m->addMenu(QStringLiteral("在线监测"));
mon->addAction(QStringLiteral("项目设备"));
mon->addAction(QStringLiteral("在线任务管理"));
auto* doc = m->addMenu(QStringLiteral("项目资料管理"));
doc->addAction(QStringLiteral("项目资料管理"));
doc->addAction(QStringLiteral("报告列表"));
auto* tools = m->addMenu(QStringLiteral("工具组件"));
tools->addAction(QStringLiteral("装置与脚本"));
tools->addAction(QStringLiteral("色阶配置"));
tools->addAction(QStringLiteral("异常类型管理"));
tools->addAction(QStringLiteral("模型管理"));
auto* exp = m->addMenu(QStringLiteral("批量导出"));
exp->addAction(QStringLiteral("文件导出"));
exp->addAction(QStringLiteral("报告导出"));
auto* alarm = m->addMenu(QStringLiteral("告警管理"));
alarm->addAction(QStringLiteral("设备告警"));
alarm->addAction(QStringLiteral("告警查询"));
m->addAction(QStringLiteral("自动任务"));
m->addAction(QStringLiteral("模板管理"));
return m;
}
QMenu* buildToolsMenu(QWidget* p)
{
auto* m = new ElaMenu(QStringLiteral("业务工具"), p);
m->addAction(QStringLiteral("ERT 思维分析"));
m->addAction(QStringLiteral("电法脚本与装置"));
m->addAction(QStringLiteral("Geo 反演"));
m->addAction(QStringLiteral("三维 GPR 综合分析"));
return m;
}
QMenu* buildDeviceMenu(QWidget* p)
{
auto* m = new ElaMenu(QStringLiteral("设备"), p);
m->addAction(QStringLiteral("连接设备"));
m->addAction(QStringLiteral("设备管理"));
return m;
}
} // namespace
QWidget* buildMenuBar(QWidget* parent)
{
auto* mb = new ElaMenuBar(parent);
mb->setObjectName(QStringLiteral("appMenuBar"));
// ElaMenuBar 自绘 Fluent 外观并自动随 ElaTheme 明暗,不再写内联 QSS。
mb->addMenu(buildViewMenu(mb));
mb->addMenu(buildProjectMenu(mb));
mb->addMenu(buildToolsMenu(mb));
mb->addMenu(buildDeviceMenu(mb));
return mb;
}
TopBar::TopBar(QWidget* parent) : QWidget(parent) {
setObjectName(QStringLiteral("appToolBar"));
setFixedHeight(56);
// 字号引用 Theme 排版令牌:工作空间切换器=title(15)、头像/用户名=body·label(13)、
// 角色名=caption(12)。原 11px 角色名上调到 12去掉只差 1px 的糊层级。
// 切换器(ElaToolButton)/图标(ElaIconButton) 自绘 Fluent不再写它们的 QSS。
// 仅保留:工具条底/分隔线、头像(圆形自定义)、用户名/角色。头像白字用 white 关键字(恒白)。
geopro::app::applyThemedStyleSheet(
this, QStringLiteral(
"#appToolBar { background:#FFFFFF; border-bottom:1px solid #E1E6EE; }"
"#topDivider { color:#E1E6EE; }"
"QToolButton::menu-indicator { image:none; }"
"#avatar { background:#2D6CB5; color:white; border-radius:17px; font-weight:%2;"
" font-size:%1px; }"
"#userName { color:#1F2A3D; font-size:%3px; font-weight:%4; }"
"#userRole { color:#8A93A3; font-size:%5px; }")
.arg(type::kBody)
.arg(type::kWeightBold)
.arg(type::kLabel)
.arg(type::kWeightSemibold)
.arg(type::kCaption));
auto* lay = new QHBoxLayout(this);
lay->setContentsMargins(14, 0, 14, 0);
lay->setSpacing(0);
// 工作空间切换器Fluent ElaToolButton数据驱动初始占位文本待 setWorkspaces 填充)。
wsBtn_ = new ElaToolButton(this);
wsBtn_->setObjectName(QStringLiteral("wsSwitcher"));
wsBtn_->setIcon(makeGlyph(Glyph::Workspace, QColor("#2D6CB5"), kWorkspaceIcon));
wsBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
wsBtn_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
wsBtn_->setPopupMode(QToolButton::InstantPopup);
wsBtn_->setCursor(Qt::PointingHandCursor);
wsBtn_->setText(QStringLiteral("正在加载工作空间…"));
wsBtn_->setMenu(new ElaMenu(wsBtn_));
lay->addWidget(wsBtn_);
lay->addSpacing(10);
lay->addWidget(makeDivider(this));
lay->addSpacing(10);
// 项目切换器Fluent ElaToolButton数据驱动
projBtn_ = new ElaToolButton(this);
projBtn_->setObjectName(QStringLiteral("wsSwitcher"));
projBtn_->setIcon(makeGlyph(Glyph::Folder, QColor("#2D6CB5"), kWorkspaceIcon));
projBtn_->setIconSize(QSize(kWorkspaceIcon, kWorkspaceIcon));
projBtn_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
projBtn_->setPopupMode(QToolButton::InstantPopup);
projBtn_->setCursor(Qt::PointingHandCursor);
projBtn_->setText(QStringLiteral("正在加载项目…"));
projBtn_->setMenu(new ElaMenu(projBtn_));
lay->addWidget(projBtn_);
lay->addStretch();
lay->addWidget(makeIconButton(this, ElaIconType::CircleQuestion, QStringLiteral("帮助")));
lay->addWidget(makeIconButton(this, ElaIconType::Bell, QStringLiteral("通知")));
lay->addWidget(makeIconButton(this, ElaIconType::Gear, QStringLiteral("设置")));
lay->addSpacing(10);
lay->addWidget(makeDivider(this));
lay->addSpacing(12);
// 用户区:头像可点击 → 弹出菜单(退出登录)。
auto* avatar = new QToolButton(this);
avatar->setObjectName(QStringLiteral("avatar"));
avatar->setText(QStringLiteral("ZL"));
avatar->setFixedSize(34, 34);
avatar->setCursor(Qt::PointingHandCursor);
avatar->setPopupMode(QToolButton::InstantPopup);
auto* userMenu = new ElaMenu(avatar);
QObject::connect(userMenu->addAction(QStringLiteral("退出登录")), &QAction::triggered, this,
[this] { emit logoutRequested(); });
avatar->setMenu(userMenu);
lay->addWidget(avatar);
lay->addSpacing(8);
auto* userBox = new QWidget(this);
auto* userLay = new QVBoxLayout(userBox);
userLay->setContentsMargins(0, 0, 0, 0);
userLay->setSpacing(0);
auto* userName = new QLabel(QStringLiteral("张磊"), userBox);
userName->setObjectName(QStringLiteral("userName"));
auto* userRole = new QLabel(QStringLiteral("高级工程师"), userBox);
userRole->setObjectName(QStringLiteral("userRole"));
userLay->addWidget(userName);
userLay->addWidget(userRole);
lay->addWidget(userBox);
}
void TopBar::setWorkspaces(const std::vector<data::Workspace>& list, const QString& currentId) {
auto* menu = new ElaMenu(wsBtn_);
auto* header = menu->addAction(QStringLiteral("切换空间"));
header->setEnabled(false);
menu->addSeparator();
auto* group = new QActionGroup(menu);
group->setExclusive(true); // 互斥:只一个勾选,避免“多选”
QString currentName;
for (const auto& w : list) {
const QString id = QString::fromStdString(w.id);
const QString name = QString::fromStdString(w.name);
auto* a = menu->addAction(name);
a->setCheckable(true);
a->setChecked(id == currentId);
group->addAction(a);
if (id == currentId) currentName = name;
QObject::connect(a, &QAction::triggered, this, [this, id, name]() {
wsBtn_->setText(name + QStringLiteral("")); // 立即反馈
emit workspaceSwitchRequested(id);
});
}
if (list.empty()) {
auto* none = menu->addAction(QStringLiteral("(暂无空间)"));
none->setEnabled(false);
}
wsBtn_->setMenu(menu);
wsBtn_->setText((currentName.isEmpty() ? QStringLiteral("选择空间") : currentName) +
QStringLiteral(""));
}
void TopBar::setProjects(const std::vector<data::ProjectSummary>& list, const QString& currentId,
bool hasMore) {
auto* menu = new ElaMenu(projBtn_);
auto* header = menu->addAction(QStringLiteral("切换项目"));
header->setEnabled(false);
menu->addSeparator();
auto* group = new QActionGroup(menu);
group->setExclusive(true);
QString currentName;
for (const auto& p : list) {
const QString id = QString::fromStdString(p.id);
const QString name = QString::fromStdString(p.name);
auto* a = menu->addAction(name);
a->setCheckable(true);
a->setChecked(id == currentId);
group->addAction(a);
if (id == currentId) currentName = name;
QObject::connect(a, &QAction::triggered, this, [this, id, name]() {
projBtn_->setText(name + QStringLiteral(""));
emit projectSwitchRequested(id);
});
}
if (list.empty()) {
auto* none = menu->addAction(QStringLiteral("(暂无项目)"));
none->setEnabled(false);
}
if (hasMore) {
menu->addSeparator();
auto* all = menu->addAction(QStringLiteral("全部项目…"));
QObject::connect(all, &QAction::triggered, this, [this]() { emit allProjectsRequested(); });
}
projBtn_->setMenu(menu);
projBtn_->setText((currentName.isEmpty() ? QStringLiteral("选择项目") : currentName) +
QStringLiteral(""));
}
void TopBar::setProjectButtonText(const QString& name) {
projBtn_->setText(name + QStringLiteral(""));
}
} // namespace geopro::app