Cockatrice/cockatrice/src/interface/widgets/server/user/user_info_popup.h
BruebachL 74a454552a
Some checks are pending
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker Image / amd64 & arm64 (push) Waiting to run
[Cards] Artist attribution (#7092)
* [Cards] Artist attribution

Took 7 minutes

Took 4 minutes

* Nudge attribution pill on home screen to align

Took 3 minutes


Took 28 seconds

Took 38 seconds

* Lint.

Took 3 minutes

* Lint.

Took 2 minutes

* Fix rebase whoopsie

Took 5 minutes

---------

Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
2026-08-21 02:54:36 +02:00

215 lines
No EOL
7.1 KiB
C++

#ifndef COCKATRICE_USER_INFO_POPUP_H
#define COCKATRICE_USER_INFO_POPUP_H
#include "../../interface/widgets/server/game_type_map.h"
#include "user_list_painter.h"
#include <QFrame>
#include <QListView>
#include <QMap>
#include <QPixmap>
#include <QStandardItemModel>
#include <libcockatrice/network/server/remote/user_level.h>
#include <libcockatrice/protocol/pb/response.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_game.pb.h>
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
class AbstractClient;
class QLabel;
class QPushButton;
class TabSupervisor;
// ── Roles ─────────────────────────────────────────────────────────────────────
namespace PopupRoles
{
constexpr int GameData = Qt::UserRole + 10;
}
// Popup theme
/**
* Palette-derived colors for the popup chrome. Both color schemes read from
* the active QPalette so custom palettes are respected. @c dark only tunes the
* blend strengths.
*/
struct PopupTheme
{
bool dark = false;
QColor bg;
QColor border;
QColor text;
QColor subText;
QColor buttonBg;
QColor buttonBorder;
QColor buttonHover;
QColor buttonPressed;
QColor buttonDisabled;
QColor closeBg;
QColor closeHover;
QColor gamesRow;
QColor gamesSelected;
QColor gamesSeparator;
QColor statusText;
static PopupTheme fromPalette(const QPalette &palette, bool dark);
};
// ── Header widget ─────────────────────────────────────────────────────────────
/**
* @class UserInfoHeaderWidget
* @brief Paints the enlarged banner card art + circular avatar section at the
* top of the UserInfoPopup.
*
* Layout mirrors UserListPainter but at a larger scale: the card art fills the
* full width as a semi-transparent background, a bottom gradient ensures the
* avatar and username text remain legible, and the status ring colour matches
* the UserListPainter convention.
*/
class UserInfoHeaderWidget : public QWidget
{
Q_OBJECT
static constexpr int HeaderHeight = 130;
static constexpr int AvatarSize = 68;
static constexpr int AvatarPawnSize = 46;
static constexpr int LeftPad = 14;
static constexpr int AvatarToTextGap = 10;
public:
explicit UserInfoHeaderWidget(QWidget *parent = nullptr);
void setUserData(const ServerInfo_User &_user,
bool _online,
const QPixmap &_avatar,
const QPixmap &_cardArt,
const CardArtParams &_params);
protected:
void paintEvent(QPaintEvent *e) override;
private:
ServerInfo_User user;
bool online = false;
QPixmap avatar;
QPixmap cardArt;
CardArtParams params;
QString attribution;
};
// ── Main popup ────────────────────────────────────────────────────────────────
/**
* @class UserInfoPopup
* @brief Floating panel showing an enlarged user card, quick action buttons,
* and a live scrollable games list.
*
* Lifecycle (mirrors DeckEditorDeckDockWidget):
* - showForUser() — populate, position externally, call show()
* - mouseEnteredPopup / mouseLeftPopup — caller manages hide timer
* - closeRequested() — emitted by the internal close button
*
* The popup is a Qt::Tool frameless child so windowOpacity animations and
* move() in screen coordinates work identically to CardInfoPictureEnlargedWidget.
*
* Action signals map 1-to-1 to UserContextMenu::exec*() methods so all action
* logic stays in one place.
*/
class UserInfoPopup : public QFrame
{
Q_OBJECT
static constexpr int PopupWidth = 316;
public:
explicit UserInfoPopup(TabSupervisor *_ts,
AbstractClient *_client,
const QMap<QString, QPixmap> *_avatarCache,
const QMap<QString, QPixmap> *_cardArtCache,
const QMap<QString, CardArtParams> *_cardArtParamsMap,
QWidget *parent);
/**
* Populate the popup for @p userName and kick off a game list fetch.
* Call show() / move() externally after this.
*/
void
showForUser(const QString &userName, const ServerInfo_User &userInfo, bool online, bool isBuddy, bool isIgnored);
void fetchGames();
[[nodiscard]] QString getCurrentUser() const
{
return currentUser;
}
/** Called when buddy/ignore status changes externally while popup is open. */
void updateActionButtons(const ServerInfo_User &userInfo, bool online, bool isBuddy, bool isIgnored);
/** Re-pulls the avatar/card art for the currently shown user (e.g. after it loads). */
void refreshHeader();
signals:
void mouseEnteredPopup();
void mouseLeftPopup();
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*() ──────────────────
void chatRequested(const QString &userName);
void detailsRequested(const QString &userName);
void showGamesRequested(const QString &userName);
void addBuddyRequested(const QString &userName);
void removeBuddyRequested(const QString &userName);
void addIgnoreRequested(const QString &userName);
void removeIgnoreRequested(const QString &userName);
void banRequested(const QString &userName);
void warnRequested(const QString &userName);
void banHistoryRequested(const QString &userName);
void warnHistoryRequested(const QString &userName);
void adminNotesRequested(const QString &userName);
void promoteToModRequested(const QString &userName);
void demoteFromModRequested(const QString &userName);
void promoteToJudgeRequested(const QString &userName);
void demoteFromJudgeRequested(const QString &userName);
protected:
void enterEvent(QEnterEvent *e) override;
void leaveEvent(QEvent *e) override;
private slots:
void refreshGames();
void onGamesReceived(const Response &r, const QString &forUser);
void onGamesContextMenu(const QPoint &pos);
private:
void buildUi();
void applyTheme();
void rebuildActionButtons(const ServerInfo_User &userInfo, bool online, bool isBuddy, bool isIgnored);
TabSupervisor *ts;
AbstractClient *client;
const QMap<QString, QPixmap> *avatarCache;
const QMap<QString, QPixmap> *cardArtCache;
const QMap<QString, CardArtParams> *cardArtParamsMap;
PopupTheme theme;
QString currentUser;
ServerInfo_User currentUserInfo;
bool currentOnline = false;
UserInfoHeaderWidget *header;
QWidget *actionArea; ///< rebuilt per user
QLabel *gamesLabel;
QFrame *separator;
QListView *gamesView;
QStandardItemModel *gamesModel;
QLabel *gamesStatus;
QPushButton *closeBtn;
QPushButton *refreshBtn;
};
#endif // COCKATRICE_USER_INFO_POPUP_H