1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 2008-2009, RedWolf Design GmbH, http://www.clonk.de/
5  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
6  *
7  * Distributed under the terms of the ISC license; see accompanying file
8  * "COPYING" for details.
9  *
10  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
11  * See accompanying file "TRADEMARK" for details.
12  *
13  * To redistribute this file separately, substitute the full license texts
14  * for the above references.
15  */
16 // player listbox used in lobby and game over dlg
17 
18 #ifndef INC_C4PlayerInfoListBox
19 #define INC_C4PlayerInfoListBox
20 
21 #include "gui/C4Gui.h"
22 
23 class C4PlayerInfoListBox : public C4GUI::ListBox
24 {
25 public:
26 	enum Spacings
27 	{
28 		// some spacings
29 		IconLabelSpacing     = 2, // space between an icon and its text
30 		ClientListBoxSpacing = 8, // space between two clients in the list
31 		PlayerListBoxIndent  = 3, // indent of player list box items
32 		NoneLabelSpacing     = 20, // indent of "- none -"-label in list box
33 
34 		SoundIconShowTime    = 1  // seconds. min time a sound icon is shown
35 	};
36 
37 	// list box mode
38 	enum Mode
39 	{
40 		PILBM_LobbyClientSort,
41 		PILBM_LobbyTeamSort,
42 		PILBM_Evaluation,
43 		PILBM_EvaluationNoWinners
44 	};
45 
46 private:
47 	// generic player list item
48 	class ListItem : public C4GUI::Window
49 	{
50 	protected:
51 		C4PlayerInfoListBox *pList;
52 		uint32_t dwBackground; // not drawn if 0
53 
54 	public:
55 		struct ID
56 		{
57 			enum IDType
58 			{
59 				PLI_NONE=0,
60 				PLI_SCRIPTPLR,    // script player caption (ID=0) - script players themselbed are regular PLI_PLAYER
61 				PLI_SAVEGAMEPLR,  // restore savegame player (ID>0), or caption (ID=0)
62 				PLI_PLAYER,       // player
63 				PLI_CLIENT,       // client label
64 				PLI_TEAM,         // team label
65 				PLI_REPLAY        // replay player (ID>0), or caption (ID=0)
66 			} idType{PLI_NONE};
67 
68 			int32_t id{0}; // player file ID or team ID or client ID
69 
70 			ID() = default;
IDID71 			ID(IDType eType, int32_t id) : idType(eType), id(id) {}
72 
73 			inline bool operator ==(const ID &r2)
74 			{
75 				return idType == r2.idType && id == r2.id;
76 			}
77 		};
78 
79 		ID idListItemID;
80 
81 		C4GameLobby::MainDlg *GetLobby() const;
Update()82 		virtual void Update() {} // periodic update callback
83 
84 	protected:
85 		void DrawElement(C4TargetFacet &cgo) override; // draw background
86 		bool CanLocalChooseTeams(int32_t idPlayer=0) const; // whether the local client can change any teams
87 
88 	public:
ListItem(C4PlayerInfoListBox * pList)89 		ListItem(C4PlayerInfoListBox *pList) : C4GUI::Window(), pList(pList), dwBackground(0) {}
90 	};
91 
92 	// lobby information and display of joined players
93 	class PlayerListItem : public ListItem
94 	{
95 	private:
96 		// subcomponents
97 		C4GUI::Icon *pIcon;       // player icon
98 		C4GUI::Label *pNameLabel; // label indicating player name
99 		C4GUI::Label *pScoreLabel; // label showing some player score (league)
100 		C4GUI::Label *pTimeLabel; // evaluation only: label showing total playing time
101 		C4GUI::Label *pExtraLabel; // evaluation only: label showing extra data set by script
102 		C4GUI::Icon *pRankIcon;    // league rank icon
103 		C4GUI::ComboBox *pTeamCombo; // team selection combo - nullptr for no-team-scens
104 		C4GUI::Picture *pTeamPic; // evaluation only: Team icon spec
105 
106 		bool fIconSet;            // whether custom icon has been set
107 		bool fJoinedInfoSet;      // join info for savegame recreation
108 		DWORD dwJoinClr, dwPlrClr;//colors currently reflected in icon
109 
110 	protected:
111 		int32_t idClient, idPlayer;                     // referenced IDs
112 		bool fFreeSavegamePlayer;                   // if set, the player is an (unassociated) savegame player
113 		bool fShownCollapsed;                       // true if small view is shown
114 
115 	protected:
116 		void UpdateOwnPos() override; // recalculate item positioning
117 		int32_t GetListItemTopSpacing() override;
118 
119 	public:
120 		PlayerListItem(C4PlayerInfoListBox *pForListBox, int32_t idClient, int32_t idPlayer, bool fSavegamePlayer, C4GUI::Element *pInsertBeforeElement); // ctor
121 		~PlayerListItem() override = default;;                         // dtor
122 
123 		void UpdateIcon(C4PlayerInfo *pInfo, C4PlayerInfo *pJoinedInfo); // update player icon
124 		void UpdateTeam();
125 		void UpdateScoreLabel(C4PlayerInfo *pInfo); // update league score labels and icons
126 		void UpdateCollapsed();
127 
128 	public:
129 		C4GUI::ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // open context menu
130 		C4GUI::ContextMenu *OnContextTakeOver(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // takeover savegame player submenu
131 		void OnCtxTakeOver(C4GUI::Element *pListItem, const int32_t &idPlayer);
132 		void OnCtxRemove(C4GUI::Element *pListItem);
133 		void OnCtxNewColor(C4GUI::Element *pListItem);
134 
135 		void OnTeamComboFill(C4GUI::ComboBox_FillCB *pFiller);
136 		bool OnTeamComboSelChange(C4GUI::ComboBox *pForCombo, int32_t idNewSelection);
137 
138 		void Update() override; // update icon and team
139 
GetInfoID()140 		int32_t GetInfoID() const { return idPlayer; }
141 		C4Network2Client *GetNetClient() const; // return associated network client
142 		C4PlayerInfo *GetPlayerInfo() const;
143 
144 		C4PlayerInfo *GetJoinedInfo() const; // if this player is joined or associated to a joined info, return the joined info
145 
146 		bool IsLocalClientPlayer() const; // whether this player is going to join locally
147 		bool CanLocalChooseTeam() const;  // whether the local client can change team for this player
148 
149 	};
150 
151 	// lobby information and display of connected clients
152 	class ClientListItem : public ListItem
153 	{
154 	private:
155 		// subcomponents
156 		C4GUI::Icon *pStatusIcon; // icon indicating client status (host, etc.)
157 		C4GUI::Label *pNameLabel; // label indicating client name
158 		C4GUI::Label *pPingLabel; // label indicating ping to client - may be nullptr
159 
160 	protected:
161 		int32_t idClient;                     // associated network interface ID
162 		DWORD dwClientClr;                    // client color used for chatting
163 
164 		bool fIsShownActive;   // whether client was active in last update
165 		time_t tLastSoundTime; // now() when the client last issued a sound (display as sound icon). 0 for no sound.
166 
167 	public:
168 		ClientListItem(C4PlayerInfoListBox *pForListBox, const C4ClientCore &rClientInfo, ListItem *pInsertBefore); // ctor
169 		~ClientListItem() override = default;                         // dtor
170 
SetColor(DWORD dwToClr)171 		void SetColor(DWORD dwToClr)              // update color of client name label
172 		{ pNameLabel->SetColor((dwClientClr=dwToClr) | C4GUI_MessageFontAlpha); }
SetStatus(C4GUI::Icons icoNewStatus)173 		void SetStatus(C4GUI::Icons icoNewStatus) // set new status
174 		{ pStatusIcon->SetIcon(icoNewStatus); }
175 		void SetPing(int32_t iToPing);                // update ping label; iToPing=-1 removes the label
176 		void UpdateCore(const C4ClientCore &rCore); // core update: re-set name and indicate whether active or not
177 		void SetSoundIcon();                        // sets the sound icon as current icon and schedules reset after some time
178 
179 		// spacing inserted between two client list items
GetListItemTopSpacing()180 		int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
GetListItemTopSpacingBar()181 		bool GetListItemTopSpacingBar() override { return true; }
182 
183 	public:
184 		void Init(const C4ClientCore &rClientInfo); // init members
185 
186 		void UpdateInfo();                                  // update for changed player info
187 
GetColor()188 		DWORD GetColor() const { return dwClientClr; } // client chat color
189 		C4Client *GetClient() const; // get client associated with this list item
190 		bool IsLocalClientPlayer() const; // whether this player is going to join locally
191 		C4GUI::Icons GetCurrentStatusIcon();              // get status icon that shows the current client state
192 		class C4Network2Client *GetNetClient() const; // return assicuated network client; nullptr for local
193 		bool IsLocal() const;
194 
Update()195 		void Update() override { UpdatePing(); UpdateInfo(); }
196 		void UpdatePing();                     // update ping label
197 
198 		C4GUI::ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY); // open context menu
199 		void OnCtxKick(C4GUI::Element *pListItem); // kick item selected in client ctx menu
200 		void OnCtxActivate(C4GUI::Element *pListItem); // toggle player/observer
201 		void OnCtxInfo(C4GUI::Element *pListItem); // show info dlg (modal)
202 		void OnCtxIgnore(C4GUI::Element *pListItem);
203 		void OnBtnAddPlr(C4GUI::Control *btn);
204 	};
205 
206 	// team label
207 	class TeamListItem : public ListItem
208 	{
209 	private:
210 		// subcomponents
211 		C4GUI::Icon *pIcon;
212 		C4GUI::Label *pNameLabel;
213 
214 		int32_t idTeam; // team ID
215 
216 	protected:
217 		void UpdateOwnPos() override; // recalculate item positioning
218 
219 	public:
220 		TeamListItem(C4PlayerInfoListBox *pForListBox, int32_t idTeam, ListItem *pInsertBefore); // ctor
221 
222 		void MouseInput(C4GUI::CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam) override; // input: mouse movement or buttons
223 
224 		// spacing inserted between of those list items; usually this is top anyway...
GetListItemTopSpacingBar()225 		bool GetListItemTopSpacingBar() override { return true; }
GetListItemTopSpacing()226 		int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
227 
228 		void Update() override;
229 
230 	private:
231 		void MoveLocalPlayersIntoTeam(); // move all local players into team marked by this label
232 	};
233 
234 	// list of unassigned savegame recreation players
235 	class FreeSavegamePlayersListItem : public ListItem
236 	{
237 	private:
238 		// subcomponents
239 		C4GUI::Icon *pIcon;
240 		C4GUI::Label *pNameLabel;
241 
242 	public:
243 		FreeSavegamePlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore); // ctor
244 
245 		// spacing inserted between of those list items; usually this is top anyway...
ListItemTopSpacingBar()246 		virtual bool ListItemTopSpacingBar() { return true; }
GetListItemTopSpacing()247 		int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
248 
249 	public:
250 		void Update() override;
251 	};
252 
253 	// list of script players (both savegame recreation and regular)
254 	class ScriptPlayersListItem : public ListItem
255 	{
256 	private:
257 		// subcomponents
258 		C4GUI::Icon *pIcon;
259 		C4GUI::Label *pNameLabel;
260 		C4GUI::IconButton *btnAddPlayer;
261 
262 	public:
263 		ScriptPlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore); // ctor
264 
265 		// spacing inserted between of those list items; usually this is top anyway...
ListItemTopSpacingBar()266 		virtual bool ListItemTopSpacingBar() { return true; }
GetListItemTopSpacing()267 		int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
268 
269 	protected:
270 		void OnBtnAddPlr(C4GUI::Control *btn);
271 
272 	public:
273 		void Update() override;
274 	};
275 
276 	// list of players in record (currently not used, because replays in network are not allowed :C)
277 	class ReplayPlayersListItem : public ListItem
278 	{
279 	private:
280 		// subcomponents
281 		C4GUI::Icon *pIcon;
282 		C4GUI::Label *pNameLabel;
283 
284 	public:
285 		ReplayPlayersListItem(C4PlayerInfoListBox *pForListBox, ListItem *pInsertBefore); // ctor
286 
287 		// spacing inserted between of those list items; usually this is top anyway...
GetListItemTopSpacingBar()288 		bool GetListItemTopSpacingBar() override { return true; }
GetListItemTopSpacing()289 		int32_t GetListItemTopSpacing() override { return ClientListBoxSpacing; }
290 	};
291 
292 	// -----------------------------------------------------------------------------------------------
293 private:
294 	Mode eMode;
295 	int32_t iMaxUncollapsedPlayers; // maximum number of players that can be displayed without collapse - valid only if fIsCollapsed
296 	bool fIsCollapsed;
297 	int32_t iTeamFilter; // if nonzero, only playeers of this team are shown in the listbox
298 
299 	uint32_t dwTextColor;
300 	CStdFont *pCustomFont;
301 
302 	enum AddMode
303 	{
304 		AM_Winners,
305 		AM_Losers,
306 		AM_All
307 	};
308 
309 	void UpdateSavegamePlayers(ListItem **ppCurrInList);
310 	void UpdateReplayPlayers(ListItem **ppCurrInList);
311 	void UpdateScriptPlayers(ListItem **ppCurrInList);
312 	void UpdatePlayersByTeam(ListItem **ppCurrInList);
313 	void UpdatePlayersByRandomTeam(ListItem **ppCurrInList);
314 	void UpdatePlayersByClient(ListItem **ppCurrInList);
315 	void UpdatePlayersByEvaluation(ListItem **ppCurrInList, bool fShowWinners);
316 	void UpdatePlayersByEvaluation(ListItem **ppCurrInList, C4Team *pTeam, AddMode eAddMode);
317 
318 	ListItem *GetPlayerListItem(ListItem::ID::IDType eType, int32_t id); // search for a player list item
319 	bool PlrListItemUpdate(ListItem::ID::IDType eType, int32_t id, class ListItem **pEnsurePos); // search for player list item with given ID in the list starting at ensurepos; ensure it's positioned at given pos; update and return true if found
320 
IsEvaluation()321 	bool IsEvaluation() const { return eMode == PILBM_Evaluation || eMode == PILBM_EvaluationNoWinners; }
IsLobby()322 	bool IsLobby() const { return eMode == PILBM_LobbyClientSort || eMode == PILBM_LobbyTeamSort; }
IsTeamFilter()323 	bool IsTeamFilter() const { return !!iTeamFilter; }
324 
325 protected:
326 	bool IsPlayerItemCollapsed(PlayerListItem *pItem); // CB from list item: return true if it should be shown small
OnPlrListSelChange(class C4GUI::Element * pEl)327 	void OnPlrListSelChange(class C4GUI::Element *pEl) { Update(); }
328 
GetTextColor()329 	uint32_t GetTextColor() const { return dwTextColor; }
GetCustomFont()330 	CStdFont *GetCustomFont() const { return pCustomFont; }
331 
332 public:
333 	C4PlayerInfoListBox(const C4Rect &rcBounds, Mode eMode, int32_t iTeamFilter=0);
334 	~C4PlayerInfoListBox() override = default;
335 
336 	void Update(); // update player list
337 	void SetClientSoundIcon(int32_t iForClientID);
338 	void SetMode(Mode eNewMode);
SetTeamFilter(int32_t idNewTeamFilter)339 	void SetTeamFilter(int32_t idNewTeamFilter) { iTeamFilter = idNewTeamFilter; }
340 	void SetCustomFont(CStdFont *pNewFont, uint32_t dwTextColor);
341 
GetMode()342 	Mode GetMode() const { return eMode; }
343 
344 	friend class PlayerListItem;
345 	friend class TeamListItem;
346 };
347 
348 
349 #endif // INC_C4PlayerInfoListBox
350