1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef GAME_CLIENT_COMPONENTS_MENUS_H
4#define GAME_CLIENT_COMPONENTS_MENUS_H
5
6#include <base/types.h>
7#include <base/vmath.h>
8
9#include <chrono>
10#include <deque>
11#include <unordered_set>
12#include <vector>
13
14#include <engine/console.h>
15#include <engine/demo.h>
16#include <engine/friends.h>
17#include <engine/serverbrowser.h>
18#include <engine/shared/config.h>
19#include <engine/shared/http.h>
20#include <engine/shared/jobs.h>
21#include <engine/shared/linereader.h>
22#include <engine/textrender.h>
23
24#include <game/client/component.h>
25#include <game/client/components/mapimages.h>
26#include <game/client/render.h>
27#include <game/client/ui.h>
28#include <game/voting.h>
29
30struct CServerProcess
31{
32 PROCESS m_Process;
33};
34
35// component to fetch keypresses, override all other input
36class CMenusKeyBinder : public CComponent
37{
38public:
39 const void *m_pKeyReaderId;
40 bool m_TakeKey;
41 bool m_GotKey;
42 IInput::CEvent m_Key;
43 int m_ModifierCombination;
44 CMenusKeyBinder();
45 virtual int Sizeof() const override { return sizeof(*this); }
46 virtual bool OnInput(const IInput::CEvent &Event) override;
47};
48
49struct SCommunityIcon
50{
51 char m_aCommunityId[CServerInfo::MAX_COMMUNITY_ID_LENGTH];
52 SHA256_DIGEST m_Sha256;
53 IGraphics::CTextureHandle m_OrgTexture;
54 IGraphics::CTextureHandle m_GreyTexture;
55};
56
57class CMenus : public CComponent
58{
59 static ColorRGBA ms_GuiColor;
60 static ColorRGBA ms_ColorTabbarInactiveOutgame;
61 static ColorRGBA ms_ColorTabbarActiveOutgame;
62 static ColorRGBA ms_ColorTabbarHoverOutgame;
63 static ColorRGBA ms_ColorTabbarInactiveIngame;
64 static ColorRGBA ms_ColorTabbarActiveIngame;
65 static ColorRGBA ms_ColorTabbarHoverIngame;
66 static ColorRGBA ms_ColorTabbarInactive;
67 static ColorRGBA ms_ColorTabbarActive;
68 static ColorRGBA ms_ColorTabbarHover;
69
70 int DoButton_FontIcon(CButtonContainer *pButtonContainer, const char *pText, int Checked, const CUIRect *pRect, int Corners = IGraphics::CORNER_ALL, bool Enabled = true);
71 int DoButton_Toggle(const void *pId, int Checked, const CUIRect *pRect, bool Active);
72 int DoButton_Menu(CButtonContainer *pButtonContainer, const char *pText, int Checked, const CUIRect *pRect, const char *pImageName = nullptr, int Corners = IGraphics::CORNER_ALL, float Rounding = 5.0f, float FontFactor = 0.0f, ColorRGBA Color = ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f));
73 int DoButton_MenuTab(CButtonContainer *pButtonContainer, const char *pText, int Checked, const CUIRect *pRect, int Corners, SUIAnimator *pAnimator = nullptr, const ColorRGBA *pDefaultColor = nullptr, const ColorRGBA *pActiveColor = nullptr, const ColorRGBA *pHoverColor = nullptr, float EdgeRounding = 10.0f, const SCommunityIcon *pCommunityIcon = nullptr);
74
75 int DoButton_CheckBox_Common(const void *pId, const char *pText, const char *pBoxText, const CUIRect *pRect);
76 int DoButton_CheckBox(const void *pId, const char *pText, int Checked, const CUIRect *pRect);
77 int DoButton_CheckBoxAutoVMarginAndSet(const void *pId, const char *pText, int *pValue, CUIRect *pRect, float VMargin);
78 int DoButton_CheckBox_Number(const void *pId, const char *pText, int Checked, const CUIRect *pRect);
79
80 ColorHSLA DoLine_ColorPicker(CButtonContainer *pResetId, float LineSize, float LabelSize, float BottomMargin, CUIRect *pMainRect, const char *pText, unsigned int *pColorValue, ColorRGBA DefaultColor, bool CheckBoxSpacing = true, int *pCheckBoxValue = nullptr, bool Alpha = false);
81 ColorHSLA DoButton_ColorPicker(const CUIRect *pRect, unsigned int *pHslaColor, bool Alpha);
82 void DoLaserPreview(const CUIRect *pRect, ColorHSLA OutlineColor, ColorHSLA InnerColor, const int LaserType);
83 int DoButton_GridHeader(const void *pId, const char *pText, int Checked, const CUIRect *pRect);
84 int DoButton_Favorite(const void *pButtonId, const void *pParentId, bool Checked, const CUIRect *pRect);
85
86 int DoKeyReader(const void *pId, const CUIRect *pRect, int Key, int ModifierCombination, int *pNewModifierCombination);
87
88 void DoSettingsControlsButtons(int Start, int Stop, CUIRect View);
89
90 float RenderSettingsControlsJoystick(CUIRect View);
91 void DoJoystickAxisPicker(CUIRect View);
92 void DoJoystickBar(const CUIRect *pRect, float Current, float Tolerance, bool Active);
93
94 bool m_SkinListNeedsUpdate = false;
95 void RandomSkin();
96
97 // menus_settings_assets.cpp
98public:
99 struct SCustomItem
100 {
101 IGraphics::CTextureHandle m_RenderTexture;
102
103 char m_aName[50];
104
105 bool operator<(const SCustomItem &Other) const { return str_comp(a: m_aName, b: Other.m_aName) < 0; }
106 };
107
108 struct SCustomEntities : public SCustomItem
109 {
110 struct SEntitiesImage
111 {
112 IGraphics::CTextureHandle m_Texture;
113 };
114 SEntitiesImage m_aImages[MAP_IMAGE_MOD_TYPE_COUNT];
115 };
116
117 struct SCustomGame : public SCustomItem
118 {
119 };
120
121 struct SCustomEmoticon : public SCustomItem
122 {
123 };
124
125 struct SCustomParticle : public SCustomItem
126 {
127 };
128
129 struct SCustomHud : public SCustomItem
130 {
131 };
132
133 struct SCustomExtras : public SCustomItem
134 {
135 };
136
137protected:
138 std::vector<SCustomEntities> m_vEntitiesList;
139 std::vector<SCustomGame> m_vGameList;
140 std::vector<SCustomEmoticon> m_vEmoticonList;
141 std::vector<SCustomParticle> m_vParticlesList;
142 std::vector<SCustomHud> m_vHudList;
143 std::vector<SCustomExtras> m_vExtrasList;
144
145 bool m_IsInit = false;
146
147 static void LoadEntities(struct SCustomEntities *pEntitiesItem, void *pUser);
148 static int EntitiesScan(const char *pName, int IsDir, int DirType, void *pUser);
149
150 static int GameScan(const char *pName, int IsDir, int DirType, void *pUser);
151 static int EmoticonsScan(const char *pName, int IsDir, int DirType, void *pUser);
152 static int ParticlesScan(const char *pName, int IsDir, int DirType, void *pUser);
153 static int HudScan(const char *pName, int IsDir, int DirType, void *pUser);
154 static int ExtrasScan(const char *pName, int IsDir, int DirType, void *pUser);
155
156 static void ConchainAssetsEntities(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
157 static void ConchainAssetGame(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
158 static void ConchainAssetParticles(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
159 static void ConchainAssetEmoticons(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
160 static void ConchainAssetHud(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
161 static void ConchainAssetExtras(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
162
163 void ClearCustomItems(int CurTab);
164
165 int m_MenuPage;
166 int m_GamePage;
167 int m_Popup;
168 bool m_ShowStart;
169 bool m_MenuActive;
170
171 bool m_JoinTutorial = false;
172 bool m_CreateDefaultFavoriteCommunities = false;
173 bool m_ForceRefreshLanPage = false;
174
175 char m_aNextServer[256];
176
177 // images
178 struct CMenuImage
179 {
180 char m_aName[64];
181 IGraphics::CTextureHandle m_OrgTexture;
182 IGraphics::CTextureHandle m_GreyTexture;
183 };
184 std::vector<CMenuImage> m_vMenuImages;
185 static int MenuImageScan(const char *pName, int IsDir, int DirType, void *pUser);
186 const CMenuImage *FindMenuImage(const char *pName);
187
188 // loading
189 class CLoadingState
190 {
191 public:
192 std::chrono::nanoseconds m_LastRender{0};
193 int m_Current;
194 int m_Total;
195 };
196 CLoadingState m_LoadingState;
197
198 //
199 char m_aMessageTopic[512];
200 char m_aMessageBody[512];
201 char m_aMessageButton[512];
202
203 CUIElement m_RefreshButton;
204 CUIElement m_ConnectButton;
205
206 // generic popups
207 typedef void (CMenus::*FPopupButtonCallback)();
208 void DefaultButtonCallback()
209 {
210 // do nothing
211 }
212 enum
213 {
214 BUTTON_CONFIRM = 0, // confirm / yes / close / ok
215 BUTTON_CANCEL, // cancel / no
216 NUM_BUTTONS
217 };
218 char m_aPopupTitle[128];
219 char m_aPopupMessage[IO_MAX_PATH_LENGTH + 256];
220 struct
221 {
222 char m_aLabel[64];
223 int m_NextPopup;
224 FPopupButtonCallback m_pfnCallback;
225 } m_aPopupButtons[NUM_BUTTONS];
226
227 void PopupMessage(const char *pTitle, const char *pMessage,
228 const char *pButtonLabel, int NextPopup = POPUP_NONE, FPopupButtonCallback pfnButtonCallback = &CMenus::DefaultButtonCallback);
229 void PopupConfirm(const char *pTitle, const char *pMessage,
230 const char *pConfirmButtonLabel, const char *pCancelButtonLabel,
231 FPopupButtonCallback pfnConfirmButtonCallback = &CMenus::DefaultButtonCallback, int ConfirmNextPopup = POPUP_NONE,
232 FPopupButtonCallback pfnCancelButtonCallback = &CMenus::DefaultButtonCallback, int CancelNextPopup = POPUP_NONE);
233
234 // some settings
235 static float ms_ButtonHeight;
236 static float ms_ListheaderHeight;
237 static float ms_ListitemAdditionalHeight;
238
239 // for settings
240 bool m_NeedRestartGraphics;
241 bool m_NeedRestartSound;
242 bool m_NeedRestartUpdate;
243 bool m_NeedSendinfo;
244 bool m_NeedSendDummyinfo;
245 int m_SettingPlayerPage;
246
247 // for map download popup
248 int64_t m_DownloadLastCheckTime;
249 int m_DownloadLastCheckSize;
250 float m_DownloadSpeed;
251
252 // for password popup
253 CLineInput m_PasswordInput;
254
255 // for call vote
256 int m_CallvoteSelectedOption;
257 int m_CallvoteSelectedPlayer;
258 CLineInputBuffered<VOTE_REASON_LENGTH> m_CallvoteReasonInput;
259 CLineInputBuffered<64> m_FilterInput;
260 bool m_ControlPageOpening;
261
262 // demo
263 enum
264 {
265 SORT_DEMONAME = 0,
266 SORT_LENGTH,
267 SORT_DATE,
268 };
269
270 struct CDemoItem
271 {
272 char m_aFilename[IO_MAX_PATH_LENGTH];
273 char m_aName[IO_MAX_PATH_LENGTH];
274 bool m_IsDir;
275 bool m_IsLink;
276 int m_StorageType;
277 time_t m_Date;
278
279 bool m_InfosLoaded;
280 bool m_Valid;
281 CDemoHeader m_Info;
282 CTimelineMarkers m_TimelineMarkers;
283 CMapInfo m_MapInfo;
284
285 int NumMarkers() const
286 {
287 return clamp<int>(val: bytes_be_to_uint(bytes: m_TimelineMarkers.m_aNumTimelineMarkers), lo: 0, hi: MAX_TIMELINE_MARKERS);
288 }
289
290 int Length() const
291 {
292 return bytes_be_to_uint(bytes: m_Info.m_aLength);
293 }
294
295 unsigned Size() const
296 {
297 return bytes_be_to_uint(bytes: m_Info.m_aMapSize);
298 }
299
300 bool operator<(const CDemoItem &Other) const
301 {
302 if(!str_comp(a: m_aFilename, b: ".."))
303 return true;
304 if(!str_comp(a: Other.m_aFilename, b: ".."))
305 return false;
306 if(m_IsDir && !Other.m_IsDir)
307 return true;
308 if(!m_IsDir && Other.m_IsDir)
309 return false;
310
311 const CDemoItem &Left = g_Config.m_BrDemoSortOrder ? Other : *this;
312 const CDemoItem &Right = g_Config.m_BrDemoSortOrder ? *this : Other;
313
314 if(g_Config.m_BrDemoSort == SORT_DEMONAME)
315 return str_comp_filenames(a: Left.m_aFilename, b: Right.m_aFilename) < 0;
316 if(g_Config.m_BrDemoSort == SORT_DATE)
317 return Left.m_Date < Right.m_Date;
318
319 if(!Other.m_InfosLoaded)
320 return m_InfosLoaded;
321 if(!m_InfosLoaded)
322 return !Other.m_InfosLoaded;
323
324 if(g_Config.m_BrDemoSort == SORT_LENGTH)
325 return Left.Length() < Right.Length();
326
327 // Unknown sort
328 return true;
329 }
330 };
331
332 char m_aCurrentDemoFolder[IO_MAX_PATH_LENGTH];
333 char m_aCurrentDemoSelectionName[IO_MAX_PATH_LENGTH];
334 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoRenameInput;
335 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoSliceInput;
336 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoSearchInput;
337#if defined(CONF_VIDEORECORDER)
338 CLineInputBuffered<IO_MAX_PATH_LENGTH> m_DemoRenderInput;
339#endif
340 int m_DemolistSelectedIndex;
341 bool m_DemolistSelectedReveal = false;
342 int m_DemolistStorageType;
343 bool m_DemolistMultipleStorages = false;
344 int m_Speed = 4;
345 bool m_StartPaused = false;
346
347 std::chrono::nanoseconds m_DemoPopulateStartTime{0};
348
349 void DemolistOnUpdate(bool Reset);
350 static int DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser);
351
352 // friends
353 class CFriendItem
354 {
355 char m_aName[MAX_NAME_LENGTH];
356 char m_aClan[MAX_CLAN_LENGTH];
357 const CServerInfo *m_pServerInfo;
358 int m_FriendState;
359 bool m_IsPlayer;
360 bool m_IsAfk;
361 // skin
362 char m_aSkin[24 + 1];
363 bool m_CustomSkinColors;
364 int m_CustomSkinColorBody;
365 int m_CustomSkinColorFeet;
366
367 public:
368 CFriendItem() {}
369 CFriendItem(const CFriendInfo *pFriendInfo) :
370 m_pServerInfo(nullptr),
371 m_IsPlayer(false),
372 m_IsAfk(false),
373 m_CustomSkinColors(false),
374 m_CustomSkinColorBody(0),
375 m_CustomSkinColorFeet(0)
376 {
377 str_copy(dst&: m_aName, src: pFriendInfo->m_aName);
378 str_copy(dst&: m_aClan, src: pFriendInfo->m_aClan);
379 m_FriendState = m_aName[0] == '\0' ? IFriends::FRIEND_CLAN : IFriends::FRIEND_PLAYER;
380 m_aSkin[0] = '\0';
381 }
382 CFriendItem(const CServerInfo::CClient &CurrentClient, const CServerInfo *pServerInfo) :
383 m_pServerInfo(pServerInfo),
384 m_FriendState(CurrentClient.m_FriendState),
385 m_IsPlayer(CurrentClient.m_Player),
386 m_IsAfk(CurrentClient.m_Afk),
387 m_CustomSkinColors(CurrentClient.m_CustomSkinColors),
388 m_CustomSkinColorBody(CurrentClient.m_CustomSkinColorBody),
389 m_CustomSkinColorFeet(CurrentClient.m_CustomSkinColorFeet)
390 {
391 str_copy(dst&: m_aName, src: CurrentClient.m_aName);
392 str_copy(dst&: m_aClan, src: CurrentClient.m_aClan);
393 str_copy(dst&: m_aSkin, src: CurrentClient.m_aSkin);
394 }
395
396 const char *Name() const { return m_aName; }
397 const char *Clan() const { return m_aClan; }
398 const CServerInfo *ServerInfo() const { return m_pServerInfo; }
399 int FriendState() const { return m_FriendState; }
400 bool IsPlayer() const { return m_IsPlayer; }
401 bool IsAfk() const { return m_IsAfk; }
402 const char *Skin() const { return m_aSkin; }
403 bool CustomSkinColors() const { return m_CustomSkinColors; }
404 int CustomSkinColorBody() const { return m_CustomSkinColorBody; }
405 int CustomSkinColorFeet() const { return m_CustomSkinColorFeet; }
406
407 const void *ListItemId() const { return &m_aName; }
408 const void *RemoveButtonId() const { return &m_FriendState; }
409 const void *CommunityTooltipId() const { return &m_IsPlayer; }
410
411 bool operator<(const CFriendItem &Other) const
412 {
413 const int Result = str_comp_nocase(a: m_aName, b: Other.m_aName);
414 return Result < 0 || (Result == 0 && str_comp_nocase(a: m_aClan, b: Other.m_aClan) < 0);
415 }
416 };
417
418 enum
419 {
420 FRIEND_PLAYER_ON = 0,
421 FRIEND_CLAN_ON,
422 FRIEND_OFF,
423 NUM_FRIEND_TYPES
424 };
425 std::vector<CFriendItem> m_avFriends[NUM_FRIEND_TYPES];
426 const CFriendItem *m_pRemoveFriend = nullptr;
427
428 // found in menus.cpp
429 void Render();
430 void RenderPopupFullscreen(CUIRect Screen);
431 void RenderPopupConnecting(CUIRect Screen);
432 void RenderPopupLoading(CUIRect Screen);
433#if defined(CONF_VIDEORECORDER)
434 void PopupConfirmDemoReplaceVideo();
435#endif
436 void RenderMenubar(CUIRect Box, IClient::EClientState ClientState);
437 void RenderNews(CUIRect MainView);
438 static void ConchainBackgroundEntities(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
439 void UpdateBackgroundEntities();
440 static void ConchainUpdateMusicState(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
441 void UpdateMusicState();
442
443 // found in menus_demo.cpp
444 vec2 m_DemoControlsPositionOffset = vec2(0.0f, 0.0f);
445 float m_LastPauseChange = -1.0f;
446 float m_LastSpeedChange = -1.0f;
447 static bool DemoFilterChat(const void *pData, int Size, void *pUser);
448 bool FetchHeader(CDemoItem &Item);
449 void FetchAllHeaders();
450 void HandleDemoSeeking(float PositionToSeek, float TimeToSeek);
451 void RenderDemoPlayer(CUIRect MainView);
452 void RenderDemoPlayerSliceSavePopup(CUIRect MainView);
453 bool m_DemoBrowserListInitialized = false;
454 void RenderDemoBrowser(CUIRect MainView);
455 void RenderDemoBrowserList(CUIRect ListView, bool &WasListboxItemActivated);
456 void RenderDemoBrowserDetails(CUIRect DetailsView);
457 void RenderDemoBrowserButtons(CUIRect ButtonsView, bool WasListboxItemActivated);
458 void PopupConfirmDeleteDemo();
459 void PopupConfirmDeleteFolder();
460
461 // found in menus_start.cpp
462 void RenderStartMenu(CUIRect MainView);
463
464 // found in menus_ingame.cpp
465 STextContainerIndex m_MotdTextContainerIndex;
466 void RenderGame(CUIRect MainView);
467 void PopupConfirmDisconnect();
468 void PopupConfirmDisconnectDummy();
469 void RenderPlayers(CUIRect MainView);
470 void RenderServerInfo(CUIRect MainView);
471 void RenderServerInfoMotd(CUIRect Motd);
472 void RenderServerControl(CUIRect MainView);
473 bool RenderServerControlKick(CUIRect MainView, bool FilterSpectators);
474 bool RenderServerControlServer(CUIRect MainView);
475 void RenderIngameHint();
476
477 // found in menus_browser.cpp
478 int m_SelectedIndex;
479 bool m_ServerBrowserShouldRevealSelection;
480 std::vector<CUIElement *> m_avpServerBrowserUiElements[IServerBrowser::NUM_TYPES];
481 void RenderServerbrowserServerList(CUIRect View, bool &WasListboxItemActivated);
482 void RenderServerbrowserStatusBox(CUIRect StatusBox, bool WasListboxItemActivated);
483 void Connect(const char *pAddress);
484 void PopupConfirmSwitchServer();
485 void RenderServerbrowserFilters(CUIRect View);
486 void ResetServerbrowserFilters();
487 void RenderServerbrowserDDNetFilter(CUIRect View,
488 IFilterList &Filter,
489 float ItemHeight, int MaxItems, int ItemsPerRow,
490 CScrollRegion &ScrollRegion, std::vector<unsigned char> &vItemIds,
491 bool UpdateCommunityCacheOnChange,
492 const std::function<const char *(int ItemIndex)> &GetItemName,
493 const std::function<void(int ItemIndex, CUIRect Item, const void *pItemId, bool Active)> &RenderItem);
494 void RenderServerbrowserCommunitiesFilter(CUIRect View);
495 void RenderServerbrowserCountriesFilter(CUIRect View);
496 void RenderServerbrowserTypesFilter(CUIRect View);
497 struct SPopupCountrySelectionContext
498 {
499 CMenus *m_pMenus;
500 int m_Selection;
501 bool m_New;
502 };
503 static CUi::EPopupMenuFunctionResult PopupCountrySelection(void *pContext, CUIRect View, bool Active);
504 void RenderServerbrowserInfo(CUIRect View);
505 void RenderServerbrowserInfoScoreboard(CUIRect View, const CServerInfo *pSelectedServer);
506 void RenderServerbrowserFriends(CUIRect View);
507 void FriendlistOnUpdate();
508 void PopupConfirmRemoveFriend();
509 void RenderServerbrowserTabBar(CUIRect TabBar);
510 void RenderServerbrowserToolBox(CUIRect ToolBox);
511 void RenderServerbrowser(CUIRect MainView);
512 template<typename F>
513 bool PrintHighlighted(const char *pName, F &&PrintFn);
514 CTeeRenderInfo GetTeeRenderInfo(vec2 Size, const char *pSkinName, bool CustomSkinColors, int CustomSkinColorBody, int CustomSkinColorFeet) const;
515 static void ConchainFriendlistUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
516 static void ConchainFavoritesUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
517 static void ConchainCommunitiesUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
518 static void ConchainUiPageUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
519 void UpdateCommunityCache(bool Force);
520
521 // community icons
522 class CAbstractCommunityIconJob
523 {
524 protected:
525 CMenus *m_pMenus;
526 char m_aCommunityId[CServerInfo::MAX_COMMUNITY_ID_LENGTH];
527 char m_aPath[IO_MAX_PATH_LENGTH];
528 int m_StorageType;
529 bool m_Success = false;
530 SHA256_DIGEST m_Sha256;
531
532 CAbstractCommunityIconJob(CMenus *pMenus, const char *pCommunityId, int StorageType);
533 virtual ~CAbstractCommunityIconJob(){};
534
535 public:
536 const char *CommunityId() const { return m_aCommunityId; }
537 bool Success() const { return m_Success; }
538 const SHA256_DIGEST &Sha256() const { return m_Sha256; }
539 };
540
541 class CCommunityIconLoadJob : public IJob, public CAbstractCommunityIconJob
542 {
543 CImageInfo m_ImageInfo;
544
545 protected:
546 void Run() override;
547
548 public:
549 CCommunityIconLoadJob(CMenus *pMenus, const char *pCommunityId, int StorageType);
550 ~CCommunityIconLoadJob();
551
552 CImageInfo &ImageInfo() { return m_ImageInfo; }
553 };
554
555 class CCommunityIconDownloadJob : public CHttpRequest, public CAbstractCommunityIconJob
556 {
557 public:
558 CCommunityIconDownloadJob(CMenus *pMenus, const char *pCommunityId, const char *pUrl, const SHA256_DIGEST &Sha256);
559 };
560
561 std::vector<SCommunityIcon> m_vCommunityIcons;
562 std::deque<std::shared_ptr<CCommunityIconLoadJob>> m_CommunityIconLoadJobs;
563 std::deque<std::shared_ptr<CCommunityIconDownloadJob>> m_CommunityIconDownloadJobs;
564 SHA256_DIGEST m_CommunityIconsInfoSha256 = SHA256_ZEROED;
565 static int CommunityIconScan(const char *pName, int IsDir, int DirType, void *pUser);
566 const SCommunityIcon *FindCommunityIcon(const char *pCommunityId);
567 bool LoadCommunityIconFile(const char *pPath, int DirType, CImageInfo &Info, SHA256_DIGEST &Sha256);
568 void LoadCommunityIconFinish(const char *pCommunityId, CImageInfo &Info, const SHA256_DIGEST &Sha256);
569 void RenderCommunityIcon(const SCommunityIcon *pIcon, CUIRect Rect, bool Active);
570 void UpdateCommunityIcons();
571
572 // skin favorite list
573 bool m_SkinFavoritesChanged = false;
574 std::unordered_set<std::string> m_SkinFavorites;
575 static void Con_AddFavoriteSkin(IConsole::IResult *pResult, void *pUserData);
576 static void Con_RemFavoriteSkin(IConsole::IResult *pResult, void *pUserData);
577 static void ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData);
578 void OnConfigSave(IConfigManager *pConfigManager);
579
580 // found in menus_settings.cpp
581 bool RenderLanguageSelection(CUIRect MainView);
582 void RenderThemeSelection(CUIRect MainView);
583 void RenderSettingsGeneral(CUIRect MainView);
584 void RenderSettingsPlayer(CUIRect MainView);
585 void RenderSettingsDummyPlayer(CUIRect MainView);
586 void RenderSettingsTee(CUIRect MainView);
587 void RenderSettingsControls(CUIRect MainView);
588 void ResetSettingsControls();
589 void RenderSettingsGraphics(CUIRect MainView);
590 void RenderSettingsSound(CUIRect MainView);
591 void RenderSettings(CUIRect MainView);
592 void RenderSettingsCustom(CUIRect MainView);
593
594 void SetNeedSendInfo();
595 void SetActive(bool Active);
596 void UpdateColors();
597
598 IGraphics::CTextureHandle m_TextureBlob;
599
600 bool CheckHotKey(int Key) const;
601
602public:
603 void RenderBackground();
604
605 static CMenusKeyBinder m_Binder;
606
607 CMenus();
608 virtual int Sizeof() const override { return sizeof(*this); }
609
610 void RenderLoading(const char *pCaption, const char *pContent, int IncreaseCounter, bool RenderLoadingBar = true, bool RenderMenuBackgroundMap = true);
611
612 bool IsInit() { return m_IsInit; }
613
614 bool IsActive() const { return m_MenuActive; }
615 void KillServer();
616
617 virtual void OnInit() override;
618 void OnConsoleInit() override;
619
620 virtual void OnStateChange(int NewState, int OldState) override;
621 virtual void OnWindowResize() override;
622 virtual void OnRefreshSkins() override;
623 virtual void OnReset() override;
624 virtual void OnRender() override;
625 virtual bool OnInput(const IInput::CEvent &Event) override;
626 virtual bool OnCursorMove(float x, float y, IInput::ECursorType CursorType) override;
627 virtual void OnShutdown() override;
628
629 enum
630 {
631 PAGE_NEWS = 1,
632 PAGE_GAME,
633 PAGE_PLAYERS,
634 PAGE_SERVER_INFO,
635 PAGE_CALLVOTE,
636 PAGE_INTERNET,
637 PAGE_LAN,
638 PAGE_FAVORITES,
639 PAGE_FAVORITE_COMMUNITY_1,
640 PAGE_FAVORITE_COMMUNITY_2,
641 PAGE_FAVORITE_COMMUNITY_3,
642 PAGE_FAVORITE_COMMUNITY_4,
643 PAGE_FAVORITE_COMMUNITY_5,
644 PAGE_DEMOS,
645 PAGE_SETTINGS,
646 PAGE_NETWORK,
647 PAGE_GHOST,
648
649 PAGE_LENGTH,
650
651 SETTINGS_LANGUAGE = 0,
652 SETTINGS_GENERAL,
653 SETTINGS_PLAYER,
654 SETTINGS_TEE,
655 SETTINGS_APPEARANCE,
656 SETTINGS_CONTROLS,
657 SETTINGS_GRAPHICS,
658 SETTINGS_SOUND,
659 SETTINGS_DDNET,
660 SETTINGS_ASSETS,
661
662 SETTINGS_LENGTH,
663
664 BIG_TAB_NEWS = 0,
665 BIG_TAB_INTERNET,
666 BIG_TAB_LAN,
667 BIG_TAB_FAVORITES,
668 BIT_TAB_FAVORITE_COMMUNITY_1,
669 BIT_TAB_FAVORITE_COMMUNITY_2,
670 BIT_TAB_FAVORITE_COMMUNITY_3,
671 BIT_TAB_FAVORITE_COMMUNITY_4,
672 BIT_TAB_FAVORITE_COMMUNITY_5,
673 BIG_TAB_DEMOS,
674
675 BIG_TAB_LENGTH,
676
677 SMALL_TAB_HOME = 0,
678 SMALL_TAB_QUIT,
679 SMALL_TAB_SETTINGS,
680 SMALL_TAB_EDITOR,
681 SMALL_TAB_DEMOBUTTON,
682 SMALL_TAB_SERVER,
683 SMALL_TAB_BROWSER_FILTER,
684 SMALL_TAB_BROWSER_INFO,
685 SMALL_TAB_BROWSER_FRIENDS,
686
687 SMALL_TAB_LENGTH,
688 };
689
690 SUIAnimator m_aAnimatorsBigPage[BIG_TAB_LENGTH];
691 SUIAnimator m_aAnimatorsSmallPage[SMALL_TAB_LENGTH];
692 SUIAnimator m_aAnimatorsSettingsTab[SETTINGS_LENGTH];
693
694 // DDRace
695 int DoButton_CheckBox_Tristate(const void *pId, const char *pText, TRISTATE Checked, const CUIRect *pRect);
696 std::vector<CDemoItem> m_vDemos;
697 std::vector<CDemoItem *> m_vpFilteredDemos;
698 void DemolistPopulate();
699 void RefreshFilteredDemos();
700 void DemoSeekTick(IDemoPlayer::ETickOffset TickOffset);
701 bool m_Dummy;
702
703 const char *GetCurrentDemoFolder() const { return m_aCurrentDemoFolder; }
704
705 // Ghost
706 struct CGhostItem
707 {
708 char m_aFilename[IO_MAX_PATH_LENGTH];
709 char m_aPlayer[MAX_NAME_LENGTH];
710
711 bool m_Failed;
712 int m_Time;
713 int m_Slot;
714 bool m_Own;
715 time_t m_Date;
716
717 CGhostItem() :
718 m_Slot(-1), m_Own(false) { m_aFilename[0] = 0; }
719
720 bool operator<(const CGhostItem &Other) const { return m_Time < Other.m_Time; }
721
722 bool Active() const { return m_Slot != -1; }
723 bool HasFile() const { return m_aFilename[0]; }
724 };
725
726 std::vector<CGhostItem> m_vGhosts;
727
728 std::chrono::nanoseconds m_GhostPopulateStartTime{0};
729
730 void GhostlistPopulate();
731 CGhostItem *GetOwnGhost();
732 void UpdateOwnGhost(CGhostItem Item);
733 void DeleteGhostItem(int Index);
734
735 bool CanDisplayWarning() const;
736
737 void PopupWarning(const char *pTopic, const char *pBody, const char *pButton, std::chrono::nanoseconds Duration);
738
739 std::chrono::nanoseconds m_PopupWarningLastTime;
740 std::chrono::nanoseconds m_PopupWarningDuration;
741
742 int m_DemoPlayerState;
743
744 enum
745 {
746 POPUP_NONE = 0,
747 POPUP_MESSAGE, // generic message popup (one button)
748 POPUP_CONFIRM, // generic confirmation popup (two buttons)
749 POPUP_FIRST_LAUNCH,
750 POPUP_POINTS,
751 POPUP_DISCONNECTED,
752 POPUP_LANGUAGE,
753 POPUP_RENAME_DEMO,
754 POPUP_RENDER_DEMO,
755 POPUP_RENDER_DONE,
756 POPUP_PASSWORD,
757 POPUP_QUIT,
758 POPUP_RESTART,
759 POPUP_WARNING,
760
761 // demo player states
762 DEMOPLAYER_NONE = 0,
763 DEMOPLAYER_SLICE_SAVE,
764 };
765
766private:
767 static int GhostlistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser);
768 void SetMenuPage(int NewPage);
769 void RefreshBrowserTab(bool Force);
770
771 // found in menus_ingame.cpp
772 void RenderInGameNetwork(CUIRect MainView);
773 void RenderGhost(CUIRect MainView);
774
775 // found in menus_settings.cpp
776 void RenderSettingsDDNet(CUIRect MainView);
777 void RenderSettingsAppearance(CUIRect MainView);
778 ColorHSLA RenderHSLScrollbars(CUIRect *pRect, unsigned int *pColor, bool Alpha = false, bool ClampedLight = false);
779
780 CServerProcess m_ServerProcess;
781};
782#endif
783