mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-06-25 16:13:54 -07:00
More granular signals, popup for user info.
Took 25 minutes Took 8 seconds Took 16 minutes
This commit is contained in:
parent
8007d40a90
commit
bf04a5b86a
6 changed files with 246 additions and 67 deletions
|
|
@ -329,6 +329,9 @@ void UserInfoPopup::buildUi()
|
||||||
m_gamesView->setMaximumHeight(220);
|
m_gamesView->setMaximumHeight(220);
|
||||||
m_gamesView->setStyleSheet(QStringLiteral("QListView{background:#0e1218;border:none;}"
|
m_gamesView->setStyleSheet(QStringLiteral("QListView{background:#0e1218;border:none;}"
|
||||||
"QListView::item:selected{background:#232e42;}"));
|
"QListView::item:selected{background:#232e42;}"));
|
||||||
|
m_gamesView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
connect(m_gamesView, &QListView::customContextMenuRequested, this, &UserInfoPopup::onGamesContextMenu);
|
||||||
|
|
||||||
root->addWidget(m_gamesView);
|
root->addWidget(m_gamesView);
|
||||||
|
|
||||||
// Close button — positioned absolutely in the top-right corner
|
// Close button — positioned absolutely in the top-right corner
|
||||||
|
|
@ -477,6 +480,51 @@ void UserInfoPopup::rebuildActionButtons(const ServerInfo_User &userInfo, bool o
|
||||||
m_actionArea->adjustSize();
|
m_actionArea->adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserInfoPopup::updateActionButtons(const ServerInfo_User &userInfo, bool online, bool isBuddy, bool isIgnored)
|
||||||
|
{
|
||||||
|
rebuildActionButtons(userInfo, online, isBuddy, isIgnored);
|
||||||
|
adjustSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserInfoPopup::onGamesContextMenu(const QPoint &pos)
|
||||||
|
{
|
||||||
|
const QModelIndex idx = m_gamesView->indexAt(pos);
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVariant var = idx.data(PopupRoles::GameData);
|
||||||
|
if (!var.isValid()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ServerInfo_Game game = var.value<ServerInfo_Game>();
|
||||||
|
|
||||||
|
QMenu menu(this);
|
||||||
|
menu.setStyleSheet(
|
||||||
|
QStringLiteral("QMenu{background:#12182a;color:#c8d8ec;border:1px solid #1e2838;border-radius:4px;}"
|
||||||
|
"QMenu::item:selected{background:#223050;}"));
|
||||||
|
|
||||||
|
const bool canJoin = !game.started() && game.player_count() < game.max_players();
|
||||||
|
QAction *join = menu.addAction(tr("Join game"));
|
||||||
|
join->setEnabled(canJoin);
|
||||||
|
|
||||||
|
QAction *spec = nullptr;
|
||||||
|
if (game.spectators_allowed()) {
|
||||||
|
spec = menu.addAction(tr("Spectate"));
|
||||||
|
}
|
||||||
|
|
||||||
|
const QAction *chosen = menu.exec(m_gamesView->viewport()->mapToGlobal(pos));
|
||||||
|
if (!chosen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chosen == join) {
|
||||||
|
emit joinGameRequested(game.game_id(), game.room_id(), false);
|
||||||
|
} else if (spec && chosen == spec) {
|
||||||
|
emit joinGameRequested(game.game_id(), game.room_id(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ── showForUser ───────────────────────────────────────────────────────────────
|
// ── showForUser ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
void UserInfoPopup::showForUser(const QString &userName,
|
void UserInfoPopup::showForUser(const QString &userName,
|
||||||
|
|
@ -565,6 +613,15 @@ void UserInfoPopup::onGamesReceived(const Response &r, const QString &forUser)
|
||||||
|
|
||||||
m_gamesStatus->hide();
|
m_gamesStatus->hide();
|
||||||
m_gamesView->show();
|
m_gamesView->show();
|
||||||
|
|
||||||
|
// Fit exactly to the number of visible rows, scroll when more than 5
|
||||||
|
constexpr int rowH = 38; // must match PopupGameDelegate::sizeHint
|
||||||
|
constexpr int maxRows = 5;
|
||||||
|
const int count = m_gamesModel->rowCount();
|
||||||
|
const int visible = qMin(count, maxRows);
|
||||||
|
m_gamesView->setFixedHeight(visible * rowH + 2);
|
||||||
|
m_gamesView->setVerticalScrollBarPolicy(count > maxRows ? Qt::ScrollBarAlwaysOn : Qt::ScrollBarAlwaysOff);
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,11 +113,17 @@ public:
|
||||||
return m_currentUser;
|
return m_currentUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called when buddy/ignore status changes externally while popup is open. */
|
||||||
|
void updateActionButtons(const ServerInfo_User &userInfo, bool online, bool isBuddy, bool isIgnored);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void mouseEnteredPopup();
|
void mouseEnteredPopup();
|
||||||
void mouseLeftPopup();
|
void mouseLeftPopup();
|
||||||
void closeRequested();
|
void closeRequested();
|
||||||
|
|
||||||
|
/** Emitted when the user requests joining or spectating a game in the list. */
|
||||||
|
void joinGameRequested(int gameId, int roomId, bool asSpectator);
|
||||||
|
|
||||||
// ── Action signals — connect to UserContextMenu::exec*() ──────────────────
|
// ── Action signals — connect to UserContextMenu::exec*() ──────────────────
|
||||||
void chatRequested(const QString &userName);
|
void chatRequested(const QString &userName);
|
||||||
void detailsRequested(const QString &userName);
|
void detailsRequested(const QString &userName);
|
||||||
|
|
@ -147,6 +153,7 @@ protected:
|
||||||
private slots:
|
private slots:
|
||||||
void refreshGames();
|
void refreshGames();
|
||||||
void onGamesReceived(const Response &r, const QString &forUser);
|
void onGamesReceived(const Response &r, const QString &forUser);
|
||||||
|
void onGamesContextMenu(const QPoint &pos);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void buildUi();
|
void buildUi();
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,9 @@ void UserListManager::handleDisconnect()
|
||||||
|
|
||||||
delete ownUserInfo;
|
delete ownUserInfo;
|
||||||
ownUserInfo = nullptr;
|
ownUserInfo = nullptr;
|
||||||
emit listsChanged();
|
|
||||||
|
// Full rebuild — all lists are gone
|
||||||
|
emit listReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::setOwnUserInfo(const ServerInfo_User &userInfo)
|
void UserListManager::setOwnUserInfo(const ServerInfo_User &userInfo)
|
||||||
|
|
@ -64,81 +66,77 @@ void UserListManager::processListUsersResponse(const Response &response)
|
||||||
const int userListSize = resp.user_list_size();
|
const int userListSize = resp.user_list_size();
|
||||||
for (int i = 0; i < userListSize; ++i) {
|
for (int i = 0; i < userListSize; ++i) {
|
||||||
const ServerInfo_User &info = resp.user_list(i);
|
const ServerInfo_User &info = resp.user_list(i);
|
||||||
const QString &userName = QString::fromStdString(info.name());
|
onlineUsers.insert(QString::fromStdString(info.name()), info);
|
||||||
onlineUsers.insert(userName, info);
|
|
||||||
}
|
}
|
||||||
emit listsChanged();
|
|
||||||
|
// Bulk load complete — widgets rebuild once from the now-populated map
|
||||||
|
emit listReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::processUserJoinedEvent(const Event_UserJoined &event)
|
void UserListManager::processUserJoinedEvent(const Event_UserJoined &event)
|
||||||
{
|
{
|
||||||
const auto &info = event.user_info();
|
const auto &info = event.user_info();
|
||||||
const QString &userName = QString::fromStdString(info.name());
|
const QString name = QString::fromStdString(info.name());
|
||||||
onlineUsers.insert(userName, info);
|
onlineUsers.insert(name, info);
|
||||||
emit listsChanged();
|
|
||||||
|
emit userJoinedOnline(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::processUserLeftEvent(const Event_UserLeft &event)
|
void UserListManager::processUserLeftEvent(const Event_UserLeft &event)
|
||||||
{
|
{
|
||||||
const auto &userName = QString::fromStdString(event.name());
|
const QString name = QString::fromStdString(event.name());
|
||||||
onlineUsers.remove(userName);
|
onlineUsers.remove(name);
|
||||||
emit listsChanged();
|
|
||||||
|
emit userLeftOnline(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::buddyListReceived(const QList<ServerInfo_User> &_buddyList)
|
void UserListManager::buddyListReceived(const QList<ServerInfo_User> &_buddyList)
|
||||||
{
|
{
|
||||||
for (const auto &user : _buddyList) {
|
for (const auto &user : _buddyList) {
|
||||||
const auto &userName = QString::fromStdString(user.name());
|
buddyUsers.insert(QString::fromStdString(user.name()), user);
|
||||||
buddyUsers.insert(userName, user);
|
|
||||||
emit listsChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bulk load — one reset covers all newly added entries
|
||||||
|
emit listReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::ignoreListReceived(const QList<ServerInfo_User> &_ignoreList)
|
void UserListManager::ignoreListReceived(const QList<ServerInfo_User> &_ignoreList)
|
||||||
{
|
{
|
||||||
for (const auto &user : _ignoreList) {
|
for (const auto &user : _ignoreList) {
|
||||||
const auto &userName = QString::fromStdString(user.name());
|
ignoredUsers.insert(QString::fromStdString(user.name()), user);
|
||||||
ignoredUsers.insert(userName, user);
|
|
||||||
emit listsChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bulk load — one reset covers all newly added entries
|
||||||
|
emit listReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::processAddToListEvent(const Event_AddToList &event)
|
void UserListManager::processAddToListEvent(const Event_AddToList &event)
|
||||||
{
|
{
|
||||||
const auto &user = event.user_info();
|
const auto &user = event.user_info();
|
||||||
const auto &userName = QString::fromStdString(user.name());
|
const QString userName = QString::fromStdString(user.name());
|
||||||
|
const QString listType = QString::fromStdString(event.list_name());
|
||||||
|
|
||||||
const auto &userListType = QString::fromStdString(event.list_name());
|
if (listType == "buddy") {
|
||||||
|
buddyUsers.insert(userName, user);
|
||||||
QMap<QString, ServerInfo_User> *userMap;
|
emit addedToBuddyList(user);
|
||||||
if (userListType == "buddy") {
|
} else if (listType == "ignore") {
|
||||||
userMap = &buddyUsers;
|
ignoredUsers.insert(userName, user);
|
||||||
} else if (userListType == "ignore") {
|
emit addedToIgnoreList(user);
|
||||||
userMap = &ignoredUsers;
|
|
||||||
} else {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap->insert(userName, user);
|
|
||||||
emit listsChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserListManager::processRemoveFromListEvent(const Event_RemoveFromList &event)
|
void UserListManager::processRemoveFromListEvent(const Event_RemoveFromList &event)
|
||||||
{
|
{
|
||||||
const auto &userListType = QString::fromStdString(event.list_name());
|
const QString listType = QString::fromStdString(event.list_name());
|
||||||
const auto &userName = QString::fromStdString(event.user_name());
|
const QString userName = QString::fromStdString(event.user_name());
|
||||||
|
|
||||||
QMap<QString, ServerInfo_User> *userMap;
|
if (listType == "buddy") {
|
||||||
if (userListType == "buddy") {
|
buddyUsers.remove(userName);
|
||||||
userMap = &buddyUsers;
|
emit removedFromBuddyList(userName);
|
||||||
} else if (userListType == "ignore") {
|
} else if (listType == "ignore") {
|
||||||
userMap = &ignoredUsers;
|
ignoredUsers.remove(userName);
|
||||||
} else {
|
emit removedFromIgnoreList(userName);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
userMap->remove(userName);
|
|
||||||
emit listsChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UserListManager::isOwnUserRegistered() const
|
bool UserListManager::isOwnUserRegistered() const
|
||||||
|
|
@ -163,16 +161,9 @@ bool UserListManager::isUserIgnored(const QString &userName) const
|
||||||
|
|
||||||
const ServerInfo_User *UserListManager::getOnlineUser(const QString &userName) const
|
const ServerInfo_User *UserListManager::getOnlineUser(const QString &userName) const
|
||||||
{
|
{
|
||||||
const QString &userNameToMatchLower = userName.toLower();
|
const QString lower = userName.toLower();
|
||||||
|
const auto it = std::find_if(onlineUsers.begin(), onlineUsers.end(), [&lower](const ServerInfo_User &user) {
|
||||||
const auto it =
|
return lower == QString::fromStdString(user.name()).toLower();
|
||||||
std::find_if(onlineUsers.begin(), onlineUsers.end(), [&userNameToMatchLower](const ServerInfo_User &user) {
|
});
|
||||||
return userNameToMatchLower == QString::fromStdString(user.name()).toLower();
|
return it != onlineUsers.end() ? &*it : nullptr;
|
||||||
});
|
|
||||||
|
|
||||||
if (it != onlineUsers.end()) {
|
|
||||||
return &*it;
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
@ -73,9 +73,26 @@ public slots:
|
||||||
void handleDisconnect();
|
void handleDisconnect();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void userLeft(const QString &userName);
|
/**
|
||||||
void userJoined(const ServerInfo_User &userInfo);
|
* The entire list needs to be rebuilt from scratch.
|
||||||
void listsChanged();
|
* Fired on disconnect, reconnect, and initial bulk loads
|
||||||
|
* (Command_ListUsers response, initial buddy/ignore lists).
|
||||||
|
*/
|
||||||
|
void listReset();
|
||||||
|
|
||||||
|
// ── Online user presence ──────────────────────────────────────────────────
|
||||||
|
/** A user came online (or joined the room). Full ServerInfo_User available. */
|
||||||
|
void userJoinedOnline(const ServerInfo_User &user);
|
||||||
|
/** A user went offline (or left the room). */
|
||||||
|
void userLeftOnline(const QString &userName);
|
||||||
|
|
||||||
|
// ── Buddy list mutations (individual, post-login) ─────────────────────────
|
||||||
|
void addedToBuddyList(const ServerInfo_User &user);
|
||||||
|
void removedFromBuddyList(const QString &userName);
|
||||||
|
|
||||||
|
// ── Ignore list mutations (individual, post-login) ────────────────────────
|
||||||
|
void addedToIgnoreList(const ServerInfo_User &user);
|
||||||
|
void removedFromIgnoreList(const QString &userName);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COCKATRICE_USER_LIST_MANAGER_H
|
#endif // COCKATRICE_USER_LIST_MANAGER_H
|
||||||
|
|
|
||||||
|
|
@ -533,15 +533,24 @@ UserListWidget::UserListWidget(TabSupervisor *_tabSupervisor,
|
||||||
m_popupPinned = true; // pin after showing
|
m_popupPinned = true; // pin after showing
|
||||||
});
|
});
|
||||||
|
|
||||||
// Unpin when selection cleared
|
|
||||||
connect(userTree->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
connect(userTree->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||||
[this](const QItemSelection &sel, const QItemSelection &) {
|
[this](const QItemSelection &sel, const QItemSelection &) {
|
||||||
|
// if (m_rebuildingTree) return;
|
||||||
if (sel.isEmpty() && m_popupPinned) {
|
if (sel.isEmpty() && m_popupPinned) {
|
||||||
m_popupPinned = false;
|
m_popupPinned = false;
|
||||||
hidePopup();
|
hidePopup();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hide popup when list scrolls (reference row has moved)
|
||||||
|
connect(userTree->verticalScrollBar(), &QScrollBar::valueChanged, this, [this] {
|
||||||
|
m_showPopupTimer->stop();
|
||||||
|
hidePopup(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Forward join requests from popup upward
|
||||||
|
connect(m_userInfoPopup, &UserInfoPopup::joinGameRequested, this, &UserListWidget::joinGameRequested);
|
||||||
|
|
||||||
connect(avatarProvider, &UserAvatarProvider::avatarUpdated, this,
|
connect(avatarProvider, &UserAvatarProvider::avatarUpdated, this,
|
||||||
[this](const QString &) { userTree->viewport()->update(); });
|
[this](const QString &) { userTree->viewport()->update(); });
|
||||||
connect(cardArtProvider, &UserCardArtProvider::cardArtUpdated, this,
|
connect(cardArtProvider, &UserCardArtProvider::cardArtUpdated, this,
|
||||||
|
|
@ -562,11 +571,94 @@ void UserListWidget::bind(UserListManager *mgr)
|
||||||
{
|
{
|
||||||
manager = mgr;
|
manager = mgr;
|
||||||
|
|
||||||
connect(manager, &UserListManager::listsChanged, this, &UserListWidget::rebuild);
|
// ── Full rebuild: disconnect / reconnect / bulk initial load ──────────────
|
||||||
|
connect(manager, &UserListManager::listReset, this, &UserListWidget::rebuild);
|
||||||
|
|
||||||
|
// ── Online users list (AllUsersList / RoomList) ───────────────────────────
|
||||||
|
if (type == AllUsersList || type == RoomList) {
|
||||||
|
connect(manager, &UserListManager::userJoinedOnline, this,
|
||||||
|
[this](const ServerInfo_User &user) { processUserInfo(user, true); });
|
||||||
|
connect(manager, &UserListManager::userLeftOnline, this, [this](const QString &name) { deleteUser(name); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Buddy list ────────────────────────────────────────────────────────────
|
||||||
|
if (type == BuddyList) {
|
||||||
|
connect(manager, &UserListManager::addedToBuddyList, this, [this](const ServerInfo_User &user) {
|
||||||
|
const QString name = QString::fromStdString(user.name());
|
||||||
|
processUserInfo(user, manager->getOnlineUser(name) != nullptr);
|
||||||
|
});
|
||||||
|
connect(manager, &UserListManager::removedFromBuddyList, this,
|
||||||
|
[this](const QString &name) { deleteUser(name); });
|
||||||
|
// Track online presence changes for buddies already in the tree
|
||||||
|
connect(manager, &UserListManager::userJoinedOnline, this, [this](const ServerInfo_User &user) {
|
||||||
|
const QString name = QString::fromStdString(user.name());
|
||||||
|
if (users.contains(name)) {
|
||||||
|
users[name]->setUserInfo(user);
|
||||||
|
setUserOnline(name, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
connect(manager, &UserListManager::userLeftOnline, this, [this](const QString &name) {
|
||||||
|
if (users.contains(name)) {
|
||||||
|
setUserOnline(name, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Ignore list ───────────────────────────────────────────────────────────
|
||||||
|
if (type == IgnoreList) {
|
||||||
|
connect(manager, &UserListManager::addedToIgnoreList, this, [this](const ServerInfo_User &user) {
|
||||||
|
const QString name = QString::fromStdString(user.name());
|
||||||
|
processUserInfo(user, manager->getOnlineUser(name) != nullptr);
|
||||||
|
});
|
||||||
|
connect(manager, &UserListManager::removedFromIgnoreList, this,
|
||||||
|
[this](const QString &name) { deleteUser(name); });
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── Popup button refresh ──────────────────────────────────────────────────
|
||||||
|
// Any buddy/ignore mutation while the popup is open refreshes its buttons
|
||||||
|
auto refreshIfPopupOpen = [this](const QString &name) {
|
||||||
|
if (m_userInfoPopup && m_userInfoPopup->isVisible() && m_userInfoPopup->currentUser() == name) {
|
||||||
|
refreshPopupButtons(name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
auto refreshCurrentPopup = [refreshIfPopupOpen](const ServerInfo_User &u) {
|
||||||
|
refreshIfPopupOpen(QString::fromStdString(u.name()));
|
||||||
|
};
|
||||||
|
|
||||||
|
connect(manager, &UserListManager::addedToBuddyList, this, refreshCurrentPopup);
|
||||||
|
connect(manager, &UserListManager::removedFromBuddyList, this, refreshIfPopupOpen);
|
||||||
|
connect(manager, &UserListManager::addedToIgnoreList, this, refreshCurrentPopup);
|
||||||
|
connect(manager, &UserListManager::removedFromIgnoreList, this, refreshIfPopupOpen);
|
||||||
|
connect(manager, &UserListManager::userJoinedOnline, this, refreshCurrentPopup);
|
||||||
|
connect(manager, &UserListManager::userLeftOnline, this, refreshIfPopupOpen);
|
||||||
|
|
||||||
rebuild();
|
rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UserListWidget::refreshPopupButtons(const QString &userName)
|
||||||
|
{
|
||||||
|
UserListTWI *item = users.value(userName);
|
||||||
|
if (!item) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const UserListProxy *proxy = tabSupervisor->getUserListManager();
|
||||||
|
const bool online = item->data(0, UserListRoles::Online).toBool();
|
||||||
|
const bool isBuddy = proxy->isUserBuddy(userName);
|
||||||
|
const bool isIgn = proxy->isUserIgnored(userName);
|
||||||
|
|
||||||
|
m_userInfoPopup->updateActionButtons(item->getUserInfo(), online, isBuddy, isIgn);
|
||||||
|
positionPopup(userName); // height may have changed — reposition
|
||||||
|
}
|
||||||
|
|
||||||
|
void UserListWidget::hideEvent(QHideEvent *e)
|
||||||
|
{
|
||||||
|
QGroupBox::hideEvent(e);
|
||||||
|
m_showPopupTimer->stop();
|
||||||
|
m_hidePopupTimer->stop();
|
||||||
|
hidePopup(true);
|
||||||
|
}
|
||||||
|
|
||||||
void UserListWidget::applyDisplayMode()
|
void UserListWidget::applyDisplayMode()
|
||||||
{
|
{
|
||||||
const bool styled = SettingsCache::instance().getStyleUserList();
|
const bool styled = SettingsCache::instance().getStyleUserList();
|
||||||
|
|
@ -698,23 +790,32 @@ void UserListWidget::positionPopup(const QString &userName)
|
||||||
|
|
||||||
QWidget *vp = userTree->viewport();
|
QWidget *vp = userTree->viewport();
|
||||||
const QRect itemR = userTree->visualItemRect(item);
|
const QRect itemR = userTree->visualItemRect(item);
|
||||||
const QPoint itemTL = vp->mapToGlobal(itemR.topLeft());
|
const QPoint itemBR = vp->mapToGlobal(itemR.bottomRight());
|
||||||
const QPoint vpTL = vp->mapToGlobal(vp->rect().topLeft());
|
const QPoint vpTL = vp->mapToGlobal(vp->rect().topLeft());
|
||||||
|
const QPoint vpTR = vp->mapToGlobal(vp->rect().topRight());
|
||||||
|
|
||||||
|
// Force a fresh size calculation so popH is accurate
|
||||||
|
m_userInfoPopup->adjustSize();
|
||||||
const int popW = m_userInfoPopup->width();
|
const int popW = m_userInfoPopup->width();
|
||||||
const int popH = m_userInfoPopup->sizeHint().height();
|
const int popH = m_userInfoPopup->height();
|
||||||
const int margin = 12;
|
const int margin = 12;
|
||||||
|
|
||||||
// Go left of the list if there's room, otherwise right
|
|
||||||
int x =
|
|
||||||
(vpTL.x() >= popW + margin) ? vpTL.x() - popW - margin : vp->mapToGlobal(vp->rect().topRight()).x() + margin;
|
|
||||||
|
|
||||||
// Align top with the hovered row, clamped to available screen space
|
|
||||||
const QRect screen = QGuiApplication::primaryScreen()->availableGeometry();
|
const QRect screen = QGuiApplication::primaryScreen()->availableGeometry();
|
||||||
int y = itemTL.y();
|
|
||||||
y = qMin(y, screen.bottom() - popH - margin);
|
// ── X: left of the list if there's room, otherwise right ─────────────────
|
||||||
|
int x = (vpTL.x() >= popW + margin) ? vpTL.x() - popW - margin : vpTR.x() + margin;
|
||||||
|
x = qBound(screen.left() + margin, x, screen.right() - popW - margin);
|
||||||
|
|
||||||
|
// ── Y: bottom of popup aligns with bottom of hovered row, grows upward ───
|
||||||
|
int y = itemBR.y() - popH;
|
||||||
|
|
||||||
|
// Clamp: never above the screen top
|
||||||
y = qMax(y, screen.top() + margin);
|
y = qMax(y, screen.top() + margin);
|
||||||
|
|
||||||
|
// Clamp: never below the screen bottom (e.g. if the popup is taller
|
||||||
|
// than the space above the row, let it spill downward rather than clip)
|
||||||
|
y = qMin(y, screen.bottom() - popH - margin);
|
||||||
|
|
||||||
m_userInfoPopup->move(x, y);
|
m_userInfoPopup->move(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -827,6 +928,7 @@ void UserListWidget::processUserInfo(const ServerInfo_User &user, bool online)
|
||||||
avatarProvider->requestAvatar(userName);
|
avatarProvider->requestAvatar(userName);
|
||||||
}
|
}
|
||||||
item->setOnline(online);
|
item->setOnline(online);
|
||||||
|
sortItems();
|
||||||
userTree->viewport()->update();
|
userTree->viewport()->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,7 @@ private:
|
||||||
int onlineCount;
|
int onlineCount;
|
||||||
QString titleStr;
|
QString titleStr;
|
||||||
void updateCount();
|
void updateCount();
|
||||||
|
void refreshPopupButtons(const QString &userName);
|
||||||
private slots:
|
private slots:
|
||||||
void userClicked(QTreeWidgetItem *item, int column);
|
void userClicked(QTreeWidgetItem *item, int column);
|
||||||
signals:
|
signals:
|
||||||
|
|
@ -182,6 +183,7 @@ signals:
|
||||||
void removeBuddy(const QString &userName);
|
void removeBuddy(const QString &userName);
|
||||||
void addIgnore(const QString &userName);
|
void addIgnore(const QString &userName);
|
||||||
void removeIgnore(const QString &userName);
|
void removeIgnore(const QString &userName);
|
||||||
|
void joinGameRequested(int gameId, int roomId, bool asSpectator);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UserListWidget(TabSupervisor *_tabSupervisor,
|
UserListWidget(TabSupervisor *_tabSupervisor,
|
||||||
|
|
@ -202,6 +204,9 @@ public:
|
||||||
}
|
}
|
||||||
void showContextMenu(const QPoint &pos, const QModelIndex &index);
|
void showContextMenu(const QPoint &pos, const QModelIndex &index);
|
||||||
void sortItems();
|
void sortItems();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void hideEvent(QHideEvent *e) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue