refactor/pure-qt-ui #3
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue