diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 9971d5384..8eb6ced29 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -73,6 +73,28 @@ int CServerBrowser::AddFilter(int SortHash, int Ping, int Country, const char* p return m_lFilters.size()-1; } +void CServerBrowser::GetFilter(int Index, int *pSortHash, int *pPing, int *pCountry, char* pGametype, char* pServerAddress) +{ + CServerFilter *pFilter = &m_lFilters[Index]; + *pSortHash = pFilter->m_SortHash; + *pPing = pFilter->m_Ping; + *pCountry = pFilter->m_Country; + str_copy(pGametype, pFilter->m_aGametype, sizeof(pFilter->m_aGametype)); + str_copy(pServerAddress, pFilter->m_aServerAddress, sizeof(pFilter->m_aServerAddress)); +} + +void CServerBrowser::SetFilter(int Index, int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress) +{ + CServerFilter *pFilter = &m_lFilters[Index]; + pFilter->m_SortHash = SortHash; + pFilter->m_Ping = Ping; + pFilter->m_Country = Country; + str_copy(pFilter->m_aGametype, pGametype, sizeof(pFilter->m_aGametype)); + str_copy(pFilter->m_aServerAddress, pServerAddress, sizeof(pFilter->m_aServerAddress)); + + pFilter->m_pServerBrowser->Update(true); +} + void CServerBrowser::RemoveFilter(int Index) { m_lFilters.remove_index(Index); diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h index e25ec290a..1595179fc 100644 --- a/src/engine/client/serverbrowser.h +++ b/src/engine/client/serverbrowser.h @@ -64,6 +64,8 @@ public: array m_lFilters; int AddFilter(int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress); + void SetFilter(int Index, int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress); + void GetFilter(int Index, int *pSortHash, int *pPing, int *pCountry, char* pGametype, char* pServerAddress); void RemoveFilter(int Index); CServerBrowser(); diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index 55d262568..c3613bc0e 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -117,6 +117,8 @@ public: virtual void RemoveFavorite(const NETADDR &Addr) = 0; virtual int AddFilter(int Flag, int Ping, int Country, const char* pGametype, const char* pServerAddress) = 0; + virtual void SetFilter(int Index, int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress) = 0; + virtual void GetFilter(int Index, int *pSortHash, int *pPing, int *pCountry, char* pGametype, char* pServerAddress) = 0; virtual void RemoveFilter(int Index) = 0; }; diff --git a/src/game/client/components/menus.cpp b/src/game/client/components/menus.cpp index de1d8ca13..3ad9b141c 100644 --- a/src/game/client/components/menus.cpp +++ b/src/game/client/components/menus.cpp @@ -74,6 +74,8 @@ CMenus::CMenus() m_FriendlistSelectedIndex = -1; + m_SelectedFilter = 0; + m_SelectedServer.m_Filter = -1; m_SelectedServer.m_Index = -1; } @@ -301,6 +303,21 @@ int CMenus::DoButton_SpriteClean(int ImageID, int SpriteID, const CUIRect *pRect return ReturnValue; } +int CMenus::DoButton_SpriteCleanID(const void *pID, int ImageID, int SpriteID, const CUIRect *pRect) +{ + int Inside = UI()->MouseInside(pRect); + + Graphics()->TextureSet(g_pData->m_aImages[ImageID].m_Id); + Graphics()->QuadsBegin(); + Graphics()->SetColor(1.0f, 1.0f, 1.0f, Inside ? 1.0f : 0.6f); + RenderTools()->SelectSprite(SpriteID); + IGraphics::CQuadItem QuadItem(pRect->x, pRect->y, pRect->w, pRect->h); + Graphics()->QuadsDrawTL(&QuadItem, 1); + Graphics()->QuadsEnd(); + + return UI()->DoButtonLogic(pID, 0, 0, pRect); +} + int CMenus::DoButton_MouseOver(int ImageID, int SpriteID, const CUIRect *pRect) { int Inside = UI()->MouseInside(pRect); @@ -1184,6 +1201,9 @@ int CMenus::Render() m_MenuPage = PAGE_START; } } + + // do overlay popups + DoPopupMenu(); } else { @@ -1451,9 +1471,18 @@ int CMenus::Render() Box.HSplitBottom(20.f, &Box, 0); Box.VMargin(20.0f, &Box); + // selected filter + CBrowserFilter *pFilter = &m_lFilters[m_SelectedFilter]; + int SortHash = 0; + int Ping = 0; + int Country = 0; + char aGametype[32]; + char aServerAddress[16]; + pFilter->GetFilter(&SortHash, &Ping, &Country, aGametype, aServerAddress); + static int ActSelection = -2; if(ActSelection == -2) - ActSelection = g_Config.m_BrFilterCountryIndex; + ActSelection = Country; static float s_ScrollValue = 0.0f; int OldSelected = -1; UiDoListboxStart(&s_ScrollValue, &Box, 50.0f, Localize("Country"), "", m_pClient->m_pCountryFlags->Num(), 6, OldSelected, s_ScrollValue); @@ -1488,14 +1517,13 @@ int CMenus::Render() static int s_Button = 0; if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Part) || m_EnterPressed) { - g_Config.m_BrFilterCountryIndex = ActSelection; - Client()->ServerBrowserUpdate(); + pFilter->SetFilter(SortHash, Ping, ActSelection, aGametype, aServerAddress); m_Popup = POPUP_NONE; } if(m_EscapePressed) { - ActSelection = g_Config.m_BrFilterCountryIndex; + ActSelection = Country; m_Popup = POPUP_NONE; } } diff --git a/src/game/client/components/menus.h b/src/game/client/components/menus.h index 0385cf53b..3ef986bc0 100644 --- a/src/game/client/components/menus.h +++ b/src/game/client/components/menus.h @@ -42,6 +42,7 @@ class CMenus : public CComponent int DoButton_DemoPlayer(const void *pID, const char *pText, const CUIRect *pRect); int DoButton_Sprite(const void *pID, int ImageID, int SpriteID, const CUIRect *pRect, int Corners); int DoButton_SpriteClean(int ImageID, int SpriteID, const CUIRect *pRect); + int DoButton_SpriteCleanID(const void *pID, int ImageID, int SpriteID, const CUIRect *pRect); int DoButton_Toggle(const void *pID, int Checked, const CUIRect *pRect, bool Active); int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, float r=5.0f, float FontFactor=0.0f, int Corners=CUI::CORNER_ALL); int DoButton_MenuImage(const void *pID, const char *pText, int Checked, const CUIRect *pRect, const char *pImageName, float r=5.0f, float FontFactor=0.0f); @@ -287,16 +288,21 @@ class CMenus : public CComponent int Filter() const; const char* Name() const; - void SetFilter(int Num); + void SetFilterNum(int Num); int NumSortedServers() const; int NumPlayers() const; const CServerInfo *SortedGet(int Index) const; const void *ID(int Index) const; + + void GetFilter(int *pSortHash, int *pPing, int *pCountry, char* pGametype, char* pServerAddress); + void SetFilter(int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress); }; array m_lFilters; + int m_SelectedFilter; + void RemoveFilter(int FilterIndex); void Move(bool Up, int Filter); @@ -406,6 +412,12 @@ class CMenus : public CComponent void RenderSettings(CUIRect MainView); void SetActive(bool Active); + + void InvokePopupMenu(void *pID, int Flags, float X, float Y, float W, float H, int (*pfnFunc)(CMenus *pMenu, CUIRect Rect), void *pExtra=0); + void DoPopupMenu(); + + static int PopupFilter(CMenus *pMenus, CUIRect View); + public: void RenderBackground(); diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 7157818db..e98afa877 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -88,11 +88,21 @@ const CServerInfo *CMenus::CBrowserFilter::SortedGet(int Index) const return m_pServerBrowser->SortedGet(m_Filter, Index); } -void CMenus::CBrowserFilter::SetFilter(int Num) +void CMenus::CBrowserFilter::SetFilterNum(int Num) { m_Filter = Num; } +void CMenus::CBrowserFilter::GetFilter(int *pSortHash, int *pPing, int *pCountry, char* pGametype, char* pServerAddress) +{ + m_pServerBrowser->GetFilter(m_Filter, pSortHash, pPing, pCountry, pGametype, pServerAddress); +} + +void CMenus::CBrowserFilter::SetFilter(int SortHash, int Ping, int Country, const char* pGametype, const char* pServerAddress) +{ + m_pServerBrowser->SetFilter(m_Filter, SortHash, Ping, Country, pGametype, pServerAddress); +} + void CMenus::RemoveFilter(int FilterIndex) { int Filter = m_lFilters[FilterIndex].Filter(); @@ -104,7 +114,7 @@ void CMenus::RemoveFilter(int FilterIndex) { CBrowserFilter *pFilter = &m_lFilters[i]; if(pFilter->Filter() > Filter) - pFilter->SetFilter(pFilter->Filter()-1); + pFilter->SetFilterNum(pFilter->Filter()-1); } } @@ -402,9 +412,11 @@ bool CMenus::RenderFilterHeader(CUIRect View, int FilterIndex) View.VSplitRight(2.0f, &Button, 0); Button.VSplitRight(18.0f, &View, &Button); - if(DoButton_SpriteClean(IMAGE_BROWSERICONS, SPRITE_BROWSERICON_EDIT, &Button)) + if(DoButton_SpriteCleanID(pFilter, IMAGE_BROWSERICONS, SPRITE_BROWSERICON_EDIT, &Button)) // TODO: using the address of filter as ID is prolly a bad idea { - // + static int s_EditPopupID = 0; + m_SelectedFilter = FilterIndex; + InvokePopupMenu(&s_EditPopupID, 0, UI()->MouseX(), UI()->MouseY(), 200.0f, 310.0f, PopupFilter); } View.VSplitRight(2.0f, &Button, 0); diff --git a/src/game/client/components/menus_popups.cpp b/src/game/client/components/menus_popups.cpp new file mode 100644 index 000000000..329dfec83 --- /dev/null +++ b/src/game/client/components/menus_popups.cpp @@ -0,0 +1,219 @@ +/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ +/* If you are missing that file, acquire a complete release at teeworlds.com. */ + +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "countryflags.h" +#include "menus.h" + + +// popup menu handling +static struct +{ + CUIRect m_Rect; + void *m_pId; + int (*m_pfnFunc)(CMenus *pMenu, CUIRect Rect); + int m_IsMenu; + void *m_pExtra; +} s_Popups[8]; + +static int g_NumPopups = 0; + +void CMenus::InvokePopupMenu(void *pID, int Flags, float x, float y, float Width, float Height, int (*pfnFunc)(CMenus *pMenu, CUIRect Rect), void *pExtra) +{ + if(x + Width > UI()->Screen()->w) + x -= Width; + if(y + Height > UI()->Screen()->h) + y -= Height; + s_Popups[g_NumPopups].m_pId = pID; + s_Popups[g_NumPopups].m_IsMenu = Flags; + s_Popups[g_NumPopups].m_Rect.x = x; + s_Popups[g_NumPopups].m_Rect.y = y; + s_Popups[g_NumPopups].m_Rect.w = Width; + s_Popups[g_NumPopups].m_Rect.h = Height; + s_Popups[g_NumPopups].m_pfnFunc = pfnFunc; + s_Popups[g_NumPopups].m_pExtra = pExtra; + g_NumPopups++; +} + +void CMenus::DoPopupMenu() +{ + for(int i = 0; i < g_NumPopups; i++) + { + bool Inside = UI()->MouseInside(&s_Popups[i].m_Rect); + UI()->SetHotItem(&s_Popups[i].m_pId); + + if(UI()->ActiveItem() == &s_Popups[i].m_pId) + { + if(!UI()->MouseButton(0)) + { + if(!Inside) + g_NumPopups--; + UI()->SetActiveItem(0); + } + } + else if(UI()->HotItem() == &s_Popups[i].m_pId) + { + if(UI()->MouseButton(0)) + UI()->SetActiveItem(&s_Popups[i].m_pId); + } + + int Corners = CUI::CORNER_ALL; + if(s_Popups[i].m_IsMenu) + Corners = CUI::CORNER_R|CUI::CORNER_B; + + CUIRect r = s_Popups[i].m_Rect; + RenderTools()->DrawUIRect(&r, vec4(0.5f,0.5f,0.5f,0.75f), Corners, 3.0f); + r.Margin(1.0f, &r); + RenderTools()->DrawUIRect(&r, vec4(0,0,0,0.75f), Corners, 3.0f); + r.Margin(4.0f, &r); + + if(s_Popups[i].m_pfnFunc(this, r)) + g_NumPopups--; + + if(Input()->KeyDown(KEY_ESCAPE)) + g_NumPopups--; + } +} + +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]; + int SortHash = 0; + int Ping = 0; + int Country = 0; + char aGametype[32]; + char aServerAddress[16]; + pFilter->GetFilter(&SortHash, &Ping, &Country, aGametype, aServerAddress); + + // 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, 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); + static int s_BrFilterEmpty = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterEmpty, Localize("Has people playing"), SortHash&IServerBrowser::FILTER_EMPTY, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_EMPTY, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterSpectators = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterSpectators, Localize("Count players only"), SortHash&IServerBrowser::FILTER_SPECTATORS, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_SPECTATORS, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterFull = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterFull, Localize("Server not full"), SortHash&IServerBrowser::FILTER_FULL, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_FULL, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterFriends = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterFriends, Localize("Show friends only"), SortHash&IServerBrowser::FILTER_FRIENDS, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_FRIENDS, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterPw = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterPw, Localize("No password"), SortHash&IServerBrowser::FILTER_PW, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_PW, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterCompatversion = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterCompatversion, Localize("Compatible version"), SortHash&IServerBrowser::FILTER_COMPAT_VERSION, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_COMPAT_VERSION, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterPure = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterPure, Localize("Standard gametype"), SortHash&IServerBrowser::FILTER_PURE, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_PURE, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterPureMap = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterPureMap, Localize("Standard map"), SortHash&IServerBrowser::FILTER_PURE_MAP, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_PURE_MAP, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(20.0f, &Button, &ServerFilter); + static int s_BrFilterGametypeStrict = 0; + if(pMenus->DoButton_CheckBox(&s_BrFilterGametypeStrict, Localize("Strict gametype filter"), SortHash&IServerBrowser::FILTER_GAMETYPE_STRICT, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_GAMETYPE_STRICT, Ping, Country, aGametype, aServerAddress); + + ServerFilter.HSplitTop(5.0f, 0, &ServerFilter); + + ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); + pMenus->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; + static int s_BrFilterGametype = 0; + if(pMenus->DoEditBox(&s_BrFilterGametype, &Button, aGametype, sizeof(aGametype), FontSize, &Offset)) + pFilter->SetFilter(SortHash, Ping, Country, aGametype, aServerAddress); + + { + ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); + CUIRect EditBox; + Button.VSplitRight(60.0f, &Button, &EditBox); + + pMenus->UI()->DoLabelScaled(&Button, Localize("Maximum ping:"), FontSize, -1); + + char aBuf[5]; + str_format(aBuf, sizeof(aBuf), "%d", 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 != Ping) + pFilter->SetFilter(SortHash, NewPing, Country, aGametype, aServerAddress); + } + + // server address + ServerFilter.HSplitTop(3.0f, 0, &ServerFilter); + ServerFilter.HSplitTop(19.0f, &Button, &ServerFilter); + pMenus->UI()->DoLabelScaled(&Button, Localize("Server address:"), FontSize, -1); + Button.VSplitRight(60.0f, 0, &Button); + static float OffsetAddr = 0.0f; + static int s_BrFilterServerAddress = 0; + if(pMenus->DoEditBox(&s_BrFilterServerAddress, &Button, aServerAddress, sizeof(aServerAddress), FontSize, &OffsetAddr)) + pFilter->SetFilter(SortHash, Ping, Country, aGametype, aServerAddress); + + // 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:"), SortHash&IServerBrowser::FILTER_COUNTRY, &Button)) + pFilter->SetFilter(SortHash^IServerBrowser::FILTER_COUNTRY, Ping, Country, aGametype, aServerAddress); + + float OldWidth = Rect.w; + Rect.w = Rect.h*2; + Rect.x += (OldWidth-Rect.w)/2.0f; + vec4 Color(1.0f, 1.0f, 1.0f, SortHash^IServerBrowser::FILTER_COUNTRY?1.0f: 0.5f); + pMenus->m_pClient->m_pCountryFlags->Render(Country, &Color, Rect.x, Rect.y, Rect.w, Rect.h); + + static int s_BrFilterCountryIndex = 0; + if(SortHash^IServerBrowser::FILTER_COUNTRY && pMenus->UI()->DoButtonLogic(&s_BrFilterCountryIndex, "", 0, &Rect)) + pMenus->m_Popup = POPUP_COUNTRY; + } + + return 0; +}