Refactor client state handling in menus

Split menu rendering explicitly by client state. This makes the code more readable by not mixing code for rendering different states together as much and fixes issues where the menu was being rendered inconsistently for one frame when the state is changed, at the cost of some additional duplicated code.

The fullscreen popups shown when in the connecting and loading client states are now hard-coded for these states, instead of being mixed together with the other fullscreen popups, which can be shown when offline, ingame or during demo playback.

As a side effect of rendering the demo controls like the regular menu, the UI color will now also affect the demo controls menu background.

Move `CBackground::ChangePosition` calls inside functions to reduce duplicate code and improve readability.

Remove unnecessary `CMenus::m_ActivePage` variable.

Closes #7834.
This commit is contained in:
Robert Müller 2024-02-06 21:41:59 +01:00
parent 58ee780fa7
commit b4a22e2fee
6 changed files with 365 additions and 273 deletions

View file

@ -56,7 +56,6 @@ float CMenus::ms_ListheaderHeight = 17.0f;
CMenus::CMenus()
{
m_Popup = POPUP_NONE;
m_ActivePage = PAGE_INTERNET;
m_MenuPage = 0;
m_GamePage = PAGE_GAME;
@ -543,18 +542,17 @@ int CMenus::DoKeyReader(const void *pId, const CUIRect *pRect, int Key, int Modi
return NewKey;
}
void CMenus::RenderMenubar(CUIRect Box)
void CMenus::RenderMenubar(CUIRect Box, IClient::EClientState ClientState)
{
CUIRect Button;
m_ActivePage = m_MenuPage;
int NewPage = -1;
int ActivePage = -1;
if(Client()->State() != IClient::STATE_OFFLINE)
m_ActivePage = m_GamePage;
if(Client()->State() == IClient::STATE_OFFLINE)
if(ClientState == IClient::STATE_OFFLINE)
{
ActivePage = m_MenuPage;
Box.VSplitLeft(33.0f, &Button, &Box);
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
@ -596,7 +594,7 @@ void CMenus::RenderMenubar(CUIRect Box)
Box.VSplitLeft(10.0f, nullptr, &Box);
Box.VSplitLeft(75.0f, &Button, &Box);
static CButtonContainer s_InternetButton;
if(DoButton_MenuTab(&s_InternetButton, FONT_ICON_EARTH_AMERICAS, m_ActivePage == PAGE_INTERNET, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_INTERNET]))
if(DoButton_MenuTab(&s_InternetButton, FONT_ICON_EARTH_AMERICAS, ActivePage == PAGE_INTERNET, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_INTERNET]))
{
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_INTERNET)
{
@ -610,7 +608,7 @@ void CMenus::RenderMenubar(CUIRect Box)
Box.VSplitLeft(75.0f, &Button, &Box);
static CButtonContainer s_LanButton;
if(DoButton_MenuTab(&s_LanButton, FONT_ICON_NETWORK_WIRED, m_ActivePage == PAGE_LAN, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_LAN]))
if(DoButton_MenuTab(&s_LanButton, FONT_ICON_NETWORK_WIRED, ActivePage == PAGE_LAN, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_LAN]))
{
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_LAN)
ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN);
@ -620,7 +618,7 @@ void CMenus::RenderMenubar(CUIRect Box)
Box.VSplitLeft(75.0f, &Button, &Box);
static CButtonContainer s_FavoritesButton;
if(DoButton_MenuTab(&s_FavoritesButton, FONT_ICON_STAR, m_ActivePage == PAGE_FAVORITES, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_FAVORITES]))
if(DoButton_MenuTab(&s_FavoritesButton, FONT_ICON_STAR, ActivePage == PAGE_FAVORITES, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_FAVORITES]))
{
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_FAVORITES)
{
@ -641,7 +639,7 @@ void CMenus::RenderMenubar(CUIRect Box)
{
Box.VSplitLeft(75.0f, &Button, &Box);
const int Page = PAGE_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex;
if(DoButton_MenuTab(&s_aFavoriteCommunityButtons[FavoriteCommunityIndex], FONT_ICON_ELLIPSIS, m_ActivePage == Page, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIT_TAB_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex], nullptr, nullptr, nullptr, 10.0f, FindCommunityIcon(pCommunity->Id())))
if(DoButton_MenuTab(&s_aFavoriteCommunityButtons[FavoriteCommunityIndex], FONT_ICON_ELLIPSIS, ActivePage == Page, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIT_TAB_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex], nullptr, nullptr, nullptr, 10.0f, FindCommunityIcon(pCommunity->Id())))
{
const int BrowserType = IServerBrowser::TYPE_FAVORITE_COMMUNITY_1 + FavoriteCommunityIndex;
if(ServerBrowser()->GetCurrentType() != BrowserType)
@ -662,48 +660,52 @@ void CMenus::RenderMenubar(CUIRect Box)
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
}
else
else if(ClientState == IClient::STATE_ONLINE)
{
ActivePage = m_GamePage;
// online menus
Box.VSplitLeft(90.0f, &Button, &Box);
static CButtonContainer s_GameButton;
if(DoButton_MenuTab(&s_GameButton, Localize("Game"), m_ActivePage == PAGE_GAME, &Button, IGraphics::CORNER_TL))
if(DoButton_MenuTab(&s_GameButton, Localize("Game"), ActivePage == PAGE_GAME, &Button, IGraphics::CORNER_TL))
NewPage = PAGE_GAME;
Box.VSplitLeft(90.0f, &Button, &Box);
static CButtonContainer s_PlayersButton;
if(DoButton_MenuTab(&s_PlayersButton, Localize("Players"), m_ActivePage == PAGE_PLAYERS, &Button, IGraphics::CORNER_NONE))
if(DoButton_MenuTab(&s_PlayersButton, Localize("Players"), ActivePage == PAGE_PLAYERS, &Button, IGraphics::CORNER_NONE))
NewPage = PAGE_PLAYERS;
Box.VSplitLeft(130.0f, &Button, &Box);
static CButtonContainer s_ServerInfoButton;
if(DoButton_MenuTab(&s_ServerInfoButton, Localize("Server info"), m_ActivePage == PAGE_SERVER_INFO, &Button, IGraphics::CORNER_NONE))
if(DoButton_MenuTab(&s_ServerInfoButton, Localize("Server info"), ActivePage == PAGE_SERVER_INFO, &Button, IGraphics::CORNER_NONE))
NewPage = PAGE_SERVER_INFO;
Box.VSplitLeft(90.0f, &Button, &Box);
static CButtonContainer s_NetworkButton;
if(DoButton_MenuTab(&s_NetworkButton, Localize("Browser"), m_ActivePage == PAGE_NETWORK, &Button, IGraphics::CORNER_NONE))
if(DoButton_MenuTab(&s_NetworkButton, Localize("Browser"), ActivePage == PAGE_NETWORK, &Button, IGraphics::CORNER_NONE))
NewPage = PAGE_NETWORK;
{
static CButtonContainer s_GhostButton;
if(GameClient()->m_GameInfo.m_Race)
{
Box.VSplitLeft(90.0f, &Button, &Box);
if(DoButton_MenuTab(&s_GhostButton, Localize("Ghost"), m_ActivePage == PAGE_GHOST, &Button, IGraphics::CORNER_NONE))
static CButtonContainer s_GhostButton;
if(DoButton_MenuTab(&s_GhostButton, Localize("Ghost"), ActivePage == PAGE_GHOST, &Button, IGraphics::CORNER_NONE))
NewPage = PAGE_GHOST;
}
}
Box.VSplitLeft(100.0f, &Button, &Box);
Box.VSplitLeft(4.0f, nullptr, &Box);
static CButtonContainer s_CallVoteButton;
if(DoButton_MenuTab(&s_CallVoteButton, Localize("Call vote"), m_ActivePage == PAGE_CALLVOTE, &Button, IGraphics::CORNER_TR))
if(DoButton_MenuTab(&s_CallVoteButton, Localize("Call vote"), ActivePage == PAGE_CALLVOTE, &Button, IGraphics::CORNER_TR))
{
NewPage = PAGE_CALLVOTE;
m_ControlPageOpening = true;
}
}
else
{
dbg_assert(false, "Client state invalid for RenderMenubar");
}
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
@ -727,7 +729,7 @@ void CMenus::RenderMenubar(CUIRect Box)
Box.VSplitRight(10.0f, &Box, nullptr);
Box.VSplitRight(33.0f, &Box, &Button);
static CButtonContainer s_SettingsButton;
if(DoButton_MenuTab(&s_SettingsButton, FONT_ICON_GEAR, m_ActivePage == PAGE_SETTINGS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_SETTINGS]))
if(DoButton_MenuTab(&s_SettingsButton, FONT_ICON_GEAR, ActivePage == PAGE_SETTINGS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_SETTINGS]))
{
NewPage = PAGE_SETTINGS;
}
@ -742,12 +744,12 @@ void CMenus::RenderMenubar(CUIRect Box)
}
GameClient()->m_Tooltips.DoToolTip(&s_EditorButton, &Button, Localize("Editor"));
if(Client()->State() == IClient::STATE_OFFLINE)
if(ClientState == IClient::STATE_OFFLINE)
{
Box.VSplitRight(10.0f, &Box, nullptr);
Box.VSplitRight(33.0f, &Box, &Button);
static CButtonContainer s_DemoButton;
if(DoButton_MenuTab(&s_DemoButton, FONT_ICON_CLAPPERBOARD, m_ActivePage == PAGE_DEMOS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_DEMOBUTTON]))
if(DoButton_MenuTab(&s_DemoButton, FONT_ICON_CLAPPERBOARD, ActivePage == PAGE_DEMOS, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_DEMOBUTTON]))
{
NewPage = PAGE_DEMOS;
}
@ -759,7 +761,7 @@ void CMenus::RenderMenubar(CUIRect Box)
if(NewPage != -1)
{
if(Client()->State() == IClient::STATE_OFFLINE)
if(ClientState == IClient::STATE_OFFLINE)
SetMenuPage(NewPage);
else
m_GamePage = NewPage;
@ -819,6 +821,8 @@ void CMenus::RenderLoading(const char *pCaption, const char *pContent, int Incre
void CMenus::RenderNews(CUIRect MainView)
{
m_pBackground->ChangePosition(CMenuBackground::POS_NEWS);
g_Config.m_UiUnreadNews = false;
MainView.Draw(ms_ColorTabbarActive, IGraphics::CORNER_B, 10.0f);
@ -998,12 +1002,6 @@ bool CMenus::CanDisplayWarning() const
void CMenus::Render()
{
if(Client()->State() == IClient::STATE_DEMOPLAYBACK && m_Popup == POPUP_NONE)
return;
CUIRect Screen = *Ui()->Screen();
Screen.Margin(10.0f, &Screen);
Ui()->MapScreen();
Ui()->ResetMouseSlow();
@ -1023,9 +1021,11 @@ void CMenus::Render()
UpdateCommunityIcons();
}
if(ServerBrowser()->DDNetInfoAvailable())
{
// Initially add DDNet as favorite community and select its tab.
// This must be delayed until the DDNet info is available.
if(m_CreateDefaultFavoriteCommunities && ServerBrowser()->DDNetInfoAvailable())
if(m_CreateDefaultFavoriteCommunities)
{
m_CreateDefaultFavoriteCommunities = false;
if(ServerBrowser()->Community(IServerBrowser::COMMUNITY_DDNET) != nullptr)
@ -1037,7 +1037,24 @@ void CMenus::Render()
}
}
if(Client()->State() == IClient::STATE_ONLINE || Client()->State() == IClient::STATE_DEMOPLAYBACK)
if(m_JoinTutorial && m_Popup == POPUP_NONE && !ServerBrowser()->IsGettingServerlist())
{
m_JoinTutorial = false;
// This is only reached on first launch, when the DDNet community tab has been created and
// activated by default, so the server info for the tutorial server should be available.
const char *pAddr = ServerBrowser()->GetTutorialServer();
if(pAddr)
{
Client()->Connect(pAddr);
}
}
}
// Determine the client state once before rendering because it can change
// while rendering which causes frames with broken user interface.
const IClient::EClientState ClientState = Client()->State();
if(ClientState == IClient::STATE_ONLINE || ClientState == IClient::STATE_DEMOPLAYBACK)
{
ms_ColorTabbarInactive = ms_ColorTabbarInactiveIngame;
ms_ColorTabbarActive = ms_ColorTabbarActiveIngame;
@ -1054,23 +1071,34 @@ void CMenus::Render()
ms_ColorTabbarHover = ms_ColorTabbarHoverOutgame;
}
if(m_Popup == POPUP_NONE)
CUIRect Screen = *Ui()->Screen();
if(Client()->State() != IClient::STATE_DEMOPLAYBACK || m_Popup != POPUP_NONE)
{
if(m_JoinTutorial && ServerBrowser()->DDNetInfoAvailable() && !ServerBrowser()->IsGettingServerlist())
{
m_JoinTutorial = false;
// This is only reached on first launch, when the DDNet community tab has been created and
// activated by default, so the server info for the tutorial server should be available.
const char *pAddr = ServerBrowser()->GetTutorialServer();
if(pAddr)
{
Client()->Connect(pAddr);
}
Screen.Margin(10.0f, &Screen);
}
if(m_ShowStart && Client()->State() == IClient::STATE_OFFLINE)
switch(ClientState)
{
case IClient::STATE_QUITTING:
case IClient::STATE_RESTARTING:
// Render nothing except menu background. This should not happen for more than one frame.
return;
case IClient::STATE_CONNECTING:
RenderPopupConnecting(Screen);
break;
case IClient::STATE_LOADING:
RenderPopupLoading(Screen);
break;
case IClient::STATE_OFFLINE:
if(m_Popup != POPUP_NONE)
{
RenderPopupFullscreen(Screen);
}
else if(m_ShowStart)
{
m_pBackground->ChangePosition(CMenuBackground::POS_START);
RenderStartMenu(Screen);
}
else
@ -1078,16 +1106,41 @@ void CMenus::Render()
CUIRect TabBar, MainView;
Screen.HSplitTop(24.0f, &TabBar, &MainView);
// render news
if(m_MenuPage < PAGE_NEWS || m_MenuPage > PAGE_SETTINGS || (Client()->State() == IClient::STATE_OFFLINE && m_MenuPage >= PAGE_GAME && m_MenuPage <= PAGE_CALLVOTE))
if(m_MenuPage == PAGE_NEWS)
{
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
SetMenuPage(PAGE_INTERNET);
RenderNews(MainView);
}
else if(m_MenuPage >= PAGE_INTERNET && m_MenuPage <= PAGE_FAVORITE_COMMUNITY_3)
{
RenderServerbrowser(MainView);
}
else if(m_MenuPage == PAGE_DEMOS)
{
RenderDemoBrowser(MainView);
}
else if(m_MenuPage == PAGE_SETTINGS)
{
RenderSettings(MainView);
}
else
{
dbg_assert(false, "m_MenuPage invalid");
}
// render current page
if(Client()->State() != IClient::STATE_OFFLINE)
RenderMenubar(TabBar, ClientState);
}
break;
case IClient::STATE_ONLINE:
if(m_Popup != POPUP_NONE)
{
RenderPopupFullscreen(Screen);
}
else
{
CUIRect TabBar, MainView;
Screen.HSplitTop(24.0f, &TabBar, &MainView);
if(m_GamePage == PAGE_GAME)
{
RenderGame(MainView);
@ -1117,54 +1170,31 @@ void CMenus::Render()
{
RenderSettings(MainView);
}
}
else if(m_MenuPage == PAGE_NEWS)
else
{
m_pBackground->ChangePosition(CMenuBackground::POS_NEWS);
RenderNews(MainView);
}
else if(m_MenuPage == PAGE_INTERNET)
{
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_INTERNET);
RenderServerbrowser(MainView);
}
else if(m_MenuPage == PAGE_LAN)
{
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_LAN);
RenderServerbrowser(MainView);
}
else if(m_MenuPage == PAGE_DEMOS)
{
m_pBackground->ChangePosition(CMenuBackground::POS_DEMOS);
RenderDemoBrowser(MainView);
}
else if(m_MenuPage == PAGE_FAVORITES)
{
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_FAVORITES);
RenderServerbrowser(MainView);
}
else if(m_MenuPage >= PAGE_FAVORITE_COMMUNITY_1 && m_MenuPage <= PAGE_FAVORITE_COMMUNITY_3)
{
m_pBackground->ChangePosition(m_MenuPage - PAGE_FAVORITE_COMMUNITY_1 + CMenuBackground::POS_BROWSER_CUSTOM0);
RenderServerbrowser(MainView);
}
else if(m_MenuPage == PAGE_SETTINGS)
{
RenderSettings(MainView);
dbg_assert(false, "m_GamePage invalid");
}
RenderMenubar(TabBar);
RenderMenubar(TabBar, ClientState);
}
break;
case IClient::STATE_DEMOPLAYBACK:
if(m_Popup != POPUP_NONE)
{
RenderPopupFullscreen(Screen);
}
else
{
RenderPopupFullscreen(Screen);
RenderDemoPlayer(Screen);
}
break;
}
Ui()->RenderPopupMenus();
// Handle this escape hotkey after popup menus
if(!m_ShowStart && Client()->State() == IClient::STATE_OFFLINE && Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
if(!m_ShowStart && ClientState == IClient::STATE_OFFLINE && Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
{
m_ShowStart = true;
}
@ -1177,7 +1207,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
const char *pExtraText = "";
const char *pButtonText = "";
bool TopAlign = false;
bool UseIpLabel = false;
ColorRGBA BgColor = ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f);
if(m_Popup == POPUP_MESSAGE || m_Popup == POPUP_CONFIRM)
@ -1186,63 +1215,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
pExtraText = m_aPopupMessage;
TopAlign = true;
}
else if(m_Popup == POPUP_CONNECTING)
{
pTitle = Localize("Connecting to");
UseIpLabel = true;
pButtonText = Localize("Abort");
if(Client()->State() == IClient::STATE_CONNECTING && time_get() - Client()->StateStartTime() > time_freq())
{
int Connectivity = Client()->UdpConnectivity(Client()->ConnectNetTypes());
switch(Connectivity)
{
case IClient::CONNECTIVITY_UNKNOWN:
break;
case IClient::CONNECTIVITY_CHECKING:
pExtraText = Localize("Trying to determine UDP connectivity...");
break;
case IClient::CONNECTIVITY_UNREACHABLE:
pExtraText = Localize("UDP seems to be filtered.");
break;
case IClient::CONNECTIVITY_DIFFERING_UDP_TCP_IP_ADDRESSES:
pExtraText = Localize("UDP and TCP IP addresses seem to be different. Try disabling VPN, proxy or network accelerators.");
break;
case IClient::CONNECTIVITY_REACHABLE:
pExtraText = Localize("No answer from server yet.");
break;
}
}
else if(Client()->MapDownloadTotalsize() > 0)
{
str_format(aBuf, sizeof(aBuf), "%s: %s", Localize("Downloading map"), Client()->MapDownloadName());
pTitle = aBuf;
UseIpLabel = false;
}
else if(Client()->State() == IClient::STATE_LOADING)
{
UseIpLabel = false;
if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_INITIAL)
{
pTitle = Localize("Connected");
pExtraText = Localize("Getting game info");
}
else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_LOADING_MAP)
{
pTitle = Localize("Connected");
pExtraText = Localize("Loading map file from storage");
}
else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_SENDING_READY)
{
pTitle = Localize("Connected");
pExtraText = Localize("Requesting to join the game");
}
else if(Client()->LoadingStateDetail() == IClient::LOADING_STATE_DETAIL_GETTING_READY)
{
pTitle = Localize("Connected");
pExtraText = Localize("Sending initial client info");
}
}
}
else if(m_Popup == POPUP_DISCONNECTED)
{
pTitle = Localize("Disconnected");
@ -1350,16 +1322,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
float FontSize = m_Popup == POPUP_FIRST_LAUNCH ? 16.0f : 20.f;
if(UseIpLabel)
{
SLabelProperties IpLabelProps;
IpLabelProps.m_MaxWidth = Part.w;
IpLabelProps.m_EllipsisAtEnd = true;
Ui()->DoLabel(&Part, Client()->ConnectAddressString(), FontSize, TEXTALIGN_MC, IpLabelProps);
Box.HSplitTop(20.f, &Part, &Box);
Box.HSplitTop(24.f, &Part, &Box);
}
Props.m_MaxWidth = (int)Part.w;
if(TopAlign)
Ui()->DoLabel(&Part, pExtraText, FontSize, TEXTALIGN_TL, Props);
@ -1477,73 +1439,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
Ui()->DoLabel(&Label, Localize("Password"), 18.0f, TEXTALIGN_ML);
Ui()->DoClearableEditBox(&m_PasswordInput, &TextBox, 12.0f);
}
else if(m_Popup == POPUP_CONNECTING)
{
Box = Screen;
Box.Margin(150.0f, &Box);
Box.HSplitBottom(20.f, &Box, &Part);
Box.HSplitBottom(24.f, &Box, &Part);
Part.VMargin(120.0f, &Part);
static CButtonContainer s_Button;
if(DoButton_Menu(&s_Button, pButtonText, 0, &Part) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
{
Client()->Disconnect();
m_Popup = POPUP_NONE;
RefreshBrowserTab(g_Config.m_UiPage);
}
if(Client()->MapDownloadTotalsize() > 0)
{
int64_t 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) / ((int)((Now - m_DownloadLastCheckTime) / time_freq()));
float StartDiff = m_DownloadLastCheckSize - 0.0f;
if(StartDiff + Diff > 0.0f)
m_DownloadSpeed = (Diff / (StartDiff + Diff)) * (Diff / 1.0f) + (StartDiff / (Diff + StartDiff)) * m_DownloadSpeed;
else
m_DownloadSpeed = 0.0f;
m_DownloadLastCheckTime = Now;
m_DownloadLastCheckSize = Client()->MapDownloadAmount();
}
Box.HSplitTop(64.f, 0, &Box);
Box.HSplitTop(24.f, &Part, &Box);
str_format(aBuf, sizeof(aBuf), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount() / 1024, Client()->MapDownloadTotalsize() / 1024, m_DownloadSpeed / 1024.0f);
Ui()->DoLabel(&Part, aBuf, 20.f, TEXTALIGN_MC);
// time left
int TimeLeft = maximum(1, m_DownloadSpeed > 0.0f ? static_cast<int>((Client()->MapDownloadTotalsize() - Client()->MapDownloadAmount()) / m_DownloadSpeed) : 1);
if(TimeLeft >= 60)
{
TimeLeft /= 60;
str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"), TimeLeft);
}
else
{
str_format(aBuf, sizeof(aBuf), TimeLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"), TimeLeft);
}
Box.HSplitTop(20.f, 0, &Box);
Box.HSplitTop(24.f, &Part, &Box);
Ui()->DoLabel(&Part, aBuf, 20.f, TEXTALIGN_MC);
// progress bar
Box.HSplitTop(20.f, 0, &Box);
Box.HSplitTop(24.f, &Part, &Box);
Part.VMargin(40.0f, &Part);
Part.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f);
Part.w = maximum(10.0f, (Part.w * Client()->MapDownloadAmount()) / Client()->MapDownloadTotalsize());
Part.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), IGraphics::CORNER_ALL, 5.0f);
}
}
else if(m_Popup == POPUP_LANGUAGE)
{
CUIRect Button;
@ -1711,7 +1606,6 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
const char *pPaused = m_StartPaused ? Localize("(paused)") : "";
str_format(aBuffer, sizeof(aBuffer), "%s: ×%g %s", Localize("Speed"), g_aSpeeds[m_Speed], pPaused);
Ui()->DoLabel(&Row, aBuffer, 12.8f, TEXTALIGN_ML);
Box.HSplitBottom(16.0f, &Box, nullptr);
Box.HSplitBottom(24.0f, &Box, &Row);
@ -1868,6 +1762,187 @@ void CMenus::RenderPopupFullscreen(CUIRect Screen)
Ui()->SetActiveItem(nullptr);
}
void CMenus::RenderPopupConnecting(CUIRect Screen)
{
const float FontSize = 20.0f;
CUIRect Box, Label;
Screen.Margin(150.0f, &Box);
Box.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f), IGraphics::CORNER_ALL, 15.0f);
Box.Margin(20.0f, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
Ui()->DoLabel(&Label, Localize("Connecting to"), 24.0f, TEXTALIGN_MC);
Box.HSplitTop(20.0f, nullptr, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
SLabelProperties Props;
Props.m_MaxWidth = Label.w;
Props.m_EllipsisAtEnd = true;
Ui()->DoLabel(&Label, Client()->ConnectAddressString(), FontSize, TEXTALIGN_MC, Props);
if(time_get() - Client()->StateStartTime() > time_freq())
{
const char *pConnectivityLabel = "";
switch(Client()->UdpConnectivity(Client()->ConnectNetTypes()))
{
case IClient::CONNECTIVITY_UNKNOWN:
break;
case IClient::CONNECTIVITY_CHECKING:
pConnectivityLabel = Localize("Trying to determine UDP connectivity...");
break;
case IClient::CONNECTIVITY_UNREACHABLE:
pConnectivityLabel = Localize("UDP seems to be filtered.");
break;
case IClient::CONNECTIVITY_DIFFERING_UDP_TCP_IP_ADDRESSES:
pConnectivityLabel = Localize("UDP and TCP IP addresses seem to be different. Try disabling VPN, proxy or network accelerators.");
break;
case IClient::CONNECTIVITY_REACHABLE:
pConnectivityLabel = Localize("No answer from server yet.");
break;
}
if(pConnectivityLabel[0] != '\0')
{
Box.HSplitTop(20.0f, nullptr, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
SLabelProperties ConnectivityLabelProps;
ConnectivityLabelProps.m_MaxWidth = Label.w;
if(TextRender()->TextWidth(FontSize, pConnectivityLabel) > Label.w)
Ui()->DoLabel(&Label, pConnectivityLabel, FontSize, TEXTALIGN_ML, ConnectivityLabelProps);
else
Ui()->DoLabel(&Label, pConnectivityLabel, FontSize, TEXTALIGN_MC);
}
}
CUIRect Button;
Box.HSplitBottom(24.0f, &Box, &Button);
Button.VMargin(100.0f, &Button);
static CButtonContainer s_Button;
if(DoButton_Menu(&s_Button, Localize("Abort"), 0, &Button) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
{
Client()->Disconnect();
Ui()->SetActiveItem(nullptr);
RefreshBrowserTab(g_Config.m_UiPage);
}
}
void CMenus::RenderPopupLoading(CUIRect Screen)
{
char aTitle[256];
char aLabel1[128];
char aLabel2[128];
if(Client()->MapDownloadTotalsize() > 0)
{
const int64_t Now = time_get();
if(Now - m_DownloadLastCheckTime >= time_freq())
{
if(m_DownloadLastCheckSize > Client()->MapDownloadAmount())
{
// map downloaded restarted
m_DownloadLastCheckSize = 0;
}
// update download speed
const float Diff = (Client()->MapDownloadAmount() - m_DownloadLastCheckSize) / ((int)((Now - m_DownloadLastCheckTime) / time_freq()));
const float StartDiff = m_DownloadLastCheckSize - 0.0f;
if(StartDiff + Diff > 0.0f)
m_DownloadSpeed = (Diff / (StartDiff + Diff)) * (Diff / 1.0f) + (StartDiff / (Diff + StartDiff)) * m_DownloadSpeed;
else
m_DownloadSpeed = 0.0f;
m_DownloadLastCheckTime = Now;
m_DownloadLastCheckSize = Client()->MapDownloadAmount();
}
str_format(aTitle, sizeof(aTitle), "%s: %s", Localize("Downloading map"), Client()->MapDownloadName());
str_format(aLabel1, sizeof(aLabel1), "%d/%d KiB (%.1f KiB/s)", Client()->MapDownloadAmount() / 1024, Client()->MapDownloadTotalsize() / 1024, m_DownloadSpeed / 1024.0f);
const int SecondsLeft = maximum(1, m_DownloadSpeed > 0.0f ? static_cast<int>((Client()->MapDownloadTotalsize() - Client()->MapDownloadAmount()) / m_DownloadSpeed) : 1);
const int MinutesLeft = SecondsLeft / 60;
if(MinutesLeft > 0)
{
str_format(aLabel2, sizeof(aLabel2), MinutesLeft == 1 ? Localize("%i minute left") : Localize("%i minutes left"), MinutesLeft);
}
else
{
str_format(aLabel2, sizeof(aLabel2), SecondsLeft == 1 ? Localize("%i second left") : Localize("%i seconds left"), SecondsLeft);
}
}
else
{
str_copy(aTitle, Localize("Connected"));
switch(Client()->LoadingStateDetail())
{
case IClient::LOADING_STATE_DETAIL_INITIAL:
str_copy(aLabel1, Localize("Getting game info"));
break;
case IClient::LOADING_STATE_DETAIL_LOADING_MAP:
str_copy(aLabel1, Localize("Loading map file from storage"));
break;
case IClient::LOADING_STATE_DETAIL_SENDING_READY:
str_copy(aLabel1, Localize("Requesting to join the game"));
break;
case IClient::LOADING_STATE_DETAIL_GETTING_READY:
str_copy(aLabel1, Localize("Sending initial client info"));
break;
default:
dbg_assert(false, "Invalid loading state for RenderPopupLoading");
break;
}
aLabel2[0] = '\0';
}
const float FontSize = 20.0f;
CUIRect Box, Label;
Screen.Margin(150.0f, &Box);
Box.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.5f), IGraphics::CORNER_ALL, 15.0f);
Box.Margin(20.0f, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
Ui()->DoLabel(&Label, aTitle, 24.0f, TEXTALIGN_MC);
Box.HSplitTop(20.0f, nullptr, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
Ui()->DoLabel(&Label, aLabel1, FontSize, TEXTALIGN_MC);
if(aLabel2[0] != '\0')
{
Box.HSplitTop(20.0f, nullptr, &Box);
Box.HSplitTop(24.0f, &Label, &Box);
SLabelProperties ExtraTextProps;
ExtraTextProps.m_MaxWidth = Label.w;
if(TextRender()->TextWidth(FontSize, aLabel2) > Label.w)
Ui()->DoLabel(&Label, aLabel2, FontSize, TEXTALIGN_ML, ExtraTextProps);
else
Ui()->DoLabel(&Label, aLabel2, FontSize, TEXTALIGN_MC);
}
if(Client()->MapDownloadTotalsize() > 0)
{
CUIRect ProgressBar;
Box.HSplitTop(20.0f, nullptr, &Box);
Box.HSplitTop(24.0f, &ProgressBar, &Box);
ProgressBar.VMargin(20.0f, &ProgressBar);
ProgressBar.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f);
ProgressBar.w = maximum(10.0f, (ProgressBar.w * Client()->MapDownloadAmount()) / Client()->MapDownloadTotalsize());
ProgressBar.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.5f), IGraphics::CORNER_ALL, 5.0f);
}
CUIRect Button;
Box.HSplitBottom(24.0f, &Box, &Button);
Button.VMargin(100.0f, &Button);
static CButtonContainer s_Button;
if(DoButton_Menu(&s_Button, Localize("Abort"), 0, &Button) || Ui()->ConsumeHotkey(CUi::HOTKEY_ESCAPE))
{
Client()->Disconnect();
Ui()->SetActiveItem(nullptr);
RefreshBrowserTab(g_Config.m_UiPage);
}
}
#if defined(CONF_VIDEORECORDER)
void CMenus::PopupConfirmDemoReplaceVideo()
{
@ -2055,15 +2130,10 @@ void CMenus::OnStateChange(int NewState, int OldState)
}
else if(NewState == IClient::STATE_LOADING)
{
m_Popup = POPUP_CONNECTING;
m_DownloadLastCheckTime = time_get();
m_DownloadLastCheckSize = 0;
m_DownloadSpeed = 0.0f;
}
else if(NewState == IClient::STATE_CONNECTING)
{
m_Popup = POPUP_CONNECTING;
}
else if(NewState == IClient::STATE_ONLINE || NewState == IClient::STATE_DEMOPLAYBACK)
{
if(m_Popup != POPUP_WARNING)
@ -2086,12 +2156,6 @@ void CMenus::OnRender()
if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK)
SetActive(true);
if(Client()->State() == IClient::STATE_DEMOPLAYBACK)
{
Ui()->MapScreen();
RenderDemoPlayer(*Ui()->Screen());
}
if(Client()->State() == IClient::STATE_ONLINE && m_pClient->m_ServerMode == CGameClient::SERVERMODE_PUREMOD)
{
Client()->Disconnect();

View file

@ -164,7 +164,6 @@ protected:
int m_MenuPage;
int m_GamePage;
int m_Popup;
int m_ActivePage;
bool m_ShowStart;
bool m_MenuActive;
@ -421,10 +420,12 @@ protected:
// found in menus.cpp
void Render();
void RenderPopupFullscreen(CUIRect Screen);
void RenderPopupConnecting(CUIRect Screen);
void RenderPopupLoading(CUIRect Screen);
#if defined(CONF_VIDEORECORDER)
void PopupConfirmDemoReplaceVideo();
#endif
void RenderMenubar(CUIRect Box);
void RenderMenubar(CUIRect Box, IClient::EClientState ClientState);
void RenderNews(CUIRect MainView);
static void ConchainUpdateMusicState(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
void UpdateMusicState();
@ -748,7 +749,6 @@ public:
POPUP_CONFIRM, // generic confirmation popup (two buttons)
POPUP_FIRST_LAUNCH,
POPUP_POINTS,
POPUP_CONNECTING,
POPUP_DISCONNECTED,
POPUP_LANGUAGE,
POPUP_RENAME_DEMO,

View file

@ -1704,6 +1704,26 @@ void CMenus::RenderServerbrowser(CUIRect MainView)
{
UpdateCommunityCache(false);
switch(g_Config.m_UiPage)
{
case PAGE_INTERNET:
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_INTERNET);
break;
case PAGE_LAN:
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_LAN);
break;
case PAGE_FAVORITES:
m_pBackground->ChangePosition(CMenuBackground::POS_BROWSER_FAVORITES);
break;
case PAGE_FAVORITE_COMMUNITY_1:
case PAGE_FAVORITE_COMMUNITY_2:
case PAGE_FAVORITE_COMMUNITY_3:
m_pBackground->ChangePosition(g_Config.m_UiPage - PAGE_FAVORITE_COMMUNITY_1 + CMenuBackground::POS_BROWSER_CUSTOM0);
break;
default:
dbg_assert(false, "ui_page invalid for RenderServerbrowser");
}
/*
+---------------------------+ +---communities---+
| | | |

View file

@ -1060,6 +1060,8 @@ void CMenus::FetchAllHeaders()
void CMenus::RenderDemoBrowser(CUIRect MainView)
{
m_pBackground->ChangePosition(CMenuBackground::POS_DEMOS);
CUIRect ListView, DetailsView, ButtonsView;
MainView.Draw(ms_ColorTabbarActive, IGraphics::CORNER_B, 10.0f);
MainView.Margin(10.0f, &MainView);

View file

@ -2105,6 +2105,10 @@ void CMenus::RenderSettings(CUIRect MainView)
m_pBackground->ChangePosition(CMenuBackground::POS_SETTINGS_ASSETS);
RenderSettingsCustom(MainView);
}
else
{
dbg_assert(false, "ui_settings_page invalid");
}
if(m_NeedRestartGraphics || m_NeedRestartSound || m_NeedRestartUpdate)
{

View file

@ -19,6 +19,8 @@
void CMenus::RenderStartMenu(CUIRect MainView)
{
m_pBackground->ChangePosition(CMenuBackground::POS_START);
// render logo
Graphics()->TextureSet(g_pData->m_aImages[IMAGE_BANNER].m_Id);
Graphics()->QuadsBegin();