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