diff --git a/src/app/TopBar.cpp b/src/app/TopBar.cpp index 471675d..3bc82ad 100644 --- a/src/app/TopBar.cpp +++ b/src/app/TopBar.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -232,22 +234,65 @@ TopBar::TopBar(QWidget* parent) : QWidget(parent) { lay->addWidget(makeDivider(this)); lay->addSpacing(12); - // 用户区:头像(圆形图标) + 姓名·职务 同一行,整块可点击 → 退出登录菜单。 - // 用 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); - auto* userMenu = new QMenu(userBtn); - QObject::connect(userMenu->addAction(QStringLiteral("退出登录")), &QAction::triggered, this, + // 用户区:头像(圆形,竖直居中) + 右侧 姓名(上)/职务(下) 左对齐 + 下拉箭头;整块可点 → 菜单。 + // 用普通 QWidget + eventFilter:QWidget 按子布局正确撑开(QPushButton 装布局会按空文字算尺寸挤成一团)。 + userRow_ = new QWidget(this); + userRow_->setObjectName(QStringLiteral("userBtn")); + userRow_->setAttribute(Qt::WA_StyledBackground, true); // 令 QSS 背景(hover)在 QWidget 上生效 + userRow_->setCursor(Qt::PointingHandCursor); + userRow_->installEventFilter(this); + auto* uLay = new QHBoxLayout(userRow_); + uLay->setContentsMargins(8, 3, 8, 3); + uLay->setSpacing(10); + + auto* avatar = new QLabel(userRow_); + avatar->setPixmap( + renderAvatar(QStringLiteral("ZL"), 34, geopro::app::tokenColor("accent/primary"), Qt::white)); + avatar->setFixedSize(34, 34); + avatar->setAttribute(Qt::WA_TransparentForMouseEvents); + uLay->addWidget(avatar, 0, Qt::AlignVCenter); + + auto* nameBox = new QWidget(userRow_); + nameBox->setAttribute(Qt::WA_TransparentForMouseEvents); + auto* nameLay = new QVBoxLayout(nameBox); + nameLay->setContentsMargins(0, 0, 0, 0); + nameLay->setSpacing(0); + auto* userName = new QLabel(QStringLiteral("张磊"), nameBox); + userName->setObjectName(QStringLiteral("userName")); + auto* userRole = new QLabel(QStringLiteral("高级工程师"), nameBox); + userRole->setObjectName(QStringLiteral("userRole")); + nameLay->addWidget(userName); + nameLay->addWidget(userRole); + uLay->addWidget(nameBox, 0, Qt::AlignVCenter); + + auto* chevronLbl = new QLabel(userRow_); + chevronLbl->setPixmap(QPixmap(geopro::app::writeChevronIcon(true, QColor("#7C8493"))) + .scaled(12, 12, Qt::KeepAspectRatio, Qt::SmoothTransformation)); + chevronLbl->setAttribute(Qt::WA_TransparentForMouseEvents); + uLay->addWidget(chevronLbl, 0, Qt::AlignVCenter); + + // 下拉菜单(加宽):账户 / 个人资料 / 偏好设置 / API 密钥 / 退出登录。 + userMenu_ = new QMenu(this); + userMenu_->setMinimumWidth(200); + userMenu_->addAction(QStringLiteral("账户")); + userMenu_->addAction(QStringLiteral("个人资料")); + QObject::connect(userMenu_->addAction(QStringLiteral("偏好设置")), &QAction::triggered, this, + [this] { emit settingsRequested(); }); + userMenu_->addAction(QStringLiteral("API 密钥")); + userMenu_->addSeparator(); + QObject::connect(userMenu_->addAction(QStringLiteral("退出登录")), &QAction::triggered, this, [this] { emit logoutRequested(); }); - userBtn->setMenu(userMenu); - lay->addWidget(userBtn); + + lay->addWidget(userRow_); +} + +bool TopBar::eventFilter(QObject* obj, QEvent* event) { + if (obj == userRow_ && event->type() == QEvent::MouseButtonRelease) { + if (userMenu_) + userMenu_->exec(userRow_->mapToGlobal(QPoint(0, userRow_->height() + 2))); + return true; + } + return QWidget::eventFilter(obj, event); } void TopBar::setWorkspaces(const std::vector& list, const QString& currentId) { diff --git a/src/app/TopBar.hpp b/src/app/TopBar.hpp index f90445e..87315d0 100644 --- a/src/app/TopBar.hpp +++ b/src/app/TopBar.hpp @@ -4,6 +4,8 @@ #include "repo/RepoTypes.hpp" class QToolButton; +class QEvent; +class QMenu; namespace geopro::app { @@ -21,6 +23,9 @@ public: bool hasMore); void setProjectButtonText(const QString& name); // 弹窗切换项目后更新按钮文字 +protected: + bool eventFilter(QObject* obj, QEvent* event) override; // 用户区整块可点 → 弹菜单 + signals: void workspaceSwitchRequested(const QString& tenantId); void projectSwitchRequested(const QString& projectId); @@ -31,6 +36,8 @@ signals: private: QToolButton* wsBtn_ = nullptr; QToolButton* projBtn_ = nullptr; + QWidget* userRow_ = nullptr; // 用户区整块(头像+姓名/职务+箭头) + QMenu* userMenu_ = nullptr; // 用户下拉菜单 }; } // namespace geopro::app