1 // Copyright 2017 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <utility> 8 #include <QPixmap> 9 #include <QStandardItem> 10 #include <QStandardItemModel> 11 #include "common/common_types.h" 12 13 namespace Column { 14 enum List { 15 EXPAND, 16 ROOM_NAME, 17 GAME_NAME, 18 HOST, 19 MEMBER, 20 TOTAL, 21 }; 22 } 23 24 class LobbyItem : public QStandardItem { 25 public: 26 LobbyItem() = default; LobbyItem(const QString & string)27 explicit LobbyItem(const QString& string) : QStandardItem(string) {} 28 virtual ~LobbyItem() override = default; 29 }; 30 31 class LobbyItemName : public LobbyItem { 32 public: 33 static const int NameRole = Qt::UserRole + 1; 34 static const int PasswordRole = Qt::UserRole + 2; 35 36 LobbyItemName() = default; LobbyItemName(bool has_password,QString name)37 explicit LobbyItemName(bool has_password, QString name) : LobbyItem() { 38 setData(name, NameRole); 39 setData(has_password, PasswordRole); 40 } 41 data(int role)42 QVariant data(int role) const override { 43 if (role == Qt::DecorationRole) { 44 bool has_password = data(PasswordRole).toBool(); 45 return has_password ? QIcon::fromTheme(QStringLiteral("lock")).pixmap(16) : QIcon(); 46 } 47 if (role != Qt::DisplayRole) { 48 return LobbyItem::data(role); 49 } 50 return data(NameRole).toString(); 51 } 52 53 bool operator<(const QStandardItem& other) const override { 54 return data(NameRole).toString().localeAwareCompare(other.data(NameRole).toString()) < 0; 55 } 56 }; 57 58 class LobbyItemDescription : public LobbyItem { 59 public: 60 static const int DescriptionRole = Qt::UserRole + 1; 61 62 LobbyItemDescription() = default; LobbyItemDescription(QString description)63 explicit LobbyItemDescription(QString description) { 64 setData(description, DescriptionRole); 65 } 66 data(int role)67 QVariant data(int role) const override { 68 if (role != Qt::DisplayRole) { 69 return LobbyItem::data(role); 70 } 71 auto description = data(DescriptionRole).toString(); 72 description.prepend(QStringLiteral("Description: ")); 73 return description; 74 } 75 76 bool operator<(const QStandardItem& other) const override { 77 return data(DescriptionRole) 78 .toString() 79 .localeAwareCompare(other.data(DescriptionRole).toString()) < 0; 80 } 81 }; 82 83 class LobbyItemGame : public LobbyItem { 84 public: 85 static const int TitleIDRole = Qt::UserRole + 1; 86 static const int GameNameRole = Qt::UserRole + 2; 87 static const int GameIconRole = Qt::UserRole + 3; 88 89 LobbyItemGame() = default; LobbyItemGame(u64 title_id,QString game_name,QPixmap smdh_icon)90 explicit LobbyItemGame(u64 title_id, QString game_name, QPixmap smdh_icon) { 91 setData(static_cast<unsigned long long>(title_id), TitleIDRole); 92 setData(game_name, GameNameRole); 93 if (!smdh_icon.isNull()) { 94 setData(smdh_icon, GameIconRole); 95 } 96 } 97 data(int role)98 QVariant data(int role) const override { 99 if (role == Qt::DecorationRole) { 100 auto val = data(GameIconRole); 101 if (val.isValid()) { 102 val = val.value<QPixmap>().scaled(16, 16, Qt::KeepAspectRatio); 103 } 104 return val; 105 } else if (role != Qt::DisplayRole) { 106 return LobbyItem::data(role); 107 } 108 return data(GameNameRole).toString(); 109 } 110 111 bool operator<(const QStandardItem& other) const override { 112 return data(GameNameRole) 113 .toString() 114 .localeAwareCompare(other.data(GameNameRole).toString()) < 0; 115 } 116 }; 117 118 class LobbyItemHost : public LobbyItem { 119 public: 120 static const int HostUsernameRole = Qt::UserRole + 1; 121 static const int HostIPRole = Qt::UserRole + 2; 122 static const int HostPortRole = Qt::UserRole + 3; 123 static const int HostVerifyUIDRole = Qt::UserRole + 4; 124 125 LobbyItemHost() = default; LobbyItemHost(QString username,QString ip,u16 port,QString verify_UID)126 explicit LobbyItemHost(QString username, QString ip, u16 port, QString verify_UID) { 127 setData(username, HostUsernameRole); 128 setData(ip, HostIPRole); 129 setData(port, HostPortRole); 130 setData(verify_UID, HostVerifyUIDRole); 131 } 132 data(int role)133 QVariant data(int role) const override { 134 if (role != Qt::DisplayRole) { 135 return LobbyItem::data(role); 136 } 137 return data(HostUsernameRole).toString(); 138 } 139 140 bool operator<(const QStandardItem& other) const override { 141 return data(HostUsernameRole) 142 .toString() 143 .localeAwareCompare(other.data(HostUsernameRole).toString()) < 0; 144 } 145 }; 146 147 class LobbyMember { 148 public: 149 LobbyMember() = default; 150 LobbyMember(const LobbyMember& other) = default; LobbyMember(QString username,QString nickname,u64 title_id,QString game_name)151 explicit LobbyMember(QString username, QString nickname, u64 title_id, QString game_name) 152 : username(std::move(username)), nickname(std::move(nickname)), title_id(title_id), 153 game_name(std::move(game_name)) {} 154 ~LobbyMember() = default; 155 GetName()156 QString GetName() const { 157 if (username.isEmpty() || username == nickname) { 158 return nickname; 159 } else { 160 return QStringLiteral("%1 (%2)").arg(nickname, username); 161 } 162 } GetTitleId()163 u64 GetTitleId() const { 164 return title_id; 165 } GetGameName()166 QString GetGameName() const { 167 return game_name; 168 } 169 170 private: 171 QString username; 172 QString nickname; 173 u64 title_id; 174 QString game_name; 175 }; 176 177 Q_DECLARE_METATYPE(LobbyMember); 178 179 class LobbyItemMemberList : public LobbyItem { 180 public: 181 static const int MemberListRole = Qt::UserRole + 1; 182 static const int MaxPlayerRole = Qt::UserRole + 2; 183 184 LobbyItemMemberList() = default; LobbyItemMemberList(QList<QVariant> members,u32 max_players)185 explicit LobbyItemMemberList(QList<QVariant> members, u32 max_players) { 186 setData(members, MemberListRole); 187 setData(max_players, MaxPlayerRole); 188 } 189 data(int role)190 QVariant data(int role) const override { 191 if (role != Qt::DisplayRole) { 192 return LobbyItem::data(role); 193 } 194 auto members = data(MemberListRole).toList(); 195 return QStringLiteral("%1 / %2").arg(QString::number(members.size()), 196 data(MaxPlayerRole).toString()); 197 } 198 199 bool operator<(const QStandardItem& other) const override { 200 // sort by rooms that have the most players 201 int left_members = data(MemberListRole).toList().size(); 202 int right_members = other.data(MemberListRole).toList().size(); 203 return left_members < right_members; 204 } 205 }; 206 207 /** 208 * Member information for when a lobby is expanded in the UI 209 */ 210 class LobbyItemExpandedMemberList : public LobbyItem { 211 public: 212 static const int MemberListRole = Qt::UserRole + 1; 213 214 LobbyItemExpandedMemberList() = default; LobbyItemExpandedMemberList(QList<QVariant> members)215 explicit LobbyItemExpandedMemberList(QList<QVariant> members) { 216 setData(members, MemberListRole); 217 } 218 data(int role)219 QVariant data(int role) const override { 220 if (role != Qt::DisplayRole) { 221 return LobbyItem::data(role); 222 } 223 auto members = data(MemberListRole).toList(); 224 QString out; 225 bool first = true; 226 for (const auto& member : members) { 227 if (!first) 228 out.append(QStringLiteral("\n")); 229 const auto& m = member.value<LobbyMember>(); 230 if (m.GetGameName().isEmpty()) { 231 out += QString(QObject::tr("%1 is not playing a game")).arg(m.GetName()); 232 } else { 233 out += QString(QObject::tr("%1 is playing %2")).arg(m.GetName(), m.GetGameName()); 234 } 235 first = false; 236 } 237 return out; 238 } 239 }; 240