fix(ui): 修复改名导致的停靠布局丢失(bump dockState键丢弃失配旧布局) + 用户区改回QToolButton(头像图标+姓名职务一行,整块可点)修复挤成一团

This commit is contained in:
gaozheng 2026-06-10 17:41:46 +08:00
parent c953b35334
commit 3ccb8df4ed
2 changed files with 42 additions and 29 deletions

View File

@ -3,12 +3,15 @@
#include <QAbstractButton>
#include <QActionGroup>
#include <QColor>
#include <QFont>
#include <QFrame>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QMenu>
#include <QMenuBar>
#include <QPushButton>
#include <QPainter>
#include <QPixmap>
#include <QSize>
#include <QStringList>
#include <QToolButton>
@ -50,6 +53,29 @@ QWidget* makeIconButton(QWidget* parent, Glyph icon, const QString& tip)
return btn;
}
// 圆形头像图标:强调色填充 + 白色缩写。2x 绘制保证高 DPI 清晰。
QPixmap renderAvatar(const QString& initials, int px, const QColor& bg, const QColor& fg)
{
constexpr int kScale = 2;
const int s = px * kScale;
QPixmap pm(s, s);
pm.fill(Qt::transparent);
QPainter p(&pm);
p.setRenderHint(QPainter::Antialiasing, true);
p.setPen(Qt::NoPen);
p.setBrush(bg);
p.drawEllipse(0, 0, s, s);
QFont f = p.font();
f.setPixelSize(static_cast<int>(s * 0.4));
f.setBold(true);
p.setFont(f);
p.setPen(fg);
p.drawText(QRect(0, 0, s, s), Qt::AlignCenter, initials);
p.end();
pm.setDevicePixelRatio(kScale);
return pm;
}
// ── 四个菜单(结构对齐需求;叶子项当前为静态占位,后续接真实页面)──
QMenu* buildViewMenu(QWidget* p)
{
@ -146,7 +172,8 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
" subcontrol-position: right center; subcontrol-origin: padding; right:8px; }"
"QToolButton#iconBtn { border:none; border-radius:8px; padding:8px; }"
"QToolButton#iconBtn:hover { background:{{bg/hover}}; }"
"#userBtn { border:none; border-radius:8px; padding:2px 4px; text-align:left; }"
"#userBtn { border:none; border-radius:8px; padding:4px 10px 4px 6px;"
" color:{{text/primary}}; font-size:%3px; }"
"#userBtn:hover { background:{{bg/hover}}; }"
"#userBtn::menu-indicator { image:none; }"
"#avatar { background:{{accent/primary}}; color:{{text/on-primary}}; border-radius:17px; font-weight:%2;"
@ -205,37 +232,21 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) {
lay->addWidget(makeDivider(this));
lay->addSpacing(12);
// 用户区:头像 + 姓名 + 职务 同一行整块可点击QPushButton + 子布局,子控件鼠标穿透→点击命中按钮)。
auto* userBtn = new QPushButton(this);
// 用户区:头像(圆形图标) + 姓名·职务 同一行,整块可点击 → 退出登录菜单。
// 用 QToolButton(图标+文字),而非 QPushButton+子布局——后者按空文本算尺寸会把内容挤成一团。
auto* userBtn = new QToolButton(this);
userBtn->setObjectName(QStringLiteral("userBtn"));
userBtn->setIcon(QIcon(renderAvatar(QStringLiteral("ZL"), 30,
geopro::app::tokenColor("accent/primary"), Qt::white)));
userBtn->setIconSize(QSize(30, 30));
userBtn->setText(QStringLiteral("张磊 · 高级工程师"));
userBtn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
userBtn->setPopupMode(QToolButton::InstantPopup);
userBtn->setCursor(Qt::PointingHandCursor);
userBtn->setFlat(true);
auto* userLay = new QHBoxLayout(userBtn);
userLay->setContentsMargins(6, 2, 10, 2);
userLay->setSpacing(8);
auto* avatar = new QLabel(QStringLiteral("ZL"), userBtn);
avatar->setObjectName(QStringLiteral("avatar"));
avatar->setFixedSize(34, 34);
avatar->setAlignment(Qt::AlignCenter);
avatar->setAttribute(Qt::WA_TransparentForMouseEvents);
userLay->addWidget(avatar);
auto* userName = new QLabel(QStringLiteral("张磊"), userBtn);
userName->setObjectName(QStringLiteral("userName"));
userName->setAttribute(Qt::WA_TransparentForMouseEvents);
userLay->addWidget(userName);
auto* userRole = new QLabel(QStringLiteral("高级工程师"), userBtn);
userRole->setObjectName(QStringLiteral("userRole"));
userRole->setAttribute(Qt::WA_TransparentForMouseEvents);
userLay->addWidget(userRole);
auto* userMenu = new QMenu(userBtn);
QObject::connect(userMenu->addAction(QStringLiteral("退出登录")), &QAction::triggered, this,
[this] { emit logoutRequested(); });
userBtn->setMenu(userMenu);
lay->addWidget(userBtn);
}

View File

@ -999,7 +999,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
const QSettings settings;
const QByteArray geo = settings.value(QStringLiteral("ui/geometry")).toByteArray();
if (!geo.isEmpty()) window.restoreGeometry(geo);
const QByteArray dockState = settings.value(QStringLiteral("ui/dockState")).toByteArray();
// 注意ADS 按 dock 唯一名作键。改过 dock 名后旧布局会失配 → bump 此键丢弃旧布局,
// 回落到下方 addDockWidget 的默认排布(再改 dock 名时同样要 bump 版本号)。
const QByteArray dockState = settings.value(QStringLiteral("ui/dockState_v2")).toByteArray();
if (!dockState.isEmpty()) {
dockManager->restoreState(dockState);
// restoreState 重建停靠区会重新显示 ADS 标题栏,再隐藏一次保持“无双标题”。
@ -1010,7 +1012,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
QObject::connect(qApp, &QCoreApplication::aboutToQuit, dockManager, [dockManager, &window]() {
QSettings settings;
settings.setValue(QStringLiteral("ui/geometry"), window.saveGeometry());
settings.setValue(QStringLiteral("ui/dockState"), dockManager->saveState());
settings.setValue(QStringLiteral("ui/dockState_v2"), dockManager->saveState());
});
}