void CMenus::UiDoListboxStart(void *pId, const CUIRect *pRect, float RowHeight, const char *pTitle, const char *pBottomText, int NumItems, int ItemsPerRow, int SelectedIndex, float ScrollValue) { CUIRect Scroll, Row; CUIRect View = *pRect; CUIRect Header, Footer; // draw header View.HSplitTop(ms_ListheaderHeight, &Header, &View); RenderTools()->DrawUIRect(&Header, vec4(1,1,1,0.25f), CUI::CORNER_T, 5.0f); UI()->DoLabel(&Header, pTitle, Header.h*ms_FontmodHeight, 0); // draw footers View.HSplitBottom(ms_ListheaderHeight, &View, &Footer); RenderTools()->DrawUIRect(&Footer, vec4(1,1,1,0.25f), CUI::CORNER_B, 5.0f); Footer.VSplitLeft(10.0f, 0, &Footer); UI()->DoLabel(&Footer, pBottomText, Header.h*ms_FontmodHeight, 0); // background RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.15f), 0, 0); // prepare the scroll View.VSplitRight(15, &View, &Scroll); // setup the variables gs_ListBoxOriginalView = View; gs_ListBoxSelectedIndex = SelectedIndex; gs_ListBoxNewSelected = SelectedIndex; gs_ListBoxItemIndex = 0; gs_ListBoxRowHeight = RowHeight; gs_ListBoxNumItems = NumItems; gs_ListBoxItemsPerRow = ItemsPerRow; gs_ListBoxDoneEvents = 0; gs_ListBoxScrollValue = ScrollValue; gs_ListBoxItemActivated = false; // do the scrollbar View.HSplitTop(gs_ListBoxRowHeight, &Row, 0); int NumViewable = (int)(gs_ListBoxOriginalView.h/Row.h) + 1; int Num = (NumItems+gs_ListBoxItemsPerRow-1)/gs_ListBoxItemsPerRow-NumViewable+1; if(Num < 0) Num = 0; if(Num > 0) { if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP)) gs_ListBoxScrollValue -= 1.0f/Num; if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN)) gs_ListBoxScrollValue += 1.0f/Num; if(gs_ListBoxScrollValue < 0.0f) gs_ListBoxScrollValue = 0.0f; if(gs_ListBoxScrollValue > 1.0f) gs_ListBoxScrollValue = 1.0f; } Scroll.HMargin(5.0f, &Scroll); gs_ListBoxScrollValue = DoScrollbarV(pId, &Scroll, gs_ListBoxScrollValue); // the list gs_ListBoxView = gs_ListBoxOriginalView; gs_ListBoxView.VMargin(5.0f, &gs_ListBoxView); UI()->ClipEnable(&gs_ListBoxView); gs_ListBoxView.y -= gs_ListBoxScrollValue*Num*Row.h; }
int CMenus::DoEditBox(void *pID, const CUIRect *pRect, char *pStr, unsigned StrSize, float FontSize, float *Offset, bool Hidden, int Corners) { int Inside = UI()->MouseInside(pRect); bool ReturnValue = false; bool UpdateOffset = false; static int s_AtIndex = 0; static bool s_DoScroll = false; static float s_ScrollStart = 0.0f; FontSize *= UI()->Scale(); if(UI()->LastActiveItem() == pID) { int Len = str_length(pStr); if(Len == 0) s_AtIndex = 0; if(Inside && UI()->MouseButton(0)) { s_DoScroll = true; s_ScrollStart = UI()->MouseX(); int MxRel = (int)(UI()->MouseX() - pRect->x); for(int i = 1; i <= Len; i++) { if(TextRender()->TextWidth(0, FontSize, pStr, i) - *Offset + 10 > MxRel) { s_AtIndex = i - 1; break; } if(i == Len) s_AtIndex = Len; } } else if(!UI()->MouseButton(0)) s_DoScroll = false; else if(s_DoScroll) { // do scrolling if(UI()->MouseX() < pRect->x && s_ScrollStart-UI()->MouseX() > 10.0f) { s_AtIndex = max(0, s_AtIndex-1); s_ScrollStart = UI()->MouseX(); UpdateOffset = true; } else if(UI()->MouseX() > pRect->x+pRect->w && UI()->MouseX()-s_ScrollStart > 10.0f) { s_AtIndex = min(Len, s_AtIndex+1); s_ScrollStart = UI()->MouseX(); UpdateOffset = true; } } for(int i = 0; i < m_NumInputEvents; i++) { Len = str_length(pStr); ReturnValue |= CLineInput::Manipulate(m_aInputEvents[i], pStr, StrSize, &Len, &s_AtIndex); } } bool JustGotActive = false; if(UI()->ActiveItem() == pID) { if(!UI()->MouseButton(0)) { s_DoScroll = false; UI()->SetActiveItem(0); } } else if(UI()->HotItem() == pID) { if(UI()->MouseButton(0)) { if (UI()->LastActiveItem() != pID) JustGotActive = true; UI()->SetActiveItem(pID); } } if(Inside) UI()->SetHotItem(pID); CUIRect Textbox = *pRect; RenderTools()->DrawUIRect(&Textbox, vec4(1, 1, 1, 0.5f), Corners, 3.0f); Textbox.VMargin(2.0f, &Textbox); Textbox.HMargin(2.0f, &Textbox); const char *pDisplayStr = pStr; char aStars[128]; if(Hidden) { unsigned s = str_length(pStr); if(s >= sizeof(aStars)) s = sizeof(aStars)-1; for(unsigned int i = 0; i < s; ++i) aStars[i] = '*'; aStars[s] = 0; pDisplayStr = aStars; } // check if the text has to be moved if(UI()->LastActiveItem() == pID && !JustGotActive && (UpdateOffset || m_NumInputEvents)) { float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); if(w-*Offset > Textbox.w) { // move to the left float wt = TextRender()->TextWidth(0, FontSize, pDisplayStr, -1); do { *Offset += min(wt-*Offset-Textbox.w, Textbox.w/3); } while(w-*Offset > Textbox.w); } else if(w-*Offset < 0.0f) { // move to the right do { *Offset = max(0.0f, *Offset-Textbox.w/3); } while(w-*Offset < 0.0f); } } UI()->ClipEnable(pRect); Textbox.x -= *Offset; UI()->DoLabel(&Textbox, pDisplayStr, FontSize, -1); // render the cursor if(UI()->LastActiveItem() == pID && !JustGotActive) { float w = TextRender()->TextWidth(0, FontSize, pDisplayStr, s_AtIndex); Textbox = *pRect; Textbox.VSplitLeft(2.0f, 0, &Textbox); Textbox.x += (w-*Offset-TextRender()->TextWidth(0, FontSize, "|", -1)/2); if((2*time_get()/time_freq()) % 2) // make it blink UI()->DoLabel(&Textbox, "|", FontSize, -1); } UI()->ClipDisable(); return ReturnValue; }
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); 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_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"); 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[128]; 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)/1024.0f; m_DownloadSpeed = absolute((m_DownloadSpeed*(1.0f-(1.0f/m_DownloadSpeed))) + (Diff*(1.0f/m_DownloadSpeed))); 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); UI()->DoLabel(&Part, aBuf, 20.f, 0, -1); // time left const char *pTimeLeftString; int TimeLeft = (Client()->MapDownloadTotalsize()-Client()->MapDownloadAmount())/(m_DownloadSpeed*1024)+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_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_FriendlistSelectedIndex); 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::RenderServerbrowserFilters(CUIRect View) { CUIRect ServerFilter = View, FilterHeader; const float FontSize = 12.0f; ServerFilter.HSplitBottom(42.5f, &ServerFilter, 0); // server filter ServerFilter.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFilter); RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerFilter, vec4(0,0,0,0.15f), CUI::CORNER_B, 4.0f); UI()->DoLabelScaled(&FilterHeader, Localize("Server filter"), FontSize+2.0f, 0); CUIRect Button; ServerFilter.VSplitLeft(5.0f, 0, &ServerFilter); ServerFilter.Margin(3.0f, &ServerFilter); ServerFilter.VMargin(5.0f, &ServerFilter); ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterEmpty, Localize("Has people playing"), g_Config.m_BrFilterEmpty, &Button)) g_Config.m_BrFilterEmpty ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if(DoButton_CheckBox(&g_Config.m_BrFilterSpectators, Localize("Count players only"), g_Config.m_BrFilterSpectators, &Button)) g_Config.m_BrFilterSpectators ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterFull, Localize("Server not full"), g_Config.m_BrFilterFull, &Button)) g_Config.m_BrFilterFull ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterFriends, Localize("Show friends only"), g_Config.m_BrFilterFriends, &Button)) g_Config.m_BrFilterFriends ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox(&g_Config.m_BrFilterPw, Localize("No password"), g_Config.m_BrFilterPw, &Button)) g_Config.m_BrFilterPw ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterCompatversion, Localize("Compatible version"), g_Config.m_BrFilterCompatversion, &Button)) g_Config.m_BrFilterCompatversion ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPure, Localize("Standard gametype"), g_Config.m_BrFilterPure, &Button)) g_Config.m_BrFilterPure ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterPureMap, Localize("Standard map"), g_Config.m_BrFilterPureMap, &Button)) g_Config.m_BrFilterPureMap ^= 1; ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); if (DoButton_CheckBox((char *)&g_Config.m_BrFilterGametypeStrict, Localize("Strict gametype filter"), g_Config.m_BrFilterGametypeStrict, &Button)) g_Config.m_BrFilterGametypeStrict ^= 1; ServerFilter.HSplitTop(5.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); UI()->DoLabelScaled(&Button, Localize("Game types:"), FontSize, -1); Button.VSplitRight(60.0f, 0, &Button); ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); static float Offset = 0.0f; if(DoEditBox(&g_Config.m_BrFilterGametype, &Button, g_Config.m_BrFilterGametype, sizeof(g_Config.m_BrFilterGametype), FontSize, &Offset)) Client()->ServerBrowserUpdate(); { ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); CUIRect EditBox; Button.VSplitRight(60.0f, &Button, &EditBox); UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, -1); char aBuf[5]; str_format(aBuf, sizeof(aBuf), "%d", g_Config.m_BrFilterPing); static float Offset = 0.0f; DoEditBox(&g_Config.m_BrFilterPing, &EditBox, aBuf, sizeof(aBuf), FontSize, &Offset); g_Config.m_BrFilterPing = clamp(str_toint(aBuf), 0, 999); } // server address ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, -1); Button.VSplitRight(60.0f, 0, &Button); static float OffsetAddr = 0.0f; if(DoEditBox(&g_Config.m_BrFilterServerAddress, &Button, g_Config.m_BrFilterServerAddress, sizeof(g_Config.m_BrFilterServerAddress), FontSize, &OffsetAddr)) Client()->ServerBrowserUpdate(); // 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); if(DoButton_CheckBox(&g_Config.m_BrFilterCountry, Localize("Player country:"), g_Config.m_BrFilterCountry, &Button)) g_Config.m_BrFilterCountry ^= 1; float OldWidth = Rect.w; Rect.w = Rect.h*2; Rect.x += (OldWidth-Rect.w)/2.0f; vec4 Color(1.0f, 1.0f, 1.0f, g_Config.m_BrFilterCountry?1.0f: 0.5f); m_pClient->m_pCountryFlags->Render(g_Config.m_BrFilterCountryIndex, &Color, Rect.x, Rect.y, Rect.w, Rect.h); if(g_Config.m_BrFilterCountry && UI()->DoButtonLogic(&g_Config.m_BrFilterCountryIndex, "", 0, &Rect)) m_Popup = POPUP_COUNTRY; } ServerFilter.HSplitBottom(5.0f, &ServerFilter, 0); ServerFilter.HSplitBottom(ms_ButtonHeight-2.0f, &ServerFilter, &Button); static int s_ClearButton = 0; if(DoButton_Menu(&s_ClearButton, Localize("Reset filter"), 0, &Button)) { g_Config.m_BrFilterString[0] = 0; g_Config.m_BrFilterFull = 0; g_Config.m_BrFilterEmpty = 0; g_Config.m_BrFilterSpectators = 0; g_Config.m_BrFilterFriends = 0; g_Config.m_BrFilterCountry = 0; g_Config.m_BrFilterCountryIndex = -1; g_Config.m_BrFilterPw = 0; g_Config.m_BrFilterPing = 999; g_Config.m_BrFilterGametype[0] = 0; g_Config.m_BrFilterGametypeStrict = 0; g_Config.m_BrFilterServerAddress[0] = 0; g_Config.m_BrFilterPure = 1; g_Config.m_BrFilterPureMap = 1; g_Config.m_BrFilterCompatversion = 1; Client()->ServerBrowserUpdate(); } }
void CMenus::RenderServerbrowserFriends(CUIRect View) { static int s_Inited = 0; if(!s_Inited) { FriendlistOnUpdate(); s_Inited = 1; } CUIRect ServerFriends = View, FilterHeader; const float FontSize = 10.0f; // header ServerFriends.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFriends); RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerFriends, vec4(0,0,0,0.15f), 0, 4.0f); UI()->DoLabelScaled(&FilterHeader, Localize("Friends"), FontSize+4.0f, 0); CUIRect Button, List; ServerFriends.Margin(3.0f, &ServerFriends); ServerFriends.VMargin(3.0f, &ServerFriends); ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends); // friends list(remove friend) static float s_ScrollValue = 0; UiDoListboxStart(&m_lFriends, &List, 30.0f, "", "", m_lFriends.size(), 1, m_FriendlistSelectedIndex, s_ScrollValue); m_lFriends.sort_range(); for(int i = 0; i < m_lFriends.size(); ++i) { CListboxItem Item = UiDoListboxNextItem(&m_lFriends[i]); if(Item.m_Visible) { Item.m_Rect.Margin(1.5f, &Item.m_Rect); CUIRect OnState; Item.m_Rect.VSplitRight(30.0f, &Item.m_Rect, &OnState); RenderTools()->DrawUIRect(&Item.m_Rect, vec4(1.0f, 1.0f, 1.0f, 0.1f), CUI::CORNER_L, 4.0f); Item.m_Rect.VMargin(2.5f, &Item.m_Rect); Item.m_Rect.HSplitTop(12.0f, &Item.m_Rect, &Button); UI()->DoLabelScaled(&Item.m_Rect, m_lFriends[i].m_pFriendInfo->m_aName, FontSize, -1); UI()->DoLabelScaled(&Button, m_lFriends[i].m_pFriendInfo->m_aClan, FontSize, -1); RenderTools()->DrawUIRect(&OnState, m_lFriends[i].m_NumFound ? vec4(0.0f, 1.0f, 0.0f, 0.25f) : vec4(1.0f, 0.0f, 0.0f, 0.25f), CUI::CORNER_R, 4.0f); OnState.HMargin((OnState.h-FontSize)/3, &OnState); OnState.VMargin(5.0f, &OnState); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%i", m_lFriends[i].m_NumFound); UI()->DoLabelScaled(&OnState, aBuf, FontSize+2, 1); } } bool Activated = false; m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated); // activate found server with friend if(Activated && !m_EnterPressed && m_lFriends[m_FriendlistSelectedIndex].m_NumFound) { bool Found = false; int NumServers = ServerBrowser()->NumSortedServers(); for (int i = 0; i < NumServers && !Found; i++) { int ItemIndex = m_SelectedIndex != -1 ? (m_SelectedIndex+i+1)%NumServers : i; const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); if(pItem->m_FriendState != IFriends::FRIEND_NO) { for(int j = 0; j < pItem->m_NumClients && !Found; ++j) { if(pItem->m_aClients[j].m_FriendState != IFriends::FRIEND_NO && str_quickhash(pItem->m_aClients[j].m_aClan) == m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_ClanHash && (!m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_aName[0] || str_quickhash(pItem->m_aClients[j].m_aName) == m_lFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_NameHash)) { str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress, sizeof(g_Config.m_UiServerAddress)); m_ScrollOffset = ItemIndex; m_SelectedIndex = ItemIndex; Found = true; } } } } } ServerFriends.HSplitTop(2.5f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); if(m_FriendlistSelectedIndex != -1) { static int s_RemoveButton = 0; if(DoButton_Menu(&s_RemoveButton, Localize("Remove"), 0, &Button)) m_Popup = POPUP_REMOVE_FRIEND; } // add friend if(m_pClient->Friends()->NumFriends() < IFriends::MAX_FRIENDS) { ServerFriends.HSplitTop(10.0f, 0, &ServerFriends); ServerFriends.HSplitTop(19.0f, &Button, &ServerFriends); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%s:", Localize("Name")); UI()->DoLabelScaled(&Button, aBuf, FontSize, -1); Button.VSplitLeft(80.0f, 0, &Button); static char s_aName[MAX_NAME_LENGTH] = {0}; static float s_OffsetName = 0.0f; DoEditBox(&s_aName, &Button, s_aName, sizeof(s_aName), FontSize, &s_OffsetName); ServerFriends.HSplitTop(3.0f, 0, &ServerFriends); ServerFriends.HSplitTop(19.0f, &Button, &ServerFriends); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Clan")); UI()->DoLabelScaled(&Button, aBuf, FontSize, -1); Button.VSplitLeft(80.0f, 0, &Button); static char s_aClan[MAX_CLAN_LENGTH] = {0}; static float s_OffsetClan = 0.0f; DoEditBox(&s_aClan, &Button, s_aClan, sizeof(s_aClan), FontSize, &s_OffsetClan); ServerFriends.HSplitTop(3.0f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); static int s_AddButton = 0; if(DoButton_Menu(&s_AddButton, Localize("Add Friend"), 0, &Button)) { m_pClient->Friends()->AddFriend(s_aName, s_aClan); FriendlistOnUpdate(); Client()->ServerBrowserUpdate(); } } }
void CMenus::RenderServerbrowserFriends(CUIRect View) { CUIRect ServerFriends = View, FilterHeader; const float FontSize = 12.0f; // header ServerFriends.HSplitTop(ms_ListheaderHeight, &FilterHeader, &ServerFriends); RenderTools()->DrawUIRect(&FilterHeader, vec4(1,1,1,0.25f), CUI::CORNER_T, 4.0f); RenderTools()->DrawUIRect(&ServerFriends, vec4(0,0,0,0.15f), 0, 4.0f); UI()->DoLabelScaled(&FilterHeader, Localize("Friends"), FontSize+2.0f, 0); CUIRect Button, List; ServerFriends.VSplitLeft(5.0f, 0, &ServerFriends); ServerFriends.Margin(3.0f, &ServerFriends); ServerFriends.VMargin(5.0f, &ServerFriends); ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends); // friends list(remove friend) static int s_FriendList = 0; static float s_ScrollValue = 0; UiDoListboxStart(&s_FriendList, &List, 40.0f, "", "", m_pClient->Friends()->NumFriends(), 1, m_FriendlistSelectedIndex, s_ScrollValue); for(int i = 0; i < m_pClient->Friends()->NumFriends(); ++i) { const CFriendInfo *pFriend = m_pClient->Friends()->GetFriend(i); CListboxItem Item = UiDoListboxNextItem(pFriend); if(Item.m_Visible) { Item.m_Rect.Margin(2.5f, &Item.m_Rect); RenderTools()->DrawUIRect(&Item.m_Rect, vec4(1.0f, 1.0f, 1.0f, 0.1f), CUI::CORNER_ALL, 4.0f); Item.m_Rect.Margin(2.5f, &Item.m_Rect); Item.m_Rect.HSplitTop(14.0f, &Item.m_Rect, &Button); UI()->DoLabelScaled(&Item.m_Rect, pFriend->m_aName, FontSize, -1); UI()->DoLabelScaled(&Button, pFriend->m_aClan, FontSize, -1); } } m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, 0); ServerFriends.HSplitTop(2.5f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); if(m_FriendlistSelectedIndex != -1) { static int s_RemoveButton = 0; if(DoButton_Menu(&s_RemoveButton, Localize("Remove"), 0, &Button)) m_Popup = POPUP_REMOVE_FRIEND; } // add friend if(m_pClient->Friends()->NumFriends() < IFriends::MAX_FRIENDS) { ServerFriends.HSplitTop(10.0f, 0, &ServerFriends); ServerFriends.HSplitTop(19.0f, &Button, &ServerFriends); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%s:", Localize("Name")); UI()->DoLabelScaled(&Button, aBuf, FontSize, -1); Button.VSplitLeft(80.0f, 0, &Button); static char s_aName[MAX_NAME_LENGTH] = {0}; static float s_OffsetName = 0.0f; DoEditBox(&s_aName, &Button, s_aName, sizeof(s_aName), FontSize, &s_OffsetName); ServerFriends.HSplitTop(3.0f, 0, &ServerFriends); ServerFriends.HSplitTop(19.0f, &Button, &ServerFriends); str_format(aBuf, sizeof(aBuf), "%s:", Localize("Clan")); UI()->DoLabelScaled(&Button, aBuf, FontSize, -1); Button.VSplitLeft(80.0f, 0, &Button); static char s_aClan[MAX_CLAN_LENGTH] = {0}; static float s_OffsetClan = 0.0f; DoEditBox(&s_aClan, &Button, s_aClan, sizeof(s_aClan), FontSize, &s_OffsetClan); ServerFriends.HSplitTop(3.0f, 0, &ServerFriends); ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends); static int s_RemoveButton = 0; if(DoButton_Menu(&s_RemoveButton, Localize("Add Friend"), 0, &Button)) { m_pClient->Friends()->AddFriend(s_aName, s_aClan); Client()->ServerBrowserUpdate(); } } }
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(m_ScrollOffset) { s_ScrollValue = (float)(m_ScrollOffset)/ScrollNum; m_ScrollOffset = 0; } if(Input()->KeyPresses(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View)) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPresses(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View)) 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; // reset friend counter for(int i = 0; i < m_lFriends.size(); m_lFriends[i++].m_NumFound = 0); for (int i = 0; i < NumServers; i++) { int ItemIndex = i; const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex); NumPlayers += g_Config.m_BrFilterSpectators ? pItem->m_NumPlayers : pItem->m_NumClients; 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; // update friend counter if(pItem->m_FriendState != IFriends::FRIEND_NO) { for(int j = 0; j < pItem->m_NumClients; ++j) { if(pItem->m_aClients[j].m_FriendState != IFriends::FRIEND_NO) { unsigned NameHash = str_quickhash(pItem->m_aClients[j].m_aName); unsigned ClanHash = str_quickhash(pItem->m_aClients[j].m_aClan); for(int f = 0; f < m_lFriends.size(); ++f) { if(ClanHash == m_lFriends[f].m_pFriendInfo->m_ClanHash && (!m_lFriends[f].m_pFriendInfo->m_aName[0] || NameHash == m_lFriends[f].m_pFriendInfo->m_NameHash)) { m_lFriends[f].m_NumFound++; if(m_lFriends[f].m_pFriendInfo->m_aName[0]) break; } } } } } // 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&IServerBrowser::FLAG_PASSWORD) DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_LOCK, &Button); } else if(ID == COL_FLAG_PURE) { if(!(pItem->m_Flags&IServerBrowser::FLAG_PURE)) 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; if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit&IServerBrowser::QUICK_MAPNAME)) { // highlight the parts that matches const char *pStr = str_find_nocase(pItem->m_aMap, g_Config.m_BrFilterString); if(pStr) { TextRender()->TextEx(&Cursor, pItem->m_aMap, (int)(pStr-pItem->m_aMap)); 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_aMap, -1); } else TextRender()->TextEx(&Cursor, pItem->m_aMap, -1); } else if(ID == COL_PLAYERS) { CUIRect Icon; Button.VMargin(4.0f, &Button); if(pItem->m_FriendState != IFriends::FRIEND_NO) { Button.VSplitLeft(Button.h, &Icon, &Button); Icon.Margin(2.0f, &Icon); DoButton_Icon(IMAGE_BROWSEICONS, SPRITE_BROWSE_HEART, &Icon); } if(g_Config.m_BrFilterSpectators) str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumPlayers, pItem->m_MaxPlayers); else str_format(aTemp, sizeof(aTemp), "%i/%i", pItem->m_NumClients, pItem->m_MaxClients); if(g_Config.m_BrFilterString[0] && (pItem->m_QuickSearchHit&IServerBrowser::QUICK_PLAYER)) 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) { str_format(aTemp, sizeof(aTemp), "%i", pItem->m_Latency); UI()->DoLabelScaled(&Button, aTemp, 12.0f, 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; TextRender()->TextEx(&Cursor, pItem->m_aGameType, -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(240.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(240.0f-w-22.0f, &QuickSearch, &Button); static float Offset = 0.0f; if(DoEditBox(&g_Config.m_BrFilterString, &QuickSearch, g_Config.m_BrFilterString, sizeof(g_Config.m_BrFilterString), 12.0f, &Offset, false, CUI::CORNER_L)) Client()->ServerBrowserUpdate(); // 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); Client()->ServerBrowserUpdate(); } } // 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 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, vec4(0.0f, 0.0f, 0.0f, 0.25f), 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)&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]); str_format(aBuf, sizeof(aBuf), Localize("%d Bytes"), Size); 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 loading demo"), pError, 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::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); } }
void CMenus::UiDoListboxStart(CButtonContainer *pBC, const CUIRect *pRect, float RowHeight, const char *pTitle, const char *pBottomText, int NumItems, int ItemsPerRow, int SelectedIndex, float ScrollValue, int CornerTop, int CornerBottom) { CUIRect Scroll, Row; CUIRect View = *pRect; CUIRect Header, Footer; if(!pTitle) pTitle = ""; if(!pBottomText) pBottomText = ""; // draw header View.HSplitTop(ms_ListheaderHeight, &Header, &View); RenderTools()->DrawUIRect(&Header, vec4(1,1,1,0.25f), CornerTop, 5.0f); UI()->DoLabel(&Header, pTitle, Header.h*ms_FontmodHeight, 0); // draw footers View.HSplitBottom(ms_ListheaderHeight, &View, &Footer); RenderTools()->DrawUIRect(&Footer, vec4(1,1,1,0.25f), CornerBottom, 5.0f); Footer.VSplitLeft(10.0f, 0, &Footer); UI()->DoLabel(&Footer, pBottomText, Header.h*ms_FontmodHeight, 0); // background RenderTools()->DrawUIRect(&View, vec4(0,0,0,0.15f), 0, 0); // prepare the scroll #if defined(__ANDROID__) View.VSplitRight(50, &View, &Scroll); #else View.VSplitRight(15, &View, &Scroll); #endif // setup the variables gs_ListBoxOriginalView = View; gs_ListBoxSelectedIndex = SelectedIndex; gs_ListBoxNewSelected = SelectedIndex; gs_ListBoxItemIndex = 0; gs_ListBoxRowHeight = RowHeight; gs_ListBoxNumItems = NumItems; gs_ListBoxItemsPerRow = ItemsPerRow; gs_ListBoxDoneEvents = 0; gs_ListBoxScrollValue = ScrollValue; gs_ListBoxItemActivated = false; // do the scrollbar View.HSplitTop(gs_ListBoxRowHeight, &Row, 0); int NumViewable = (int)(gs_ListBoxOriginalView.h/Row.h) + 1; int Num = (NumItems+gs_ListBoxItemsPerRow-1)/gs_ListBoxItemsPerRow-NumViewable+1; if(Num < 0) Num = 0; if(Num > 0) { static std::map<const void*, std::pair<float, float> > s_NewVals; // maybe a map seems hacky, but it's a convenient way to get it to work // initialize if(s_NewVals.find(pBC->GetID()) == s_NewVals.end()) { s_NewVals[pBC->GetID()] = std::pair<float, float>(0.0f, 0.0f); } float& s_NewVal = s_NewVals[pBC->GetID()].first; if(UI()->ActiveItem() == pBC->GetID() || UI()->MouseInside(&Scroll)) // do not intervene the scrollbar's own logic s_NewVal = gs_ListBoxScrollValue; else { if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View) && m_pClient->m_pGameConsole->IsClosed()) s_NewVal -= 3.0f/Num; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View) && m_pClient->m_pGameConsole->IsClosed()) s_NewVal += 3.0f/Num; if(s_NewVal < 0.0f) s_NewVal = 0.0f; if(s_NewVal > 1.0f) s_NewVal = 1.0f; if(gs_ListBoxScrollValue != s_NewVals[pBC->GetID()].second) // move freely { float old = s_NewVal; s_NewVal = gs_ListBoxScrollValue; gs_ListBoxScrollValue = old; } smooth_set(&gs_ListBoxScrollValue, s_NewVal, 23.0f, Client()->RenderFrameTime()); s_NewVals[pBC->GetID()].second = gs_ListBoxScrollValue; } } Scroll.HMargin(5.0f, &Scroll); gs_ListBoxScrollValue = DoScrollbarV(pBC, &Scroll, gs_ListBoxScrollValue); // the list gs_ListBoxView = gs_ListBoxOriginalView; gs_ListBoxView.VMargin(5.0f, &gs_ListBoxView); UI()->ClipEnable(&gs_ListBoxView); gs_ListBoxView.y -= gs_ListBoxScrollValue*Num*Row.h; }
void CMenus::RenderDemoList(CUIRect MainView) { CALLSTACK_ADD(); 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++) { CPointerContainer Container(s_aCols[i].m_Caption); if(DoButton_GridHeader(&Container, 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 CButtonContainer s_ScrollBar; 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()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&ListBox) && m_pClient->m_pGameConsole->IsClosed()) s_ScrollValue -= 3.0f/ScrollNum; if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&ListBox) && m_pClient->m_pGameConsole->IsClosed()) 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()->HotItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #else if (m_EnterPressed || (Input()->MouseDoubleClick() && UI()->HotItem() == m_lDemos[m_DemolistSelectedIndex].m_aName)) #endif { UI()->SetActiveItem(0); Activated = true; } static CButtonContainer s_RefreshButton; if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect) || Input()->KeyPress(KEY_F5) || (Input()->KeyPress(KEY_R) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL)))) { DemolistPopulate(); DemolistOnUpdate(false); } static CButtonContainer s_PlayButton; 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 CButtonContainer s_DeleteButton; 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 CButtonContainer s_RenameButton; 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::RenderStartMenu(CUIRect MainView) { // render logo Graphics()->TextureSet(g_pData->m_aImages[IMAGE_BANNER].m_Id); Graphics()->QuadsBegin(); Graphics()->SetColor(1,1,1,1); IGraphics::CQuadItem QuadItem(MainView.w/2-140, 60, 280, 70); Graphics()->QuadsDrawTL(&QuadItem, 1); Graphics()->QuadsEnd(); CUIRect TopMenu, BottomMenu; MainView.VMargin(MainView.w/2-190.0f, &TopMenu); TopMenu.HSplitTop(365.0f, &TopMenu, &BottomMenu); //TopMenu.HSplitBottom(145.0f, &TopMenu, 0); RenderTools()->DrawUIRect4(&TopMenu, vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, g_Config.m_ClMenuAlpha/100.0f), vec4(0.0f, 0.0f, 0.0f, g_Config.m_ClMenuAlpha/100.0f), CUI::CORNER_B, 10.0f); TopMenu.HSplitTop(145.0f, 0, &TopMenu); CUIRect Button; int NewPage = -1; TopMenu.HSplitBottom(40.0f, &TopMenu, &Button); static CButtonContainer s_SettingsButton; if(DoButton_Menu(&s_SettingsButton, Localize("Settings"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "settings" : 0, CUI::CORNER_ALL, 10.0f, 0.5f) || CheckHotKey(KEY_S)) NewPage = PAGE_SETTINGS; /*TopMenu.HSplitBottom(5.0f, &TopMenu, 0); // little space TopMenu.HSplitBottom(40.0f, &TopMenu, &Bottom); static int s_LocalServerButton = 0; if(g_Config.m_ClShowStartMenuImages) { if(DoButton_MenuImage(&s_LocalServerButton, Localize("Local server"), 0, &Button, "local_server", 10.0f, 0.5f)) { } } else { if(DoButton_Menu(&s_LocalServerButton, Localize("Local server"), 0, &Button, CUI::CORNER_ALL, 10.0f, 0.5f)) { } }*/ TopMenu.HSplitBottom(5.0f, &TopMenu, 0); // little space TopMenu.HSplitBottom(40.0f, &TopMenu, &Button); static CButtonContainer s_DemoButton; if(DoButton_Menu(&s_DemoButton, Localize("Demos"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "demos" : 0, CUI::CORNER_ALL, 10.0f, 0.5f) || CheckHotKey(KEY_D)) { NewPage = PAGE_DEMOS; DemolistPopulate(); DemolistOnUpdate(false); } static bool EditorHotkeyWasPressed = true; static float EditorHotKeyChecktime = 0; TopMenu.HSplitBottom(5.0f, &TopMenu, 0); // little space TopMenu.HSplitBottom(40.0f, &TopMenu, &Button); static CButtonContainer s_MapEditorButton; if(DoButton_Menu(&s_MapEditorButton, Localize("Editor"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "editor" : 0, CUI::CORNER_ALL, 10.0f, 0.5f) || (!EditorHotkeyWasPressed && Client()->LocalTime() - EditorHotKeyChecktime < 0.1f && CheckHotKey(KEY_E))) { g_Config.m_ClEditor = 1; Input()->MouseModeRelative(); EditorHotkeyWasPressed = true; } if(!Input()->KeyIsPressed(KEY_E)) { EditorHotkeyWasPressed = false; EditorHotKeyChecktime = Client()->LocalTime(); } TopMenu.HSplitBottom(5.0f, &TopMenu, 0); // little space TopMenu.HSplitBottom(40.0f, &TopMenu, &Button); static CButtonContainer s_PlayButton; if(DoButton_Menu(&s_PlayButton, Localize("Play"), 0, &Button, g_Config.m_ClShowStartMenuImages ? "play_game" : 0, CUI::CORNER_ALL, 10.0f, 0.5f) || m_EnterPressed || CheckHotKey(KEY_P)) NewPage = g_Config.m_UiBrowserPage; BottomMenu.HSplitTop(90.0f, 0, &BottomMenu); RenderTools()->DrawUIRect4(&BottomMenu, vec4(0.0f, 0.0f, 0.0f, g_Config.m_ClMenuAlpha/100.0f), vec4(0.0f, 0.0f, 0.0f, g_Config.m_ClMenuAlpha/100.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), vec4(0.0f, 0.0f, 0.0f, 0.0f), CUI::CORNER_T, 10.0f); BottomMenu.HSplitTop(40.0f, &Button, &TopMenu); static CButtonContainer s_QuitButton; if(DoButton_Menu(&s_QuitButton, Localize("Quit"), 0, &Button, 0, CUI::CORNER_ALL, 10.0f, 0.5f) || m_EscapePressed || CheckHotKey(KEY_Q)) 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()->DoLabel(&Version, aBuf, 14.0f, CUI::ALIGN_CENTER); TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); } UI()->DoLabel(&Version, GAME_RELEASE_VERSION, 14.0f, CUI::ALIGN_RIGHT); if(NewPage != -1) SetMenuPage(NewPage); }
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); }
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; }
float CMenus::RenderDemoDetails(CUIRect View, void *pUser) { CMenus *pSelf = (CMenus*)pUser; // render demo info if(!pSelf->m_DemolistSelectedIsDir && pSelf->m_DemolistSelectedIndex >= 0 && pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Valid) { CUIRect Button; const float ButtonHeight = 20.0f; const float Spacing = 2.0f; View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); pSelf->DoInfoBox(&Button, Localize("Created"), pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aTimestamp); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); pSelf->DoInfoBox(&Button, Localize("Type"), pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aType); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); int Length = ((pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aLength[0]<<24)&0xFF000000) | ((pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aLength[1]<<16)&0xFF0000) | ((pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aLength[2]<<8)&0xFF00) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aLength[3]&0xFF); char aBuf[64]; str_format(aBuf, sizeof(aBuf), "%d:%02d", Length/60, Length%60); pSelf->DoInfoBox(&Button, Localize("Length"), aBuf); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); str_format(aBuf, sizeof(aBuf), "%d", pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_Version); pSelf->DoInfoBox(&Button, Localize("Version"), aBuf); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); pSelf->DoInfoBox(&Button, Localize("Netversion"), pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aNetversion); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); const int MarkerCount = DemoGetMarkerCount(pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info); str_format(aBuf, sizeof(aBuf), "%d", MarkerCount); if(MarkerCount > 0) pSelf->TextRender()->TextColor(0.5, 1, 0.5, 1); pSelf->DoInfoBox(&Button, Localize("Markers"), aBuf); pSelf->TextRender()->TextColor(1, 1, 1, 1); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); pSelf->DoInfoBox(&Button, Localize("Map"), pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapName); View.HSplitTop(Spacing, 0, &View); View.HSplitTop(ButtonHeight, &Button, &View); Button.VMargin(ButtonHeight, &Button); CUIRect ButtonRight; Button.VSplitMid(&Button, &ButtonRight); float Size = float((pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapSize[0]<<24) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapSize[1]<<16) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapSize[2]<<8) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapSize[3]))/1024.0f; str_format(aBuf, sizeof(aBuf), Localize("%.3f KiB"), Size); pSelf->DoInfoBox(&Button, Localize("Size"), aBuf); unsigned Crc = (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapCrc[0]<<24) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapCrc[1]<<16) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapCrc[2]<<8) | (pSelf->m_lDemos[pSelf->m_DemolistSelectedIndex].m_Info.m_aMapCrc[3]); str_format(aBuf, sizeof(aBuf), "%08x", Crc); pSelf->DoInfoBox(&ButtonRight, Localize("Crc"), aBuf); } //unused return 0.0f; }
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; }