int CMenus::Render() { CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); static bool s_First = true; if(s_First) { if(g_Config.m_UiPage == PAGE_INTERNET) ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); else if(g_Config.m_UiPage == PAGE_LAN) ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); else if(g_Config.m_UiPage == PAGE_FAVORITES) ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES); m_pClient->m_pSounds->Enqueue(CSounds::CHN_MUSIC, SOUND_MENU); s_First = false; } if(Client()->State() == IClient::STATE_ONLINE) { ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame; ms_ColorTabbarActive = ms_ColorTabbarActiveIngame; } else { RenderBackground(); ms_ColorTabbarInactive = ms_ColorTabbarInactiveOutgame; ms_ColorTabbarActive = ms_ColorTabbarActiveOutgame; } CUIRect TabBar; CUIRect MainView; // some margin around the screen Screen.Margin(10.0f, &Screen); static bool s_SoundCheck = false; if(!s_SoundCheck && m_Popup == POPUP_NONE) { if(Client()->SoundInitFailed()) m_Popup = POPUP_SOUNDERROR; s_SoundCheck = true; } if(m_Popup == POPUP_NONE) { // do tab bar Screen.HSplitTop(24.0f, &TabBar, &MainView); TabBar.VMargin(20.0f, &TabBar); RenderMenubar(TabBar); // news is not implemented yet if(g_Config.m_UiPage <= PAGE_NEWS || g_Config.m_UiPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiPage >= PAGE_GAME && g_Config.m_UiPage <= PAGE_CALLVOTE)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); g_Config.m_UiPage = PAGE_INTERNET; } // render current page if(Client()->State() != IClient::STATE_OFFLINE) { if(m_GamePage == PAGE_GAME) RenderGame(MainView); else if(m_GamePage == PAGE_PLAYERS) RenderPlayers(MainView); else if(m_GamePage == PAGE_SERVER_INFO) RenderServerInfo(MainView); else if(m_GamePage == PAGE_DDRace) RenderInGameDDRace(MainView); else if(m_GamePage == PAGE_CALLVOTE) RenderServerControl(MainView); else if(m_GamePage == PAGE_SETTINGS) RenderSettings(MainView); else if(m_GamePage == PAGE_GHOST) RenderGhost(MainView); else if(m_GamePage == PAGE_BROWSER) RenderInGameBrowser(MainView); } else if(g_Config.m_UiPage == PAGE_NEWS) RenderNews(MainView); else if(g_Config.m_UiPage == PAGE_INTERNET) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_LAN) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_DEMOS) RenderDemoList(MainView); else if(g_Config.m_UiPage == PAGE_FAVORITES) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_SETTINGS) RenderSettings(MainView); } else { // make sure that other windows doesn't do anything funnay! //UI()->SetHotItem(0); //UI()->SetActiveItem(0); char aBuf[128]; const char *pTitle = ""; const char *pExtraText = ""; const char *pButtonText = ""; int ExtraAlign = 0; if(m_Popup == POPUP_MESSAGE) { pTitle = m_aMessageTopic; pExtraText = m_aMessageBody; pButtonText = m_aMessageButton; } else if(m_Popup == POPUP_CONNECTING) { pTitle = Localize("Connecting to"); pExtraText = g_Config.m_UiServerAddress; // TODO: query the client about the address pButtonText = Localize("Abort"); if(Client()->MapDownloadTotalsize() > 0) { pTitle = Localize("Downloading map"); pExtraText = ""; } } else if(m_Popup == POPUP_DISCONNECTED) { pTitle = Localize("Disconnected"); pExtraText = Client()->ErrorString(); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PURE) { pTitle = Localize("Disconnected"); pExtraText = Localize("The server is running a non-standard tuning on a pure game type."); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_DELETE_DEMO) { pTitle = Localize("Delete demo"); pExtraText = Localize("Are you sure that you want to delete the demo?"); ExtraAlign = -1; } else if(m_Popup == POPUP_RENAME_DEMO) { pTitle = Localize("Rename demo"); pExtraText = ""; ExtraAlign = -1; } else if(m_Popup == POPUP_REMOVE_FRIEND) { pTitle = Localize("Remove friend"); pExtraText = Localize("Are you sure that you want to remove the player from your friends list?"); ExtraAlign = -1; } else if(m_Popup == POPUP_SOUNDERROR) { pTitle = Localize("Sound error"); pExtraText = Localize("The audio device couldn't be initialised."); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PASSWORD) { pTitle = Localize("Password incorrect"); pExtraText = ""; pButtonText = Localize("Try again"); } else if(m_Popup == POPUP_QUIT) { pTitle = Localize("Quit"); pExtraText = Localize("Are you sure that you want to quit?"); ExtraAlign = -1; } else if(m_Popup == POPUP_FIRST_LAUNCH) { pTitle = Localize("Welcome to Teeworlds"); pExtraText = Localize("As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server."); pButtonText = Localize("Ok"); ExtraAlign = -1; } CUIRect Box, Part; Box = Screen; Box.VMargin(150.0f/UI()->Scale(), &Box); Box.HMargin(150.0f/UI()->Scale(), &Box); // render the box RenderTools()->DrawUIRect(&Box, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); UI()->DoLabelScaled(&Part, pTitle, 24.f, 0); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); Part.VMargin(20.f/UI()->Scale(), &Part); if(ExtraAlign == -1) UI()->DoLabelScaled(&Part, pExtraText, 20.f, -1, (int)Part.w); else UI()->DoLabelScaled(&Part, pExtraText, 20.f, 0, -1); if(m_Popup == POPUP_QUIT) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); // additional info Box.HSplitTop(10.0f, 0, &Box); Box.VMargin(20.f/UI()->Scale(), &Box); if(m_pClient->Editor()->HasUnsavedData()) { char aBuf[256]; str_format(aBuf, sizeof(aBuf), "%s\n%s", Localize("There's an unsaved map in the editor, you might want to save it before you quit the game."), Localize("Quit anyway?")); UI()->DoLabelScaled(&Box, aBuf, 20.f, -1, Part.w-20.0f); } // buttons Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) Client()->Quit(); } else if(m_Popup == POPUP_PASSWORD) { CUIRect Label, TextBox, TryAgain, Abort; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &TryAgain); TryAgain.VMargin(20.0f, &TryAgain); Abort.VMargin(20.0f, &Abort); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Try again"), 0, &TryAgain) || m_EnterPressed) { Client()->Connect(g_Config.m_UiServerAddress); } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Password"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &Offset, true); } else if(m_Popup == POPUP_CONNECTING) { Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed) { Client()->Disconnect(); m_Popup = POPUP_NONE; } if(Client()->MapDownloadTotalsize() > 0) { int64 Now = time_get(); if(Now-m_DownloadLastCheckTime >= time_freq()) { if(m_DownloadLastCheckSize > Client()->MapDownloadAmount()) { // map downloaded restarted m_DownloadLastCheckSize = 0; } // update download speed float Diff = Client()->MapDownloadAmount()-m_DownloadLastCheckSize; float StartDiff = m_DownloadLastCheckSize-0.0f; if(StartDiff+Diff > 0.0f) m_DownloadSpeed = (Diff/(StartDiff+Diff))*(Diff/1.0f) + (StartDiff/(Diff+StartDiff))*m_DownloadSpeed; else m_DownloadSpeed = 0.0f; m_DownloadLastCheckTime = Now; m_DownloadLastCheckSize = Client()->MapDownloadAmount(); } Box.HSplitTop(64.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); str_format(aBuf, sizeof(aBuf), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount()/1024, Client()->MapDownloadTotalsize()/1024, m_DownloadSpeed/1024.0f); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // time left const char *pTimeLeftString; int TimeLeft = max(1, m_DownloadSpeed > 0.0f ? static_cast<int>((Client()->MapDownloadTotalsize()-Client()->MapDownloadAmount())/m_DownloadSpeed) : 1); if(TimeLeft >= 60) { TimeLeft /= 60; pTimeLeftString = TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"); } else pTimeLeftString = TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"); Box.HSplitTop(20.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); str_format(aBuf, sizeof(aBuf), pTimeLeftString, TimeLeft); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // progress bar Box.HSplitTop(20.f, 0, &Box); Box.HSplitTop(24.f, &Part, &Box); Part.VMargin(40.0f, &Part); RenderTools()->DrawUIRect(&Part, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 5.0f); Part.w = max(10.0f, (Part.w*Client()->MapDownloadAmount())/Client()->MapDownloadTotalsize()); RenderTools()->DrawUIRect(&Part, vec4(1.0f, 1.0f, 1.0f, 0.5f), CUI::CORNER_ALL, 5.0f); } } else if(m_Popup == POPUP_LANGUAGE) { Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); Box.HSplitTop(20.f, &Part, &Box); Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Box.HSplitBottom(20.f, &Box, 0); Box.VMargin(20.0f, &Box); RenderLanguageSelection(Box); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Part) || m_EscapePressed || m_EnterPressed) m_Popup = POPUP_FIRST_LAUNCH; } else if(m_Popup == POPUP_COUNTRY) { Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); Box.HSplitTop(20.f, &Part, &Box); Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Box.HSplitBottom(20.f, &Box, 0); Box.VMargin(20.0f, &Box); static int ActSelection = -2; if(ActSelection == -2) ActSelection = g_Config.m_BrFilterCountryIndex; static float s_ScrollValue = 0.0f; int OldSelected = -1; UiDoListboxStart(&s_ScrollValue, &Box, 50.0f, Localize("Country"), "", m_pClient->m_pCountryFlags->Num(), 6, OldSelected, s_ScrollValue); for(int i = 0; i < m_pClient->m_pCountryFlags->Num(); ++i) { const CCountryFlags::CCountryFlag *pEntry = m_pClient->m_pCountryFlags->GetByIndex(i); if(pEntry->m_CountryCode == ActSelection) OldSelected = i; CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected == i); if(Item.m_Visible) { CUIRect Label; Item.m_Rect.Margin(5.0f, &Item.m_Rect); Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label); float OldWidth = Item.m_Rect.w; Item.m_Rect.w = Item.m_Rect.h*2; Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f; Graphics()->TextureSet(pEntry->m_Texture); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, 0); } } const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0); if(OldSelected != NewSelected) ActSelection = m_pClient->m_pCountryFlags->GetByIndex(NewSelected)->m_CountryCode; Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Part) || m_EnterPressed) { g_Config.m_BrFilterCountryIndex = ActSelection; Client()->ServerBrowserUpdate(); m_Popup = POPUP_NONE; } if(m_EscapePressed) { ActSelection = g_Config.m_BrFilterCountryIndex; m_Popup = POPUP_NONE; } } else if(m_Popup == POPUP_DELETE_DEMO) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) { m_Popup = POPUP_NONE; // delete demo if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); if(Storage()->RemoveFile(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } else PopupMessage(Localize("Error"), Localize("Unable to delete the demo"), Localize("Ok")); } } } else if(m_Popup == POPUP_RENAME_DEMO) { CUIRect Label, TextBox, Ok, Abort; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &Ok); Ok.VMargin(20.0f, &Ok); Abort.VMargin(20.0f, &Abort); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonOk = 0; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || m_EnterPressed) { m_Popup = POPUP_NONE; // rename demo if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBufOld[512]; str_format(aBufOld, sizeof(aBufOld), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); int Length = str_length(m_aCurrentDemoFile); char aBufNew[512]; if(Length <= 4 || m_aCurrentDemoFile[Length-5] != '.' || str_comp_nocase(m_aCurrentDemoFile+Length-4, "demo")) str_format(aBufNew, sizeof(aBufNew), "%s/%s.demo", m_aCurrentDemoFolder, m_aCurrentDemoFile); else str_format(aBufNew, sizeof(aBufNew), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); if(Storage()->RenameFile(aBufOld, aBufNew, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } else PopupMessage(Localize("Error"), Localize("Unable to rename the demo"), Localize("Ok")); } } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(120.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("New name:"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset); } else if(m_Popup == POPUP_REMOVE_FRIEND) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) { m_Popup = POPUP_NONE; // remove friend if(m_FriendlistSelectedIndex >= 0) { m_pClient->Friends()->RemoveFriend(m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aName, m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aClan); FriendlistOnUpdate(); Client()->ServerBrowserUpdate(); } } } else if(m_Popup == POPUP_FIRST_LAUNCH) { CUIRect Label, TextBox; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); static int s_EnterButton = 0; if(DoButton_Menu(&s_EnterButton, Localize("Enter"), 0, &Part) || m_EnterPressed) m_Popup = POPUP_NONE; Box.HSplitBottom(40.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Nickname"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &Offset); } else { Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed) m_Popup = POPUP_NONE; } } return 0; }
void CMenus::RenderPlayers(CUIRect MainView) { CUIRect Button, ButtonBar, Options, Player; RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 10.0f); // player options MainView.Margin(10.0f, &Options); RenderTools()->DrawUIRect(&Options, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); Options.Margin(10.0f, &Options); Options.HSplitTop(50.0f, &Button, &Options); UI()->DoLabelScaled(&Button, Localize("Player options"), 34.0f, -1); // headline Options.HSplitTop(34.0f, &ButtonBar, &Options); ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar); UI()->DoLabelScaled(&Player, Localize("Player"), 24.0f, -1); ButtonBar.HMargin(1.0f, &ButtonBar); float Width = ButtonBar.h*2.0f; ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_MUTE); IGraphics::CQuadItem QuadItem(Button.x, Button.y, Button.w, Button.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); ButtonBar.VSplitLeft(20.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_FRIEND); QuadItem = IGraphics::CQuadItem(Button.x, Button.y, Button.w, Button.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // options static int s_aPlayerIDs[MAX_CLIENTS][2] = {{0}}; int Teams[3] = { TEAM_RED, TEAM_BLUE, TEAM_SPECTATORS }; for(int Team = 0; Team < 3; ++Team) { for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) { if(i == m_pClient->m_LocalClientID || !m_pClient->m_aClients[i].m_Active || m_pClient->m_aClients[i].m_Team != Teams[Team]) continue; Options.HSplitTop(28.0f, &ButtonBar, &Options); if(Count++%2 == 0) RenderTools()->DrawUIRect(&ButtonBar, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar); // player info Player.VSplitLeft(28.0f, &Button, &Player); CTeeRenderInfo Info = m_pClient->m_aClients[i].m_RenderInfo; Info.m_Size = Button.h; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Button.x+Button.h/2, Button.y+Button.h/2)); Player.HSplitTop(1.5f, 0, &Player); Player.VSplitMid(&Player, &Button); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Player.x, Player.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Player.w; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[i].m_aName, -1); TextRender()->SetCursor(&Cursor, Button.x,Button.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[i].m_aClan, -1); // ignore button ButtonBar.HMargin(2.0f, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button); Button.VSplitLeft(Button.h, &Button, 0); if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[i].m_Friend) DoButton_Toggle(&s_aPlayerIDs[i][0], 1, &Button, false); else if(DoButton_Toggle(&s_aPlayerIDs[i][0], m_pClient->m_aClients[i].m_ChatIgnore, &Button, true)) m_pClient->m_aClients[i].m_ChatIgnore ^= 1; // friend button ButtonBar.VSplitLeft(20.0f, &Button, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button); Button.VSplitLeft(Button.h, &Button, 0); if(DoButton_Toggle(&s_aPlayerIDs[i][1], m_pClient->m_aClients[i].m_Friend, &Button, true)) { if(m_pClient->m_aClients[i].m_Friend) m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[i].m_aName, m_pClient->m_aClients[i].m_aClan); else m_pClient->Friends()->AddFriend(m_pClient->m_aClients[i].m_aName, m_pClient->m_aClients[i].m_aClan); m_pClient->m_aClients[i].m_Friend ^= 1; } } } }
void CMenus::RenderDemoPlayer(CUIRect MainView) { const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); const float SeekBarHeight = 15.0f; const float ButtonbarHeight = 20.0f; const float NameBarHeight = 20.0f; const float Margins = 5.0f; float TotalHeight; if(m_MenuActive) TotalHeight = SeekBarHeight+ButtonbarHeight+NameBarHeight+Margins*3; else TotalHeight = SeekBarHeight+Margins*2; MainView.HSplitBottom(TotalHeight, 0, &MainView); MainView.VSplitLeft(50.0f, 0, &MainView); MainView.VSplitRight(450.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f); MainView.Margin(5.0f, &MainView); CUIRect SeekBar, ButtonBar, NameBar; int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick; int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick; if(m_MenuActive) { MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); ButtonBar.HSplitTop(Margins, 0, &ButtonBar); ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar); NameBar.HSplitTop(4.0f, 0, &NameBar); } else SeekBar = MainView; // do seekbar { static int s_SeekBarID = 0; void *id = &s_SeekBarID; char aBuffer[128]; RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f); float Amount = CurrentTick/(float)TotalTicks; CUIRect FilledBar = SeekBar; FilledBar.w = 10.0f + (FilledBar.w-10.0f)*Amount; RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f); str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d", CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60, TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60); UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h*0.70f, 0); // do the logic int Inside = UI()->MouseInside(&SeekBar); if(UI()->ActiveItem() == id) { if(!UI()->MouseButton(0)) UI()->SetActiveItem(0); else { static float PrevAmount = 0.0f; float Amount = (UI()->MouseX()-SeekBar.x)/(float)SeekBar.w; if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount-Amount) >= 0.01f) { PrevAmount = Amount; m_pClient->OnReset(); m_pClient->m_SuppressEvents = true; DemoPlayer()->SetPos(Amount); m_pClient->m_SuppressEvents = false; } } } else if(UI()->HotItem() == id) { if(UI()->MouseButton(0)) UI()->SetActiveItem(id); } if(Inside) UI()->SetHotItem(id); } if(CurrentTick == TotalTicks) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } bool IncreaseDemoSpeed = false, DecreaseDemoSpeed = false; if(m_MenuActive) { // do buttons CUIRect Button; // combined play and pause button ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_PlayPauseButton = 0; if(!pInfo->m_Paused) { if(DoButton_Sprite(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PAUSE, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Pause(); } else { if(DoButton_Sprite(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PLAY, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Unpause(); } // stop button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_ResetButton = 0; if(DoButton_Sprite(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, false, &Button, CUI::CORNER_ALL)) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } // slowdown ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SlowDownButton = 0; if(DoButton_Sprite(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, 0, &Button, CUI::CORNER_ALL) || Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) DecreaseDemoSpeed = true; // fastforward ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_FastForwardButton = 0; if(DoButton_Sprite(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, 0, &Button, CUI::CORNER_ALL)) IncreaseDemoSpeed = true; // speed meter ButtonBar.VSplitLeft(Margins*3, 0, &ButtonBar); char aBuffer[64]; if(pInfo->m_Speed >= 1.0f) str_format(aBuffer, sizeof(aBuffer), "x%.0f", pInfo->m_Speed); else str_format(aBuffer, sizeof(aBuffer), "x%.2f", pInfo->m_Speed); UI()->DoLabel(&ButtonBar, aBuffer, Button.h*0.7f, -1); // close button ButtonBar.VSplitRight(ButtonbarHeight*3, &ButtonBar, &Button); static int s_ExitButton = 0; if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), 0, &Button)) Client()->Disconnect(); // demo name char aBuf[128]; str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), DemoPlayer()->GetDemoName()); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y, Button.h*0.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = MainView.w; TextRender()->TextEx(&Cursor, aBuf, -1); } if(IncreaseDemoSpeed || Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) { if(pInfo->m_Speed < 0.1f) DemoPlayer()->SetSpeed(0.1f); else if(pInfo->m_Speed < 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed < 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed < 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed < 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed < 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed < 4.0f) DemoPlayer()->SetSpeed(4.0f); else DemoPlayer()->SetSpeed(8.0f); } else if(DecreaseDemoSpeed || Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) { if(pInfo->m_Speed > 4.0f) DemoPlayer()->SetSpeed(4.0f); else if(pInfo->m_Speed > 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed > 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed > 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed > 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed > 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed > 0.1f) DemoPlayer()->SetSpeed(0.1f); else DemoPlayer()->SetSpeed(0.05f); } }
void CMenus::RenderDemoPlayer(CUIRect MainView) { const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); const float SeekBarHeight = 15.0f; const float ButtonbarHeight = 20.0f; const float NameBarHeight = 20.0f; const float Margins = 5.0f; float TotalHeight; static int64 LastSpeedChange = 0; // render popups if (m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE) { CUIRect Screen = *UI()->Screen(); CUIRect Box, Part, Part2; Box = Screen; Box.VMargin(150.0f/UI()->Scale(), &Box); #if defined(__ANDROID__) Box.HMargin(100.0f/UI()->Scale(), &Box); #else Box.HMargin(150.0f/UI()->Scale(), &Box); #endif // render the box RenderTools()->DrawUIRect(&Box, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); UI()->DoLabelScaled(&Part, Localize("Select a name"), 24.f, 0); Box.HSplitTop(20.f/UI()->Scale(), &Part, &Box); Box.HSplitTop(24.f/UI()->Scale(), &Part, &Box); Part.VMargin(20.f/UI()->Scale(), &Part); UI()->DoLabelScaled(&Part, m_aDemoPlayerPopupHint, 24.f, 0); CUIRect Label, TextBox, Ok, Abort; Box.HSplitBottom(20.f, &Box, &Part); #if defined(__ANDROID__) Box.HSplitBottom(60.f, &Box, &Part); #else Box.HSplitBottom(24.f, &Box, &Part); #endif Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &Ok); Ok.VMargin(20.0f, &Ok); Abort.VMargin(20.0f, &Abort); static int s_RemoveChat = 0; static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_DemoPlayerState = DEMOPLAYER_NONE; static int s_ButtonOk = 0; if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || m_EnterPressed) { if (str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0) str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name"), sizeof(m_aDemoPlayerPopupHint)); else { m_DemoPlayerState = DEMOPLAYER_NONE; int len = str_length(m_aCurrentDemoFile); if(len < 5 || str_comp_nocase(&m_aCurrentDemoFile[len-5], ".demo")) str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile)); char aPath[512]; str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile); Client()->DemoSlice(aPath, s_RemoveChat); } } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(60.f, &Box, &Part2); #if defined(__ANDROID__) Box.HSplitBottom(60.f, &Box, &Part2); Box.HSplitBottom(60.f, &Box, &Part); #else Box.HSplitBottom(24.f, &Box, &Part2); Box.HSplitBottom(24.f, &Box, &Part); #endif Part2.VSplitLeft(60.0f, 0, &Label); if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &Label)) { s_RemoveChat ^= 1; } Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(120.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("New name:"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset); } // handle mousewheel independent of active menu if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) { if(pInfo->m_Speed < 0.1f) DemoPlayer()->SetSpeed(0.1f); else if(pInfo->m_Speed < 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed < 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed < 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed < 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed < 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed < 4.0f) DemoPlayer()->SetSpeed(4.0f); else DemoPlayer()->SetSpeed(8.0f); LastSpeedChange = time_get(); } else if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) { if(pInfo->m_Speed > 4.0f) DemoPlayer()->SetSpeed(4.0f); else if(pInfo->m_Speed > 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed > 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed > 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed > 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed > 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed > 0.1f) DemoPlayer()->SetSpeed(0.1f); else DemoPlayer()->SetSpeed(0.05f); LastSpeedChange = time_get(); } TotalHeight = SeekBarHeight+ButtonbarHeight+NameBarHeight+Margins*3; // render speed info if (g_Config.m_ClDemoShowSpeed && time_get() - LastSpeedChange < time_freq() * 1) { CUIRect Screen = *UI()->Screen(); char aSpeedBuf[256]; str_format(aSpeedBuf, sizeof(aSpeedBuf), "×%.2f", pInfo->m_Speed); TextRender()->Text(0, 120.0f, Screen.y+Screen.h - 120.0f - TotalHeight, 60.0f, aSpeedBuf, -1); } if(!m_MenuActive) return; MainView.HSplitBottom(TotalHeight, 0, &MainView); MainView.VSplitLeft(50.0f, 0, &MainView); MainView.VSplitLeft(450.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f); MainView.Margin(5.0f, &MainView); CUIRect SeekBar, ButtonBar, NameBar; int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick; int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick; MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); ButtonBar.HSplitTop(Margins, 0, &ButtonBar); ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar); NameBar.HSplitTop(4.0f, 0, &NameBar); // do seekbar { static int s_SeekBarID = 0; void *id = &s_SeekBarID; char aBuffer[128]; // draw seek bar RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 5.0f); // draw filled bar float Amount = CurrentTick/(float)TotalTicks; CUIRect FilledBar = SeekBar; FilledBar.w = 10.0f + (FilledBar.w-10.0f)*Amount; RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 5.0f); // draw markers for(int i = 0; i < pInfo->m_NumTimelineMarkers; i++) { float Ratio = (pInfo->m_aTimelineMarkers[i]-pInfo->m_FirstTick) / (float)TotalTicks; Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); IGraphics::CQuadItem QuadItem(SeekBar.x + (SeekBar.w-10.0f)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // draw slice markers // begin if (g_Config.m_ClDemoSliceBegin != -1) { float Ratio = (g_Config.m_ClDemoSliceBegin-pInfo->m_FirstTick) / (float)TotalTicks; Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 0.0f, 0.0f, 1.0f); IGraphics::CQuadItem QuadItem(10.0f + SeekBar.x + (SeekBar.w-10.0f)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // end if (g_Config.m_ClDemoSliceEnd != -1) { float Ratio = (g_Config.m_ClDemoSliceEnd-pInfo->m_FirstTick) / (float)TotalTicks; Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 0.0f, 0.0f, 1.0f); IGraphics::CQuadItem QuadItem(10.0f + SeekBar.x + (SeekBar.w-10.0f)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // draw time str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d", CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60, TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60); UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h*0.70f, 0); // do the logic int Inside = UI()->MouseInside(&SeekBar); if(UI()->ActiveItem() == id) { if(!UI()->MouseButton(0)) UI()->SetActiveItem(0); else { static float PrevAmount = 0.0f; float Amount = (UI()->MouseX()-SeekBar.x)/(float)SeekBar.w; if(Input()->KeyPressed(KEY_LSHIFT) || Input()->KeyPressed(KEY_RSHIFT)) { Amount = PrevAmount + (Amount-PrevAmount) * 0.05f; if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount-Amount) >= 0.0001f) { //PrevAmount = Amount; m_pClient->OnReset(); m_pClient->m_SuppressEvents = true; DemoPlayer()->SetPos(Amount); m_pClient->m_SuppressEvents = false; m_pClient->m_pMapLayersBackGround->EnvelopeUpdate(); m_pClient->m_pMapLayersForeGround->EnvelopeUpdate(); } } else { if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount-Amount) >= 0.001f) { PrevAmount = Amount; m_pClient->OnReset(); m_pClient->m_SuppressEvents = true; DemoPlayer()->SetPos(Amount); m_pClient->m_SuppressEvents = false; m_pClient->m_pMapLayersBackGround->EnvelopeUpdate(); m_pClient->m_pMapLayersForeGround->EnvelopeUpdate(); } } } } else if(UI()->HotItem() == id) { if(UI()->MouseButton(0)) UI()->SetActiveItem(id); } if(Inside) UI()->SetHotItem(id); } if(CurrentTick == TotalTicks) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } bool IncreaseDemoSpeed = false, DecreaseDemoSpeed = false; // do buttons CUIRect Button; // combined play and pause button ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_PlayPauseButton = 0; if(!pInfo->m_Paused) { if(DoButton_Sprite(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PAUSE, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Pause(); } else { if(DoButton_Sprite(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PLAY, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Unpause(); } // stop button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_ResetButton = 0; if(DoButton_Sprite(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, false, &Button, CUI::CORNER_ALL)) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } // slowdown ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SlowDownButton = 0; if(DoButton_Sprite(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, 0, &Button, CUI::CORNER_ALL) || Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) DecreaseDemoSpeed = true; // fastforward ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_FastForwardButton = 0; if(DoButton_Sprite(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, 0, &Button, CUI::CORNER_ALL)) IncreaseDemoSpeed = true; // speed meter ButtonBar.VSplitLeft(Margins*3, 0, &ButtonBar); char aBuffer[64]; if(pInfo->m_Speed >= 1.0f) str_format(aBuffer, sizeof(aBuffer), "×%.0f", pInfo->m_Speed); else str_format(aBuffer, sizeof(aBuffer), "×%.2f", pInfo->m_Speed); UI()->DoLabel(&ButtonBar, aBuffer, Button.h*0.7f, -1); // slice begin button ButtonBar.VSplitLeft(Margins*10, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SliceBeginButton = 0; if(DoButton_Sprite(&s_SliceBeginButton, IMAGE_DEMOBUTTONS2, SPRITE_DEMOBUTTON_SLICE_BEGIN, 0, &Button, CUI::CORNER_ALL)) Client()->DemoSliceBegin(); // slice end button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SliceEndButton = 0; if(DoButton_Sprite(&s_SliceEndButton, IMAGE_DEMOBUTTONS2, SPRITE_DEMOBUTTON_SLICE_END, 0, &Button, CUI::CORNER_ALL)) Client()->DemoSliceEnd(); // slice save button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static int s_SliceSaveButton = 0; if(DoButton_Sprite(&s_SliceSaveButton, IMAGE_FILEICONS, SPRITE_FILE_DEMO2, 0, &Button, CUI::CORNER_ALL)) { str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile)); m_aDemoPlayerPopupHint[0] = '\0'; m_DemoPlayerState = DEMOPLAYER_SLICE_SAVE; } // close button ButtonBar.VSplitRight(ButtonbarHeight*3, &ButtonBar, &Button); static int s_ExitButton = 0; if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), 0, &Button)) { Client()->Disconnect(); DemolistPopulate(); DemolistOnUpdate(false); } // demo name char aDemoName[64] = {0}; DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); char aBuf[128]; str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y, Button.h*0.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = MainView.w; TextRender()->TextEx(&Cursor, aBuf, -1); if(IncreaseDemoSpeed) { if(pInfo->m_Speed < 0.1f) DemoPlayer()->SetSpeed(0.1f); else if(pInfo->m_Speed < 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed < 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed < 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed < 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed < 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed < 4.0f) DemoPlayer()->SetSpeed(4.0f); else DemoPlayer()->SetSpeed(8.0f); LastSpeedChange = time_get(); } else if(DecreaseDemoSpeed) { if(pInfo->m_Speed > 4.0f) DemoPlayer()->SetSpeed(4.0f); else if(pInfo->m_Speed > 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed > 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed > 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed > 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed > 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed > 0.1f) DemoPlayer()->SetSpeed(0.1f); else DemoPlayer()->SetSpeed(0.05f); LastSpeedChange = time_get(); } }
void CMenus::RenderPlayers(CUIRect MainView) { CUIRect Button, ButtonBar, Options, Player; RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); // player options MainView.Margin(10.0f, &Options); RenderTools()->DrawUIRect(&Options, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); Options.Margin(10.0f, &Options); Options.HSplitTop(50.0f, &Button, &Options); UI()->DoLabelScaled(&Button, Localize("Player options"), 34.0f, -1); // headline Options.HSplitTop(34.0f, &ButtonBar, &Options); ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar); UI()->DoLabelScaled(&Player, Localize("Player"), 24.0f, -1); ButtonBar.HMargin(1.0f, &ButtonBar); float Width = ButtonBar.h*2.0f; ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_MUTE); IGraphics::CQuadItem QuadItem(Button.x, Button.y, Button.w, Button.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); ButtonBar.VSplitLeft(20.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_FRIEND); QuadItem = IGraphics::CQuadItem(Button.x, Button.y, Button.w, Button.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // options static int s_aPlayerIDs[MAX_CLIENTS][2] = {{0}}; for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) { if(!m_pClient->m_Snap.m_paInfoByTeam[i]) continue; int Index = m_pClient->m_Snap.m_paInfoByTeam[i]->m_ClientID; if(Index == m_pClient->m_Snap.m_LocalClientID) continue; Options.HSplitTop(28.0f, &ButtonBar, &Options); if(Count++%2 == 0) RenderTools()->DrawUIRect(&ButtonBar, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); ButtonBar.VSplitRight(220.0f, &Player, &ButtonBar); // player info Player.VSplitLeft(28.0f, &Button, &Player); CTeeRenderInfo Info = m_pClient->m_aClients[Index].m_RenderInfo; Info.m_Size = Button.h; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Button.x+Button.h/2, Button.y+Button.h/2)); Player.HSplitTop(1.5f, 0, &Player); Player.VSplitMid(&Player, &Button); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Player.x, Player.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Player.w; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[Index].m_aName, -1); TextRender()->SetCursor(&Cursor, Button.x,Button.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[Index].m_aClan, -1); // ignore button ButtonBar.HMargin(2.0f, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button); Button.VSplitLeft(Button.h, &Button, 0); if(DoButton_Toggle(&s_aPlayerIDs[Index][0], m_pClient->m_aClients[Index].m_ChatIgnore, &Button)) m_pClient->m_aClients[Index].m_ChatIgnore ^= 1; // friend button ButtonBar.VSplitLeft(20.0f, &Button, &ButtonBar); ButtonBar.VSplitLeft(Width, &Button, &ButtonBar); Button.VSplitLeft((Width-Button.h)/4.0f, 0, &Button); Button.VSplitLeft(Button.h, &Button, 0); if(DoButton_Toggle(&s_aPlayerIDs[Index][1], m_pClient->m_aClients[Index].m_Friend, &Button)) { if(m_pClient->m_aClients[Index].m_Friend) m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[Index].m_aName, m_pClient->m_aClients[Index].m_aClan); else m_pClient->Friends()->AddFriend(m_pClient->m_aClients[Index].m_aName, m_pClient->m_aClients[Index].m_aClan); } } /* CUIRect bars; votearea.HSplitTop(10.0f, 0, &votearea); votearea.HSplitTop(25.0f + 10.0f*3 + 25.0f, &votearea, &bars); RenderTools()->DrawUIRect(&votearea, color_tabbar_active, CUI::CORNER_ALL, 10.0f); votearea.VMargin(20.0f, &votearea); votearea.HMargin(10.0f, &votearea); votearea.HSplitBottom(35.0f, &votearea, &bars); if(gameclient.voting->is_voting()) { // do yes button votearea.VSplitLeft(50.0f, &button, &votearea); static int yes_button = 0; if(UI()->DoButton(&yes_button, "Yes", 0, &button, ui_draw_menu_button, 0)) gameclient.voting->vote(1); // do no button votearea.VSplitLeft(5.0f, 0, &votearea); votearea.VSplitLeft(50.0f, &button, &votearea); static int no_button = 0; if(UI()->DoButton(&no_button, "No", 0, &button, ui_draw_menu_button, 0)) gameclient.voting->vote(-1); // do time left votearea.VSplitRight(50.0f, &votearea, &button); char buf[256]; str_format(buf, sizeof(buf), "%d", gameclient.voting->seconds_left()); UI()->DoLabel(&button, buf, 24.0f, 0); // do description and command votearea.VSplitLeft(5.0f, 0, &votearea); UI()->DoLabel(&votearea, gameclient.voting->vote_description(), 14.0f, -1); votearea.HSplitTop(16.0f, 0, &votearea); UI()->DoLabel(&votearea, gameclient.voting->vote_command(), 10.0f, -1); // do bars bars.HSplitTop(10.0f, 0, &bars); bars.HMargin(5.0f, &bars); gameclient.voting->render_bars(bars, true); } else { UI()->DoLabel(&votearea, "No vote in progress", 18.0f, -1); }*/ }
void CMenus::RenderServerControl(CUIRect MainView) { static int s_ControlPage = 0; // render background CUIRect Bottom, Extended, TabBar, Button; MainView.HSplitTop(20.0f, &Bottom, &MainView); RenderTools()->DrawUIRect(&Bottom, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f); MainView.HSplitTop(20.0f, &TabBar, &MainView); RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_B, 10.0f); MainView.Margin(10.0f, &MainView); MainView.HSplitBottom(90.0f, &MainView, &Extended); // tab bar { TabBar.VSplitLeft(TabBar.w/3, &Button, &TabBar); static int s_Button0 = 0; if(DoButton_MenuTab(&s_Button0, Localize("Change settings"), s_ControlPage == 0, &Button, 0)) s_ControlPage = 0; TabBar.VSplitMid(&Button, &TabBar); static int s_Button1 = 0; if(DoButton_MenuTab(&s_Button1, Localize("Kick player"), s_ControlPage == 1, &Button, 0)) s_ControlPage = 1; static int s_Button2 = 0; if(DoButton_MenuTab(&s_Button2, Localize("Move player to spectators"), s_ControlPage == 2, &TabBar, 0)) s_ControlPage = 2; } // render page MainView.HSplitBottom(ms_ButtonHeight + 5*2, &MainView, &Bottom); Bottom.HMargin(5.0f, &Bottom); if(s_ControlPage == 0) RenderServerControlServer(MainView); else if(s_ControlPage == 1) RenderServerControlKick(MainView, false); else if(s_ControlPage == 2) RenderServerControlKick(MainView, true); // vote menu { CUIRect Button; Bottom.VSplitRight(120.0f, &Bottom, &Button); static int s_CallVoteButton = 0; if(DoButton_Menu(&s_CallVoteButton, Localize("Call vote"), 0, &Button)) { if(s_ControlPage == 0) m_pClient->m_pVoting->CallvoteOption(m_CallvoteSelectedOption, m_aCallvoteReason); else if(s_ControlPage == 1) { if(m_CallvoteSelectedPlayer >= 0 && m_CallvoteSelectedPlayer < MAX_CLIENTS && m_pClient->m_Snap.m_paPlayerInfos[m_CallvoteSelectedPlayer]) { m_pClient->m_pVoting->CallvoteKick(m_CallvoteSelectedPlayer, m_aCallvoteReason); SetActive(false); } } else if(s_ControlPage == 2) { if(m_CallvoteSelectedPlayer >= 0 && m_CallvoteSelectedPlayer < MAX_CLIENTS && m_pClient->m_Snap.m_paPlayerInfos[m_CallvoteSelectedPlayer]) { m_pClient->m_pVoting->CallvoteSpectate(m_CallvoteSelectedPlayer, m_aCallvoteReason); SetActive(false); } } m_aCallvoteReason[0] = 0; } // render kick reason CUIRect Reason; Bottom.VSplitRight(40.0f, &Bottom, 0); Bottom.VSplitRight(160.0f, &Bottom, &Reason); Reason.HSplitTop(5.0f, 0, &Reason); const char *pLabel = Localize("Reason:"); UI()->DoLabelScaled(&Reason, pLabel, 14.0f, -1); float w = TextRender()->TextWidth(0, 14.0f, pLabel, -1); Reason.VSplitLeft(w+10.0f, 0, &Reason); static float s_Offset = 0.0f; DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, CUI::CORNER_ALL); // extended features (only available when authed in rcon) if(Client()->RconAuthed()) { // background Extended.Margin(10.0f, &Extended); Extended.HSplitTop(20.0f, &Bottom, &Extended); Extended.HSplitTop(5.0f, 0, &Extended); // force vote Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(120.0f, &Button, &Bottom); static int s_ForceVoteButton = 0; if(DoButton_Menu(&s_ForceVoteButton, Localize("Force vote"), 0, &Button)) { if(s_ControlPage == 0) m_pClient->m_pVoting->CallvoteOption(m_CallvoteSelectedOption, m_aCallvoteReason, true); else if(s_ControlPage == 1) { if(m_CallvoteSelectedPlayer >= 0 && m_CallvoteSelectedPlayer < MAX_CLIENTS && m_pClient->m_Snap.m_paPlayerInfos[m_CallvoteSelectedPlayer]) { m_pClient->m_pVoting->CallvoteKick(m_CallvoteSelectedPlayer, m_aCallvoteReason, true); SetActive(false); } } else if(s_ControlPage == 2) { if(m_CallvoteSelectedPlayer >= 0 && m_CallvoteSelectedPlayer < MAX_CLIENTS && m_pClient->m_Snap.m_paPlayerInfos[m_CallvoteSelectedPlayer]) { m_pClient->m_pVoting->CallvoteSpectate(m_CallvoteSelectedPlayer, m_aCallvoteReason, true); SetActive(false); } } m_aCallvoteReason[0] = 0; } if(s_ControlPage == 0) { // remove vote Bottom.VSplitRight(10.0f, &Bottom, 0); Bottom.VSplitRight(120.0f, 0, &Button); static int s_RemoveVoteButton = 0; if(DoButton_Menu(&s_RemoveVoteButton, Localize("Remove"), 0, &Button)) m_pClient->m_pVoting->RemovevoteOption(m_CallvoteSelectedOption); // add vote Extended.HSplitTop(20.0f, &Bottom, &Extended); Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(250.0f, &Button, &Bottom); UI()->DoLabelScaled(&Button, Localize("Vote description:"), 14.0f, -1); Bottom.VSplitLeft(20.0f, 0, &Button); UI()->DoLabelScaled(&Button, Localize("Vote command:"), 14.0f, -1); static char s_aVoteDescription[64] = {0}; static char s_aVoteCommand[512] = {0}; Extended.HSplitTop(20.0f, &Bottom, &Extended); Bottom.VSplitRight(10.0f, &Bottom, 0); Bottom.VSplitRight(120.0f, &Bottom, &Button); static int s_AddVoteButton = 0; if(DoButton_Menu(&s_AddVoteButton, Localize("Add"), 0, &Button)) if(s_aVoteDescription[0] != 0 && s_aVoteCommand[0] != 0) m_pClient->m_pVoting->AddvoteOption(s_aVoteDescription, s_aVoteCommand); Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(250.0f, &Button, &Bottom); static float s_OffsetDesc = 0.0f; DoEditBox(&s_aVoteDescription, &Button, s_aVoteDescription, sizeof(s_aVoteDescription), 14.0f, &s_OffsetDesc, false, CUI::CORNER_ALL); Bottom.VMargin(20.0f, &Button); static float s_OffsetCmd = 0.0f; DoEditBox(&s_aVoteCommand, &Button, s_aVoteCommand, sizeof(s_aVoteCommand), 14.0f, &s_OffsetCmd, false, CUI::CORNER_ALL); } } } }
void CMenus::RenderServerbrowserServerDetail(CUIRect View) { CUIRect ServerDetails = View; CUIRect ServerScoreBoard, ServerHeader; const CServerInfo *pSelectedServer = ServerBrowser()->SortedGet(m_SelectedIndex); //server_details.VSplitLeft(10.0f, 0x0, &server_details); // split off a piece to use for scoreboard ServerDetails.HSplitTop(140.0f, &ServerDetails, &ServerScoreBoard); ServerDetails.HSplitBottom(10.0f, &ServerDetails, 0x0); // server details CTextCursor Cursor; const float FontSize = 12.0f; ServerDetails.HSplitTop(20.0f, &ServerHeader, &ServerDetails); RenderTools()->DrawUIRect(&ServerHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerDetails, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); ServerHeader.VSplitLeft(8.0f, 0x0, &ServerHeader); UI()->DoLabelScaled(&ServerHeader, Localize("Server details"), FontSize+2.0f, -1); ServerDetails.VSplitLeft(5.0f, 0x0, &ServerDetails); ServerDetails.Margin(3.0f, &ServerDetails); if (pSelectedServer) { CUIRect Row; static CLocConstString s_aLabels[] = { "Version", // Localize - these strings are localized within CLocConstString "Game type", "Ping"}; CUIRect LeftColumn; CUIRect RightColumn; // { CUIRect Button; ServerDetails.HSplitBottom(20.0f, &ServerDetails, &Button); static int s_AddFavButton = 0; if(DoButton_CheckBox(&s_AddFavButton, Localize("Favorite"), pSelectedServer->m_Favorite, &Button)) { if(pSelectedServer->m_Favorite) ServerBrowser()->RemoveFavorite(pSelectedServer->m_NetAddr); else ServerBrowser()->AddFavorite(pSelectedServer->m_NetAddr); } } //UI()->DoLabel(&row, temp, font_size, -1); ServerDetails.VSplitLeft(5.0f, 0x0, &ServerDetails); ServerDetails.VSplitLeft(80.0f, &LeftColumn, &RightColumn); for (unsigned int i = 0; i < sizeof(s_aLabels) / sizeof(s_aLabels[0]); i++) { LeftColumn.HSplitTop(15.0f, &Row, &LeftColumn); UI()->DoLabelScaled(&Row, s_aLabels[i], FontSize, -1); } RightColumn.HSplitTop(15.0f, &Row, &RightColumn); TextRender()->SetCursor(&Cursor, Row.x, Row.y, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Row.w; TextRender()->TextEx(&Cursor, pSelectedServer->m_aVersion, -1); RightColumn.HSplitTop(15.0f, &Row, &RightColumn); TextRender()->SetCursor(&Cursor, Row.x, Row.y, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Row.w; TextRender()->TextEx(&Cursor, pSelectedServer->m_aGameType, -1); char aTemp[16]; str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_Latency); RightColumn.HSplitTop(15.0f, &Row, &RightColumn); TextRender()->SetCursor(&Cursor, Row.x, Row.y, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Row.w; TextRender()->TextEx(&Cursor, aTemp, -1); } // server scoreboard ServerScoreBoard.HSplitBottom(10.0f, &ServerScoreBoard, 0x0); ServerScoreBoard.HSplitTop(20.0f, &ServerHeader, &ServerScoreBoard); RenderTools()->DrawUIRect(&ServerHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerScoreBoard, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); ServerHeader.VSplitLeft(8.0f, 0x0, &ServerHeader); UI()->DoLabelScaled(&ServerHeader, Localize("Scoreboard"), FontSize+2.0f, -1); ServerScoreBoard.VSplitLeft(5.0f, 0x0, &ServerScoreBoard); ServerScoreBoard.Margin(3.0f, &ServerScoreBoard); if (pSelectedServer) { for (int i = 0; i < pSelectedServer->m_NumPlayers; i++) { CUIRect Row; char aTemp[16]; ServerScoreBoard.HSplitTop(16.0f, &Row, &ServerScoreBoard); str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_aPlayers[i].m_Score); TextRender()->SetCursor(&Cursor, Row.x, Row.y, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = 25.0f; TextRender()->TextEx(&Cursor, aTemp, -1); Row.VSplitLeft(25.0f, 0x0, &Row); TextRender()->SetCursor(&Cursor, Row.x, Row.y, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Row.w; const char *pName = pSelectedServer->m_aPlayers[i].m_aName; if(g_Config.m_BrFilterString[0]) { // highlight the parts that matches const char *s = str_find_nocase(pName, g_Config.m_BrFilterString); if(s) { TextRender()->TextEx(&Cursor, pName, (int)(s-pName)); TextRender()->TextColor(0.4f,0.4f,1,1); TextRender()->TextEx(&Cursor, s, str_length(g_Config.m_BrFilterString)); TextRender()->TextColor(1,1,1,1); TextRender()->TextEx(&Cursor, s+str_length(g_Config.m_BrFilterString), -1); } else TextRender()->TextEx(&Cursor, pName, -1); } else TextRender()->TextEx(&Cursor, pName, -1); } } }
void CMenus::RenderDemoPlayer(CUIRect MainView) { const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo(); const float SeekBarHeight = 15.0f; const float ButtonbarHeight = 20.0f; const float NameBarHeight = 20.0f; const float Margins = 5.0f; float TotalHeight; if(m_MenuActive) TotalHeight = SeekBarHeight+ButtonbarHeight+NameBarHeight+Margins*3; else TotalHeight = SeekBarHeight+Margins*2; MainView.HSplitBottom(TotalHeight, 0, &MainView); MainView.VSplitLeft(50.0f, 0, &MainView); MainView.VSplitRight(450.0f, &MainView, 0); if (m_SeekBarActive || m_MenuActive) // only draw the background if SeekBar or Menu is active RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_T, 10.0f); MainView.Margin(5.0f, &MainView); CUIRect SeekBar, ButtonBar, NameBar; int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick; int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick; // we can toggle the seekbar using CTRL if(!m_MenuActive && (Input()->KeyPress(KEY_LCTRL) || Input()->KeyPress(KEY_RCTRL))) { if (m_SeekBarActive) m_SeekBarActive = false; else { m_SeekBarActive = true; m_SeekBarActivatedTime = time_get(); // stores at which point of time the seekbar was activated, so we can automatically hide it after few seconds } } if(m_SeekBarActivatedTime < time_get() - 5*time_freq()) m_SeekBarActive = false; if(m_MenuActive) { MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar); ButtonBar.HSplitTop(Margins, 0, &ButtonBar); ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar); NameBar.HSplitTop(4.0f, 0, &NameBar); m_SeekBarActive = true; m_SeekBarActivatedTime = time_get(); } else SeekBar = MainView; // do seekbar if(m_SeekBarActive || m_MenuActive) { static int s_SeekBarID = 0; void *id = &s_SeekBarID; char aBuffer[128]; const float Rounding = 5.0f; // draw seek bar RenderTools()->DrawUIRect(&SeekBar, vec4(0,0,0,0.5f), CUI::CORNER_ALL, Rounding); // draw filled bar float Amount = CurrentTick/(float)TotalTicks; CUIRect FilledBar = SeekBar; FilledBar.w = max(2*Rounding, FilledBar.w*Amount); RenderTools()->DrawUIRect(&FilledBar, vec4(1,1,1,0.5f), CUI::CORNER_ALL, Rounding); // draw markers for(int i = 0; i < pInfo->m_NumTimelineMarkers; i++) { float Ratio = (pInfo->m_aTimelineMarkers[i]-pInfo->m_FirstTick) / (float)TotalTicks; Graphics()->TextureClear(); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f); IGraphics::CQuadItem QuadItem(SeekBar.x + (SeekBar.w-2*Rounding)*Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // draw time str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d", CurrentTick/SERVER_TICK_SPEED/60, (CurrentTick/SERVER_TICK_SPEED)%60, TotalTicks/SERVER_TICK_SPEED/60, (TotalTicks/SERVER_TICK_SPEED)%60); UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h*0.70f, CUI::ALIGN_CENTER); // do the logic int Inside = UI()->MouseInside(&SeekBar); if(UI()->CheckActiveItem(id)) { if(!UI()->MouseButton(0)) UI()->SetActiveItem(0); else { static float PrevAmount = 0.0f; float Amount = (UI()->MouseX()-SeekBar.x)/(float)SeekBar.w; if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount-Amount) >= (1.0f/UI()->Screen()->w)) { PrevAmount = Amount; m_pClient->OnReset(); m_pClient->m_SuppressEvents = true; DemoPlayer()->SetPos(Amount); m_pClient->m_SuppressEvents = false; m_pClient->m_pMapLayersBackGround->EnvelopeUpdate(); m_pClient->m_pMapLayersForeGround->EnvelopeUpdate(); } } } else if(UI()->HotItem() == id) { if(UI()->MouseButton(0)) UI()->SetActiveItem(id); } if(Inside) UI()->SetHotItem(id); } if(CurrentTick == TotalTicks) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } bool IncreaseDemoSpeed = false, DecreaseDemoSpeed = false; //add spacebar for toggling Play/Pause if(Input()->KeyPress(KEY_SPACE)) { if(!pInfo->m_Paused) DemoPlayer()->Pause(); else DemoPlayer()->Unpause(); } if(m_MenuActive) { // do buttons CUIRect Button; // combined play and pause button ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_PlayPauseButton; if(!pInfo->m_Paused) { if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PAUSE, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Pause(); } else { if(DoButton_SpriteID(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_PLAY, false, &Button, CUI::CORNER_ALL)) DemoPlayer()->Unpause(); } // stop button ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_ResetButton; if(DoButton_SpriteID(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, false, &Button, CUI::CORNER_ALL)) { m_pClient->OnReset(); DemoPlayer()->Pause(); DemoPlayer()->SetPos(0); } // slowdown ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_SlowDownButton; if(DoButton_SpriteID(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, false, &Button, CUI::CORNER_ALL)) DecreaseDemoSpeed = true; // fastforward ButtonBar.VSplitLeft(Margins, 0, &ButtonBar); ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar); static CButtonContainer s_FastForwardButton; if(DoButton_SpriteID(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, false, &Button, CUI::CORNER_ALL)) IncreaseDemoSpeed = true; // speed meter ButtonBar.VSplitLeft(Margins*3, 0, &ButtonBar); char aBuffer[64]; if(pInfo->m_Speed >= 1.0f) str_format(aBuffer, sizeof(aBuffer), "x%.0f", pInfo->m_Speed); else str_format(aBuffer, sizeof(aBuffer), "x%.2f", pInfo->m_Speed); UI()->DoLabel(&ButtonBar, aBuffer, Button.h*0.7f, CUI::ALIGN_LEFT); // close button ButtonBar.VSplitRight(ButtonbarHeight*3, &ButtonBar, &Button); static CButtonContainer s_ExitButton; if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), &Button)) Client()->Disconnect(); // demo name char aDemoName[64] = {0}; DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName)); char aBuf[128]; str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName); CTextCursor Cursor; TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y, Button.h*0.5f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = MainView.w; TextRender()->TextEx(&Cursor, aBuf, -1); } if(IncreaseDemoSpeed || Input()->KeyPress(KEY_MOUSE_WHEEL_UP) || Input()->KeyPress(KEY_PLUS) || Input()->KeyPress(KEY_KP_PLUS)) { if(pInfo->m_Speed < 0.1f) DemoPlayer()->SetSpeed(0.1f); else if(pInfo->m_Speed < 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed < 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed < 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed < 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed < 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed < 4.0f) DemoPlayer()->SetSpeed(4.0f); else DemoPlayer()->SetSpeed(8.0f); } else if(DecreaseDemoSpeed || Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) || Input()->KeyPress(KEY_MINUS) || Input()->KeyPress(KEY_KP_MINUS)) { if(pInfo->m_Speed > 4.0f) DemoPlayer()->SetSpeed(4.0f); else if(pInfo->m_Speed > 2.0f) DemoPlayer()->SetSpeed(2.0f); else if(pInfo->m_Speed > 1.0f) DemoPlayer()->SetSpeed(1.0f); else if(pInfo->m_Speed > 0.75f) DemoPlayer()->SetSpeed(0.75f); else if(pInfo->m_Speed > 0.5f) DemoPlayer()->SetSpeed(0.5f); else if(pInfo->m_Speed > 0.25f) DemoPlayer()->SetSpeed(0.25f); else if(pInfo->m_Speed > 0.1f) DemoPlayer()->SetSpeed(0.1f); else DemoPlayer()->SetSpeed(0.05f); } }
void CScoreboard::RenderScoreboard(float x, float y, float w, int Team, const char *pTitle) { if(Team == TEAM_SPECTATORS) return; float h = 430.0f; if(!pTitle) h = 760.0f; CUIRect area; area.x = x; area.y = y; area.w = w; area.h = h; Graphics()->BlendNormal(); Graphics()->TextureSet(-1); // render title CUIRect rTitle; area.HSplitTop(60.0f, &rTitle, &area); float TitleFontsize = 40.0f; if(!pTitle) { if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) pTitle = Localize("Game over"); else pTitle = Localize("Score board"); RenderTools()->DrawUIRect(&rTitle, HexToVec4(g_Config.m_hcContainerHeaderBackgroundColor), CUI::CORNER_T, 10.0f); } else { if (Team == TEAM_RED) RenderTools()->DrawUIRect(&rTitle, vec4(1.0f, 0.0f, 0.0f, 0.5f), CUI::CORNER_T, 10.0f); if (Team == TEAM_BLUE) RenderTools()->DrawUIRect(&rTitle, vec4(0.0f, 0.0f, 1.0f, 0.5f), CUI::CORNER_T, 10.0f); } rTitle.Margin(10.0f, &rTitle); char aBuf[128] = {0}; if(m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_TEAMS) { if(m_pClient->m_Snap.m_pGameDataObj) { int Score = Team == TEAM_RED ? m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed : m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue; str_format(aBuf, sizeof(aBuf), "%d", Score); } } else { if(m_pClient->m_Snap.m_SpecInfo.m_Active && m_pClient->m_Snap.m_SpecInfo.m_SpectatorID != SPEC_FREEVIEW && m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID]) { int Score = m_pClient->m_Snap.m_paPlayerInfos[m_pClient->m_Snap.m_SpecInfo.m_SpectatorID]->m_Score; str_format(aBuf, sizeof(aBuf), "%d", Score); } else if(m_pClient->m_Snap.m_pLocalInfo) { int Score = m_pClient->m_Snap.m_pLocalInfo->m_Score; str_format(aBuf, sizeof(aBuf), "%d", Score); } } float tw = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1); CUIRect rTitlePoints; rTitle.VSplitRight(tw+5.0f, 0x0, &rTitlePoints); TextRender()->Text(0, rTitlePoints.x, rTitlePoints.y-5.0f, TitleFontsize, aBuf, -1); // calculate measurements x += 10.0f; float LineHeight = 40.0f; float TeeSizeMod = 0.8f; float Spacing = 0.0f; float ScoreOffset = x+10.0f, ScoreLength = 60.0f; float TeeOffset = area.x+90.0f, TeeLength = 60*TeeSizeMod; float NameOffset = TeeOffset+TeeLength, NameLength = 300.0f-TeeLength; float PingOffset = x+610.0f, PingLength = 65.0f; float CountryOffset = PingOffset-(LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f, CountryLength = (LineHeight-Spacing-TeeSizeMod*5.0f)*2.0f; float ClanOffset = x+370.0f, ClanLength = 230.0f-CountryLength; // render headlines CUIRect rHeadLines, rLabel; area.HSplitTop(40.0f, &rHeadLines, &area); RenderTools()->DrawUIRect(&rHeadLines, HexToVec4(g_Config.m_hcListHeaderBackgroundColor), 0, 0.0f); rHeadLines.Margin(5.0f,&rHeadLines); y += 50.0f; float HeadlineFontsize = 22.0f; rHeadLines.VSplitLeft(90.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Score"), -1); rHeadLines.VSplitLeft(335.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Name"), -1); rHeadLines.VSplitLeft(210.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Clan"), -1); rHeadLines.VSplitLeft(80.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Ping"), -1); RenderTools()->DrawUIRect(&area, HexToVec4(g_Config.m_hcContainerBackgroundColor), CUI::CORNER_B, 10.0f); // render player entries float FontSize = 24.0f; CTextCursor Cursor; x = area.x; y = area.y; int nPlayers = 0; for(int i = 0; i < MAX_CLIENTS; i++) { // make sure that we render the correct team const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByScore[i]; if(!pInfo || pInfo->m_Team != Team) continue; nPlayers++; // background so it's easy to find the local player or the followed one in spectator mode if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID)) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRectExt(x, y, w, LineHeight, 0.0f, 0); Graphics()->QuadsEnd(); } // score str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ScoreLength; TextRender()->TextEx(&Cursor, aBuf, -1); // flag if ((m_pClient->m_Snap.m_pGameInfoObj->m_GameFlags&GAMEFLAG_FLAGS) && m_pClient->m_Snap.m_pGameDataObj && (m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierRed == pInfo->m_ClientID || m_pClient->m_Snap.m_pGameDataObj->m_FlagCarrierBlue == pInfo->m_ClientID)) { Graphics()->BlendNormal(); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_FLAGS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(pInfo->m_Team==TEAM_RED ? SPRITE_FLAG_BLUE03 : SPRITE_FLAG_RED03, SPRITE_FLAG_FLIP_X); float Size = LineHeight; IGraphics::CQuadItem QuadItem(TeeOffset+0.0f, y-5.0f-Spacing/2.0f+1.0f, Size/2.0f, Size); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); } // avatar CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo; TeeInfo.m_Size *= TeeSizeMod; RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2+1.0f)); // name if (g_Config.m_hcColorClan && m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aClan[0] != 0 && str_comp_nocase(m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aClan) == 0) //H-Client TextRender()->TextColor(0.7f, 0.7f, 0.2f, 1.0f); TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = NameLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); // clan tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2-5.0f, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ClanLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); // country flag Graphics()->TextureSet(m_pClient->m_pCountryFlags->GetByCountryCode(m_pClient->m_aClients[pInfo->m_ClientID].m_Country)->m_Texture); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f); IGraphics::CQuadItem QuadItem(CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // ping //H-Client const int maxLatency = 200; vec3 Rgb = HslToRgb(vec3(1.0f, 1.0f, 0.5f)); if (pInfo->m_Latency <= maxLatency) Rgb = HslToRgb(vec3((((maxLatency - pInfo->m_Latency) * 0.35f) / maxLatency), 1.0f, 0.5f)); TextRender()->TextColor(Rgb.r, Rgb.g, Rgb.b, 1.0f); // str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = PingLength; TextRender()->TextEx(&Cursor, aBuf, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); y += LineHeight+Spacing; } //Title char aTitle[128]={0}; str_format(aTitle, sizeof(aTitle), "%s [%d]", pTitle, nPlayers); TextRender()->Text(0, rTitle.x, rTitle.y-5.0f, TitleFontsize, aTitle, -1); }
void CMenus::RenderServerbrowserServerList(CUIRect View) { CUIRect Headers; CUIRect Status; View.HSplitTop(ms_ListheaderHeight, &Headers, &View); View.HSplitBottom(28.0f, &View, &Status); // split of the scrollbar RenderTools()->DrawUIRect(&Headers, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); Headers.VSplitRight(20.0f, &Headers, 0); struct CColumn { int m_ID; int m_Sort; CLocConstString m_Caption; int m_Direction; float m_Width; int m_Flags; CUIRect m_Rect; CUIRect m_Spacer; }; enum { FIXED=1, SPACER=2, COL_FLAG_LOCK=0, COL_FLAG_PURE, COL_FLAG_FAV, COL_NAME, COL_GAMETYPE, COL_MAP, COL_PLAYERS, COL_PING, COL_VERSION, }; static CColumn s_aCols[] = { {-1, -1, " ", -1, 2.0f, 0, {0}, {0}}, {COL_FLAG_LOCK, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_FLAG_PURE, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_FLAG_FAV, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_NAME, IServerBrowser::SORT_NAME, "Name", 0, 300.0f, 0, {0}, {0}}, // Localize - these strings are localized within CLocConstString {COL_GAMETYPE, IServerBrowser::SORT_GAMETYPE, "Type", 1, 50.0f, 0, {0}, {0}}, {COL_MAP, IServerBrowser::SORT_MAP, "Map", 1, 100.0f, 0, {0}, {0}}, {COL_PLAYERS, IServerBrowser::SORT_NUMPLAYERS, "Players", 1, 60.0f, 0, {0}, {0}}, {-1, -1, " ", 1, 10.0f, 0, {0}, {0}}, {COL_PING, IServerBrowser::SORT_PING, "Ping", 1, 40.0f, FIXED, {0}, {0}}, }; // This is just for scripts/update_localization.py to work correctly (all other strings are already Localize()'d somewhere else). Don't remove! // Localize("Type"); int NumCols = sizeof(s_aCols)/sizeof(CColumn); // do layout for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == -1) { Headers.VSplitLeft(s_aCols[i].m_Width, &s_aCols[i].m_Rect, &Headers); if(i+1 < NumCols) { //Cols[i].flags |= SPACER; Headers.VSplitLeft(2, &s_aCols[i].m_Spacer, &Headers); } } } for(int i = NumCols-1; i >= 0; i--) { if(s_aCols[i].m_Direction == 1) { Headers.VSplitRight(s_aCols[i].m_Width, &Headers, &s_aCols[i].m_Rect); Headers.VSplitRight(2, &Headers, &s_aCols[i].m_Spacer); } } for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == 0) s_aCols[i].m_Rect = Headers; } // do headers for(int i = 0; i < NumCols; i++) { if(DoButton_GridHeader(s_aCols[i].m_Caption, s_aCols[i].m_Caption, g_Config.m_BrSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect)) { if(s_aCols[i].m_Sort != -1) { if(g_Config.m_BrSort == s_aCols[i].m_Sort) g_Config.m_BrSortOrder ^= 1; else g_Config.m_BrSortOrder = 0; g_Config.m_BrSort = s_aCols[i].m_Sort; } } } RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.15f), 0, 0); CUIRect Scroll; View.VSplitRight(15, &View, &Scroll); int NumServers = ServerBrowser()->NumSortedServers(); // display important messages in the middle of the screen so no // users misses it { CUIRect MsgBox = View; MsgBox.y += View.h/3; if(m_ActivePage == PAGE_INTERNET && ServerBrowser()->IsRefreshingMasters()) UI()->DoLabelScaled(&MsgBox, Localize("Refreshing master servers"), 16.0f, 0); else if(!ServerBrowser()->NumServers()) UI()->DoLabelScaled(&MsgBox, Localize("No servers found"), 16.0f, 0); else if(ServerBrowser()->NumServers() && !NumServers) UI()->DoLabelScaled(&MsgBox, Localize("No servers match your filter criteria"), 16.0f, 0); } int Num = (int)(View.h/s_aCols[0].m_Rect.h) + 1; static int s_ScrollBar = 0; static float s_ScrollValue = 0; Scroll.HMargin(5.0f, &Scroll); s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); int ScrollNum = NumServers-Num+1; if(ScrollNum > 0) { if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) s_ScrollValue += 3.0f/ScrollNum; } else ScrollNum = 0; if(m_SelectedIndex > -1) { for(int i = 0; i < m_NumInputEvents; i++) { int NewIndex = -1; if(m_aInputEvents[i].m_Flags&IInput::FLAG_PRESS) { if(m_aInputEvents[i].m_Key == KEY_DOWN) NewIndex = m_SelectedIndex + 1; if(m_aInputEvents[i].m_Key == KEY_UP) NewIndex = m_SelectedIndex - 1; } if(NewIndex > -1 && NewIndex < NumServers) { //scroll float IndexY = View.y - s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h + NewIndex*s_aCols[0].m_Rect.h; int Scroll = View.y > IndexY ? -1 : View.y+View.h < IndexY+s_aCols[0].m_Rect.h ? 1 : 0; if(Scroll) { if(Scroll < 0) { int NumScrolls = (View.y-IndexY+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue -= (1.0f/ScrollNum)*NumScrolls; } else { int NumScrolls = (IndexY+s_aCols[0].m_Rect.h-(View.y+View.h)+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue += (1.0f/ScrollNum)*NumScrolls; } } m_SelectedIndex = NewIndex; const CServerInfo *pItem = ServerBrowser()->SortedGet(m_SelectedIndex); str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress, sizeof(g_Config.m_UiServerAddress)); } } } if(s_ScrollValue < 0) s_ScrollValue = 0; if(s_ScrollValue > 1) s_ScrollValue = 1; // set clipping UI()->ClipEnable(&View); CUIRect OriginalView = View; View.y -= s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h; int NewSelected = -1; int NumPlayers = 0; m_SelectedIndex = -1; for (int i = 0; i < NumServers; i++) { const CServerInfo *pItem = ServerBrowser()->SortedGet(i); NumPlayers += pItem->m_NumPlayers; } for (int i = 0; i < NumServers; i++) { int ItemIndex = i; const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); CUIRect Row; CUIRect SelectHitBox; int Selected = str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0; //selected_index==ItemIndex; View.HSplitTop(17.0f, &Row, &View); SelectHitBox = Row; if(Selected) m_SelectedIndex = i; // make sure that only those in view can be selected if(Row.y+Row.h > OriginalView.y && Row.y < OriginalView.y+OriginalView.h) { if(Selected) { CUIRect r = Row; r.Margin(1.5f, &r); RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f); } // clip the selection if(SelectHitBox.y < OriginalView.y) // top { SelectHitBox.h -= OriginalView.y-SelectHitBox.y; SelectHitBox.y = OriginalView.y; } else if(SelectHitBox.y+SelectHitBox.h > OriginalView.y+OriginalView.h) // bottom SelectHitBox.h = OriginalView.y+OriginalView.h-SelectHitBox.y; if(UI()->DoButtonLogic(pItem, "", Selected, &SelectHitBox)) { NewSelected = ItemIndex; } } else { // reset active item, if not visible if(UI()->ActiveItem() == pItem) UI()->SetActiveItem(0); // don't render invisible items continue; } for(int c = 0; c < NumCols; c++) { CUIRect Button; char aTemp[64]; Button.x = s_aCols[c].m_Rect.x; Button.y = Row.y; Button.h = Row.h; Button.w = s_aCols[c].m_Rect.w; int ID = s_aCols[c].m_ID; if(ID == COL_FLAG_LOCK) { if(pItem->m_Flags & SERVER_FLAG_PASSWORD) DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_LOCK, &Button); } else if(ID == COL_FLAG_PURE) { if( str_comp(pItem->m_aGameType, "DM") == 0 || str_comp(pItem->m_aGameType, "TDM") == 0 || str_comp(pItem->m_aGameType, "CTF") == 0) { // pure server } else { // unpure DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_UNPURE, &Button); } } else if(ID == COL_FLAG_FAV) { if(pItem->m_Favorite) DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_HEART, &Button); } else if(ID == COL_NAME) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit&IServerBrowser::QUICK_SERVERNAME)) { // highlight the parts that matches const char *pStr = str_find_nocase(pItem->m_aName, g_Config.m_BrFilterString); if(pStr) { TextRender()->TextEx(&Cursor, pItem->m_aName, (int)(pStr-pItem->m_aName)); TextRender()->TextColor(0.4f,0.4f,1.0f,1); TextRender()->TextEx(&Cursor, pStr, str_length(g_Config.m_BrFilterString)); TextRender()->TextColor(1,1,1,1); TextRender()->TextEx(&Cursor, pStr+str_length(g_Config.m_BrFilterString), -1); } else TextRender()->TextEx(&Cursor, pItem->m_aName, -1); } else TextRender()->TextEx(&Cursor, pItem->m_aName, -1); } else if(ID == COL_MAP) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; TextRender()->TextEx(&Cursor, pItem->m_aMap, -1); } else if(ID == COL_PLAYERS) { if(g_Config.m_ClHighlightPlayer == 1) { if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 15.0f) TextRender()->TextColor(0.5f,1,0.5f,1); else if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 25.0f) TextRender()->TextColor(0.65f,1.0f,0.65f,1); else if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 45.0f) TextRender()->TextColor(0.75f,1.0f,0.65f,1); else if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 65.0f) TextRender()->TextColor(0.95f,0.95f,0.65f,1); else if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 85.0f) TextRender()->TextColor(0.95f,0.65f,0.65f,1); else if(pItem->m_NumPlayers * 100.f / pItem->m_MaxPlayers <= 100.0f) TextRender()->TextColor(0.95f,0.25f,0.25f,1); else TextRender()->TextColor(1,1,1,1); } str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumPlayers, pItem->m_MaxPlayers); if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit&IServerBrowser::QUICK_PLAYERNAME)) TextRender()->TextColor(0.4f,0.4f,1.0f,1); UI()->DoLabelScaled(&Button, aTemp, 12.0f, 1); TextRender()->TextColor(1,1,1,1); } else if(ID == COL_PING) { if(g_Config.m_ClHighlightPing == 1) { if(pItem->m_Latency <= 45) TextRender()->TextColor(0.5f,1,0.5f,1); else if(pItem->m_Latency <= 95) TextRender()->TextColor(0.85f,1.0f,0.65f,1); else if(pItem->m_Latency <= 110) TextRender()->TextColor(0.95f,0.85f,0.65f,1); else if(pItem->m_Latency <= 135) TextRender()->TextColor(0.95f,0.45f,0.45f,1); else TextRender()->TextColor(0.95f,0.25f,0.25f,1); } str_format(aTemp, sizeof(aTemp), "%i", pItem->m_Latency); UI()->DoLabelScaled(&Button, aTemp, 12.0f, 1); TextRender()->TextColor(1,1,1,1); } else if(ID == COL_VERSION) { const char *pVersion = pItem->m_aVersion; UI()->DoLabelScaled(&Button, pVersion, 12.0f, 1); } else if(ID == COL_GAMETYPE) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f*UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; if(g_Config.m_ClHighlightGametypes == 1) { if( str_comp(pItem->m_aGameType, "DM") == 0 || str_comp(pItem->m_aGameType, "TDM") == 0 || str_comp(pItem->m_aGameType, "CTF") == 0) TextRender()->TextColor(0.5f,1,0.5f,1); else TextRender()->TextColor(1,1,1,1); } TextRender()->TextEx(&Cursor, pItem->m_aGameType, -1); TextRender()->TextColor(1,1,1,1); } } } UI()->ClipDisable(); if(NewSelected != -1) { // select the new server const CServerInfo *pItem = ServerBrowser()->SortedGet(NewSelected); str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress, sizeof(g_Config.m_UiServerAddress)); if(Input()->MouseDoubleClick()) Client()->Connect(g_Config.m_UiServerAddress); } RenderTools()->DrawUIRect(&Status, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); Status.Margin(5.0f, &Status); // render quick search CUIRect QuickSearch, Button; Status.VSplitLeft(260.0f, &QuickSearch, &Status); const char *pLabel = Localize("Quick search:"); UI()->DoLabelScaled(&QuickSearch, pLabel, 12.0f, -1); float w = TextRender()->TextWidth(0, 12.0f, pLabel, -1); QuickSearch.VSplitLeft(w, 0, &QuickSearch); QuickSearch.VSplitLeft(5.0f, 0, &QuickSearch); QuickSearch.VSplitLeft(260.0f-w-22.0f, &QuickSearch, &Button); static float Offset = 0.0f; DoEditBox(&g_Config.m_BrFilterString, &QuickSearch, g_Config.m_BrFilterString, sizeof(g_Config.m_BrFilterString), 12.0f, &Offset, false, CUI::CORNER_L); // clear button { static int s_ClearButton = 0; RenderTools()->DrawUIRect(&Button, vec4(1,1,1,0.33f)*ButtonColorMul(&s_ClearButton), CUI::CORNER_R, 3.0f); UI()->DoLabel(&Button, "x", Button.h*ms_FontmodHeight, 0); if(UI()->DoButtonLogic(&s_ClearButton, "x", 0, &Button)) { g_Config.m_BrFilterString[0] = 0; UI()->SetActiveItem(&g_Config.m_BrFilterString); } } // render status char aBuf[128]; if(ServerBrowser()->IsRefreshing()) str_format(aBuf, sizeof(aBuf), Localize("%d%% loaded"), ServerBrowser()->LoadingProgression()); else str_format(aBuf, sizeof(aBuf), Localize("%d of %d servers, %d players"), ServerBrowser()->NumSortedServers(), ServerBrowser()->NumServers(), NumPlayers); Status.VSplitRight(TextRender()->TextWidth(0, 14.0f, aBuf, -1), 0, &Status); UI()->DoLabelScaled(&Status, aBuf, 14.0f, -1); }
void CScoreboard::RenderScoreboard64(float x, float y, float w, int Team, const char *pTitle) { if(Team == TEAM_SPECTATORS) return; bool isDDRace = Client()->IsServerType("ddrace"); float h = 760.0f; CUIRect area; area.x = x; area.y = y; area.w = w; area.h = h; Graphics()->BlendNormal(); Graphics()->TextureSet(-1); // render title CUIRect rTitle; area.HSplitTop(60.0f, &rTitle, &area); float TitleFontsize = 40.0f; if(m_pClient->m_Snap.m_pGameInfoObj->m_GameStateFlags&GAMESTATEFLAG_GAMEOVER) pTitle = Localize("Game over"); else pTitle = Localize("Score board"); RenderTools()->DrawUIRect(&rTitle, HexToVec4(g_Config.m_hcContainerHeaderBackgroundColor), CUI::CORNER_T, 10.0f); rTitle.Margin(10.0f, &rTitle); char aBuf[128] = {0}; if(m_pClient->m_Snap.m_pGameDataObj) { int Score = Team == TEAM_RED ? m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreRed : m_pClient->m_Snap.m_pGameDataObj->m_TeamscoreBlue; str_format(aBuf, sizeof(aBuf), "%d", Score); } float tw = TextRender()->TextWidth(0, TitleFontsize, aBuf, -1); CUIRect rTitlePoints; rTitle.VSplitRight(tw+5.0f, 0x0, &rTitlePoints); TextRender()->Text(0, rTitlePoints.x, rTitlePoints.y-5.0f, TitleFontsize, aBuf, -1); float LineHeight = 40.0f; float TeeSizeMod = 0.4f; float Spacing = 0.0f; float HeadlineFontsize = 12.0f; float FontSize = 14.0f; int part = 0; CTextCursor Cursor; CUIRect parts[4]; area.VSplitMid(&parts[0], &parts[2]); parts[0].VSplitMid(&parts[0], &parts[1]); parts[2].VSplitMid(&parts[2], &parts[3]); float ScoreOffset, ScoreLength; float TeeOffset, TeeLength; float NameOffset, NameLength; float PingOffset, PingLength; float CountryOffset, CountryLength; float ClanOffset, ClanLength; int nPlayers = 0; bool fi = false; for(int i = 0; i < MAX_CLIENTS; i++) { if (!fi || (i%16) == 0) { if (fi) part++; x = parts[part].x; y = parts[part].y; ScoreOffset = x+10.0f; ScoreLength = 60.0f; TeeOffset = parts[part].x+90.0f; TeeLength = 60*TeeSizeMod; NameOffset = TeeOffset+TeeLength; NameLength = 200.0f-TeeLength; PingOffset = x+390.0f; PingLength = 65.0f; CountryOffset = PingOffset-(LineHeight-Spacing-TeeSizeMod); CountryLength = (LineHeight-Spacing-TeeSizeMod*3.0f)*2.0f; ClanOffset = x+230.0f; ClanLength = 230.0f-CountryLength; // render headlines CUIRect rHeadLines, rLabel; parts[part].HSplitTop(40.0f, &rHeadLines, &parts[part]); RenderTools()->DrawUIRect(&rHeadLines, HexToVec4(g_Config.m_hcListHeaderBackgroundColor), 0, 0.0f); rHeadLines.Margin(5.0f,&rHeadLines); y += 50.0f; rHeadLines.VSplitLeft(80.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x + 20.0f, rLabel.y, HeadlineFontsize, Localize(isDDRace?"Time":"Score"), -1); rHeadLines.VSplitLeft(200.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Name"), -1); rHeadLines.VSplitLeft(150.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Clan"), -1); rHeadLines.VSplitLeft(80.0f, &rLabel, &rHeadLines); TextRender()->Text(0, rLabel.x, rLabel.y, HeadlineFontsize, Localize("Ping"), -1); int corner = 0; if (part==0) corner = CUI::CORNER_BL; else if (part==3) corner = CUI::CORNER_BR; vec4 baColor = HexToVec4(g_Config.m_hcContainerBackgroundColor); RenderTools()->DrawUIRect(&parts[part], vec4(baColor.r, baColor.g, baColor.b, part%2==0?0.5f:0.65f), corner, 10.0f); fi = true; } // make sure that we render the correct team const CNetObj_PlayerInfo *pInfo = m_pClient->m_Snap.m_paInfoByDDTeam[i]; if(!pInfo) continue; nPlayers++; // background so it's easy to find the local player or the followed one in spectator mode if(pInfo->m_Local || (m_pClient->m_Snap.m_SpecInfo.m_Active && pInfo->m_ClientID == m_pClient->m_Snap.m_SpecInfo.m_SpectatorID)) { Graphics()->TextureSet(-1); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.25f); RenderTools()->DrawRoundRectExt(x, y, parts[part].w, LineHeight, 0.0f, 0); Graphics()->QuadsEnd(); } // score if(isDDRace) { if (pInfo->m_Score == -9999) str_copy(aBuf, "––:––", sizeof(aBuf)); else { int Time = abs(pInfo->m_Score); str_format(aBuf, sizeof(aBuf), "%02d:%02d", Time/60, Time%60); } } else str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Score, -999, 999)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, ScoreOffset+ScoreLength-tw, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ScoreLength; TextRender()->TextEx(&Cursor, aBuf, -1); // avatar CTeeRenderInfo TeeInfo = m_pClient->m_aClients[pInfo->m_ClientID].m_RenderInfo; TeeInfo.m_Size *= TeeSizeMod; RenderTools()->RenderTee(CAnimState::GetIdle(), &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(TeeOffset+TeeLength/2, y+LineHeight/2-3.0f)); // name if (g_Config.m_hcColorClan && m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aClan[0] != 0 && str_comp_nocase(m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, m_pClient->m_aClients[m_pClient->m_Snap.m_LocalClientID].m_aClan) == 0) //H-Client TextRender()->TextColor(0.7f, 0.7f, 0.2f, 1.0f); TextRender()->SetCursor(&Cursor, NameOffset, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = NameLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aName, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); // clan tw = TextRender()->TextWidth(0, FontSize, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); TextRender()->SetCursor(&Cursor, ClanOffset+ClanLength/2-tw/2-5.0f, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = ClanLength; TextRender()->TextEx(&Cursor, m_pClient->m_aClients[pInfo->m_ClientID].m_aClan, -1); // country flag Graphics()->TextureSet(m_pClient->m_pCountryFlags->GetByCountryCode(m_pClient->m_aClients[pInfo->m_ClientID].m_Country)->m_Texture); Graphics()->QuadsBegin(); Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f); IGraphics::CQuadItem QuadItem(CountryOffset, y+(Spacing+TeeSizeMod*5.0f)/2.0f, CountryLength, LineHeight-Spacing-TeeSizeMod*5.0f); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // ping //H-Client const int maxLatency = 200; vec3 Rgb = HslToRgb(vec3(1.0f, 1.0f, 0.5f)); if (pInfo->m_Latency <= maxLatency) Rgb = HslToRgb(vec3((((maxLatency - pInfo->m_Latency) * 0.35f) / maxLatency), 1.0f, 0.5f)); TextRender()->TextColor(Rgb.r, Rgb.g, Rgb.b, 1.0f); // str_format(aBuf, sizeof(aBuf), "%d", clamp(pInfo->m_Latency, 0, 1000)); tw = TextRender()->TextWidth(0, FontSize, aBuf, -1); TextRender()->SetCursor(&Cursor, PingOffset+PingLength-tw, y+Spacing+3.0f, FontSize, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = PingLength; TextRender()->TextEx(&Cursor, aBuf, -1); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); y += LineHeight+Spacing; } //Title char aTitle[128]={0}; str_format(aTitle, sizeof(aTitle), "%s [%d]", pTitle, nPlayers); TextRender()->Text(0, rTitle.x, rTitle.y-5.0f, TitleFontsize, aTitle, -1); }
int CMenus::PopupFilter(CMenus *pMenus, CUIRect View) { CUIRect ServerFilter = View, FilterHeader; const float FontSize = 12.0f; // slected filter CBrowserFilter *pFilter = &pMenus->m_lFilters[pMenus->m_SelectedFilter]; CServerFilterInfo FilterInfo; pFilter->GetFilter(&FilterInfo); // server filter ServerFilter.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFilter); pMenus->RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); pMenus->RenderTools()->DrawUIRect(&ServerFilter, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); pMenus->UI()->DoLabelScaled(&FilterHeader, Localize("Server filter"), FontSize+2.0f, CUI::ALIGN_CENTER); CUIRect Button; ServerFilter.VSplitLeft(5.0f, 0, &ServerFilter); ServerFilter.Margin(3.0f, &ServerFilter); ServerFilter.VMargin(5.0f, &ServerFilter); int NewSortHash = FilterInfo.m_SortHash; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterEmpty = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterEmpty, Localize("Has people playing"), FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_EMPTY; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterSpectators = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterSpectators, Localize("Count players only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_SPECTATORS; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterFull = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterFull, Localize("Server not full"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FULL; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterFriends = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterFriends, Localize("Show friends only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FRIENDS; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPw = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPw, Localize("No password"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PW, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PW; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterCompatversion = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterCompatversion, Localize("Compatible version"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COMPAT_VERSION, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COMPAT_VERSION; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPure = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPure, Localize("Standard gametype"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterPureMap = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterPureMap, Localize("Standard map"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PURE_MAP, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_PURE_MAP; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); static int s_BrFilterGametypeStrict = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterGametypeStrict, Localize("Strict gametype filter"), FilterInfo.m_SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_GAMETYPE_STRICT; if(FilterInfo.m_SortHash != NewSortHash) { FilterInfo.m_SortHash = NewSortHash; pFilter->SetFilter(&FilterInfo); } ServerFilter.HSplitTop(5.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); pMenus->UI()->DoLabelScaled(&Button, Localize("Game types:"), FontSize, CUI::ALIGN_LEFT); Button.VSplitRight(60.0f, 0, &Button); ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); static float Offset = 0.0f; static int s_BrFilterGametype = 0; if(pMenus->DoEditBox(&s_BrFilterGametype, &Button, FilterInfo.m_aGametype, sizeof(FilterInfo.m_aGametype), FontSize, &Offset)) pFilter->SetFilter(&FilterInfo); { ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); CUIRect EditBox; Button.VSplitRight(60.0f, &Button, &EditBox); pMenus->UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, CUI::ALIGN_LEFT); char aBuf[5]; str_format(aBuf, sizeof(aBuf), "%d", FilterInfo.m_Ping); static float Offset = 0.0f; static int s_BrFilterPing = 0; pMenus->DoEditBox(&s_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), FontSize, &Offset); int NewPing = clamp(str_toint(aBuf), 0, 999); if(NewPing != FilterInfo.m_Ping) { FilterInfo.m_Ping = NewPing; pFilter->SetFilter(&FilterInfo); } } // server address ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); pMenus->UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, CUI::ALIGN_LEFT); Button.VSplitRight(60.0f, 0, &Button); static float OffsetAddr = 0.0f; static int s_BrFilterServerAddress = 0; if(pMenus->DoEditBox(&s_BrFilterServerAddress, &Button, FilterInfo.m_aAddress, sizeof(FilterInfo.m_aAddress), FontSize, &OffsetAddr)) pFilter->SetFilter(&FilterInfo); // player country { CUIRect Rect; ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(26.0f, &Button, &ServerFilter); Button.VSplitRight(60.0f, &Button, &Rect); Button.HMargin(3.0f, &Button); static int s_BrFilterCountry = 0; if(pMenus->DoButton_CheckBox(&s_BrFilterCountry, Localize("Player country:"), FilterInfo.m_SortHash&IServerBrowser::FILTER_COUNTRY, &Button)) { FilterInfo.m_SortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY; pFilter->SetFilter(&FilterInfo); } float OldWidth = Rect.w; Rect.w = Rect.h*2; Rect.x += (OldWidth-Rect.w)/2.0f; vec4 Color(1.0f, 1.0f, 1.0f, FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY?1.0f: 0.5f); pMenus->m_pClient->m_pCountryFlags->Render(FilterInfo.m_Country, &Color, Rect.x, Rect.y, Rect.w, Rect.h); static int s_BrFilterCountryIndex = 0; if(FilterInfo.m_SortHash^IServerBrowser::FILTER_COUNTRY && pMenus->UI()->DoButtonLogic(&s_BrFilterCountryIndex, "", 0, &Rect)) pMenus->m_Popup = POPUP_COUNTRY; } return 0; }
void CMenus::RenderDemoList(CUIRect MainView) { static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); DemolistOnUpdate(true); s_Inited = 1; } char aFooterLabel[128] = {0}; if(m_DemolistSelectedIndex >= 0) { CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex]; if(str_comp(Item->m_aFilename, "..") == 0) str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel)); else if(m_DemolistSelectedIsDir) str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel)); else { if(!Item->m_InfosLoaded) { char aBuffer[512]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename); Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, &Item->m_Info); Item->m_InfosLoaded = true; } if(!Item->m_Valid) str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel)); else str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel)); } } // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, RenameRect, ListBox; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect); ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &RenameRect, &ButtonBar); MainView.HSplitBottom(140.0f, &ListBox, &MainView); // render demo info MainView.VMargin(5.0f, &MainView); MainView.HSplitBottom(5.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); if(!m_DemolistSelectedIsDir && m_DemolistSelectedIndex >= 0 && m_lDemos[m_DemolistSelectedIndex].m_Valid) { CUIRect Left, Right, Labels; MainView.Margin(20.0f, &MainView); MainView.VSplitMid(&Labels, &MainView); // left side Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Created:"), 14.0f, -1); char aTimestamp[256]; str_timestamp_ex(m_lDemos[m_DemolistSelectedIndex].m_Date, aTimestamp, sizeof(aTimestamp), "%Y-%m-%d %H:%M:%S"); UI()->DoLabelScaled(&Right, aTimestamp, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Type:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aType, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Length:"), 14.0f, -1); int Length = ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[0]<<24)&0xFF000000) | ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[1]<<16)&0xFF0000) | ((m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[2]<<8)&0xFF00) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[3]&0xFF); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Version:"), 14.0f, -1); str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].m_Info.m_Version); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); // right side Labels = MainView; Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Map:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapName, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Size:"), 14.0f, -1); unsigned Size = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[3]); if(Size > 1024*1024) str_format(aBuf, sizeof(aBuf), Localize("%.2f MiB"), float(Size)/(1024*1024)); else str_format(aBuf, sizeof(aBuf), Localize("%.2f KiB"), float(Size)/1024); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1); unsigned Crc = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[3]); str_format(aBuf, sizeof(aBuf), "%08x", Crc); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Netversion:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aNetversion, 14.0f, -1); } // demo list CUIRect Headers; ListBox.HSplitTop(ms_ListheaderHeight, &Headers, &ListBox); struct CColumn { int m_ID; int m_Sort; CLocConstString m_Caption; int m_Direction; float m_Width; int m_Flags; CUIRect m_Rect; CUIRect m_Spacer; }; enum { COL_ICON=0, COL_DEMONAME, COL_DATE, SORT_DEMONAME=0, SORT_DATE, }; static CColumn s_aCols[] = { {COL_ICON, -1, " ", -1, 14.0f, 0, {0}, {0}}, {COL_DEMONAME, SORT_DEMONAME, "Demo", 0, 0.0f, 0, {0}, {0}}, {COL_DATE, SORT_DATE, "Date", 1, 300.0f, 0, {0}, {0}}, }; RenderTools()->DrawUIRect(&Headers, vec4(0.0f,0,0,0.15f), 0, 0); int NumCols = sizeof(s_aCols)/sizeof(CColumn); // do layout for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == -1) { Headers.VSplitLeft(s_aCols[i].m_Width, &s_aCols[i].m_Rect, &Headers); if(i+1 < NumCols) { //Cols[i].flags |= SPACER; Headers.VSplitLeft(2, &s_aCols[i].m_Spacer, &Headers); } } } for(int i = NumCols-1; i >= 0; i--) { if(s_aCols[i].m_Direction == 1) { Headers.VSplitRight(s_aCols[i].m_Width, &Headers, &s_aCols[i].m_Rect); Headers.VSplitRight(2, &Headers, &s_aCols[i].m_Spacer); } } for(int i = 0; i < NumCols; i++) { if(s_aCols[i].m_Direction == 0) s_aCols[i].m_Rect = Headers; } // do headers for(int i = 0; i < NumCols; i++) { if(DoButton_GridHeader(s_aCols[i].m_Caption, s_aCols[i].m_Caption, g_Config.m_BrDemoSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect)) { if(s_aCols[i].m_Sort != -1) { if(g_Config.m_BrDemoSort == s_aCols[i].m_Sort) g_Config.m_BrDemoSortOrder ^= 1; else g_Config.m_BrDemoSortOrder = 0; g_Config.m_BrDemoSort = s_aCols[i].m_Sort; } DemolistPopulate(); DemolistOnUpdate(false); } } // scrollbar CUIRect Scroll; #if defined(__ANDROID__) ListBox.VSplitRight(50, &ListBox, &Scroll); #else ListBox.VSplitRight(15, &ListBox, &Scroll); #endif int Num = (int)(ListBox.h/s_aCols[0].m_Rect.h) + 1; static int s_ScrollBar = 0; static float s_ScrollValue = 0; Scroll.HMargin(5.0f, &Scroll); s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue); int ScrollNum = m_lDemos.size()-Num+1; if(ScrollNum > 0) { if(m_ScrollOffset) { s_ScrollValue = (float)(m_ScrollOffset)/ScrollNum; m_ScrollOffset = 0; } if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&ListBox)) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&ListBox)) s_ScrollValue += 3.0f/ScrollNum; } else ScrollNum = 0; if(m_DemolistSelectedIndex > -1) { for(int i = 0; i < m_NumInputEvents; i++) { int NewIndex = -1; if(m_aInputEvents[i].m_Flags&IInput::FLAG_PRESS) { if(m_aInputEvents[i].m_Key == KEY_DOWN) NewIndex = m_DemolistSelectedIndex + 1; if(m_aInputEvents[i].m_Key == KEY_UP) NewIndex = m_DemolistSelectedIndex - 1; } if(NewIndex > -1 && NewIndex < m_lDemos.size()) { //scroll float IndexY = ListBox.y - s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h + NewIndex*s_aCols[0].m_Rect.h; int Scroll = ListBox.y > IndexY ? -1 : ListBox.y+ListBox.h < IndexY+s_aCols[0].m_Rect.h ? 1 : 0; if(Scroll) { if(Scroll < 0) { int NumScrolls = (ListBox.y-IndexY+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue -= (1.0f/ScrollNum)*NumScrolls; } else { int NumScrolls = (IndexY+s_aCols[0].m_Rect.h-(ListBox.y+ListBox.h)+s_aCols[0].m_Rect.h-1.0f)/s_aCols[0].m_Rect.h; s_ScrollValue += (1.0f/ScrollNum)*NumScrolls; } } m_DemolistSelectedIndex = NewIndex; str_copy(g_Config.m_UiDemoSelected, m_lDemos[NewIndex].m_aName, sizeof(g_Config.m_UiDemoSelected)); DemolistOnUpdate(false); } } } if(s_ScrollValue < 0) s_ScrollValue = 0; if(s_ScrollValue > 1) s_ScrollValue = 1; // set clipping UI()->ClipEnable(&ListBox); CUIRect OriginalView = ListBox; ListBox.y -= s_ScrollValue*ScrollNum*s_aCols[0].m_Rect.h; int NewSelected = -1; #if defined(__ANDROID__) int DoubleClicked = 0; #endif int ItemIndex = -1; for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) { ItemIndex++; CUIRect Row; CUIRect SelectHitBox; ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox); SelectHitBox = Row; int Selected = ItemIndex == m_DemolistSelectedIndex; // make sure that only those in view can be selected if(Row.y+Row.h > OriginalView.y && Row.y < OriginalView.y+OriginalView.h) { if(Selected) { CUIRect r = Row; r.Margin(1.5f, &r); RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f); } // clip the selection if(SelectHitBox.y < OriginalView.y) // top { SelectHitBox.h -= OriginalView.y-SelectHitBox.y; SelectHitBox.y = OriginalView.y; } else if(SelectHitBox.y+SelectHitBox.h > OriginalView.y+OriginalView.h) // bottom SelectHitBox.h = OriginalView.y+OriginalView.h-SelectHitBox.y; if(UI()->DoButtonLogic(r.front().m_aName /* TODO: */, "", Selected, &SelectHitBox)) { NewSelected = ItemIndex; str_copy(g_Config.m_UiDemoSelected, r.front().m_aName, sizeof(g_Config.m_UiDemoSelected)); DemolistOnUpdate(false); #if defined(__ANDROID__) if(NewSelected == m_DoubleClickIndex) DoubleClicked = 1; #endif m_DoubleClickIndex = NewSelected; } } else { // don't render invisible items continue; } for(int c = 0; c < NumCols; c++) { CUIRect Button; Button.x = s_aCols[c].m_Rect.x; Button.y = Row.y; Button.h = Row.h; Button.w = s_aCols[c].m_Rect.w; int ID = s_aCols[c].m_ID; if (ID == COL_ICON) { DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &Button); } else if(ID == COL_DEMONAME) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; TextRender()->TextEx(&Cursor, r.front().m_aName, -1); } else if (ID == COL_DATE && !r.front().m_IsDir) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Button.x, Button.y, 12.0f * UI()->Scale(), TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END); Cursor.m_LineWidth = Button.w; char aBuf[256]; str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), "%Y-%m-%d %H:%M:%S"); TextRender()->TextEx(&Cursor, aBuf, -1); } } } UI()->ClipDisable(); bool Activated = false; #if defined(__ANDROID__) if (m_EnterPressed || (DoubleClicked && UI()->ActiveItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #else if (m_EnterPressed || (Input()->MouseDoubleClick() && UI()->ActiveItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #endif { UI()->SetActiveItem(0); Activated = true; } static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) { DemolistPopulate(); DemolistOnUpdate(false); } static int s_PlayButton = 0; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated) { if(m_DemolistSelectedIndex >= 0) { if(m_DemolistSelectedIsDir) // folder { if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { char aTemp[256]; str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); DemolistOnUpdate(true); } else // file { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); else { UI()->SetActiveItem(0); return; } } } } if(!m_DemolistSelectedIsDir) { static int s_DeleteButton = 0; if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_DELETE_DEMO; return; } } static int s_RenameButton = 0; if(DoButton_Menu(&s_RenameButton, Localize("Rename"), 0, &RenameRect)) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_RENAME_DEMO; str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile)); return; } } } }
void CMenus::RenderServerControl(CUIRect MainView) { if(m_pClient->m_LocalClientID == -1) return; static int s_ControlPage = 0; const char *pNotification = 0; char aBuf[64]; if(m_pClient->m_aClients[m_pClient->m_LocalClientID].m_Team == TEAM_SPECTATORS) pNotification = Localize("Spectators aren't allowed to start a vote."); else if(m_pClient->m_pVoting->IsVoting()) pNotification = Localize("Wait for current vote to end before calling a new one."); else if(m_pClient->m_pVoting->CallvoteBlockTime() != 0) { str_format(aBuf, sizeof(aBuf), Localize("You must wait %d seconds before making another vote"), m_pClient->m_pVoting->CallvoteBlockTime()); pNotification = aBuf; } bool Authed = Client()->RconAuthed(); if(pNotification && !Authed) { // only print notice CUIRect Bar; MainView.HSplitTop(45.0f, &Bar, &MainView); RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_ALL, 10.0f); Bar.HMargin(15.0f, &Bar); UI()->DoLabelScaled(&Bar, pNotification, 14.0f, 0); return; } // tab bar CUIRect Bottom, Extended, TabBar, Button; MainView.HSplitTop(20.0f, &Bottom, &MainView); RenderTools()->DrawUIRect(&Bottom, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_T, 10.0f); MainView.HSplitTop(20.0f, &TabBar, &MainView); { TabBar.VSplitLeft(TabBar.w/3, &Button, &TabBar); static int s_Button0 = 0; if(DoButton_MenuTab(&s_Button0, Localize("Change settings"), s_ControlPage == 0, &Button, 0)) s_ControlPage = 0; TabBar.VSplitMid(&Button, &TabBar); static int s_Button1 = 0; if(DoButton_MenuTab(&s_Button1, Localize("Kick player"), s_ControlPage == 1, &Button, 0)) s_ControlPage = 1; static int s_Button2 = 0; if(DoButton_MenuTab(&s_Button2, Localize("Move player to spectators"), s_ControlPage == 2, &TabBar, 0)) s_ControlPage = 2; } if(s_ControlPage == 1) { if(!m_pClient->m_ServerSettings.m_KickVote) pNotification = Localize("Server does not allow voting to kick players"); else if(m_pClient->m_GameInfo.m_aTeamSize[TEAM_RED]+m_pClient->m_GameInfo.m_aTeamSize[TEAM_BLUE] < m_pClient->m_ServerSettings.m_KickMin) { str_format(aBuf, sizeof(aBuf), Localize("Kick voting requires %d players on the server"), m_pClient->m_ServerSettings.m_KickMin); pNotification = aBuf; } } else if(s_ControlPage == 2 && !m_pClient->m_ServerSettings.m_SpecVote) pNotification = Localize("Server does not allow voting to move players to spectators"); if(pNotification && !Authed) { // only print notice CUIRect Bar; MainView.HSplitTop(45.0f, &Bar, &MainView); RenderTools()->DrawUIRect(&Bar, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 10.0f); Bar.HMargin(15.0f, &Bar); UI()->DoLabelScaled(&Bar, pNotification, 14.0f, 0); return; } // render background RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_B, 10.0f); MainView.Margin(10.0f, &MainView); MainView.HSplitBottom(90.0f, &MainView, &Extended); // render page MainView.HSplitBottom(ms_ButtonHeight + 5*2, &MainView, &Bottom); Bottom.HMargin(5.0f, &Bottom); if(s_ControlPage == 0) RenderServerControlServer(MainView); else if(s_ControlPage == 1) RenderServerControlKick(MainView, false); else if(s_ControlPage == 2) RenderServerControlKick(MainView, true); // vote menu { Bottom.VSplitRight(120.0f, &Bottom, &Button); // render kick reason CUIRect Reason, ClearButton; Bottom.VSplitRight(40.0f, &Bottom, 0); Bottom.VSplitRight(160.0f, &Bottom, &Reason); Reason.HSplitTop(5.0f, 0, &Reason); Reason.VSplitRight(Reason.h, &Reason, &ClearButton); const char *pLabel = Localize("Reason:"); UI()->DoLabelScaled(&Reason, pLabel, 14.0f, -1); float w = TextRender()->TextWidth(0, 14.0f, pLabel, -1); Reason.VSplitLeft(w+10.0f, 0, &Reason); static float s_Offset = 0.0f; DoEditBox(&m_aCallvoteReason, &Reason, m_aCallvoteReason, sizeof(m_aCallvoteReason), 14.0f, &s_Offset, false, CUI::CORNER_L); // clear button { static int s_ClearButton = 0; float *pClearButtonFade = ButtonFade(&s_ClearButton, 0.6f); RenderTools()->DrawUIRect(&ClearButton, vec4(1.0f, 1.0f, 1.0f, 0.33f+(*pClearButtonFade/0.6f)*0.165f), CUI::CORNER_R, 3.0f); UI()->DoLabel(&ClearButton, "x", ClearButton.h*ms_FontmodHeight, 0); if(UI()->DoButtonLogic(&s_ClearButton, "x", 0, &ClearButton)) m_aCallvoteReason[0] = 0; } if(pNotification == 0) { // call vote static int s_CallVoteButton = 0; if(DoButton_Menu(&s_CallVoteButton, Localize("Call vote"), 0, &Button)) HandleCallvote(s_ControlPage, false); } else { // print notice UI()->DoLabelScaled(&Bottom, pNotification, 14.0f, -1, Bottom.w); } // extended features (only available when authed in rcon) if(Authed) { // background Extended.Margin(10.0f, &Extended); Extended.HSplitTop(20.0f, &Bottom, &Extended); Extended.HSplitTop(5.0f, 0, &Extended); // force vote Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(120.0f, &Button, &Bottom); static int s_ForceVoteButton = 0; if(DoButton_Menu(&s_ForceVoteButton, Localize("Force vote"), 0, &Button)) HandleCallvote(s_ControlPage, true); if(s_ControlPage == 0) { // remove vote Bottom.VSplitRight(10.0f, &Bottom, 0); Bottom.VSplitRight(120.0f, 0, &Button); static int s_RemoveVoteButton = 0; if(DoButton_Menu(&s_RemoveVoteButton, Localize("Remove"), 0, &Button)) m_pClient->m_pVoting->RemovevoteOption(m_CallvoteSelectedOption); // add vote Extended.HSplitTop(20.0f, &Bottom, &Extended); Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(250.0f, &Button, &Bottom); UI()->DoLabelScaled(&Button, Localize("Vote description:"), 14.0f, -1); Bottom.VSplitLeft(20.0f, 0, &Button); UI()->DoLabelScaled(&Button, Localize("Vote command:"), 14.0f, -1); static char s_aVoteDescription[64] = {0}; static char s_aVoteCommand[512] = {0}; Extended.HSplitTop(20.0f, &Bottom, &Extended); Bottom.VSplitRight(10.0f, &Bottom, 0); Bottom.VSplitRight(120.0f, &Bottom, &Button); static int s_AddVoteButton = 0; if(DoButton_Menu(&s_AddVoteButton, Localize("Add"), 0, &Button)) if(s_aVoteDescription[0] != 0 && s_aVoteCommand[0] != 0) m_pClient->m_pVoting->AddvoteOption(s_aVoteDescription, s_aVoteCommand); Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(250.0f, &Button, &Bottom); static float s_OffsetDesc = 0.0f; DoEditBox(&s_aVoteDescription, &Button, s_aVoteDescription, sizeof(s_aVoteDescription), 14.0f, &s_OffsetDesc, false, CUI::CORNER_ALL); Bottom.VMargin(20.0f, &Button); static float s_OffsetCmd = 0.0f; DoEditBox(&s_aVoteCommand, &Button, s_aVoteCommand, sizeof(s_aVoteCommand), 14.0f, &s_OffsetCmd, false, CUI::CORNER_ALL); } } } }
void CMenus::RenderServerbrowser(CUIRect MainView) { RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); CUIRect View; MainView.Margin(10.0f, &View); /* +-----------------+ +------+ | | | | | | | tool | | | | box | | | | | | | +------+ +-----------------+ button status toolbar box */ //CUIRect filters; CUIRect StatusToolBox; CUIRect ToolBox; CUIRect ButtonBox; // split off a piece for filters, details and scoreboard View.VSplitRight(200.0f, &View, &ToolBox); ToolBox.HSplitBottom(80.0f, &ToolBox, &ButtonBox); View.HSplitBottom(ms_ButtonHeight+5.0f, &View, &StatusToolBox); RenderServerbrowserServerList(View); int ToolboxPage = g_Config.m_UiToolboxPage; ToolBox.VSplitLeft(5.0f, 0, &ToolBox); // do tabbar { CUIRect TabBar; CUIRect TabButton0, TabButton1; ToolBox.HSplitTop(22.0f, &TabBar, &ToolBox); TabBar.VSplitMid(&TabButton0, &TabButton1); //TabButton0.VSplitRight(5.0f, &TabButton0, 0); //TabButton1.VSplitLeft(5.0f, 0, &TabButton1); static int s_FiltersTab = 0; if (DoButton_MenuTab(&s_FiltersTab, Localize("Filter"), ToolboxPage==0, &TabButton0, CUI::CORNER_TL)) ToolboxPage = 0; static int s_InfoTab = 0; if (DoButton_MenuTab(&s_InfoTab, Localize("Info"), ToolboxPage==1, &TabButton1, CUI::CORNER_TR)) ToolboxPage = 1; } g_Config.m_UiToolboxPage = ToolboxPage; RenderTools()->DrawUIRect(&ToolBox, vec4(0,0,0,0.15f), 0, 0); ToolBox.HSplitTop(5.0f, 0, &ToolBox); if(ToolboxPage == 0) RenderServerbrowserFilters(ToolBox); else if(ToolboxPage == 1) RenderServerbrowserServerDetail(ToolBox); { StatusToolBox.HSplitTop(5.0f, 0, &StatusToolBox); CUIRect Button; //buttons.VSplitRight(20.0f, &buttons, &button); StatusToolBox.VSplitRight(110.0f, &StatusToolBox, &Button); Button.VMargin(2.0f, &Button); static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &Button)) { if(g_Config.m_UiPage == PAGE_INTERNET) ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); else if(g_Config.m_UiPage == PAGE_LAN) ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); else if(g_Config.m_UiPage == PAGE_FAVORITES) ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES); } char aBuf[512]; if(str_comp(Client()->LatestVersion(), "0") != 0) str_format(aBuf, sizeof(aBuf), Localize("Teeworlds %s is out! Download it at www.teeworlds.com!"), Client()->LatestVersion()); else str_format(aBuf, sizeof(aBuf), Localize("Current version: %s"), GAME_VERSION); UI()->DoLabelScaled(&StatusToolBox, aBuf, 14.0f, -1); } // do the button box { ButtonBox.VSplitLeft(5.0f, 0, &ButtonBox); ButtonBox.VSplitRight(5.0f, &ButtonBox, 0); CUIRect Button; ButtonBox.HSplitBottom(ms_ButtonHeight, &ButtonBox, &Button); Button.VSplitRight(120.0f, 0, &Button); Button.VMargin(2.0f, &Button); //button.VMargin(2.0f, &button); static int s_JoinButton = 0; if(DoButton_Menu(&s_JoinButton, Localize("Connect"), 0, &Button) || m_EnterPressed) { //dbg_msg("", "%s", g_Config.m_UiServerAddress); Client()->Connect(g_Config.m_UiServerAddress); m_EnterPressed = false; } ButtonBox.HSplitBottom(5.0f, &ButtonBox, &Button); ButtonBox.HSplitBottom(20.0f, &ButtonBox, &Button); static float Offset = 0.0f; DoEditBox(&g_Config.m_UiServerAddress, &Button, g_Config.m_UiServerAddress, sizeof(g_Config.m_UiServerAddress), 14.0f, &Offset); ButtonBox.HSplitBottom(20.0f, &ButtonBox, &Button); UI()->DoLabelScaled(&Button, Localize("Host address"), 14.0f, -1); } }
int CMenus::Render() { CUIRect Screen = *UI()->Screen(); Graphics()->MapScreen(Screen.x, Screen.y, Screen.w, Screen.h); static bool s_First = true; if(s_First) { if(g_Config.m_UiPage == PAGE_INTERNET) ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); else if(g_Config.m_UiPage == PAGE_LAN) ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN); else if(g_Config.m_UiPage == PAGE_FAVORITES) ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES); s_First = false; } if(Client()->State() == IClient::STATE_ONLINE) { ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame; ms_ColorTabbarActive = ms_ColorTabbarActiveIngame; } else { RenderBackground(); ms_ColorTabbarInactive = ms_ColorTabbarInactiveOutgame; ms_ColorTabbarActive = ms_ColorTabbarActiveOutgame; } CUIRect TabBar; CUIRect MainView; // some margin around the screen Screen.Margin(10.0f, &Screen); if(m_Popup == POPUP_NONE) { // do tab bar Screen.HSplitTop(24.0f, &TabBar, &MainView); TabBar.VMargin(20.0f, &TabBar); RenderMenubar(TabBar); // news is not implemented yet if(g_Config.m_UiPage <= PAGE_NEWS || g_Config.m_UiPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && g_Config.m_UiPage >= PAGE_GAME && g_Config.m_UiPage <= PAGE_CALLVOTE)) { ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET); g_Config.m_UiPage = PAGE_INTERNET; } // render current page if(Client()->State() != IClient::STATE_OFFLINE) { if(m_GamePage == PAGE_GAME) RenderGame(MainView); else if(m_GamePage == PAGE_SERVER_INFO) RenderServerInfo(MainView); else if(m_GamePage == PAGE_CALLVOTE) RenderServerControl(MainView); else if(m_GamePage == PAGE_SETTINGS) RenderSettings(MainView); } else if(g_Config.m_UiPage == PAGE_NEWS) RenderNews(MainView); else if(g_Config.m_UiPage == PAGE_INTERNET) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_LAN) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_DEMOS) RenderDemoList(MainView); else if(g_Config.m_UiPage == PAGE_FAVORITES) RenderServerbrowser(MainView); else if(g_Config.m_UiPage == PAGE_SETTINGS) RenderSettings(MainView); } else { // make sure that other windows doesn't do anything funnay! //UI()->SetHotItem(0); //UI()->SetActiveItem(0); char aBuf[128]; const char *pTitle = ""; const char *pExtraText = ""; const char *pButtonText = ""; int ExtraAlign = 0; if(m_Popup == POPUP_MESSAGE) { pTitle = m_aMessageTopic; pExtraText = m_aMessageBody; pButtonText = m_aMessageButton; } else if(m_Popup == POPUP_CONNECTING) { pTitle = Localize("Connecting to"); pExtraText = g_Config.m_UiServerAddress; // TODO: query the client about the address pButtonText = Localize("Abort"); if(Client()->MapDownloadTotalsize() > 0) { pTitle = Localize("Downloading map"); str_format(aBuf, sizeof(aBuf), "%d/%d KiB", Client()->MapDownloadAmount()/1024, Client()->MapDownloadTotalsize()/1024); pExtraText = aBuf; } } else if(m_Popup == POPUP_DISCONNECTED) { pTitle = Localize("Disconnected"); pExtraText = Client()->ErrorString(); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PURE) { pTitle = Localize("Disconnected"); pExtraText = Localize("The server is running a non-standard tuning on a pure game type."); pButtonText = Localize("Ok"); ExtraAlign = -1; } else if(m_Popup == POPUP_PASSWORD) { pTitle = Localize("Password incorrect"); pExtraText = Client()->ErrorString(); pButtonText = Localize("Try again"); } else if(m_Popup == POPUP_QUIT) { pTitle = Localize("Quit"); pExtraText = Localize("Are you sure that you want to quit?"); } else if(m_Popup == POPUP_FIRST_LAUNCH) { pTitle = Localize("Welcome to Teeworlds"); pExtraText = Localize("As this is the first time you launch the game, please enter your nick name below. It's recommended that you check the settings to adjust them to your liking before joining a server."); pButtonText = Localize("Ok"); ExtraAlign = -1; } CUIRect Box, Part; Box = Screen; Box.VMargin(150.0f, &Box); Box.HMargin(150.0f, &Box); // render the box RenderTools()->DrawUIRect(&Box, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 15.0f); Box.HSplitTop(20.f, &Part, &Box); Box.HSplitTop(24.f, &Part, &Box); UI()->DoLabel(&Part, pTitle, 24.f, 0); Box.HSplitTop(20.f, &Part, &Box); Box.HSplitTop(24.f, &Part, &Box); Part.VMargin(20.f, &Part); if(ExtraAlign == -1) UI()->DoLabel(&Part, pExtraText, 20.f, -1, (int)Part.w); else UI()->DoLabel(&Part, pExtraText, 20.f, 0, -1); if(m_Popup == POPUP_QUIT) { CUIRect Yes, No; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&No, &Yes); Yes.VMargin(20.0f, &Yes); No.VMargin(20.0f, &No); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("No"), 0, &No) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Yes"), 0, &Yes) || m_EnterPressed) Client()->Quit(); } else if(m_Popup == POPUP_PASSWORD) { CUIRect Label, TextBox, TryAgain, Abort; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); Part.VSplitMid(&Abort, &TryAgain); TryAgain.VMargin(20.0f, &TryAgain); Abort.VMargin(20.0f, &Abort); static int s_ButtonAbort = 0; if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed) m_Popup = POPUP_NONE; static int s_ButtonTryAgain = 0; if(DoButton_Menu(&s_ButtonTryAgain, Localize("Try again"), 0, &TryAgain) || m_EnterPressed) { Client()->Connect(g_Config.m_UiServerAddress); } Box.HSplitBottom(60.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Password"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_Password, &TextBox, g_Config.m_Password, sizeof(g_Config.m_Password), 12.0f, &Offset, true); } else if(m_Popup == POPUP_FIRST_LAUNCH) { CUIRect Label, TextBox; Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(80.0f, &Part); static int s_EnterButton = 0; if(DoButton_Menu(&s_EnterButton, Localize("Enter"), 0, &Part) || m_EnterPressed) m_Popup = POPUP_NONE; Box.HSplitBottom(40.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VSplitLeft(60.0f, 0, &Label); Label.VSplitLeft(100.0f, 0, &TextBox); TextBox.VSplitLeft(20.0f, 0, &TextBox); TextBox.VSplitRight(60.0f, &TextBox, 0); UI()->DoLabel(&Label, Localize("Nickname"), 18.0f, -1); static float Offset = 0.0f; DoEditBox(&g_Config.m_PlayerName, &TextBox, g_Config.m_PlayerName, sizeof(g_Config.m_PlayerName), 12.0f, &Offset); } else { Box.HSplitBottom(20.f, &Box, &Part); Box.HSplitBottom(24.f, &Box, &Part); Part.VMargin(120.0f, &Part); static int s_Button = 0; if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || m_EscapePressed || m_EnterPressed) { if(m_Popup == POPUP_CONNECTING) Client()->Disconnect(); m_Popup = POPUP_NONE; } } } return 0; }
void CMenus::RenderSettingsIdentPlayer(CUIRect MainView, int Page) { CIdentity::CIdentEntry *pEntry = m_pClient->m_pIdentity->GetIdent(Page); if(!m_pClient->m_pIdentity->NumIdents() || !pEntry) return; CUIRect Button, Label; // skin info const CSkins::CSkin *pOwnSkin = m_pClient->m_pSkins->Get(m_pClient->m_pSkins->Find(pEntry->m_aSkin)); CTeeRenderInfo OwnSkinInfo; if(pEntry->m_UseCustomColor) { OwnSkinInfo.m_Texture = pOwnSkin->m_ColorTexture; OwnSkinInfo.m_ColorBody = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorBody); OwnSkinInfo.m_ColorFeet = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorFeet); } else { OwnSkinInfo.m_Texture = pOwnSkin->m_OrgTexture; OwnSkinInfo.m_ColorBody = vec4(1.0f, 1.0f, 1.0f, 1.0f); OwnSkinInfo.m_ColorFeet = vec4(1.0f, 1.0f, 1.0f, 1.0f); } OwnSkinInfo.m_Size = 50.0f*UI()->Scale(); char aBuf[128]; MainView.Margin(10.0f, &MainView); MainView.HSplitTop(50.0f, &Label, &MainView); RenderTools()->DrawUIRect(&Label, vec4(1,1,1,0.2f), CUI::CORNER_ALL, 25.0f); Label.VSplitLeft(15.0f, 0, &Label); Label.HSplitTop(3.0f, 0, &Label); const bool IsMain = m_pClient->m_pIdentity->UsingIdent(Page, false); const bool IsDummy = m_pClient->m_pIdentity->UsingIdent(Page, true); str_format(aBuf, sizeof(aBuf), "%s", IsMain && !IsDummy ? Localize("Main Identity: ") : !IsMain && IsDummy ? Localize("Dummy's Identity: ") : IsMain && IsDummy ? Localize("Both's Identity: ") : ""); if(str_length(pEntry->m_aTitle) > 0) str_append(aBuf, pEntry->m_aTitle, sizeof(aBuf)); else str_append(aBuf, pEntry->m_aName, sizeof(aBuf)); UI()->DoLabelScaled(&Label, aBuf, 35.0f, -1, (int)Label.w); MainView.HSplitTop(10.0f, 0, &MainView); // skin view MainView.HSplitTop(50.0f, &Label, 0); Label.VSplitMid(0, &Label); RenderTools()->DrawUIRect(&Label, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); RenderTools()->RenderTee(CAnimState::GetIdle(), &OwnSkinInfo, 0, vec2(1, 0), vec2(Label.x+30.0f, Label.y+28.0f)); Label.HSplitTop(15.0f, 0, &Label); Label.VSplitLeft(70.0f, 0, &Label); UI()->DoLabelScaled(&Label, pEntry->m_aSkin, 14.0f, -1, 150); // ident title MainView.HSplitTop(20.0f, &Button, &MainView); Button.VSplitLeft(80.0f, &Label, &Button); Button.VSplitLeft(150.0f, &Button, 0); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Title")); UI()->DoLabelScaled(&Label, aBuf, 14.0, -1); static float s_OffsetTitle[512] = {0.0f}; CPointerContainer ContainerTitle(&s_OffsetTitle[Page]); if(DoEditBox(&ContainerTitle, &Button, pEntry->m_aTitle, sizeof(pEntry->m_aTitle), 14.0f, &s_OffsetTitle[Page], false, CUI::CORNER_ALL, "", 0, Localize("a custom title to display this identity"))) m_NeedSendinfo = true; // player name MainView.HSplitTop(3.0f, 0, &MainView); MainView.HSplitTop(20.0f, &Button, &MainView); Button.VSplitLeft(80.0f, &Label, &Button); Button.VSplitLeft(150.0f, &Button, 0); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Name")); UI()->DoLabelScaled(&Label, aBuf, 14.0, -1); static float s_OffsetName[512] = {0.0f}; CPointerContainer ContainerName(&s_OffsetName[Page]); if(DoEditBox(&ContainerName, &Button, pEntry->m_aName, sizeof(g_Config.m_PlayerName), 14.0f, &s_OffsetName[Page])) m_NeedSendinfo = true; // player clan MainView.HSplitTop(3.0f, 0, &MainView); MainView.HSplitTop(20.0f, &Button, &MainView); Button.VSplitLeft(80.0f, &Label, &Button); Button.VSplitLeft(150.0f, &Button, 0); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Clan")); UI()->DoLabelScaled(&Label, aBuf, 14.0, -1); static float s_OffsetClan[512] = {0.0f}; CPointerContainer ContainerClan(&s_OffsetClan[Page]); if(DoEditBox(&ContainerClan, &Button, pEntry->m_aClan, sizeof(g_Config.m_PlayerClan), 14.0f, &s_OffsetClan[Page])) m_NeedSendinfo = true; // apply identity MainView.HSplitTop(3.0f, 0, &MainView); MainView.HSplitTop(20.0f, &Button, &MainView); Button.VSplitLeft(80.0f, &Label, &Button); Button.VSplitLeft(150.0f, &Button, 0); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Apply as")); UI()->DoLabelScaled(&Label, aBuf, 14.0, -1); Button.VSplitMid(&Button, &Label); static CButtonContainer s_ApplyButtonMain[512], s_ApplyButtonDummy[512]; if(!IsMain) { if(DoButton_Menu(&s_ApplyButtonMain[Page], Localize("Main"), 0, &Button, "", CUI::CORNER_L|CUI::CORNER_R*IsDummy, vec4(0.7f, 0.7f, 0.2f, 1.0f))) GameClient()->m_pIdentity->ApplyIdent(Page, false); } if(!IsDummy) { if(DoButton_Menu(&s_ApplyButtonDummy[Page], Localize("Dummy"), 0, &Label, "", CUI::CORNER_R|CUI::CORNER_L*IsMain, vec4(0.2f, 0.7f, 0.7f, 1.0f))) GameClient()->m_pIdentity->ApplyIdent(Page, true); } // country flag selector int *Country = &pEntry->m_Country; MainView.HSplitTop(20.0f, 0, &MainView); static float s_ScrollValue = 0.0f; int OldSelected = -1; static CButtonContainer s_Listbox; UiDoListboxStart(&s_Listbox, &MainView, 50.0f, Localize("Country"), "", m_pClient->m_pCountryFlags->Num(), 6, OldSelected, s_ScrollValue); for(int i = 0; i < m_pClient->m_pCountryFlags->Num(); ++i) { const CCountryFlags::CCountryFlag *pFlag = m_pClient->m_pCountryFlags->GetByIndex(i); if(pFlag->m_CountryCode == *Country) OldSelected = i; CPointerContainer Container(&pFlag->m_CountryCode); CListboxItem Item = UiDoListboxNextItem(&Container, OldSelected == i); if(Item.m_Visible) { CUIRect FlagLabel; Item.m_Rect.Margin(5.0f, &Item.m_Rect); Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &FlagLabel); float OldWidth = Item.m_Rect.w; Item.m_Rect.w = Item.m_Rect.h*2; Item.m_Rect.x += (OldWidth-Item.m_Rect.w)/ 2.0f; vec4 Color(1.0f, 1.0f, 1.0f, 1.0f); m_pClient->m_pCountryFlags->Render(pFlag->m_CountryCode, &Color, Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h); if(pFlag->m_Texture != -1) UI()->DoLabel(&FlagLabel, pFlag->m_aCountryCodeString, 10.0f, 0); } } const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0); if(OldSelected != NewSelected) { *Country = m_pClient->m_pCountryFlags->GetByIndex(NewSelected)->m_CountryCode; if(m_Dummy) m_NeedSendDummyinfo = true; else m_NeedSendinfo = true; } }
void CMenus::RenderStartMenu(CUIRect MainView) { CUIRect Menu; MainView.VMargin(MainView.w/2-190.0f, &Menu); Menu.HMargin(145.0f, &Menu); RenderTools()->DrawUIRect(&Menu, vec4(0,0,0,0.5f), CUI::CORNER_ALL, 10.0f); Menu.Margin(5.0f, &Menu); CUIRect Button; Menu.HSplitTop(40.0f, &Button, &Menu); static int s_PlayButton = 0; if(DoButton_MenuImage(&s_PlayButton, Localize("Play Game"), 0, &Button, "play_game", 10.0f, 0.5f)) m_MenuPage = g_Config.m_UiBrowserPage; Menu.HSplitTop(5.0f, 0, &Menu); // little space Menu.HSplitTop(40.0f, &Button, &Menu); static int s_MapEditorButton = 0; if(DoButton_MenuImage(&s_MapEditorButton, Localize("Map Editor"), 0, &Button, "editor", 10.0f, 0.5f)) { g_Config.m_ClEditor = 1; Input()->MouseModeRelative(); } Menu.HSplitTop(5.0f, 0, &Menu); // little space Menu.HSplitTop(40.0f, &Button, &Menu); static int s_DemoButton = 0; if(DoButton_MenuImage(&s_DemoButton, Localize("Demos"), 0, &Button, "demos", 10.0f, 0.5f)) { m_MenuPage = PAGE_DEMOS; DemolistPopulate(); DemolistOnUpdate(false); } Menu.HSplitTop(5.0f, 0, &Menu); // little space Menu.HSplitTop(40.0f, &Button, &Menu); static int s_LocalServerButton = 0; if(DoButton_MenuImage(&s_LocalServerButton, Localize("Create Local Server"), 0, &Button, "local_server", 10.0f, 0.5f)) { } Menu.HSplitTop(5.0f, 0, &Menu); // little space Menu.HSplitTop(40.0f, &Button, &Menu); static int s_SettingsButton = 0; if(DoButton_MenuImage(&s_SettingsButton, Localize("Settings"), 0, &Button, "settings", 10.0f, 0.5f)) { m_MenuPage = PAGE_SETTINGS; } Menu.HSplitBottom(45.0f, &Menu, &Button); static int s_QuitButton = 0; if(DoButton_Menu(&s_QuitButton, Localize("Quit Game"), 0, &Button, 15.0f, 0.5f)) m_Popup = POPUP_QUIT; // render version CUIRect Version; MainView.HSplitBottom(50.0f, 0, &Version); Version.VMargin(50.0f, &Version); char aBuf[64]; if(str_comp(Client()->LatestVersion(), "0") != 0) { str_format(aBuf, sizeof(aBuf), Localize("Teeworlds %s is out! Download it at www.teeworlds.com!"), Client()->LatestVersion()); TextRender()->TextColor(1.0f, 0.4f, 0.4f, 1.0f); UI()->DoLabelScaled(&Version, aBuf, 14.0f, 0); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); } UI()->DoLabelScaled(&Version, GAME_VERSION, 14.0f, 1); }
void CMenus::RenderSettingsIdentTee(CUIRect MainView, int Page) { CIdentity::CIdentEntry *pEntry = m_pClient->m_pIdentity->GetIdent(Page); if(!m_pClient->m_pIdentity->NumIdents() || !pEntry) return; CUIRect Button, Label, View; // skin info const CSkins::CSkin *pOwnSkin = m_pClient->m_pSkins->Get(m_pClient->m_pSkins->Find(pEntry->m_aSkin)); CTeeRenderInfo OwnSkinInfo; if(pEntry->m_UseCustomColor) { OwnSkinInfo.m_Texture = pOwnSkin->m_ColorTexture; OwnSkinInfo.m_ColorBody = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorBody); OwnSkinInfo.m_ColorFeet = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorFeet); } else { OwnSkinInfo.m_Texture = pOwnSkin->m_OrgTexture; OwnSkinInfo.m_ColorBody = vec4(1.0f, 1.0f, 1.0f, 1.0f); OwnSkinInfo.m_ColorFeet = vec4(1.0f, 1.0f, 1.0f, 1.0f); } OwnSkinInfo.m_Size = 50.0f*UI()->Scale(); MainView.Margin(10.0f, &MainView); MainView.HSplitTop(50.0f, &Label, &MainView); Label.VSplitMid(&View, &Label); // skin view RenderTools()->DrawUIRect(&Label, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 10.0f); RenderTools()->RenderTee(CAnimState::GetIdle(), &OwnSkinInfo, 0, vec2(1, 0), vec2(Label.x+30.0f, Label.y+28.0f)); Label.HSplitTop(15.0f, 0, &Label); Label.VSplitLeft(70.0f, 0, &Label); UI()->DoLabelScaled(&Label, pEntry->m_aSkin, 14.0f, -1, 150); // player name View.HSplitTop(20.0f, &Button, &View); Button.VSplitLeft(230.0f, &Button, 0); static CButtonContainer s_VanillaSkinsOnly; if(DoButton_CheckBox(&s_VanillaSkinsOnly, Localize("Allow Vanilla Skins only"), g_Config.m_ClVanillaSkinsOnly, &Button)) { g_Config.m_ClVanillaSkinsOnly ^= 1; GameClient()->m_pSkins->RefreshSkinList(); m_InitSkinlist = true; } // player clan View.HSplitTop(5.0f, 0, &View); View.HSplitTop(20.0f, &Button, &View); Button.VSplitLeft(230.0f, &Button, 0); static CButtonContainer s_CheckboxUseCustomColor; if(DoButton_CheckBox(&s_CheckboxUseCustomColor, Localize("Custom colors"), pEntry->m_UseCustomColor, &Button)) { pEntry->m_UseCustomColor ^= 1; m_NeedSendinfo = true; } // apply identity MainView.HSplitTop(5.0f, 0, &MainView); // vanilla skins only MainView.HSplitTop(10.0f, 0, &View); if(pEntry->m_UseCustomColor) { CUIRect aRects[2]; MainView.VSplitMid(&aRects[0], &aRects[1]); aRects[0].VSplitRight(10.0f, &aRects[0], 0); aRects[1].VSplitRight(10.0f, &aRects[1], 0); int *paColors[2] = { &pEntry->m_ColorBody, &pEntry->m_ColorFeet }; const char *paParts[] = { Localize("Body"), Localize("Feet")}; const char *paLabels[] = { Localize("Hue"), Localize("Sat."), Localize("Lht.")}; static int s_aColorSlider[2][3] = { { 0 } }; for(int i = 0; i < 2; i++) { aRects[i].HSplitTop(20.0f, &Label, &aRects[i]); UI()->DoLabelScaled(&Label, paParts[i], 14.0f, -1); aRects[i].VSplitLeft(20.0f, 0, &aRects[i]); aRects[i].HSplitTop(2.5f, 0, &aRects[i]); int PrevColor = *paColors[i]; int Color = 0; for(int s = 0; s < 3; s++) { aRects[i].HSplitTop(20.0f, &Label, &aRects[i]); Label.VSplitLeft(100.0f, &Label, &Button); Button.HMargin(2.0f, &Button); float k = ((PrevColor>>((2-s)*8))&0xff) / 255.0f; CPointerContainer Container(&s_aColorSlider[i][s]); k = DoScrollbarH(&Container, &Button, k, 0, (int)(k * 100.0f)); Color <<= 8; Color += clamp((int)(k*255), 0, 255); UI()->DoLabelScaled(&Label, paLabels[s], 14.0f, -1); } if(PrevColor != Color) m_NeedSendinfo = true; *paColors[i] = Color; } }
void CMenus::RenderServerInfo(CUIRect MainView) { if(!m_pClient->m_Snap.m_pLocalInfo) return; // fetch server info CServerInfo CurrentServerInfo; Client()->GetServerInfo(&CurrentServerInfo); // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); CUIRect View, ServerInfo, GameInfo, Motd; float x = 0.0f; float y = 0.0f; char aBuf[1024]; // set view to use for all sub-modules MainView.Margin(10.0f, &View); // serverinfo View.HSplitTop(View.h/2/UI()->Scale()-5.0f, &ServerInfo, &Motd); ServerInfo.VSplitLeft(View.w/2/UI()->Scale()-5.0f, &ServerInfo, &GameInfo); RenderTools()->DrawUIRect(&ServerInfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); ServerInfo.Margin(5.0f, &ServerInfo); x = 5.0f; y = 0.0f; TextRender()->Text(0, ServerInfo.x+x, ServerInfo.y+y, 32, Localize("Server info"), 250); y += 32.0f+5.0f; mem_zero(aBuf, sizeof(aBuf)); str_format( aBuf, sizeof(aBuf), "%s\n\n" "%s: %s\n" "%s: %d\n" "%s: %s\n" "%s: %s\n", CurrentServerInfo.m_aName, Localize("Address"), g_Config.m_UiServerAddress, Localize("Ping"), m_pClient->m_Snap.m_pLocalInfo->m_Latency, Localize("Version"), CurrentServerInfo.m_aVersion, Localize("Password"), CurrentServerInfo.m_Flags &1 ? Localize("Yes") : Localize("No") ); TextRender()->Text(0, ServerInfo.x+x, ServerInfo.y+y, 20, aBuf, 250); { CUIRect Button; int IsFavorite = ServerBrowser()->IsFavorite(CurrentServerInfo.m_NetAddr); ServerInfo.HSplitBottom(20.0f, &ServerInfo, &Button); static int s_AddFavButton = 0; if(DoButton_CheckBox(&s_AddFavButton, Localize("Favorite"), IsFavorite, &Button)) { if(IsFavorite) ServerBrowser()->RemoveFavorite(CurrentServerInfo.m_NetAddr); else ServerBrowser()->AddFavorite(CurrentServerInfo.m_NetAddr); } } // gameinfo GameInfo.VSplitLeft(10.0f, 0x0, &GameInfo); RenderTools()->DrawUIRect(&GameInfo, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); GameInfo.Margin(5.0f, &GameInfo); x = 5.0f; y = 0.0f; TextRender()->Text(0, GameInfo.x+x, GameInfo.y+y, 32, Localize("Game info"), 250); y += 32.0f+5.0f; if(m_pClient->m_Snap.m_pGameInfoObj) { mem_zero(aBuf, sizeof(aBuf)); str_format( aBuf, sizeof(aBuf), "\n\n" "%s: %s\n" "%s: %s\n" "%s: %d\n" "%s: %d\n" "\n" "%s: %d/%d\n", Localize("Game type"), CurrentServerInfo.m_aGameType, Localize("Map"), CurrentServerInfo.m_aMap, Localize("Score limit"), m_pClient->m_Snap.m_pGameInfoObj->m_ScoreLimit, Localize("Time limit"), m_pClient->m_Snap.m_pGameInfoObj->m_TimeLimit, Localize("Players"), m_pClient->m_Snap.m_NumPlayers, CurrentServerInfo.m_MaxClients ); TextRender()->Text(0, GameInfo.x+x, GameInfo.y+y, 20, aBuf, 250); } // motd Motd.HSplitTop(10.0f, 0, &Motd); RenderTools()->DrawUIRect(&Motd, vec4(1,1,1,0.25f), CUI::CORNER_ALL, 10.0f); Motd.Margin(5.0f, &Motd); y = 0.0f; x = 5.0f; TextRender()->Text(0, Motd.x+x, Motd.y+y, 32, Localize("MOTD"), -1); y += 32.0f+5.0f; TextRender()->Text(0, Motd.x+x, Motd.y+y, 16, m_pClient->m_pMotd->m_aServerMotd, (int)Motd.w); }
void CMenus::RenderSettingsIdent(CUIRect MainView) { CALLSTACK_ADD(); static int s_LegacyIsOpen = 0; if(s_LegacyIsOpen) { s_LegacyIsOpen = RenderSettingsIdentLegacy(MainView); return; } // render background CUIRect Temp, TabBar, Button, Label, View; static int Page = 0; int numID = m_pClient->m_pIdentity->NumIdents(); // add a new identity from current settings as we need at least one if(numID == 0) m_pClient->m_pIdentity->AddIdent(); MainView.VSplitLeft(240.0f, &TabBar, &MainView); TabBar.VSplitRight(2.0f, &TabBar, &Button); RenderTools()->DrawUIRect(&Button, vec4(0.0f, 0.8f, 0.6f, 0.5f), 0, 0); TabBar.HSplitTop(20.0f, &Button, &TabBar); static CButtonContainer s_ButtonOpenLegacy; if(DoButton_Menu(&s_ButtonOpenLegacy, Localize("Open legacy view"), 0, &Button, 0, CUI::CORNER_T)) s_LegacyIsOpen = 1; static CButtonContainer s_aDeleteIDs[512]; static CButtonContainer s_aUpIDs[512]; static CButtonContainer s_aDownIDs[512]; static CButtonContainer s_aPageIDs[512]; static CButtonContainer s_LeftListbox; static float s_LeftListboxScrollVal = 0.0f; UiDoListboxStart(&s_LeftListbox, &TabBar, 24.0f, "", "", numID+1, 1, -1, s_LeftListboxScrollVal, 0); for(int i = 0; i < numID+1; i++) { if(i >= 512) break; CIdentity::CIdentEntry *pEntry = m_pClient->m_pIdentity->GetIdent(i); CPointerContainer Container(pEntry); CListboxItem Item = UiDoListboxNextItem(&Container, false/*Page == i*/); if(!Item.m_Visible) continue; Button = Item.m_Rect; if(i == numID) { Button.HSplitBottom(4.0f, &Button, 0); Button.VSplitRight(240.0f, 0, &Temp); if(DoButton_MenuTab(&s_aPageIDs[i], Localize("Add Identity"), false, &Button, CUI::CORNER_B, vec4(0.7f, 0.7f, 0.2f, ms_ColorTabbarActive.a), vec4(0.7f, 0.7f, 0.2f, ms_ColorTabbarInactive.a))) m_pClient->m_pIdentity->AddIdent(); break; } if(DoButton_MenuTab(&s_aPageIDs[i], "", Page == i, &Button, i == 0 ? CUI::CORNER_T : 0, vec4(0.2f, 0.6f, 0.2f, ms_ColorTabbarActive.a), vec4(0.2f, 0.6f, 0.2f, ms_ColorTabbarInactive.a))) Page = i; Button.VSplitRight(Button.h, 0, &Temp); Temp.Margin(4.0f, &Temp); if(m_pClient->m_pIdentity->NumIdents() > 1) { if(DoButton_Menu(&s_aDeleteIDs[i], "×", 0, &Temp, 0, CUI::CORNER_R | (i < numID - 1 ? 0 : CUI::CORNER_L), vec4(0.7f, 0.2f, 0.2f, 0.9f))) { m_pClient->m_pIdentity->DeleteIdent(i); if(i < Page) Page--; } } if(i < numID-1) { Button.VSplitRight(Button.h, 0, &Temp); Temp.Margin(4.0f, &Temp); Temp.x -= 16.0f; if(DoButton_Menu(&s_aDownIDs[i], "↓", 0, &Temp, 0, i >= 1 ? 0 : CUI::CORNER_L)) { m_pClient->m_pIdentity->SwapIdent(i, 1); m_MousePos.y += 36.0f; if(Page == i) Page++; else if(i == Page-1) Page--; } } if(i >= 1) { Button.VSplitRight(Button.h, 0, &Temp); Temp.Margin(4.0f, &Temp); Temp.x -= 32.0f; if(DoButton_Menu(&s_aUpIDs[i], "↑", 0, &Temp, 0, i < numID-1 ? CUI::CORNER_L : CUI::CORNER_ALL)) { m_MousePos.y -= 36.0f; m_pClient->m_pIdentity->SwapIdent(i, -1); if(i == Page) Page--; else if(i == Page+1) Page++; } } Button.HSplitTop(Button.h*0.25f, 0, &Label); static int DefaultSkin = -1; if(DefaultSkin < 0) DefaultSkin = m_pClient->m_pSkins->Find("default"); int SkinID = m_pClient->m_pSkins->Find(pEntry->m_aSkin); if(SkinID < 0) SkinID = DefaultSkin; const CSkins::CSkin *pOwnSkin = m_pClient->m_pSkins->Get(SkinID); CTeeRenderInfo OwnSkinInfo; if(pEntry->m_UseCustomColor) { OwnSkinInfo.m_Texture = pOwnSkin->m_ColorTexture; OwnSkinInfo.m_ColorBody = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorBody); OwnSkinInfo.m_ColorFeet = m_pClient->m_pSkins->GetColorV4(pEntry->m_ColorFeet); } else { OwnSkinInfo.m_Texture = pOwnSkin->m_OrgTexture; OwnSkinInfo.m_ColorBody = vec4(1.0f, 1.0f, 1.0f, 1.0f); OwnSkinInfo.m_ColorFeet = vec4(1.0f, 1.0f, 1.0f, 1.0f); } OwnSkinInfo.m_Size = 26.0f*UI()->Scale(); RenderTools()->RenderTee(CAnimState::GetIdle(), &OwnSkinInfo, 0, vec2(1, 0), vec2(Button.x + OwnSkinInfo.m_Size, Button.y + Button.h *0.6f)); Button.HMargin(2.0f, &Button); Button.HSplitBottom(16.0f, 0, &Button); const bool IsMain = m_pClient->m_pIdentity->UsingIdent(i, false); const bool IsDummy = m_pClient->m_pIdentity->UsingIdent(i, true); vec3 rgb = IsMain && !IsDummy ? vec3(0.7f, 0.7f, 0.2f) : !IsMain && IsDummy ? vec3(0.2f, 0.7f, 0.7f) : IsMain && IsDummy ? vec3(0.2f, 0.7f, 0.2f) : vec3(1,1,1); TextRender()->TextColor(rgb.r, rgb.g, rgb.b, 1.0f); if(str_length(pEntry->m_aTitle) > 0) UI()->DoLabelScaled(&Button, pEntry->m_aTitle, 14.0f, 0); else UI()->DoLabelScaled(&Button, pEntry->m_aName, 14.0f, 0); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); } UiDoListboxEnd(&s_LeftListboxScrollVal, 0); MainView.HSplitTop(20.0f, &Temp, &View); Temp.VMargin(5.0f, &Temp); Temp.VSplitMid(&Button, &Temp); MainView.Margin(10.0f, &MainView); static int s_ControlPage = 0; CButtonContainer s_ButtonPlayer; if(DoButton_MenuTab(&s_ButtonPlayer, Localize("Player"), s_ControlPage == 0, &Button, CUI::CORNER_L)) s_ControlPage = 0; CButtonContainer s_ButtonTee; if(DoButton_MenuTab(&s_ButtonTee, Localize("Tee"), s_ControlPage == 1, &Temp, CUI::CORNER_R)) s_ControlPage = 1; if(s_ControlPage == 0) RenderSettingsIdentPlayer(View, Page); if(s_ControlPage == 1) RenderSettingsIdentTee(View, Page); }
CMenus::CListboxItem CMenus::UiDoListboxNextItem(const void *pId, bool Selected) { int ThisItemIndex = gs_ListBoxItemIndex; if(Selected) { if(gs_ListBoxSelectedIndex == gs_ListBoxNewSelected) gs_ListBoxNewSelected = ThisItemIndex; gs_ListBoxSelectedIndex = ThisItemIndex; } CListboxItem Item = UiDoListboxNextRow(); if(Item.m_Visible && UI()->DoButtonLogic(pId, "", gs_ListBoxSelectedIndex == gs_ListBoxItemIndex, &Item.m_HitRect)) gs_ListBoxNewSelected = ThisItemIndex; // process input, regard selected index if(gs_ListBoxSelectedIndex == ThisItemIndex) { if(!gs_ListBoxDoneEvents) { gs_ListBoxDoneEvents = 1; if(m_EnterPressed || (UI()->ActiveItem() == pId && Input()->MouseDoubleClick())) { gs_ListBoxItemActivated = true; UI()->SetActiveItem(0); } else { for(int i = 0; i < m_NumInputEvents; i++) { int NewIndex = -1; if(m_aInputEvents[i].m_Flags&IInput::FLAG_PRESS) { if(m_aInputEvents[i].m_Key == KEY_DOWN) NewIndex = gs_ListBoxNewSelected + 1; if(m_aInputEvents[i].m_Key == KEY_UP) NewIndex = gs_ListBoxNewSelected - 1; } if(NewIndex > -1 && NewIndex < gs_ListBoxNumItems) { // scroll float Offset = (NewIndex/gs_ListBoxItemsPerRow-gs_ListBoxNewSelected/gs_ListBoxItemsPerRow)*gs_ListBoxRowHeight; int Scroll = gs_ListBoxOriginalView.y > Item.m_Rect.y+Offset ? -1 : gs_ListBoxOriginalView.y+gs_ListBoxOriginalView.h < Item.m_Rect.y+Item.m_Rect.h+Offset ? 1 : 0; if(Scroll) { int NumViewable = (int)(gs_ListBoxOriginalView.h/gs_ListBoxRowHeight) + 1; int ScrollNum = (gs_ListBoxNumItems+gs_ListBoxItemsPerRow-1)/gs_ListBoxItemsPerRow-NumViewable+1; if(Scroll < 0) { int Num = (gs_ListBoxOriginalView.y-Item.m_Rect.y-Offset+gs_ListBoxRowHeight-1.0f)/gs_ListBoxRowHeight; gs_ListBoxScrollValue -= (1.0f/ScrollNum)*Num; } else { int Num = (Item.m_Rect.y+Item.m_Rect.h+Offset-(gs_ListBoxOriginalView.y+gs_ListBoxOriginalView.h)+gs_ListBoxRowHeight-1.0f)/ gs_ListBoxRowHeight; gs_ListBoxScrollValue += (1.0f/ScrollNum)*Num; } if(gs_ListBoxScrollValue < 0.0f) gs_ListBoxScrollValue = 0.0f; if(gs_ListBoxScrollValue > 1.0f) gs_ListBoxScrollValue = 1.0f; } gs_ListBoxNewSelected = NewIndex; } } } } //selected_index = i; CUIRect r = Item.m_Rect; r.Margin(1.5f, &r); RenderTools()->DrawUIRect(&r, vec4(1,1,1,0.5f), CUI::CORNER_ALL, 4.0f); } return Item; }
void CMenus::RenderPlayers(CUIRect MainView) { const float ButtonHeight = 20.0f; const float Spacing = 2.0f; const float NameWidth = 250.0f; const float ClanWidth = 250.0f; CUIRect Label, Row; MainView.HSplitBottom(80.0f, &MainView, 0); MainView.HSplitTop(20.0f, 0, &MainView); RenderTools()->DrawUIRect(&MainView, vec4(0.0f, 0.0f, 0.0f, 0.25f+ms_BackgroundAlpha), CUI::CORNER_ALL, 5.0f); // player options MainView.HSplitTop(ButtonHeight, &Label, &MainView); Label.y += 2.0f; UI()->DoLabel(&Label, Localize("Player options"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_CENTER); RenderTools()->DrawUIRect(&MainView, vec4(0.0, 0.0, 0.0, 0.25f), CUI::CORNER_ALL, 5.0f); MainView.Margin(5.0f, &MainView); // headline MainView.HSplitTop(ButtonHeight, &Row, &MainView); Row.VSplitLeft(ButtonHeight+Spacing, 0, &Row); Row.VSplitLeft(NameWidth, &Label, &Row); Label.y += 2.0f; UI()->DoLabel(&Label, Localize("Player"), ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT); Row.VSplitRight(2*ButtonHeight, &Row, &Label); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_MUTE); IGraphics::CQuadItem QuadItem(Label.x, Label.y, Label.w, Label.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); Row.VSplitRight(2*Spacing, &Row, 0); Row.VSplitRight(2*ButtonHeight, &Row, &Label); Graphics()->TextureSet(g_pData->m_aImages[IMAGE_GUIICONS].m_Id); Graphics()->QuadsBegin(); RenderTools()->SelectSprite(SPRITE_GUIICON_FRIEND); QuadItem = IGraphics::CQuadItem(Label.x, Label.y, Label.w, Label.h); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); // options static int s_aPlayerIDs[MAX_CLIENTS][2] = {{0}}; int Teams[3] = { TEAM_RED, TEAM_BLUE, TEAM_SPECTATORS }; for(int Team = 0; Team < 3; ++Team) { for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i) { if(i == m_pClient->m_LocalClientID || !m_pClient->m_aClients[i].m_Active || m_pClient->m_aClients[i].m_Team != Teams[Team]) continue; MainView.HSplitTop(ButtonHeight, &Row, &MainView); if(Count++ % 2 == 0) RenderTools()->DrawUIRect(&Row, vec4(1.0f, 1.0f, 1.0f, 0.25f), CUI::CORNER_ALL, 5.0f); // player info Row.VSplitLeft(ButtonHeight, &Label, &Row); Label.y += 2.0f; CTeeRenderInfo Info = m_pClient->m_aClients[i].m_RenderInfo; Info.m_Size = Label.h; RenderTools()->RenderTee(CAnimState::GetIdle(), &Info, EMOTE_NORMAL, vec2(1.0f, 0.0f), vec2(Label.x + Label.h / 2, Label.y + Label.h / 2)); Row.VSplitLeft(2*Spacing, 0, &Row); Row.VSplitLeft(NameWidth, &Label, &Row); Label.y += 2.0f; if(g_Config.m_ClShowUserId) { CTextCursor Cursor; TextRender()->SetCursor(&Cursor, Label.x, Label.y, ButtonHeight*ms_FontmodHeight*0.8f, TEXTFLAG_RENDER); RenderTools()->DrawClientID(TextRender(), &Cursor, i); Label.VSplitLeft(ButtonHeight, 0, &Label); } char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[i].m_aName : ""); UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT); Row.VSplitLeft(Spacing, 0, &Row); Row.VSplitLeft(ClanWidth, &Label, &Row); Label.y += 2.0f; str_format(aBuf, sizeof(aBuf), "%s", g_Config.m_ClShowsocial ? m_pClient->m_aClients[i].m_aClan : ""); UI()->DoLabel(&Label, aBuf, ButtonHeight*ms_FontmodHeight*0.8f, CUI::ALIGN_LEFT); // ignore button Row.VSplitRight(ButtonHeight/2, &Row, 0); Row.VSplitRight(ButtonHeight, &Row, &Label); if(g_Config.m_ClFilterchat == 2 || (g_Config.m_ClFilterchat == 1 && !m_pClient->m_aClients[i].m_Friend)) DoButton_Toggle(&s_aPlayerIDs[i][0], 1, &Label, false); else if(DoButton_Toggle(&s_aPlayerIDs[i][0], m_pClient->m_aClients[i].m_ChatIgnore, &Label, true)) m_pClient->m_aClients[i].m_ChatIgnore ^= 1; // friend button Row.VSplitRight(2*Spacing+ButtonHeight,&Row, 0); Row.VSplitRight(ButtonHeight, &Row, &Label); if(DoButton_Toggle(&s_aPlayerIDs[i][1], m_pClient->m_aClients[i].m_Friend, &Label, true)) { if(m_pClient->m_aClients[i].m_Friend) m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[i].m_aName, m_pClient->m_aClients[i].m_aClan); else m_pClient->Friends()->AddFriend(m_pClient->m_aClients[i].m_aName, m_pClient->m_aClients[i].m_aClan); m_pClient->m_aClients[i].m_Friend ^= 1; } } } }
void CMenus::RenderDemoList(CUIRect MainView) { static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); DemolistOnUpdate(true); s_Inited = 1; } char aFooterLabel[128] = {0}; if(m_DemolistSelectedIndex >= 0) { CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex]; if(str_comp(Item->m_aFilename, "..") == 0) str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel)); else if(m_DemolistSelectedIsDir) str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel)); else { if(!Item->m_InfosLoaded) { char aBuffer[512]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename); Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, &Item->m_Info); Item->m_InfosLoaded = true; } if(!Item->m_Valid) str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel)); else str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel)); } } // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, RenameRect, FileIcon, ListBox; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect); ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &RenameRect, &ButtonBar); MainView.HSplitBottom(140.0f, &ListBox, &MainView); // render demo info MainView.VMargin(5.0f, &MainView); MainView.HSplitBottom(5.0f, &MainView, 0); RenderTools()->DrawUIRect(&MainView, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); if(!m_DemolistSelectedIsDir && m_DemolistSelectedIndex >= 0 && m_lDemos[m_DemolistSelectedIndex].m_Valid) { CUIRect Left, Right, Labels; MainView.Margin(20.0f, &MainView); MainView.VSplitMid(&Labels, &MainView); // left side Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Created:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aTimestamp, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Type:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aType, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Length:"), 14.0f, -1); int Length = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aLength[3]); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Version:"), 14.0f, -1); str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].m_Info.m_Version); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); // right side Labels = MainView; Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Map:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapName, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Size:"), 14.0f, -1); Length = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[3]); str_format(aBuf, sizeof(aBuf), Localize("%d Bytes"), Length); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(20.0f, 0, &Left); Left.VSplitLeft(130.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1); unsigned Crc = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[0]<<24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[1]<<16) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[2]<<8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapCrc[3]); str_format(aBuf, sizeof(aBuf), "%08x", Crc); UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1); Labels.HSplitTop(5.0f, 0, &Labels); Labels.HSplitTop(20.0f, &Left, &Labels); Left.VSplitLeft(150.0f, &Left, &Right); UI()->DoLabelScaled(&Left, Localize("Netversion:"), 14.0f, -1); UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aNetversion, 14.0f, -1); } static int s_DemoListId = 0; static float s_ScrollValue = 0; UiDoListboxStart(&s_DemoListId, &ListBox, 17.0f, Localize("Demos"), aFooterLabel, m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue); for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) { CListboxItem Item = UiDoListboxNextItem((void*)(&r.front())); if(Item.m_Visible) { Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Item.m_Rect); Item.m_Rect.VSplitLeft(5.0f, 0, &Item.m_Rect); DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &FileIcon); UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1); } } bool Activated = false; m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); DemolistOnUpdate(false); static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) { DemolistPopulate(); DemolistOnUpdate(false); } static int s_PlayButton = 0; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated) { if(m_DemolistSelectedIndex >= 0) { if(m_DemolistSelectedIsDir) // folder { if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { char aTemp[256]; str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); DemolistOnUpdate(true); } else // file { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); else { UI()->SetActiveItem(0); return; } } } } if(!m_DemolistSelectedIsDir) { static int s_DeleteButton = 0; if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_DELETE_DEMO; return; } } static int s_RenameButton = 0; if(DoButton_Menu(&s_RenameButton, Localize("Rename"), 0, &RenameRect)) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_RENAME_DEMO; str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile)); return; } } } }
void CMenus::RenderDemoList(CUIRect MainView) { static int s_Inited = 0; if(!s_Inited) { DemolistPopulate(); DemolistOnUpdate(true); s_Inited = 1; } // delete demo if(m_DemolistDelEntry) { if(m_DemolistSelectedIndex >= 0 && !m_DemolistSelectedIsDir) { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); if(Storage()->RemoveFile(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType)) { DemolistPopulate(); DemolistOnUpdate(false); } } m_DemolistDelEntry = false; } char aFooterLabel[128] = {0}; if(m_DemolistSelectedIndex >= 0) { CDemoItem *Item = &m_lDemos[m_DemolistSelectedIndex]; if(str_comp(Item->m_aFilename, "..") == 0) str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel)); else if(m_DemolistSelectedIsDir) str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel)); else { if(!Item->m_InfosLoaded) { char aBuffer[512]; str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item->m_aFilename); Item->m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item->m_StorageType, Item->m_aMap, sizeof(Item->m_aMap)); Item->m_InfosLoaded = true; } if(!Item->m_Valid) str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel)); else str_format(aFooterLabel, sizeof(aFooterLabel), "%s: %s", Localize("Map"), Item->m_aMap); } } // render background RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_ALL, 10.0f); MainView.Margin(10.0f, &MainView); CUIRect ButtonBar, RefreshRect, PlayRect, DeleteRect, FileIcon; MainView.HSplitBottom(ms_ButtonHeight+5.0f, &MainView, &ButtonBar); ButtonBar.HSplitTop(5.0f, 0, &ButtonBar); ButtonBar.VSplitRight(130.0f, &ButtonBar, &PlayRect); ButtonBar.VSplitLeft(130.0f, &RefreshRect, &ButtonBar); ButtonBar.VSplitLeft(10.0f, &DeleteRect, &ButtonBar); ButtonBar.VSplitLeft(120.0f, &DeleteRect, &ButtonBar); static int s_DemoListId = 0; static float s_ScrollValue = 0; UiDoListboxStart(&s_DemoListId, &MainView, 17.0f, Localize("Demos"), aFooterLabel, m_lDemos.size(), 1, m_DemolistSelectedIndex, s_ScrollValue); for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front()) { CListboxItem Item = UiDoListboxNextItem((void*)(&r.front())); if(Item.m_Visible) { Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Item.m_Rect); Item.m_Rect.VSplitLeft(5.0f, 0, &Item.m_Rect); DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir?SPRITE_FILE_FOLDER:SPRITE_FILE_DEMO1, &FileIcon); UI()->DoLabel(&Item.m_Rect, r.front().m_aName, Item.m_Rect.h*ms_FontmodHeight, -1); } } bool Activated = false; m_DemolistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); DemolistOnUpdate(false); static int s_RefreshButton = 0; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect)) { DemolistPopulate(); DemolistOnUpdate(false); } static int s_PlayButton = 0; if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir?Localize("Open"):Localize("Play"), 0, &PlayRect) || Activated) { if(m_DemolistSelectedIndex >= 0) { if(m_DemolistSelectedIsDir) // folder { if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder fs_parent_dir(m_aCurrentDemoFolder); else // sub folder { char aTemp[256]; str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp)); str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename); m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType; } DemolistPopulate(); DemolistOnUpdate(true); } else // file { char aBuf[512]; str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename); const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType); if(pError) PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok")); else { UI()->SetActiveItem(0); return; } } } } if(!m_DemolistSelectedIsDir) { static int s_DeleteButton = 0; if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed) { if(m_DemolistSelectedIndex >= 0) { UI()->SetActiveItem(0); m_Popup = POPUP_DELETE_DEMO; } } } }