mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 22:48:18 +00:00
Port CListBox
from upstream, smooth scrolling for all lists
Replace existing listbox implementations (`CMenus::UiDoListbox*` and `HandleListInputs` functions) with `CListBox` from upstream. Reimplement additional feature that was already present in ddnet: page up/down, home and end key handling. Affects the following lists: - server browser - server browser scoreboard - server browser friends - country / region selection popup (server browser filter) - player skin list - player country / region list - theme list - assets list - graphics resolutions list - dropdown menus (e.g. graphics fullscreen mode) - ingame player list - vote options list - kick/specvote lists - ghost list - language list (in settings and in popup on first launch) - demo browser - editor file browser (saving, loading, adding images / sounds) - The search / filename input is also improved so navigating a filtered list works correctly by porting the logic from upstream. There are minor changes to the visual appearance of some lists, due to changed margins. The vertical alignment of some list item texts is improved so the text is centered vertically.
This commit is contained in:
parent
f79daac222
commit
91a23f00cb
|
@ -2277,6 +2277,8 @@ if(CLIENT)
|
||||||
skin.h
|
skin.h
|
||||||
ui.cpp
|
ui.cpp
|
||||||
ui.h
|
ui.h
|
||||||
|
ui_listbox.cpp
|
||||||
|
ui_listbox.h
|
||||||
ui_rect.cpp
|
ui_rect.cpp
|
||||||
ui_rect.h
|
ui_rect.h
|
||||||
ui_scrollregion.cpp
|
ui_scrollregion.cpp
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <game/client/components/menu_background.h>
|
#include <game/client/components/menu_background.h>
|
||||||
#include <game/client/components/sounds.h>
|
#include <game/client/components/sounds.h>
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/generated/client_data.h>
|
#include <game/generated/client_data.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
|
||||||
|
@ -79,7 +80,6 @@ CMenus::CMenus()
|
||||||
m_aCallvoteReason[0] = 0;
|
m_aCallvoteReason[0] = 0;
|
||||||
|
|
||||||
m_FriendlistSelectedIndex = -1;
|
m_FriendlistSelectedIndex = -1;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
|
|
||||||
m_DemoPlayerState = DEMOPLAYER_NONE;
|
m_DemoPlayerState = DEMOPLAYER_NONE;
|
||||||
m_Dummy = false;
|
m_Dummy = false;
|
||||||
|
@ -705,7 +705,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
if(DoButton_MenuTab(&s_StartButton, pHomeScreenButtonLabel, false, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_HOME], pHomeButtonColor, pHomeButtonColor, pHomeButtonColorHover, 10.0f, 0))
|
if(DoButton_MenuTab(&s_StartButton, pHomeScreenButtonLabel, false, &Button, IGraphics::CORNER_T, &m_aAnimatorsSmallPage[SMALL_TAB_HOME], pHomeButtonColor, pHomeButtonColor, pHomeButtonColorHover, 10.0f, 0))
|
||||||
{
|
{
|
||||||
m_ShowStart = true;
|
m_ShowStart = true;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextRender()->SetRenderFlags(0);
|
TextRender()->SetRenderFlags(0);
|
||||||
|
@ -721,7 +720,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
if(DoButton_MenuTab(&s_NewsButton, Localize("News"), m_ActivePage == PAGE_NEWS, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_NEWS]))
|
if(DoButton_MenuTab(&s_NewsButton, Localize("News"), m_ActivePage == PAGE_NEWS, &Button, IGraphics::CORNER_T, &m_aAnimatorsBigPage[BIG_TAB_NEWS]))
|
||||||
{
|
{
|
||||||
NewPage = PAGE_NEWS;
|
NewPage = PAGE_NEWS;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(m_ActivePage == PAGE_DEMOS)
|
else if(m_ActivePage == PAGE_DEMOS)
|
||||||
|
@ -732,7 +730,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
{
|
{
|
||||||
DemolistPopulate();
|
DemolistPopulate();
|
||||||
NewPage = PAGE_DEMOS;
|
NewPage = PAGE_DEMOS;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -744,7 +741,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_INTERNET)
|
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_INTERNET)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
||||||
NewPage = PAGE_INTERNET;
|
NewPage = PAGE_INTERNET;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box.VSplitLeft(100.0f, &Button, &Box);
|
Box.VSplitLeft(100.0f, &Button, &Box);
|
||||||
|
@ -754,7 +750,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_LAN)
|
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_LAN)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN);
|
||||||
NewPage = PAGE_LAN;
|
NewPage = PAGE_LAN;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box.VSplitLeft(100.0f, &Button, &Box);
|
Box.VSplitLeft(100.0f, &Button, &Box);
|
||||||
|
@ -764,7 +759,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_FAVORITES)
|
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_FAVORITES)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES);
|
||||||
NewPage = PAGE_FAVORITES;
|
NewPage = PAGE_FAVORITES;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box.VSplitLeft(90.0f, &Button, &Box);
|
Box.VSplitLeft(90.0f, &Button, &Box);
|
||||||
|
@ -777,7 +771,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET);
|
||||||
}
|
}
|
||||||
NewPage = PAGE_DDNET;
|
NewPage = PAGE_DDNET;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Box.VSplitLeft(90.0f, &Button, &Box);
|
Box.VSplitLeft(90.0f, &Button, &Box);
|
||||||
|
@ -790,7 +783,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
|
||||||
}
|
}
|
||||||
NewPage = PAGE_KOG;
|
NewPage = PAGE_KOG;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1323,7 +1315,6 @@ int CMenus::Render()
|
||||||
{
|
{
|
||||||
UpdateMusicState();
|
UpdateMusicState();
|
||||||
s_Frame++;
|
s_Frame++;
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
|
|
||||||
RefreshBrowserTab(g_Config.m_UiPage);
|
RefreshBrowserTab(g_Config.m_UiPage);
|
||||||
if(g_Config.m_UiPage == PAGE_INTERNET)
|
if(g_Config.m_UiPage == PAGE_INTERNET)
|
||||||
|
@ -1397,7 +1388,6 @@ int CMenus::Render()
|
||||||
{
|
{
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
||||||
SetMenuPage(PAGE_INTERNET);
|
SetMenuPage(PAGE_INTERNET);
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// render current page
|
// render current page
|
||||||
|
@ -1837,36 +1827,38 @@ int CMenus::Render()
|
||||||
}
|
}
|
||||||
else if(m_Popup == POPUP_LANGUAGE)
|
else if(m_Popup == POPUP_LANGUAGE)
|
||||||
{
|
{
|
||||||
Box = Screen;
|
CUIRect Button;
|
||||||
Box.Margin(150.0f, &Box);
|
Screen.Margin(150.0f, &Box);
|
||||||
Box.HSplitTop(20.f, &Part, &Box);
|
Box.HSplitTop(20.0f, nullptr, &Box);
|
||||||
Box.HSplitBottom(20.f, &Box, &Part);
|
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||||
Box.HSplitBottom(24.f, &Box, &Part);
|
Box.HSplitBottom(24.0f, &Box, &Button);
|
||||||
Box.HSplitBottom(20.f, &Box, 0);
|
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||||
Box.VMargin(20.0f, &Box);
|
Box.VMargin(20.0f, &Box);
|
||||||
RenderLanguageSelection(Box);
|
const bool Activated = RenderLanguageSelection(Box);
|
||||||
Part.VMargin(120.0f, &Part);
|
Button.VMargin(120.0f, &Button);
|
||||||
|
|
||||||
static CButtonContainer s_Button;
|
static CButtonContainer s_Button;
|
||||||
if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Part) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
if(DoButton_Menu(&s_Button, Localize("Ok"), 0, &Button) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || Activated)
|
||||||
m_Popup = POPUP_FIRST_LAUNCH;
|
m_Popup = POPUP_FIRST_LAUNCH;
|
||||||
}
|
}
|
||||||
else if(m_Popup == POPUP_COUNTRY)
|
else if(m_Popup == POPUP_COUNTRY)
|
||||||
{
|
{
|
||||||
Box = Screen;
|
CUIRect ButtonBar;
|
||||||
Box.Margin(150.0f, &Box);
|
Screen.Margin(150.0f, &Box);
|
||||||
Box.HSplitTop(20.f, &Part, &Box);
|
Box.HSplitTop(20.0f, nullptr, &Box);
|
||||||
Box.HSplitBottom(20.f, &Box, &Part);
|
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||||
Box.HSplitBottom(24.f, &Box, &Part);
|
Box.HSplitBottom(24.0f, &Box, &ButtonBar);
|
||||||
Box.HSplitBottom(20.f, &Box, 0);
|
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||||
Box.VMargin(20.0f, &Box);
|
Box.VMargin(20.0f, &Box);
|
||||||
|
ButtonBar.VMargin(100.0f, &ButtonBar);
|
||||||
|
|
||||||
static int s_CurSelection = -2;
|
static int s_CurSelection = -2;
|
||||||
if(s_CurSelection == -2)
|
if(s_CurSelection == -2)
|
||||||
s_CurSelection = g_Config.m_BrFilterCountryIndex;
|
s_CurSelection = g_Config.m_BrFilterCountryIndex;
|
||||||
static float s_ScrollValue = 0.0f;
|
|
||||||
|
static CListBox s_ListBox;
|
||||||
int OldSelected = -1;
|
int OldSelected = -1;
|
||||||
UiDoListboxStart(&s_ScrollValue, &Box, 50.0f, Localize("Country / Region"), "", m_pClient->m_CountryFlags.Num(), 6, OldSelected, s_ScrollValue);
|
s_ListBox.DoStart(50.0f, m_pClient->m_CountryFlags.Num(), 10, 1, OldSelected, &Box);
|
||||||
|
|
||||||
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -1874,29 +1866,31 @@ int CMenus::Render()
|
||||||
if(pEntry->m_CountryCode == s_CurSelection)
|
if(pEntry->m_CountryCode == s_CurSelection)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i);
|
const CListboxItem Item = s_ListBox.DoNextItem(pEntry, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
CUIRect Label;
|
|
||||||
Item.m_Rect.Margin(5.0f, &Item.m_Rect);
|
CUIRect FlagRect, Label;
|
||||||
Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
|
Item.m_Rect.Margin(5.0f, &FlagRect);
|
||||||
float OldWidth = Item.m_Rect.w;
|
FlagRect.HSplitBottom(12.0f, &FlagRect, &Label);
|
||||||
Item.m_Rect.w = Item.m_Rect.h * 2;
|
Label.HSplitTop(2.0f, nullptr, &Label);
|
||||||
Item.m_Rect.x += (OldWidth - Item.m_Rect.w) / 2.0f;
|
const float OldWidth = FlagRect.w;
|
||||||
|
FlagRect.w = FlagRect.h * 2.0f;
|
||||||
|
FlagRect.x += (OldWidth - FlagRect.w) / 2.0f;
|
||||||
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
m_pClient->m_CountryFlags.Render(pEntry->m_CountryCode, &Color, Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h);
|
m_pClient->m_CountryFlags.Render(pEntry->m_CountryCode, &Color, FlagRect.x, FlagRect.y, FlagRect.w, FlagRect.h);
|
||||||
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER);
|
|
||||||
}
|
SLabelProperties ItemLabelProps;
|
||||||
|
ItemLabelProps.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER, ItemLabelProps);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Activated = false;
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, &Activated);
|
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
s_CurSelection = m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
|
s_CurSelection = m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
|
||||||
|
|
||||||
CUIRect CancelButton, OkButton;
|
CUIRect CancelButton, OkButton;
|
||||||
Part.VMargin(100.0f, &Part);
|
ButtonBar.VSplitMid(&CancelButton, &OkButton, 40.0f);
|
||||||
Part.VSplitMid(&CancelButton, &OkButton, 40.0f);
|
|
||||||
|
|
||||||
static CButtonContainer s_CancelButton;
|
static CButtonContainer s_CancelButton;
|
||||||
if(DoButton_Menu(&s_CancelButton, Localize("Cancel"), 0, &CancelButton) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE))
|
if(DoButton_Menu(&s_CancelButton, Localize("Cancel"), 0, &CancelButton) || UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE))
|
||||||
|
@ -1906,7 +1900,7 @@ int CMenus::Render()
|
||||||
}
|
}
|
||||||
|
|
||||||
static CButtonContainer s_OkButton;
|
static CButtonContainer s_OkButton;
|
||||||
if(DoButton_Menu(&s_OkButton, Localize("Ok"), 0, &OkButton) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || Activated)
|
if(DoButton_Menu(&s_OkButton, Localize("Ok"), 0, &OkButton) || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || s_ListBox.WasItemActivated())
|
||||||
{
|
{
|
||||||
g_Config.m_BrFilterCountryIndex = s_CurSelection;
|
g_Config.m_BrFilterCountryIndex = s_CurSelection;
|
||||||
Client()->ServerBrowserUpdate();
|
Client()->ServerBrowserUpdate();
|
||||||
|
@ -2195,35 +2189,35 @@ void CMenus::PopupConfirmDemoReplaceVideo()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void CMenus::RenderThemeSelection(CUIRect MainView, bool Header)
|
void CMenus::RenderThemeSelection(CUIRect MainView)
|
||||||
{
|
{
|
||||||
std::vector<CTheme> &vThemesRef = m_pBackground->GetThemes();
|
const std::vector<CTheme> &vThemes = m_pBackground->GetThemes();
|
||||||
|
|
||||||
int SelectedTheme = -1;
|
int SelectedTheme = -1;
|
||||||
for(int i = 0; i < (int)vThemesRef.size(); i++)
|
for(int i = 0; i < (int)vThemes.size(); i++)
|
||||||
{
|
{
|
||||||
if(str_comp(vThemesRef[i].m_Name.c_str(), g_Config.m_ClMenuMap) == 0)
|
if(str_comp(vThemes[i].m_Name.c_str(), g_Config.m_ClMenuMap) == 0)
|
||||||
{
|
{
|
||||||
SelectedTheme = i;
|
SelectedTheme = i;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const int OldSelected = SelectedTheme;
|
||||||
|
|
||||||
static int s_ListBox = 0;
|
static CListBox s_ListBox;
|
||||||
static float s_ScrollValue = 0.0f;
|
s_ListBox.DoHeader(&MainView, Localize("Theme"), 20.0f);
|
||||||
UiDoListboxStart(&s_ListBox, &MainView, 26.0f, Localize("Theme"), "", vThemesRef.size(), 1, -1, s_ScrollValue);
|
s_ListBox.DoStart(20.0f, vThemes.size(), 1, 3, SelectedTheme, nullptr, true);
|
||||||
|
|
||||||
for(int i = 0; i < (int)vThemesRef.size(); i++)
|
for(int i = 0; i < (int)vThemes.size(); i++)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(&vThemesRef[i].m_Name, i == SelectedTheme);
|
const CTheme &Theme = vThemes[i];
|
||||||
|
const CListboxItem Item = s_ListBox.DoNextItem(&Theme.m_Name, i == SelectedTheme);
|
||||||
CTheme &Theme = vThemesRef[i];
|
|
||||||
|
|
||||||
if(!Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CUIRect Icon;
|
CUIRect Icon, Label;
|
||||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Icon, &Item.m_Rect);
|
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Icon, &Label);
|
||||||
|
|
||||||
// draw icon if it exists
|
// draw icon if it exists
|
||||||
if(Theme.m_IconTexture.IsValid())
|
if(Theme.m_IconTexture.IsValid())
|
||||||
|
@ -2254,16 +2248,18 @@ void CMenus::RenderThemeSelection(CUIRect MainView, bool Header)
|
||||||
else // generic
|
else // generic
|
||||||
str_copy(aName, Theme.m_Name.c_str());
|
str_copy(aName, Theme.m_Name.c_str());
|
||||||
|
|
||||||
UI()->DoLabel(&Item.m_Rect, aName, 16 * CUI::ms_FontmodHeight, TEXTALIGN_LEFT);
|
SLabelProperties Props;
|
||||||
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Label, aName, 16.0f * CUI::ms_FontmodHeight, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ItemActive = false;
|
SelectedTheme = s_ListBox.DoEnd();
|
||||||
int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0, &ItemActive);
|
|
||||||
|
|
||||||
if(ItemActive && NewSelected != SelectedTheme)
|
if(OldSelected != SelectedTheme)
|
||||||
{
|
{
|
||||||
str_copy(g_Config.m_ClMenuMap, vThemesRef[NewSelected].m_Name.c_str());
|
const CTheme &Theme = vThemes[SelectedTheme];
|
||||||
m_pBackground->LoadMenuBackground(vThemesRef[NewSelected].m_HasDay, vThemesRef[NewSelected].m_HasNight);
|
str_copy(g_Config.m_ClMenuMap, Theme.m_Name.c_str());
|
||||||
|
m_pBackground->LoadMenuBackground(Theme.m_HasDay, Theme.m_HasNight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2631,76 +2627,3 @@ void CMenus::RefreshBrowserTab(int UiPage)
|
||||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
|
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMenus::HandleListInputs(const CUIRect &View, float &ScrollValue, const float ScrollAmount, int *pScrollOffset, const float ElemHeight, int &SelectedIndex, const int NumElems)
|
|
||||||
{
|
|
||||||
if(NumElems == 0)
|
|
||||||
{
|
|
||||||
ScrollValue = 0;
|
|
||||||
SelectedIndex = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int NewIndex = -1;
|
|
||||||
int Num = (int)(View.h / ElemHeight);
|
|
||||||
int ScrollNum = maximum(NumElems - Num, 0);
|
|
||||||
if(ScrollNum > 0)
|
|
||||||
{
|
|
||||||
if(pScrollOffset && *pScrollOffset >= 0)
|
|
||||||
{
|
|
||||||
ScrollValue = (float)(*pScrollOffset) / ScrollNum;
|
|
||||||
*pScrollOffset = -1;
|
|
||||||
}
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View))
|
|
||||||
ScrollValue -= 3.0f / ScrollNum;
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View))
|
|
||||||
ScrollValue += 3.0f / ScrollNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScrollValue = clamp(ScrollValue, 0.0f, 1.0f);
|
|
||||||
SelectedIndex = clamp(SelectedIndex, 0, NumElems - 1);
|
|
||||||
|
|
||||||
for(int i = 0; i < m_NumInputEvents; i++)
|
|
||||||
{
|
|
||||||
if(m_aInputEvents[i].m_Flags & IInput::FLAG_PRESS)
|
|
||||||
{
|
|
||||||
if(UI()->LastActiveItem() == &g_Config.m_UiServerAddress)
|
|
||||||
return false;
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_DOWN)
|
|
||||||
NewIndex = minimum(SelectedIndex + 1, NumElems - 1);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_UP)
|
|
||||||
NewIndex = maximum(SelectedIndex - 1, 0);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_PAGEUP)
|
|
||||||
NewIndex = maximum(SelectedIndex - 25, 0);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_PAGEDOWN)
|
|
||||||
NewIndex = minimum(SelectedIndex + 25, NumElems - 1);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_HOME)
|
|
||||||
NewIndex = 0;
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_END)
|
|
||||||
NewIndex = NumElems - 1;
|
|
||||||
}
|
|
||||||
if(NewIndex > -1 && NewIndex < NumElems)
|
|
||||||
{
|
|
||||||
//scroll
|
|
||||||
float IndexY = View.y - ScrollValue * ScrollNum * ElemHeight + NewIndex * ElemHeight;
|
|
||||||
int Scroll = View.y > IndexY ? -1 : View.y + View.h < IndexY + ElemHeight ? 1 : 0;
|
|
||||||
if(Scroll)
|
|
||||||
{
|
|
||||||
if(Scroll < 0)
|
|
||||||
{
|
|
||||||
int NumScrolls = (View.y - IndexY + ElemHeight - 1.0f) / ElemHeight;
|
|
||||||
ScrollValue -= (1.0f / ScrollNum) * NumScrolls;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int NumScrolls = (IndexY + ElemHeight - (View.y + View.h) + ElemHeight - 1.0f) / ElemHeight;
|
|
||||||
ScrollValue += (1.0f / ScrollNum) * NumScrolls;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectedIndex = NewIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NewIndex != -1;
|
|
||||||
}
|
|
||||||
|
|
|
@ -195,22 +195,6 @@ class CMenus : public CComponent
|
||||||
return UI()->DoButtonLogic(pID, Checked, pRect);
|
return UI()->DoButtonLogic(pID, Checked, pRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CListboxItem
|
|
||||||
{
|
|
||||||
int m_Visible;
|
|
||||||
int m_Selected;
|
|
||||||
CUIRect m_Rect;
|
|
||||||
CUIRect m_HitRect;
|
|
||||||
};
|
|
||||||
|
|
||||||
void UiDoListboxStart(const void *pID, const CUIRect *pRect, float RowHeight, const char *pTitle, const char *pBottomText, int NumItems,
|
|
||||||
int ItemsPerRow, int SelectedIndex, float ScrollValue, bool LogicOnly = false);
|
|
||||||
CListboxItem UiDoListboxNextItem(const void *pID, bool Selected = false, bool KeyEvents = true, bool NoHoverEffects = false);
|
|
||||||
CListboxItem UiDoListboxNextRow();
|
|
||||||
int UiDoListboxEnd(float *pScrollValue, bool *pItemActivated, bool *pListBoxActive = nullptr);
|
|
||||||
|
|
||||||
int UiLogicGetCurrentClickedItem();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Places and renders a tooltip near pNearRect.
|
* Places and renders a tooltip near pNearRect.
|
||||||
* For now only works correctly with single line tooltips, since Text width calculation gets broken when there are multiple lines.
|
* For now only works correctly with single line tooltips, since Text width calculation gets broken when there are multiple lines.
|
||||||
|
@ -541,8 +525,6 @@ protected:
|
||||||
|
|
||||||
// found in menus_browser.cpp
|
// found in menus_browser.cpp
|
||||||
int m_SelectedIndex;
|
int m_SelectedIndex;
|
||||||
int m_DoubleClickIndex;
|
|
||||||
int m_ScrollOffset;
|
|
||||||
void RenderServerbrowserServerList(CUIRect View);
|
void RenderServerbrowserServerList(CUIRect View);
|
||||||
void Connect(const char *pAddress);
|
void Connect(const char *pAddress);
|
||||||
void PopupConfirmSwitchServer();
|
void PopupConfirmSwitchServer();
|
||||||
|
@ -565,8 +547,8 @@ protected:
|
||||||
void OnConfigSave(IConfigManager *pConfigManager);
|
void OnConfigSave(IConfigManager *pConfigManager);
|
||||||
|
|
||||||
// found in menus_settings.cpp
|
// found in menus_settings.cpp
|
||||||
void RenderLanguageSelection(CUIRect MainView);
|
bool RenderLanguageSelection(CUIRect MainView);
|
||||||
void RenderThemeSelection(CUIRect MainView, bool Header = true);
|
void RenderThemeSelection(CUIRect MainView);
|
||||||
void RenderSettingsGeneral(CUIRect MainView);
|
void RenderSettingsGeneral(CUIRect MainView);
|
||||||
void RenderSettingsPlayer(CUIRect MainView);
|
void RenderSettingsPlayer(CUIRect MainView);
|
||||||
void RenderSettingsDummyPlayer(CUIRect MainView);
|
void RenderSettingsDummyPlayer(CUIRect MainView);
|
||||||
|
@ -746,7 +728,6 @@ private:
|
||||||
static int GhostlistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser);
|
static int GhostlistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser);
|
||||||
void SetMenuPage(int NewPage);
|
void SetMenuPage(int NewPage);
|
||||||
void RefreshBrowserTab(int UiPage);
|
void RefreshBrowserTab(int UiPage);
|
||||||
bool HandleListInputs(const CUIRect &View, float &ScrollValue, float ScrollAmount, int *pScrollOffset, float ElemHeight, int &SelectedIndex, int NumElems);
|
|
||||||
|
|
||||||
// found in menus_ingame.cpp
|
// found in menus_ingame.cpp
|
||||||
void RenderInGameNetwork(CUIRect MainView);
|
void RenderInGameNetwork(CUIRect MainView);
|
||||||
|
|
|
@ -12,12 +12,12 @@
|
||||||
|
|
||||||
#include <game/client/components/console.h>
|
#include <game/client/components/console.h>
|
||||||
#include <game/client/components/countryflags.h>
|
#include <game/client/components/countryflags.h>
|
||||||
|
#include <game/client/gameclient.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
|
||||||
#include <game/client/gameclient.h>
|
|
||||||
|
|
||||||
#include "menus.h"
|
#include "menus.h"
|
||||||
|
|
||||||
static const int gs_OffsetColFlagLock = 2;
|
static const int gs_OffsetColFlagLock = 2;
|
||||||
|
@ -160,9 +160,6 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
|
|
||||||
View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
||||||
|
|
||||||
CUIRect Scroll;
|
|
||||||
View.VSplitRight(20.0f, &View, &Scroll);
|
|
||||||
|
|
||||||
int NumServers = ServerBrowser()->NumSortedServers();
|
int NumServers = ServerBrowser()->NumSortedServers();
|
||||||
|
|
||||||
// display important messages in the middle of the screen so no
|
// display important messages in the middle of the screen so no
|
||||||
|
@ -178,34 +175,22 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
UI()->DoLabel(&MsgBox, Localize("No servers match your filter criteria"), 16.0f, TEXTALIGN_CENTER);
|
UI()->DoLabel(&MsgBox, Localize("No servers match your filter criteria"), 16.0f, TEXTALIGN_CENTER);
|
||||||
}
|
}
|
||||||
|
|
||||||
static float s_ScrollValue = 0;
|
|
||||||
|
|
||||||
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
|
|
||||||
|
|
||||||
if(UI()->ConsumeHotkey(CUI::HOTKEY_TAB))
|
if(UI()->ConsumeHotkey(CUI::HOTKEY_TAB))
|
||||||
{
|
{
|
||||||
const int Direction = Input()->ShiftIsPressed() ? -1 : 1;
|
const int Direction = Input()->ShiftIsPressed() ? -1 : 1;
|
||||||
g_Config.m_UiToolboxPage = (g_Config.m_UiToolboxPage + 3 + Direction) % 3;
|
g_Config.m_UiToolboxPage = (g_Config.m_UiToolboxPage + 3 + Direction) % 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(HandleListInputs(View, s_ScrollValue, 3.0f, &m_ScrollOffset, s_aCols[0].m_Rect.h, m_SelectedIndex, NumServers))
|
static CListBox s_ListBox;
|
||||||
{
|
s_ListBox.DoStart(ms_ListheaderHeight, NumServers, 1, 3, m_SelectedIndex, &View, false);
|
||||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(m_SelectedIndex);
|
|
||||||
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set clipping
|
|
||||||
UI()->ClipEnable(&View);
|
|
||||||
|
|
||||||
CUIRect OriginalView = View;
|
|
||||||
int Num = (int)(View.h / s_aCols[0].m_Rect.h) + 1;
|
|
||||||
int ScrollNum = maximum(NumServers - Num + 1, 0);
|
|
||||||
View.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
|
||||||
|
|
||||||
int NewSelected = -1;
|
|
||||||
bool DoubleClicked = false;
|
|
||||||
int NumPlayers = 0;
|
int NumPlayers = 0;
|
||||||
|
static int s_PrevSelectedIndex = -1;
|
||||||
|
if(s_PrevSelectedIndex != m_SelectedIndex)
|
||||||
|
{
|
||||||
|
s_ListBox.ScrollToSelected();
|
||||||
|
s_PrevSelectedIndex = m_SelectedIndex;
|
||||||
|
}
|
||||||
m_SelectedIndex = -1;
|
m_SelectedIndex = -1;
|
||||||
|
|
||||||
// reset friend counter
|
// reset friend counter
|
||||||
|
@ -229,23 +214,17 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
|
|
||||||
for(int i = 0; i < NumServers; i++)
|
for(int i = 0; i < NumServers; i++)
|
||||||
{
|
{
|
||||||
int ItemIndex = i;
|
const CServerInfo *pItem = ServerBrowser()->SortedGet(i);
|
||||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex);
|
|
||||||
NumPlayers += pItem->m_NumFilteredPlayers;
|
NumPlayers += pItem->m_NumFilteredPlayers;
|
||||||
CUIRect Row;
|
|
||||||
|
|
||||||
const int UIRectCount = 2 + (COL_VERSION + 1) * 3;
|
if(pItem->m_pUIElement == nullptr)
|
||||||
//initialize
|
|
||||||
if(pItem->m_pUIElement == NULL)
|
|
||||||
{
|
{
|
||||||
|
const int UIRectCount = 2 + (COL_VERSION + 1) * 3;
|
||||||
pItem->m_pUIElement = UI()->GetNewUIElement(UIRectCount);
|
pItem->m_pUIElement = UI()->GetNewUIElement(UIRectCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Selected = str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0; //selected_index==ItemIndex;
|
const CListboxItem ListItem = s_ListBox.DoNextItem(pItem, str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0);
|
||||||
|
if(ListItem.m_Selected)
|
||||||
View.HSplitTop(ms_ListheaderHeight, &Row, &View);
|
|
||||||
|
|
||||||
if(Selected)
|
|
||||||
m_SelectedIndex = i;
|
m_SelectedIndex = i;
|
||||||
|
|
||||||
// update friend counter
|
// update friend counter
|
||||||
|
@ -273,31 +252,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure that only those in view can be selected
|
if(!ListItem.m_Visible)
|
||||||
if(Row.y + Row.h > OriginalView.y && Row.y < OriginalView.y + OriginalView.h)
|
|
||||||
{
|
|
||||||
if(Selected)
|
|
||||||
{
|
|
||||||
CUIRect r = Row;
|
|
||||||
r.Margin(0.5f, &r);
|
|
||||||
pItem->m_pUIElement->Rect(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
else if(UI()->MouseHovered(&Row))
|
|
||||||
{
|
|
||||||
CUIRect r = Row;
|
|
||||||
r.Margin(0.5f, &r);
|
|
||||||
pItem->m_pUIElement->Rect(0)->Draw(&r, ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->DoButtonLogic(pItem, Selected, &Row))
|
|
||||||
{
|
|
||||||
NewSelected = ItemIndex;
|
|
||||||
if(NewSelected == m_DoubleClickIndex)
|
|
||||||
DoubleClicked = true;
|
|
||||||
m_DoubleClickIndex = NewSelected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
// reset active item, if not visible
|
// reset active item, if not visible
|
||||||
if(UI()->CheckActiveItem(pItem))
|
if(UI()->CheckActiveItem(pItem))
|
||||||
|
@ -312,8 +267,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
CUIRect Button;
|
CUIRect Button;
|
||||||
char aTemp[64];
|
char aTemp[64];
|
||||||
Button.x = s_aCols[c].m_Rect.x;
|
Button.x = s_aCols[c].m_Rect.x;
|
||||||
Button.y = Row.y;
|
Button.y = ListItem.m_Rect.y;
|
||||||
Button.h = Row.h;
|
Button.h = ListItem.m_Rect.h;
|
||||||
Button.w = s_aCols[c].m_Rect.w;
|
Button.w = s_aCols[c].m_Rect.w;
|
||||||
|
|
||||||
int ID = s_aCols[c].m_ID;
|
int ID = s_aCols[c].m_ID;
|
||||||
|
@ -469,16 +424,22 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UI()->ClipDisable();
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
|
if(NewSelected != m_SelectedIndex)
|
||||||
if(NewSelected != -1)
|
{
|
||||||
|
m_SelectedIndex = NewSelected;
|
||||||
|
if(m_SelectedIndex >= 0)
|
||||||
{
|
{
|
||||||
// select the new server
|
// select the new server
|
||||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(NewSelected);
|
const CServerInfo *pItem = ServerBrowser()->SortedGet(NewSelected);
|
||||||
|
if(pItem)
|
||||||
|
{
|
||||||
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
||||||
if(DoubleClicked && Input()->MouseDoubleClick())
|
|
||||||
Connect(g_Config.m_UiServerAddress);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(s_ListBox.WasItemActivated())
|
||||||
|
Connect(g_Config.m_UiServerAddress);
|
||||||
|
|
||||||
// Render bar that shows the loading progression.
|
// Render bar that shows the loading progression.
|
||||||
// The bar is only shown while loading and fades out when it's done.
|
// The bar is only shown while loading and fades out when it's done.
|
||||||
|
@ -1123,30 +1084,22 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
|
|
||||||
if(pSelectedServer)
|
if(pSelectedServer)
|
||||||
{
|
{
|
||||||
static int s_VoteList = 0;
|
static CListBox s_ListBox;
|
||||||
static float s_ScrollValue = 0;
|
s_ListBox.DoAutoSpacing(1.0f);
|
||||||
UiDoListboxStart(&s_VoteList, &ServerScoreBoard, 26.0f, Localize("Scoreboard"), "", pSelectedServer->m_NumReceivedClients, 1, -1, s_ScrollValue);
|
s_ListBox.DoStart(25.0f, pSelectedServer->m_NumReceivedClients, 1, 3, -1, &ServerScoreBoard);
|
||||||
|
|
||||||
for(int i = 0; i < pSelectedServer->m_NumReceivedClients; i++)
|
for(int i = 0; i < pSelectedServer->m_NumReceivedClients; i++)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(&pSelectedServer->m_aClients[i]);
|
const CServerInfo::CClient &CurrentClient = pSelectedServer->m_aClients[i];
|
||||||
|
const CListboxItem Item = s_ListBox.DoNextItem(&CurrentClient);
|
||||||
|
|
||||||
if(!Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CUIRect Name, Clan, Score, Flag;
|
CUIRect Name, Clan, Score, Flag;
|
||||||
Item.m_Rect.HSplitTop(25.0f, &Name, &Item.m_Rect);
|
Name = Item.m_Rect;
|
||||||
if(UiLogicGetCurrentClickedItem() == i)
|
|
||||||
{
|
|
||||||
if(pSelectedServer->m_aClients[i].m_FriendState == IFriends::FRIEND_PLAYER)
|
|
||||||
m_pClient->Friends()->RemoveFriend(pSelectedServer->m_aClients[i].m_aName, pSelectedServer->m_aClients[i].m_aClan);
|
|
||||||
else
|
|
||||||
m_pClient->Friends()->AddFriend(pSelectedServer->m_aClients[i].m_aName, pSelectedServer->m_aClients[i].m_aClan);
|
|
||||||
FriendlistOnUpdate();
|
|
||||||
Client()->ServerBrowserUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA Color = pSelectedServer->m_aClients[i].m_FriendState == IFriends::FRIEND_NO ?
|
ColorRGBA Color = CurrentClient.m_FriendState == IFriends::FRIEND_NO ?
|
||||||
ColorRGBA(1.0f, 1.0f, 1.0f, (i % 2 + 1) * 0.05f) :
|
ColorRGBA(1.0f, 1.0f, 1.0f, (i % 2 + 1) * 0.05f) :
|
||||||
ColorRGBA(0.5f, 1.0f, 0.5f, 0.15f + (i % 2 + 1) * 0.05f);
|
ColorRGBA(0.5f, 1.0f, 0.5f, 0.15f + (i % 2 + 1) * 0.05f);
|
||||||
Name.Draw(Color, IGraphics::CORNER_ALL, 4.0f);
|
Name.Draw(Color, IGraphics::CORNER_ALL, 4.0f);
|
||||||
|
@ -1159,17 +1112,17 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
// score
|
// score
|
||||||
char aTemp[16];
|
char aTemp[16];
|
||||||
|
|
||||||
if(!pSelectedServer->m_aClients[i].m_Player)
|
if(!CurrentClient.m_Player)
|
||||||
str_copy(aTemp, "SPEC");
|
str_copy(aTemp, "SPEC");
|
||||||
else if((str_find_nocase(pSelectedServer->m_aGameType, "race") || str_find_nocase(pSelectedServer->m_aGameType, "fastcap")) && g_Config.m_ClDDRaceScoreBoard)
|
else if((str_find_nocase(pSelectedServer->m_aGameType, "race") || str_find_nocase(pSelectedServer->m_aGameType, "fastcap")) && g_Config.m_ClDDRaceScoreBoard)
|
||||||
{
|
{
|
||||||
if(pSelectedServer->m_aClients[i].m_Score == -9999 || pSelectedServer->m_aClients[i].m_Score == 0)
|
if(CurrentClient.m_Score == -9999 || CurrentClient.m_Score == 0)
|
||||||
aTemp[0] = 0;
|
aTemp[0] = 0;
|
||||||
else
|
else
|
||||||
str_time((int64_t)abs(pSelectedServer->m_aClients[i].m_Score) * 100, TIME_HOURS, aTemp, sizeof(aTemp));
|
str_time((int64_t)abs(CurrentClient.m_Score) * 100, TIME_HOURS, aTemp, sizeof(aTemp));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
str_format(aTemp, sizeof(aTemp), "%d", pSelectedServer->m_aClients[i].m_Score);
|
str_format(aTemp, sizeof(aTemp), "%d", CurrentClient.m_Score);
|
||||||
|
|
||||||
float ScoreFontSize = 12.0f;
|
float ScoreFontSize = 12.0f;
|
||||||
while(ScoreFontSize >= 4.0f && TextRender()->TextWidth(0, ScoreFontSize, aTemp, -1, -1.0f) > Score.w)
|
while(ScoreFontSize >= 4.0f && TextRender()->TextWidth(0, ScoreFontSize, aTemp, -1, -1.0f) > Score.w)
|
||||||
|
@ -1182,7 +1135,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
// name
|
// name
|
||||||
TextRender()->SetCursor(&Cursor, Name.x, Name.y + (Name.h - (FontSize - 2)) / 2.f, FontSize - 2, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
TextRender()->SetCursor(&Cursor, Name.x, Name.y + (Name.h - (FontSize - 2)) / 2.f, FontSize - 2, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||||
Cursor.m_LineWidth = Name.w;
|
Cursor.m_LineWidth = Name.w;
|
||||||
const char *pName = pSelectedServer->m_aClients[i].m_aName;
|
const char *pName = CurrentClient.m_aName;
|
||||||
bool Printed = false;
|
bool Printed = false;
|
||||||
if(g_Config.m_BrFilterString[0])
|
if(g_Config.m_BrFilterString[0])
|
||||||
Printed = PrintHighlighted(pName, [this, &Cursor, pName](const char *pFilteredStr, const int FilterLen) {
|
Printed = PrintHighlighted(pName, [this, &Cursor, pName](const char *pFilteredStr, const int FilterLen) {
|
||||||
|
@ -1198,7 +1151,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
// clan
|
// clan
|
||||||
TextRender()->SetCursor(&Cursor, Clan.x, Clan.y + (Clan.h - (FontSize - 2)) / 2.f, FontSize - 2, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
TextRender()->SetCursor(&Cursor, Clan.x, Clan.y + (Clan.h - (FontSize - 2)) / 2.f, FontSize - 2, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||||
Cursor.m_LineWidth = Clan.w;
|
Cursor.m_LineWidth = Clan.w;
|
||||||
const char *pClan = pSelectedServer->m_aClients[i].m_aClan;
|
const char *pClan = CurrentClient.m_aClan;
|
||||||
Printed = false;
|
Printed = false;
|
||||||
if(g_Config.m_BrFilterString[0])
|
if(g_Config.m_BrFilterString[0])
|
||||||
Printed = PrintHighlighted(pClan, [this, &Cursor, pClan](const char *pFilteredStr, const int FilterLen) {
|
Printed = PrintHighlighted(pClan, [this, &Cursor, pClan](const char *pFilteredStr, const int FilterLen) {
|
||||||
|
@ -1213,10 +1166,20 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
||||||
|
|
||||||
// flag
|
// flag
|
||||||
ColorRGBA FColor(1.0f, 1.0f, 1.0f, 0.5f);
|
ColorRGBA FColor(1.0f, 1.0f, 1.0f, 0.5f);
|
||||||
m_pClient->m_CountryFlags.Render(pSelectedServer->m_aClients[i].m_Country, &FColor, Flag.x, Flag.y, Flag.w, Flag.h);
|
m_pClient->m_CountryFlags.Render(CurrentClient.m_Country, &FColor, Flag.x, Flag.y, Flag.w, Flag.h);
|
||||||
}
|
}
|
||||||
|
|
||||||
UiDoListboxEnd(&s_ScrollValue, 0);
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
|
if(s_ListBox.WasItemSelected())
|
||||||
|
{
|
||||||
|
const CServerInfo::CClient &SelectedClient = pSelectedServer->m_aClients[NewSelected];
|
||||||
|
if(SelectedClient.m_FriendState == IFriends::FRIEND_PLAYER)
|
||||||
|
m_pClient->Friends()->RemoveFriend(SelectedClient.m_aName, SelectedClient.m_aClan);
|
||||||
|
else
|
||||||
|
m_pClient->Friends()->AddFriend(SelectedClient.m_aName, SelectedClient.m_aClan);
|
||||||
|
FriendlistOnUpdate();
|
||||||
|
Client()->ServerBrowserUpdate();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1276,34 +1239,35 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
||||||
FilterHeader.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_T, 4.0f);
|
FilterHeader.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_T, 4.0f);
|
||||||
ServerFriends.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 4.0f);
|
ServerFriends.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 4.0f);
|
||||||
UI()->DoLabel(&FilterHeader, Localize("Friends"), FontSize + 4.0f, TEXTALIGN_CENTER);
|
UI()->DoLabel(&FilterHeader, Localize("Friends"), FontSize + 4.0f, TEXTALIGN_CENTER);
|
||||||
CUIRect Button, List;
|
|
||||||
|
|
||||||
|
CUIRect List;
|
||||||
ServerFriends.Margin(3.0f, &ServerFriends);
|
ServerFriends.Margin(3.0f, &ServerFriends);
|
||||||
ServerFriends.VMargin(3.0f, &ServerFriends);
|
ServerFriends.VMargin(3.0f, &ServerFriends);
|
||||||
ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends);
|
ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends);
|
||||||
|
|
||||||
// friends list(remove friend)
|
// friends list(remove friend)
|
||||||
static float s_ScrollValue = 0;
|
static CListBox s_ListBox;
|
||||||
if(m_FriendlistSelectedIndex >= (int)m_vFriends.size())
|
if(m_FriendlistSelectedIndex >= (int)m_vFriends.size())
|
||||||
m_FriendlistSelectedIndex = m_vFriends.size() - 1;
|
m_FriendlistSelectedIndex = m_vFriends.size() - 1;
|
||||||
UiDoListboxStart(&m_vFriends, &List, 30.0f, "", "", m_vFriends.size(), 1, m_FriendlistSelectedIndex, s_ScrollValue);
|
s_ListBox.DoAutoSpacing(3.0f);
|
||||||
|
s_ListBox.DoStart(30.0f, m_vFriends.size(), 1, 3, m_FriendlistSelectedIndex, &List);
|
||||||
|
|
||||||
std::sort(m_vFriends.begin(), m_vFriends.end());
|
std::sort(m_vFriends.begin(), m_vFriends.end());
|
||||||
for(auto &Friend : m_vFriends)
|
for(size_t i = 0; i < m_vFriends.size(); ++i)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(&Friend.m_NumFound, false, false);
|
const auto &Friend = m_vFriends[i];
|
||||||
|
const CListboxItem Item = s_ListBox.DoNextItem(&Friend, m_FriendlistSelectedIndex >= 0 && (size_t)m_FriendlistSelectedIndex == i);
|
||||||
|
if(!Item.m_Visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
if(Item.m_Visible)
|
CUIRect NameClanLabels, NameLabel, ClanLabel, OnState;
|
||||||
{
|
Item.m_Rect.VSplitRight(30.0f, &NameClanLabels, &OnState);
|
||||||
Item.m_Rect.Margin(1.5f, &Item.m_Rect);
|
NameClanLabels.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.1f), IGraphics::CORNER_L, 4.0f);
|
||||||
CUIRect OnState;
|
|
||||||
Item.m_Rect.VSplitRight(30.0f, &Item.m_Rect, &OnState);
|
|
||||||
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.1f), IGraphics::CORNER_L, 4.0f);
|
|
||||||
|
|
||||||
Item.m_Rect.VMargin(2.5f, &Item.m_Rect);
|
NameClanLabels.VMargin(2.5f, &NameClanLabels);
|
||||||
Item.m_Rect.HSplitTop(12.0f, &Item.m_Rect, &Button);
|
NameClanLabels.HSplitTop(12.0f, &NameLabel, &ClanLabel);
|
||||||
UI()->DoLabel(&Item.m_Rect, Friend.m_pFriendInfo->m_aName, FontSize, TEXTALIGN_LEFT);
|
UI()->DoLabel(&NameLabel, Friend.m_pFriendInfo->m_aName, FontSize, TEXTALIGN_LEFT);
|
||||||
UI()->DoLabel(&Button, Friend.m_pFriendInfo->m_aClan, FontSize, TEXTALIGN_LEFT);
|
UI()->DoLabel(&ClanLabel, Friend.m_pFriendInfo->m_aClan, FontSize, TEXTALIGN_LEFT);
|
||||||
|
|
||||||
OnState.Draw(Friend.m_NumFound ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.25f) : ColorRGBA(1.0f, 0.0f, 0.0f, 0.25f), IGraphics::CORNER_R, 4.0f);
|
OnState.Draw(Friend.m_NumFound ? ColorRGBA(0.0f, 1.0f, 0.0f, 0.25f) : ColorRGBA(1.0f, 0.0f, 0.0f, 0.25f), IGraphics::CORNER_R, 4.0f);
|
||||||
OnState.HMargin((OnState.h - FontSize) / 3, &OnState);
|
OnState.HMargin((OnState.h - FontSize) / 3, &OnState);
|
||||||
|
@ -1312,13 +1276,11 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
||||||
str_format(aBuf, sizeof(aBuf), "%i", Friend.m_NumFound);
|
str_format(aBuf, sizeof(aBuf), "%i", Friend.m_NumFound);
|
||||||
UI()->DoLabel(&OnState, aBuf, FontSize + 2, TEXTALIGN_RIGHT);
|
UI()->DoLabel(&OnState, aBuf, FontSize + 2, TEXTALIGN_RIGHT);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool Activated = false;
|
m_FriendlistSelectedIndex = s_ListBox.DoEnd();
|
||||||
m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated);
|
|
||||||
|
|
||||||
// activate found server with friend
|
// activate found server with friend
|
||||||
if(Activated && m_vFriends[m_FriendlistSelectedIndex].m_NumFound)
|
if(s_ListBox.WasItemActivated() && m_vFriends[m_FriendlistSelectedIndex].m_NumFound)
|
||||||
{
|
{
|
||||||
bool Found = false;
|
bool Found = false;
|
||||||
int NumServers = ServerBrowser()->NumSortedServers();
|
int NumServers = ServerBrowser()->NumSortedServers();
|
||||||
|
@ -1336,7 +1298,6 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
||||||
str_quickhash(pItem->m_aClients[j].m_aName) == m_vFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_NameHash))
|
str_quickhash(pItem->m_aClients[j].m_aName) == m_vFriends[m_FriendlistSelectedIndex].m_pFriendInfo->m_NameHash))
|
||||||
{
|
{
|
||||||
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
||||||
m_ScrollOffset = ItemIndex;
|
|
||||||
m_SelectedIndex = ItemIndex;
|
m_SelectedIndex = ItemIndex;
|
||||||
Found = true;
|
Found = true;
|
||||||
}
|
}
|
||||||
|
@ -1345,6 +1306,7 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CUIRect Button;
|
||||||
ServerFriends.HSplitTop(2.5f, 0, &ServerFriends);
|
ServerFriends.HSplitTop(2.5f, 0, &ServerFriends);
|
||||||
ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends);
|
ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends);
|
||||||
if(m_FriendlistSelectedIndex != -1)
|
if(m_FriendlistSelectedIndex != -1)
|
||||||
|
|
|
@ -14,11 +14,10 @@
|
||||||
#include <game/client/components/console.h>
|
#include <game/client/components/console.h>
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/localization.h>
|
|
||||||
|
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/generated/client_data.h>
|
#include <game/generated/client_data.h>
|
||||||
|
#include <game/localization.h>
|
||||||
|
|
||||||
#include "maplayers.h"
|
#include "maplayers.h"
|
||||||
#include "menus.h"
|
#include "menus.h"
|
||||||
|
@ -636,246 +635,6 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
|
||||||
HandleDemoSeeking(PositionToSeek, TimeToSeek);
|
HandleDemoSeeking(PositionToSeek, TimeToSeek);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CUIRect gs_ListBoxOriginalView;
|
|
||||||
static CUIRect gs_ListBoxView;
|
|
||||||
static float gs_ListBoxRowHeight;
|
|
||||||
static int gs_ListBoxItemIndex;
|
|
||||||
static int gs_ListBoxSelectedIndex;
|
|
||||||
static int gs_ListBoxNewSelected;
|
|
||||||
static int gs_ListBoxDoneEvents;
|
|
||||||
static int gs_ListBoxNumItems;
|
|
||||||
static int gs_ListBoxItemsPerRow;
|
|
||||||
static float gs_ListBoxScrollValue;
|
|
||||||
static bool gs_ListBoxItemActivated;
|
|
||||||
static bool gs_ListBoxClicked;
|
|
||||||
|
|
||||||
void CMenus::UiDoListboxStart(const void *pID, const CUIRect *pRect, float RowHeight, const char *pTitle, const char *pBottomText, int NumItems,
|
|
||||||
int ItemsPerRow, int SelectedIndex, float ScrollValue, bool LogicOnly)
|
|
||||||
{
|
|
||||||
CUIRect Scroll, Row;
|
|
||||||
CUIRect View = *pRect;
|
|
||||||
|
|
||||||
if(!LogicOnly)
|
|
||||||
{
|
|
||||||
// background
|
|
||||||
View.Draw(ColorRGBA(0, 0, 0, 0.15f), IGraphics::CORNER_ALL, 5.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
View.VSplitRight(20.0f, &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;
|
|
||||||
gs_ListBoxClicked = false;
|
|
||||||
|
|
||||||
// do the scrollbar
|
|
||||||
View.HSplitTop(gs_ListBoxRowHeight, &Row, 0);
|
|
||||||
|
|
||||||
int NumViewable = (int)(gs_ListBoxOriginalView.h / Row.h) * gs_ListBoxItemsPerRow;
|
|
||||||
//int Num = (NumItems + gs_ListBoxItemsPerRow - 1) / gs_ListBoxItemsPerRow - NumViewable + 1;
|
|
||||||
int Num = ceil((NumItems - NumViewable) / (float)gs_ListBoxItemsPerRow);
|
|
||||||
if(Num <= 0)
|
|
||||||
{
|
|
||||||
Num = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View))
|
|
||||||
gs_ListBoxScrollValue -= Num == 1 ? 0.1f : 3.0f / Num;
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View))
|
|
||||||
gs_ListBoxScrollValue += Num == 1 ? 0.1f : 3.0f / Num;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Num == 0)
|
|
||||||
gs_ListBoxScrollValue = 0;
|
|
||||||
else
|
|
||||||
gs_ListBoxScrollValue = UI()->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;
|
|
||||||
}
|
|
||||||
|
|
||||||
CMenus::CListboxItem CMenus::UiDoListboxNextRow()
|
|
||||||
{
|
|
||||||
static CUIRect s_RowView;
|
|
||||||
CListboxItem Item = {0};
|
|
||||||
if(gs_ListBoxItemIndex % gs_ListBoxItemsPerRow == 0)
|
|
||||||
gs_ListBoxView.HSplitTop(gs_ListBoxRowHeight /*-2.0f*/, &s_RowView, &gs_ListBoxView);
|
|
||||||
|
|
||||||
s_RowView.VSplitLeft(s_RowView.w / (gs_ListBoxItemsPerRow - gs_ListBoxItemIndex % gs_ListBoxItemsPerRow), &Item.m_Rect, &s_RowView);
|
|
||||||
|
|
||||||
Item.m_Visible = 1;
|
|
||||||
//item.rect = row;
|
|
||||||
|
|
||||||
Item.m_HitRect = Item.m_Rect;
|
|
||||||
|
|
||||||
//CUIRect select_hit_box = item.rect;
|
|
||||||
|
|
||||||
if(gs_ListBoxSelectedIndex == gs_ListBoxItemIndex)
|
|
||||||
Item.m_Selected = 1;
|
|
||||||
|
|
||||||
// make sure that only those in view can be selected
|
|
||||||
if(Item.m_Rect.y + Item.m_Rect.h > gs_ListBoxOriginalView.y)
|
|
||||||
{
|
|
||||||
if(Item.m_HitRect.y < Item.m_HitRect.y) // clip the selection
|
|
||||||
{
|
|
||||||
Item.m_HitRect.h -= gs_ListBoxOriginalView.y - Item.m_HitRect.y;
|
|
||||||
Item.m_HitRect.y = gs_ListBoxOriginalView.y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Item.m_Visible = 0;
|
|
||||||
|
|
||||||
// check if we need to do more
|
|
||||||
if(Item.m_Rect.y > gs_ListBoxOriginalView.y + gs_ListBoxOriginalView.h)
|
|
||||||
Item.m_Visible = 0;
|
|
||||||
|
|
||||||
gs_ListBoxItemIndex++;
|
|
||||||
return Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
CMenus::CListboxItem CMenus::UiDoListboxNextItem(const void *pId, bool Selected, bool KeyEvents, bool NoHoverEffects)
|
|
||||||
{
|
|
||||||
int ThisItemIndex = gs_ListBoxItemIndex;
|
|
||||||
if(Selected)
|
|
||||||
{
|
|
||||||
if(gs_ListBoxSelectedIndex == gs_ListBoxNewSelected)
|
|
||||||
gs_ListBoxNewSelected = ThisItemIndex;
|
|
||||||
gs_ListBoxSelectedIndex = ThisItemIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextRow();
|
|
||||||
|
|
||||||
CUIRect HitRect = Item.m_HitRect;
|
|
||||||
|
|
||||||
if(HitRect.y < gs_ListBoxOriginalView.y)
|
|
||||||
{
|
|
||||||
float TmpDiff = gs_ListBoxOriginalView.y - HitRect.y;
|
|
||||||
HitRect.y = gs_ListBoxOriginalView.y;
|
|
||||||
HitRect.h -= TmpDiff;
|
|
||||||
}
|
|
||||||
|
|
||||||
HitRect.h = minimum(HitRect.h, (gs_ListBoxOriginalView.y + gs_ListBoxOriginalView.h) - HitRect.y);
|
|
||||||
|
|
||||||
bool DoubleClickable = false;
|
|
||||||
if(Item.m_Visible && UI()->DoButtonLogic(pId, gs_ListBoxSelectedIndex == gs_ListBoxItemIndex, &HitRect))
|
|
||||||
{
|
|
||||||
DoubleClickable |= gs_ListBoxNewSelected == ThisItemIndex;
|
|
||||||
gs_ListBoxClicked = true;
|
|
||||||
gs_ListBoxNewSelected = ThisItemIndex;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process input, regard selected index
|
|
||||||
if(gs_ListBoxSelectedIndex == ThisItemIndex)
|
|
||||||
{
|
|
||||||
if(!gs_ListBoxDoneEvents)
|
|
||||||
{
|
|
||||||
gs_ListBoxDoneEvents = 1;
|
|
||||||
|
|
||||||
if(UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (DoubleClickable && Input()->MouseDoubleClick()))
|
|
||||||
{
|
|
||||||
gs_ListBoxItemActivated = true;
|
|
||||||
UI()->SetActiveItem(nullptr);
|
|
||||||
}
|
|
||||||
else if(KeyEvents)
|
|
||||||
{
|
|
||||||
for(int i = 0; i < m_NumInputEvents; i++)
|
|
||||||
{
|
|
||||||
int NewIndex = -1;
|
|
||||||
if(m_aInputEvents[i].m_Flags & IInput::FLAG_PRESS)
|
|
||||||
{
|
|
||||||
if(m_aInputEvents[i].m_Key == KEY_DOWN)
|
|
||||||
NewIndex = gs_ListBoxNewSelected + 1;
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_UP)
|
|
||||||
NewIndex = gs_ListBoxNewSelected - 1;
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_PAGEUP)
|
|
||||||
NewIndex = maximum(gs_ListBoxNewSelected - 20, 0);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_PAGEDOWN)
|
|
||||||
NewIndex = minimum(gs_ListBoxNewSelected + 20, gs_ListBoxNumItems - 1);
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_HOME)
|
|
||||||
NewIndex = 0;
|
|
||||||
else if(m_aInputEvents[i].m_Key == KEY_END)
|
|
||||||
NewIndex = gs_ListBoxNumItems - 1;
|
|
||||||
}
|
|
||||||
if(NewIndex > -1 && NewIndex < gs_ListBoxNumItems)
|
|
||||||
{
|
|
||||||
// scroll
|
|
||||||
float Offset = (NewIndex / gs_ListBoxItemsPerRow - gs_ListBoxNewSelected / gs_ListBoxItemsPerRow) * gs_ListBoxRowHeight;
|
|
||||||
int Scroll = gs_ListBoxOriginalView.y > Item.m_Rect.y + Offset ? -1 :
|
|
||||||
gs_ListBoxOriginalView.y + gs_ListBoxOriginalView.h < Item.m_Rect.y + Item.m_Rect.h + Offset ? 1 : 0;
|
|
||||||
if(Scroll)
|
|
||||||
{
|
|
||||||
int NumViewable = (int)(gs_ListBoxOriginalView.h / gs_ListBoxRowHeight) + 1;
|
|
||||||
int ScrollNum = (gs_ListBoxNumItems + gs_ListBoxItemsPerRow - 1) / gs_ListBoxItemsPerRow - NumViewable + 1;
|
|
||||||
if(Scroll < 0)
|
|
||||||
{
|
|
||||||
int Num = (gs_ListBoxOriginalView.y - Item.m_Rect.y - Offset + gs_ListBoxRowHeight - 1.0f) / gs_ListBoxRowHeight;
|
|
||||||
gs_ListBoxScrollValue -= (1.0f / ScrollNum) * Num;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int Num = (Item.m_Rect.y + Item.m_Rect.h + Offset - (gs_ListBoxOriginalView.y + gs_ListBoxOriginalView.h) + gs_ListBoxRowHeight - 1.0f) /
|
|
||||||
gs_ListBoxRowHeight;
|
|
||||||
gs_ListBoxScrollValue += (1.0f / ScrollNum) * Num;
|
|
||||||
}
|
|
||||||
if(gs_ListBoxScrollValue < 0.0f)
|
|
||||||
gs_ListBoxScrollValue = 0.0f;
|
|
||||||
if(gs_ListBoxScrollValue > 1.0f)
|
|
||||||
gs_ListBoxScrollValue = 1.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
gs_ListBoxNewSelected = NewIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//selected_index = i;
|
|
||||||
CUIRect r = Item.m_Rect;
|
|
||||||
r.Margin(1.5f, &r);
|
|
||||||
r.Draw(ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
else if(UI()->MouseInside(&HitRect) && !NoHoverEffects)
|
|
||||||
{
|
|
||||||
CUIRect r = Item.m_Rect;
|
|
||||||
r.Margin(1.5f, &r);
|
|
||||||
r.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Item;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated, bool *pListBoxActive)
|
|
||||||
{
|
|
||||||
UI()->ClipDisable();
|
|
||||||
if(pScrollValue)
|
|
||||||
*pScrollValue = gs_ListBoxScrollValue;
|
|
||||||
if(pItemActivated)
|
|
||||||
*pItemActivated = gs_ListBoxItemActivated;
|
|
||||||
if(pListBoxActive)
|
|
||||||
*pListBoxActive = gs_ListBoxClicked;
|
|
||||||
return gs_ListBoxNewSelected;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CMenus::UiLogicGetCurrentClickedItem()
|
|
||||||
{
|
|
||||||
if(gs_ListBoxClicked)
|
|
||||||
return gs_ListBoxNewSelected;
|
|
||||||
else
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser)
|
int CMenus::DemolistFetchCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser)
|
||||||
{
|
{
|
||||||
CMenus *pSelf = (CMenus *)pUser;
|
CMenus *pSelf = (CMenus *)pUser;
|
||||||
|
@ -1206,78 +965,26 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// scrollbar
|
static CListBox s_ListBox;
|
||||||
CUIRect Scroll;
|
s_ListBox.DoStart(ms_ListheaderHeight, m_vDemos.size(), 1, 3, m_DemolistSelectedIndex, &ListBox, false);
|
||||||
ListBox.VSplitRight(20.0f, &ListBox, &Scroll);
|
|
||||||
|
|
||||||
static float s_ScrollValue = 0;
|
|
||||||
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
|
|
||||||
|
|
||||||
int PreviousIndex = m_DemolistSelectedIndex;
|
|
||||||
HandleListInputs(ListBox, s_ScrollValue, 3.0f, &m_ScrollOffset, s_aCols[0].m_Rect.h, m_DemolistSelectedIndex, m_vDemos.size());
|
|
||||||
if(PreviousIndex != m_DemolistSelectedIndex)
|
|
||||||
{
|
|
||||||
str_copy(g_Config.m_UiDemoSelected, m_vDemos[m_DemolistSelectedIndex].m_aName);
|
|
||||||
DemolistOnUpdate(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set clipping
|
|
||||||
UI()->ClipEnable(&ListBox);
|
|
||||||
|
|
||||||
CUIRect OriginalView = ListBox;
|
|
||||||
int Num = (int)(ListBox.h / s_aCols[0].m_Rect.h) + 1;
|
|
||||||
int ScrollNum = maximum<int>(m_vDemos.size() - Num + 1, 0);
|
|
||||||
ListBox.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
|
||||||
|
|
||||||
int ItemIndex = -1;
|
int ItemIndex = -1;
|
||||||
bool DoubleClicked = false;
|
|
||||||
|
|
||||||
for(auto &Item : m_vDemos)
|
for(auto &Item : m_vDemos)
|
||||||
{
|
{
|
||||||
ItemIndex++;
|
ItemIndex++;
|
||||||
|
|
||||||
CUIRect Row;
|
const CListboxItem ListItem = s_ListBox.DoNextItem(&Item, ItemIndex == m_DemolistSelectedIndex);
|
||||||
ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox);
|
if(!ListItem.m_Visible)
|
||||||
|
|
||||||
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 Rect = Row;
|
|
||||||
Rect.Margin(0.5f, &Rect);
|
|
||||||
Rect.Draw(ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
else if(UI()->MouseHovered(&Row))
|
|
||||||
{
|
|
||||||
CUIRect Rect = Row;
|
|
||||||
Rect.Margin(0.5f, &Rect);
|
|
||||||
Rect.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->DoButtonLogic(Item.m_aName, Selected, &Row))
|
|
||||||
{
|
|
||||||
DoubleClicked |= ItemIndex == m_DoubleClickIndex;
|
|
||||||
str_copy(g_Config.m_UiDemoSelected, Item.m_aName);
|
|
||||||
DemolistOnUpdate(false);
|
|
||||||
m_DoubleClickIndex = ItemIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// don't render invisible items
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
|
CUIRect Row = ListItem.m_Rect;
|
||||||
CUIRect FileIcon;
|
CUIRect FileIcon;
|
||||||
Row.VSplitLeft(Row.h, &FileIcon, &Row);
|
Row.VSplitLeft(Row.h, &FileIcon, &Row);
|
||||||
Row.VSplitLeft(5.0f, 0, &Row);
|
Row.VSplitLeft(5.0f, 0, &Row);
|
||||||
FileIcon.Margin(1.0f, &FileIcon);
|
FileIcon.Margin(1.0f, &FileIcon);
|
||||||
FileIcon.x += 2.0f;
|
FileIcon.x += 2.0f;
|
||||||
const char *pIconType;
|
|
||||||
|
|
||||||
|
const char *pIconType;
|
||||||
if(str_comp(Item.m_aFilename, "..") == 0)
|
if(str_comp(Item.m_aFilename, "..") == 0)
|
||||||
pIconType = "\xEF\xA0\x82";
|
pIconType = "\xEF\xA0\x82";
|
||||||
else if(Item.m_IsDir)
|
else if(Item.m_IsDir)
|
||||||
|
@ -1338,13 +1045,13 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UI()->ClipDisable();
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
|
if(NewSelected != m_DemolistSelectedIndex)
|
||||||
bool Activated = false;
|
|
||||||
if(UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (DoubleClicked && Input()->MouseDoubleClick()))
|
|
||||||
{
|
{
|
||||||
UI()->SetActiveItem(nullptr);
|
m_DemolistSelectedIndex = NewSelected;
|
||||||
Activated = true;
|
if(m_DemolistSelectedIndex >= 0)
|
||||||
|
str_copy(g_Config.m_UiDemoSelected, m_vDemos[m_DemolistSelectedIndex].m_aName);
|
||||||
|
DemolistOnUpdate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static CButtonContainer s_RefreshButton;
|
static CButtonContainer s_RefreshButton;
|
||||||
|
@ -1362,7 +1069,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
||||||
}
|
}
|
||||||
|
|
||||||
static CButtonContainer s_PlayButton;
|
static CButtonContainer s_PlayButton;
|
||||||
if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir ? Localize("Open") : Localize("Play", "Demo browser"), 0, &PlayRect) || Activated || (Input()->KeyPress(KEY_P) && m_pClient->m_GameConsole.IsClosed() && m_DemoPlayerState == DEMOPLAYER_NONE))
|
if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir ? Localize("Open") : Localize("Play", "Demo browser"), 0, &PlayRect) || s_ListBox.WasItemActivated() || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (Input()->KeyPress(KEY_P) && m_pClient->m_GameConsole.IsClosed() && m_DemoPlayerState == DEMOPLAYER_NONE))
|
||||||
{
|
{
|
||||||
if(m_DemolistSelectedIndex >= 0)
|
if(m_DemolistSelectedIndex >= 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/client/ui_scrollregion.h>
|
#include <game/client/ui_scrollregion.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
|
||||||
|
@ -242,16 +243,15 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
||||||
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
||||||
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_MUTE, &Button);
|
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_MUTE, &Button);
|
||||||
|
|
||||||
ButtonBar.VSplitLeft(20.0f, 0, &ButtonBar);
|
ButtonBar.VSplitLeft(20.0f, nullptr, &ButtonBar);
|
||||||
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
||||||
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_EMOTICON_MUTE, &Button);
|
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_EMOTICON_MUTE, &Button);
|
||||||
|
|
||||||
ButtonBar.VSplitLeft(20.0f, 0, &ButtonBar);
|
ButtonBar.VSplitLeft(20.0f, nullptr, &ButtonBar);
|
||||||
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
||||||
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_FRIEND, &Button);
|
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_FRIEND, &Button);
|
||||||
|
|
||||||
int TotalPlayers = 0;
|
int TotalPlayers = 0;
|
||||||
|
|
||||||
for(const auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName)
|
for(const auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName)
|
||||||
{
|
{
|
||||||
if(!pInfoByName)
|
if(!pInfoByName)
|
||||||
|
@ -265,14 +265,11 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
||||||
TotalPlayers++;
|
TotalPlayers++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s_VoteList = 0;
|
static CListBox s_ListBox;
|
||||||
static float s_ScrollValue = 0;
|
s_ListBox.DoStart(24.0f, TotalPlayers, 1, 3, -1, &Options);
|
||||||
CUIRect List = Options;
|
|
||||||
// List.HSplitTop(28.0f, 0, &List);
|
|
||||||
UiDoListboxStart(&s_VoteList, &List, 24.0f, "", "", TotalPlayers, 1, -1, s_ScrollValue);
|
|
||||||
|
|
||||||
// options
|
// options
|
||||||
static int s_aPlayerIDs[MAX_CLIENTS][3] = {{0}};
|
static char s_aPlayerIDs[MAX_CLIENTS][3] = {{0}};
|
||||||
|
|
||||||
for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i)
|
for(int i = 0, Count = 0; i < MAX_CLIENTS; ++i)
|
||||||
{
|
{
|
||||||
|
@ -280,25 +277,27 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int Index = m_pClient->m_Snap.m_apInfoByName[i]->m_ClientID;
|
int Index = m_pClient->m_Snap.m_apInfoByName[i]->m_ClientID;
|
||||||
|
|
||||||
if(Index == m_pClient->m_Snap.m_LocalClientID)
|
if(Index == m_pClient->m_Snap.m_LocalClientID)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(&m_pClient->m_aClients[Index]);
|
CGameClient::CClientData &CurrentClient = m_pClient->m_aClients[Index];
|
||||||
|
const CListboxItem Item = s_ListBox.DoNextItem(&CurrentClient);
|
||||||
|
|
||||||
Count++;
|
Count++;
|
||||||
|
|
||||||
if(!Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
CUIRect Row = Item.m_Rect;
|
||||||
if(Count % 2 == 1)
|
if(Count % 2 == 1)
|
||||||
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 10.0f);
|
Row.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f);
|
||||||
Item.m_Rect.VSplitRight(300.0f, &Player, &Item.m_Rect);
|
Row.VSplitRight(s_ListBox.ScrollbarWidthMax() - s_ListBox.ScrollbarWidth(), &Row, nullptr);
|
||||||
|
Row.VSplitRight(300.0f, &Player, &Row);
|
||||||
|
|
||||||
// player info
|
// player info
|
||||||
Player.VSplitLeft(28.0f, &Button, &Player);
|
Player.VSplitLeft(28.0f, &Button, &Player);
|
||||||
|
|
||||||
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[Index].m_RenderInfo;
|
CTeeRenderInfo TeeInfo = CurrentClient.m_RenderInfo;
|
||||||
TeeInfo.m_Size = Button.h;
|
TeeInfo.m_Size = Button.h;
|
||||||
|
|
||||||
CAnimState *pIdleState = CAnimState::GetIdle();
|
CAnimState *pIdleState = CAnimState::GetIdle();
|
||||||
|
@ -308,59 +307,57 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
||||||
|
|
||||||
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
||||||
|
|
||||||
Player.HSplitTop(1.5f, 0, &Player);
|
Player.HSplitTop(1.5f, nullptr, &Player);
|
||||||
Player.VSplitMid(&Player, &Button);
|
Player.VSplitMid(&Player, &Button);
|
||||||
Item.m_Rect.VSplitRight(200.0f, &Button2, &Item.m_Rect);
|
Row.VSplitRight(210.0f, &Button2, &Row);
|
||||||
CTextCursor Cursor;
|
CTextCursor Cursor;
|
||||||
TextRender()->SetCursor(&Cursor, Player.x, Player.y + (Player.h - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
TextRender()->SetCursor(&Cursor, Player.x, Player.y + (Player.h - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||||
Cursor.m_LineWidth = Player.w;
|
Cursor.m_LineWidth = Player.w;
|
||||||
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[Index].m_aName, -1);
|
TextRender()->TextEx(&Cursor, CurrentClient.m_aName, -1);
|
||||||
|
|
||||||
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 14.f) / 2.f, 14.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||||
Cursor.m_LineWidth = Button.w;
|
Cursor.m_LineWidth = Button.w;
|
||||||
TextRender()->TextEx(&Cursor, m_pClient->m_aClients[Index].m_aClan, -1);
|
TextRender()->TextEx(&Cursor, CurrentClient.m_aClan, -1);
|
||||||
|
|
||||||
// TextRender()->SetCursor(&Cursor, Button2.x,Button2.y, 14.0f, TEXTFLAG_RENDER|TEXTFLAG_STOP_AT_END);
|
|
||||||
// Cursor.m_LineWidth = Button.w;
|
|
||||||
ColorRGBA Color(1.0f, 1.0f, 1.0f, 0.5f);
|
ColorRGBA Color(1.0f, 1.0f, 1.0f, 0.5f);
|
||||||
m_pClient->m_CountryFlags.Render(m_pClient->m_aClients[Index].m_Country, &Color,
|
m_pClient->m_CountryFlags.Render(CurrentClient.m_Country, &Color,
|
||||||
Button2.x, Button2.y + Button2.h / 2.0f - 0.75f * Button2.h / 2.0f, 1.5f * Button2.h, 0.75f * Button2.h);
|
Button2.x, Button2.y + Button2.h / 2.0f - 0.75f * Button2.h / 2.0f, 1.5f * Button2.h, 0.75f * Button2.h);
|
||||||
|
|
||||||
// ignore chat button
|
// ignore chat button
|
||||||
Item.m_Rect.HMargin(2.0f, &Item.m_Rect);
|
Row.HMargin(2.0f, &Row);
|
||||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
Row.VSplitLeft(Width, &Button, &Row);
|
||||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||||
Button.VSplitLeft(Button.h, &Button, 0);
|
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||||
if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
|
if(g_Config.m_ClShowChatFriends && !CurrentClient.m_Friend)
|
||||||
DoButton_Toggle(&s_aPlayerIDs[Index][0], 1, &Button, false);
|
DoButton_Toggle(&s_aPlayerIDs[Index][0], 1, &Button, false);
|
||||||
else if(DoButton_Toggle(&s_aPlayerIDs[Index][0], m_pClient->m_aClients[Index].m_ChatIgnore, &Button, true))
|
else if(DoButton_Toggle(&s_aPlayerIDs[Index][0], CurrentClient.m_ChatIgnore, &Button, true))
|
||||||
m_pClient->m_aClients[Index].m_ChatIgnore ^= 1;
|
CurrentClient.m_ChatIgnore ^= 1;
|
||||||
|
|
||||||
// ignore emoticon button
|
// ignore emoticon button
|
||||||
Item.m_Rect.VSplitLeft(20.0f, &Button, &Item.m_Rect);
|
Row.VSplitLeft(30.0f, nullptr, &Row);
|
||||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
Row.VSplitLeft(Width, &Button, &Row);
|
||||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||||
Button.VSplitLeft(Button.h, &Button, 0);
|
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||||
if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
|
if(g_Config.m_ClShowChatFriends && !CurrentClient.m_Friend)
|
||||||
DoButton_Toggle(&s_aPlayerIDs[Index][1], 1, &Button, false);
|
DoButton_Toggle(&s_aPlayerIDs[Index][1], 1, &Button, false);
|
||||||
else if(DoButton_Toggle(&s_aPlayerIDs[Index][1], m_pClient->m_aClients[Index].m_EmoticonIgnore, &Button, true))
|
else if(DoButton_Toggle(&s_aPlayerIDs[Index][1], CurrentClient.m_EmoticonIgnore, &Button, true))
|
||||||
m_pClient->m_aClients[Index].m_EmoticonIgnore ^= 1;
|
CurrentClient.m_EmoticonIgnore ^= 1;
|
||||||
|
|
||||||
// friend button
|
// friend button
|
||||||
Item.m_Rect.VSplitLeft(20.0f, &Button, &Item.m_Rect);
|
Row.VSplitLeft(10.0f, nullptr, &Row);
|
||||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
Row.VSplitLeft(Width, &Button, &Row);
|
||||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||||
Button.VSplitLeft(Button.h, &Button, 0);
|
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||||
if(DoButton_Toggle(&s_aPlayerIDs[Index][2], m_pClient->m_aClients[Index].m_Friend, &Button, true))
|
if(DoButton_Toggle(&s_aPlayerIDs[Index][2], CurrentClient.m_Friend, &Button, true))
|
||||||
{
|
{
|
||||||
if(m_pClient->m_aClients[Index].m_Friend)
|
if(CurrentClient.m_Friend)
|
||||||
m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[Index].m_aName, m_pClient->m_aClients[Index].m_aClan);
|
m_pClient->Friends()->RemoveFriend(CurrentClient.m_aName, CurrentClient.m_aClan);
|
||||||
else
|
else
|
||||||
m_pClient->Friends()->AddFriend(m_pClient->m_aClients[Index].m_aName, m_pClient->m_aClients[Index].m_aClan);
|
m_pClient->Friends()->AddFriend(CurrentClient.m_aName, CurrentClient.m_aClan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UiDoListboxEnd(&s_ScrollValue, 0);
|
s_ListBox.DoEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMenus::RenderServerInfo(CUIRect MainView)
|
void CMenus::RenderServerInfo(CUIRect MainView)
|
||||||
|
@ -492,8 +489,6 @@ void CMenus::RenderServerInfo(CUIRect MainView)
|
||||||
|
|
||||||
bool CMenus::RenderServerControlServer(CUIRect MainView)
|
bool CMenus::RenderServerControlServer(CUIRect MainView)
|
||||||
{
|
{
|
||||||
static int s_VoteList = 0;
|
|
||||||
static float s_ScrollValue = 0;
|
|
||||||
CUIRect List = MainView;
|
CUIRect List = MainView;
|
||||||
int Total = m_pClient->m_Voting.m_NumVoteOptions;
|
int Total = m_pClient->m_Voting.m_NumVoteOptions;
|
||||||
int NumVoteOptions = 0;
|
int NumVoteOptions = 0;
|
||||||
|
@ -508,7 +503,8 @@ bool CMenus::RenderServerControlServer(CUIRect MainView)
|
||||||
TotalShown++;
|
TotalShown++;
|
||||||
}
|
}
|
||||||
|
|
||||||
UiDoListboxStart(&s_VoteList, &List, 19.0f, "", "", TotalShown, 1, s_CurVoteOption, s_ScrollValue);
|
static CListBox s_ListBox;
|
||||||
|
s_ListBox.DoStart(19.0f, TotalShown, 1, 3, s_CurVoteOption, &List);
|
||||||
|
|
||||||
int i = -1;
|
int i = -1;
|
||||||
for(CVoteOptionClient *pOption = m_pClient->m_Voting.m_pFirst; pOption; pOption = pOption->m_pNext)
|
for(CVoteOptionClient *pOption = m_pClient->m_Voting.m_pFirst; pOption; pOption = pOption->m_pNext)
|
||||||
|
@ -517,21 +513,23 @@ bool CMenus::RenderServerControlServer(CUIRect MainView)
|
||||||
if(m_aFilterString[0] != '\0' && !str_utf8_find_nocase(pOption->m_aDescription, m_aFilterString))
|
if(m_aFilterString[0] != '\0' && !str_utf8_find_nocase(pOption->m_aDescription, m_aFilterString))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(pOption);
|
|
||||||
|
|
||||||
if(Item.m_Visible)
|
|
||||||
UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, 13.0f, TEXTALIGN_LEFT);
|
|
||||||
|
|
||||||
if(NumVoteOptions < Total)
|
if(NumVoteOptions < Total)
|
||||||
aIndices[NumVoteOptions] = i;
|
aIndices[NumVoteOptions] = i;
|
||||||
NumVoteOptions++;
|
NumVoteOptions++;
|
||||||
|
|
||||||
|
const CListboxItem Item = s_ListBox.DoNextItem(pOption);
|
||||||
|
if(!Item.m_Visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SLabelProperties Props;
|
||||||
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, 13.0f, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Call;
|
s_CurVoteOption = s_ListBox.DoEnd();
|
||||||
s_CurVoteOption = UiDoListboxEnd(&s_ScrollValue, &Call);
|
|
||||||
if(s_CurVoteOption < Total)
|
if(s_CurVoteOption < Total)
|
||||||
m_CallvoteSelectedOption = aIndices[s_CurVoteOption];
|
m_CallvoteSelectedOption = aIndices[s_CurVoteOption];
|
||||||
return Call;
|
return s_ListBox.WasItemActivated();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
|
bool CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
|
||||||
|
@ -556,36 +554,36 @@ bool CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
|
||||||
aPlayerIDs[NumOptions++] = Index;
|
aPlayerIDs[NumOptions++] = Index;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s_VoteList = 0;
|
static CListBox s_ListBox;
|
||||||
static float s_ScrollValue = 0;
|
s_ListBox.DoStart(24.0f, NumOptions, 1, 3, Selected, &MainView);
|
||||||
CUIRect List = MainView;
|
|
||||||
UiDoListboxStart(&s_VoteList, &List, 24.0f, "", "", NumOptions, 1, Selected, s_ScrollValue);
|
|
||||||
|
|
||||||
for(int i = 0; i < NumOptions; i++)
|
for(int i = 0; i < NumOptions; i++)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(&aPlayerIDs[i]);
|
const CListboxItem Item = s_ListBox.DoNextItem(&aPlayerIDs[i]);
|
||||||
|
if(!Item.m_Visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CUIRect TeeRect, Label;
|
||||||
|
Item.m_Rect.VSplitLeft(Item.m_Rect.h, &TeeRect, &Label);
|
||||||
|
|
||||||
if(Item.m_Visible)
|
|
||||||
{
|
|
||||||
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[aPlayerIDs[i]].m_RenderInfo;
|
CTeeRenderInfo TeeInfo = m_pClient->m_aClients[aPlayerIDs[i]].m_RenderInfo;
|
||||||
TeeInfo.m_Size = Item.m_Rect.h;
|
TeeInfo.m_Size = TeeRect.h;
|
||||||
|
|
||||||
CAnimState *pIdleState = CAnimState::GetIdle();
|
CAnimState *pIdleState = CAnimState::GetIdle();
|
||||||
vec2 OffsetToMid;
|
vec2 OffsetToMid;
|
||||||
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &TeeInfo, OffsetToMid);
|
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &TeeInfo, OffsetToMid);
|
||||||
vec2 TeeRenderPos(Item.m_Rect.x + Item.m_Rect.h / 2, Item.m_Rect.y + Item.m_Rect.h / 2 + OffsetToMid.y);
|
vec2 TeeRenderPos(TeeRect.x + TeeInfo.m_Size / 2, TeeRect.y + TeeInfo.m_Size / 2 + OffsetToMid.y);
|
||||||
|
|
||||||
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
RenderTools()->RenderTee(pIdleState, &TeeInfo, EMOTE_NORMAL, vec2(1.0f, 0.0f), TeeRenderPos);
|
||||||
|
|
||||||
Item.m_Rect.x += TeeInfo.m_Size;
|
SLabelProperties Props;
|
||||||
UI()->DoLabel(&Item.m_Rect, m_pClient->m_aClients[aPlayerIDs[i]].m_aName, 16.0f, TEXTALIGN_LEFT);
|
Props.m_AlignVertically = 0;
|
||||||
}
|
UI()->DoLabel(&Item.m_Rect, m_pClient->m_aClients[aPlayerIDs[i]].m_aName, 16.0f, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Call;
|
Selected = s_ListBox.DoEnd();
|
||||||
Selected = UiDoListboxEnd(&s_ScrollValue, &Call);
|
|
||||||
m_CallvoteSelectedPlayer = Selected != -1 ? aPlayerIDs[Selected] : -1;
|
m_CallvoteSelectedPlayer = Selected != -1 ? aPlayerIDs[Selected] : -1;
|
||||||
return Call;
|
return s_ListBox.WasItemActivated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMenus::RenderServerControl(CUIRect MainView)
|
void CMenus::RenderServerControl(CUIRect MainView)
|
||||||
|
@ -1007,70 +1005,37 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
|
|
||||||
View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
||||||
|
|
||||||
CUIRect Scroll;
|
const int NumGhosts = m_vGhosts.size();
|
||||||
View.VSplitRight(20.0f, &View, &Scroll);
|
|
||||||
|
|
||||||
static float s_ScrollValue = 0;
|
|
||||||
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
|
|
||||||
|
|
||||||
int NumGhosts = m_vGhosts.size();
|
|
||||||
static int s_SelectedIndex = 0;
|
static int s_SelectedIndex = 0;
|
||||||
HandleListInputs(View, s_ScrollValue, 1.0f, nullptr, s_aCols[0].m_Rect.h, s_SelectedIndex, NumGhosts);
|
static CListBox s_ListBox;
|
||||||
|
s_ListBox.DoStart(17.0f, NumGhosts, 1, 3, s_SelectedIndex, &View, false);
|
||||||
// set clipping
|
|
||||||
UI()->ClipEnable(&View);
|
|
||||||
|
|
||||||
CUIRect OriginalView = View;
|
|
||||||
int Num = (int)(View.h / s_aCols[0].m_Rect.h) + 1;
|
|
||||||
int ScrollNum = maximum(NumGhosts - Num + 1, 0);
|
|
||||||
View.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
|
||||||
|
|
||||||
int NewSelected = -1;
|
|
||||||
bool DoubleClicked = false;
|
|
||||||
|
|
||||||
for(int i = 0; i < NumGhosts; i++)
|
for(int i = 0; i < NumGhosts; i++)
|
||||||
{
|
{
|
||||||
const CGhostItem *pItem = &m_vGhosts[i];
|
const CGhostItem *pGhost = &m_vGhosts[i];
|
||||||
CUIRect Row;
|
const CListboxItem Item = s_ListBox.DoNextItem(pGhost);
|
||||||
View.HSplitTop(17.0f, &Row, &View);
|
if(!Item.m_Visible)
|
||||||
|
continue;
|
||||||
// make sure that only those in view can be selected
|
|
||||||
if(Row.y + Row.h > OriginalView.y && Row.y < OriginalView.y + OriginalView.h)
|
|
||||||
{
|
|
||||||
if(i == s_SelectedIndex)
|
|
||||||
{
|
|
||||||
CUIRect r = Row;
|
|
||||||
r.Margin(1.5f, &r);
|
|
||||||
r.Draw(ColorRGBA(1, 1, 1, 0.5f), IGraphics::CORNER_ALL, 4.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(UI()->DoButtonLogic(pItem, 0, &Row))
|
|
||||||
{
|
|
||||||
NewSelected = i;
|
|
||||||
DoubleClicked |= NewSelected == m_DoubleClickIndex;
|
|
||||||
m_DoubleClickIndex = NewSelected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ColorRGBA rgb = ColorRGBA(1.0f, 1.0f, 1.0f);
|
ColorRGBA rgb = ColorRGBA(1.0f, 1.0f, 1.0f);
|
||||||
if(pItem->m_Own)
|
if(pGhost->m_Own)
|
||||||
rgb = color_cast<ColorRGBA>(ColorHSLA(0.33f, 1.0f, 0.75f));
|
rgb = color_cast<ColorRGBA>(ColorHSLA(0.33f, 1.0f, 0.75f));
|
||||||
|
|
||||||
TextRender()->TextColor(rgb.WithAlpha(pItem->HasFile() ? 1.0f : 0.5f));
|
TextRender()->TextColor(rgb.WithAlpha(pGhost->HasFile() ? 1.0f : 0.5f));
|
||||||
|
|
||||||
for(int c = 0; c < NumCols; c++)
|
for(int c = 0; c < NumCols; c++)
|
||||||
{
|
{
|
||||||
CUIRect Button;
|
CUIRect Button;
|
||||||
Button.x = s_aCols[c].m_Rect.x;
|
Button.x = s_aCols[c].m_Rect.x;
|
||||||
Button.y = Row.y;
|
Button.y = Item.m_Rect.y;
|
||||||
Button.h = Row.h;
|
Button.h = Item.m_Rect.h;
|
||||||
Button.w = s_aCols[c].m_Rect.w;
|
Button.w = s_aCols[c].m_Rect.w;
|
||||||
|
|
||||||
int Id = s_aCols[c].m_Id;
|
int Id = s_aCols[c].m_Id;
|
||||||
|
|
||||||
if(Id == COL_ACTIVE)
|
if(Id == COL_ACTIVE)
|
||||||
{
|
{
|
||||||
if(pItem->Active())
|
if(pGhost->Active())
|
||||||
{
|
{
|
||||||
Graphics()->WrapClamp();
|
Graphics()->WrapClamp();
|
||||||
Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[(SPRITE_OOP + 7) - SPRITE_OOP]);
|
Graphics()->TextureSet(GameClient()->m_EmoticonsSkin.m_aSpriteEmoticons[(SPRITE_OOP + 7) - SPRITE_OOP]);
|
||||||
|
@ -1088,7 +1053,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f) / 2.f, 12.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f) / 2.f, 12.0f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
||||||
Cursor.m_LineWidth = Button.w;
|
Cursor.m_LineWidth = Button.w;
|
||||||
|
|
||||||
TextRender()->TextEx(&Cursor, pItem->m_aPlayer, -1);
|
TextRender()->TextEx(&Cursor, pGhost->m_aPlayer, -1);
|
||||||
}
|
}
|
||||||
else if(Id == COL_TIME)
|
else if(Id == COL_TIME)
|
||||||
{
|
{
|
||||||
|
@ -1097,7 +1062,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
Cursor.m_LineWidth = Button.w;
|
Cursor.m_LineWidth = Button.w;
|
||||||
|
|
||||||
char aBuf[64];
|
char aBuf[64];
|
||||||
str_time(pItem->m_Time / 10, TIME_HOURS_CENTISECS, aBuf, sizeof(aBuf));
|
str_time(pGhost->m_Time / 10, TIME_HOURS_CENTISECS, aBuf, sizeof(aBuf));
|
||||||
TextRender()->TextEx(&Cursor, aBuf, -1);
|
TextRender()->TextEx(&Cursor, aBuf, -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1105,10 +1070,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
|
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
UI()->ClipDisable();
|
s_SelectedIndex = s_ListBox.DoEnd();
|
||||||
|
|
||||||
if(NewSelected != -1)
|
|
||||||
s_SelectedIndex = NewSelected;
|
|
||||||
|
|
||||||
Status.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_B, 5.0f);
|
Status.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_B, 5.0f);
|
||||||
Status.Margin(5.0f, &Status);
|
Status.Margin(5.0f, &Status);
|
||||||
|
@ -1136,7 +1098,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
||||||
|
|
||||||
static CButtonContainer s_GhostButton;
|
static CButtonContainer s_GhostButton;
|
||||||
const char *pText = pGhost->Active() ? Localize("Deactivate") : Localize("Activate");
|
const char *pText = pGhost->Active() ? Localize("Deactivate") : Localize("Activate");
|
||||||
if(DoButton_Menu(&s_GhostButton, pText, 0, &Button) || (DoubleClicked && Input()->MouseDoubleClick()))
|
if(DoButton_Menu(&s_GhostButton, pText, 0, &Button) || s_ListBox.WasItemActivated())
|
||||||
{
|
{
|
||||||
if(pGhost->Active())
|
if(pGhost->Active())
|
||||||
{
|
{
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/client/skin.h>
|
#include <game/client/skin.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/client/ui_scrollregion.h>
|
#include <game/client/ui_scrollregion.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
|
||||||
|
@ -366,9 +367,9 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
|
||||||
|
|
||||||
// country flag selector
|
// country flag selector
|
||||||
MainView.HSplitTop(20.0f, 0, &MainView);
|
MainView.HSplitTop(20.0f, 0, &MainView);
|
||||||
static float s_ScrollValue = 0.0f;
|
|
||||||
int OldSelected = -1;
|
int OldSelected = -1;
|
||||||
UiDoListboxStart(&s_ScrollValue, &MainView, 50.0f, Localize("Country / Region"), "", m_pClient->m_CountryFlags.Num(), 6, OldSelected, s_ScrollValue);
|
static CListBox s_ListBox;
|
||||||
|
s_ListBox.DoStart(50.0f, m_pClient->m_CountryFlags.Num(), 10, 3, OldSelected, &MainView, true, &s_ListBoxUsed);
|
||||||
|
|
||||||
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
for(size_t i = 0; i < m_pClient->m_CountryFlags.Num(); ++i)
|
||||||
{
|
{
|
||||||
|
@ -376,26 +377,29 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
|
||||||
if(pEntry->m_CountryCode == *pCountry)
|
if(pEntry->m_CountryCode == *pCountry)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, s_ListBoxUsed);
|
const CListboxItem Item = s_ListBox.DoNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, &s_ListBoxUsed);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
Item.m_Rect.Margin(5.0f, &Item.m_Rect);
|
|
||||||
Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
|
CUIRect FlagRect;
|
||||||
float OldWidth = Item.m_Rect.w;
|
Item.m_Rect.Margin(5.0f, &FlagRect);
|
||||||
Item.m_Rect.w = Item.m_Rect.h * 2;
|
FlagRect.HSplitBottom(12.0f, &FlagRect, &Label);
|
||||||
Item.m_Rect.x += (OldWidth - Item.m_Rect.w) / 2.0f;
|
Label.HSplitTop(2.0f, nullptr, &Label);
|
||||||
|
float OldWidth = FlagRect.w;
|
||||||
|
FlagRect.w = FlagRect.h * 2;
|
||||||
|
FlagRect.x += (OldWidth - FlagRect.w) / 2.0f;
|
||||||
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
m_pClient->m_CountryFlags.Render(pEntry->m_CountryCode, &Color, Item.m_Rect.x, Item.m_Rect.y, Item.m_Rect.w, Item.m_Rect.h);
|
m_pClient->m_CountryFlags.Render(pEntry->m_CountryCode, &Color, FlagRect.x, FlagRect.y, FlagRect.w, FlagRect.h);
|
||||||
|
|
||||||
if(pEntry->m_Texture.IsValid())
|
if(pEntry->m_Texture.IsValid())
|
||||||
|
{
|
||||||
|
SLabelProperties ItemLabelProps;
|
||||||
|
ItemLabelProps.m_AlignVertically = 0;
|
||||||
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER);
|
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Clicked = false;
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0, &Clicked);
|
|
||||||
if(Clicked)
|
|
||||||
s_ListBoxUsed = true;
|
|
||||||
|
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
{
|
{
|
||||||
*pCountry = m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
|
*pCountry = m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
|
||||||
|
@ -711,7 +715,8 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
static std::vector<CUISkin> s_vSkinListHelper;
|
static std::vector<CUISkin> s_vSkinListHelper;
|
||||||
static std::vector<CUISkin> s_vFavoriteSkinListHelper;
|
static std::vector<CUISkin> s_vFavoriteSkinListHelper;
|
||||||
static int s_SkinCount = 0;
|
static int s_SkinCount = 0;
|
||||||
static float s_ScrollValue = 0.0f;
|
static CListBox s_ListBox;
|
||||||
|
|
||||||
// be nice to the CPU
|
// be nice to the CPU
|
||||||
static auto s_SkinLastRebuildTime = time_get_nanoseconds();
|
static auto s_SkinLastRebuildTime = time_get_nanoseconds();
|
||||||
const auto CurTime = time_get_nanoseconds();
|
const auto CurTime = time_get_nanoseconds();
|
||||||
|
@ -780,7 +785,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
};
|
};
|
||||||
|
|
||||||
int OldSelected = -1;
|
int OldSelected = -1;
|
||||||
UiDoListboxStart(&s_InitSkinlist, &SkinList, 50.0f, Localize("Skins"), "", s_vSkinList.size(), 4, OldSelected, s_ScrollValue);
|
s_ListBox.DoStart(50.0f, s_vSkinList.size(), 4, 1, OldSelected, &SkinList);
|
||||||
for(size_t i = 0; i < s_vSkinList.size(); ++i)
|
for(size_t i = 0; i < s_vSkinList.size(); ++i)
|
||||||
{
|
{
|
||||||
const CSkin *pSkinToBeDraw = s_vSkinList[i].m_pSkin;
|
const CSkin *pSkinToBeDraw = s_vSkinList[i].m_pSkin;
|
||||||
|
@ -788,10 +793,11 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
if(str_comp(pSkinToBeDraw->GetName(), pSkinName) == 0)
|
if(str_comp(pSkinToBeDraw->GetName(), pSkinName) == 0)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
const CListboxItem Item = s_ListBox.DoNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
auto OriginalRect = Item.m_Rect;
|
|
||||||
|
const CUIRect OriginalRect = Item.m_Rect;
|
||||||
|
|
||||||
CTeeRenderInfo Info = OwnSkinInfo;
|
CTeeRenderInfo Info = OwnSkinInfo;
|
||||||
Info.m_CustomColoredSkin = *pUseCustomColor;
|
Info.m_CustomColoredSkin = *pUseCustomColor;
|
||||||
|
@ -801,14 +807,15 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
Info.m_SkinMetrics = pSkinToBeDraw->m_Metrics;
|
Info.m_SkinMetrics = pSkinToBeDraw->m_Metrics;
|
||||||
|
|
||||||
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &Info, OffsetToMid);
|
RenderTools()->GetRenderTeeOffsetToRenderedTee(pIdleState, &Info, OffsetToMid);
|
||||||
TeeRenderPos = vec2(Item.m_Rect.x + 30, Item.m_Rect.y + Item.m_Rect.h / 2 + OffsetToMid.y);
|
TeeRenderPos = vec2(OriginalRect.x + 30, OriginalRect.y + OriginalRect.h / 2 + OffsetToMid.y);
|
||||||
RenderTools()->RenderTee(pIdleState, &Info, Emote, vec2(1.0f, 0.0f), TeeRenderPos);
|
RenderTools()->RenderTee(pIdleState, &Info, Emote, vec2(1.0f, 0.0f), TeeRenderPos);
|
||||||
|
|
||||||
Item.m_Rect.VSplitLeft(60.0f, 0, &Item.m_Rect);
|
OriginalRect.VSplitLeft(60.0f, 0, &Label);
|
||||||
{
|
{
|
||||||
SLabelProperties Props;
|
SLabelProperties Props;
|
||||||
Props.m_MaxWidth = Item.m_Rect.w;
|
Props.m_MaxWidth = Label.w;
|
||||||
UI()->DoLabel(&Item.m_Rect, pSkinToBeDraw->GetName(), 12.0f, TEXTALIGN_LEFT, Props);
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Label, pSkinToBeDraw->GetName(), 12.0f, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
if(g_Config.m_Debug)
|
if(g_Config.m_Debug)
|
||||||
{
|
{
|
||||||
|
@ -816,7 +823,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
Graphics()->TextureClear();
|
Graphics()->TextureClear();
|
||||||
Graphics()->QuadsBegin();
|
Graphics()->QuadsBegin();
|
||||||
Graphics()->SetColor(BloodColor.r, BloodColor.g, BloodColor.b, 1.0f);
|
Graphics()->SetColor(BloodColor.r, BloodColor.g, BloodColor.b, 1.0f);
|
||||||
IGraphics::CQuadItem QuadItem(Item.m_Rect.x, Item.m_Rect.y, 12.0f, 12.0f);
|
IGraphics::CQuadItem QuadItem(Label.x, Label.y, 12.0f, 12.0f);
|
||||||
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
||||||
Graphics()->QuadsEnd();
|
Graphics()->QuadsEnd();
|
||||||
}
|
}
|
||||||
|
@ -853,9 +860,8 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
{
|
{
|
||||||
mem_copy(pSkinName, s_vSkinList[NewSelected].m_pSkin->GetName(), sizeof(g_Config.m_ClPlayerSkin));
|
mem_copy(pSkinName, s_vSkinList[NewSelected].m_pSkin->GetName(), sizeof(g_Config.m_ClPlayerSkin));
|
||||||
|
@ -1435,22 +1441,25 @@ int CMenus::RenderDropDown(int &CurDropDownState, CUIRect *pRect, int CurSelecti
|
||||||
{
|
{
|
||||||
if(CurDropDownState != 0)
|
if(CurDropDownState != 0)
|
||||||
{
|
{
|
||||||
|
const float RowHeight = 24.0f;
|
||||||
|
const float RowSpacing = 3.0f;
|
||||||
CUIRect ListRect;
|
CUIRect ListRect;
|
||||||
pRect->HSplitTop(24.0f * PickNum, &ListRect, pRect);
|
pRect->HSplitTop((RowHeight + RowSpacing) * PickNum, &ListRect, pRect);
|
||||||
char aBuf[1024];
|
static CListBox s_ListBox;
|
||||||
UiDoListboxStart(&pButtonContainer, &ListRect, 24.0f, "", aBuf, PickNum, 1, CurSelection, ScrollVal);
|
s_ListBox.DoAutoSpacing(RowSpacing);
|
||||||
|
s_ListBox.DoStart(RowHeight, PickNum, 1, 3, CurSelection, &ListRect);
|
||||||
for(int i = 0; i < PickNum; ++i)
|
for(int i = 0; i < PickNum; ++i)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(pIDs[i], CurSelection == i);
|
const CListboxItem Item = s_ListBox.DoNextItem(pIDs[i], CurSelection == i);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
str_copy(aBuf, pStr[i]);
|
|
||||||
UI()->DoLabel(&Item.m_Rect, aBuf, 16.0f, TEXTALIGN_CENTER);
|
SLabelProperties Props;
|
||||||
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Item.m_Rect, pStr[i], 16.0f, TEXTALIGN_CENTER, Props);
|
||||||
}
|
}
|
||||||
}
|
int NewIndex = s_ListBox.DoEnd();
|
||||||
bool ClickedItem = false;
|
if(s_ListBox.WasItemSelected() || s_ListBox.WasItemActivated())
|
||||||
int NewIndex = UiDoListboxEnd(&ScrollVal, NULL, &ClickedItem);
|
|
||||||
if(ClickedItem)
|
|
||||||
{
|
{
|
||||||
CurDropDownState = 0;
|
CurDropDownState = 0;
|
||||||
return NewIndex;
|
return NewIndex;
|
||||||
|
@ -1518,7 +1527,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
||||||
MainView.VSplitLeft(340.0f, &MainView, 0);
|
MainView.VSplitLeft(340.0f, &MainView, 0);
|
||||||
|
|
||||||
// display mode list
|
// display mode list
|
||||||
static float s_ScrollValue = 0;
|
static CListBox s_ListBox;
|
||||||
static const float sc_RowHeightResList = 22.0f;
|
static const float sc_RowHeightResList = 22.0f;
|
||||||
static const float sc_FontSizeResListHeader = 12.0f;
|
static const float sc_FontSizeResListHeader = 12.0f;
|
||||||
static const float sc_FontSizeResList = 10.0f;
|
static const float sc_FontSizeResList = 10.0f;
|
||||||
|
@ -1529,7 +1538,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
||||||
}
|
}
|
||||||
|
|
||||||
UI()->DoLabel(&ModeLabel, aBuf, sc_FontSizeResListHeader, TEXTALIGN_CENTER);
|
UI()->DoLabel(&ModeLabel, aBuf, sc_FontSizeResListHeader, TEXTALIGN_CENTER);
|
||||||
UiDoListboxStart(&s_NumNodes, &ModeList, sc_RowHeightResList, Localize("Display Modes"), aBuf, s_NumNodes - 1, 1, OldSelected, s_ScrollValue);
|
s_ListBox.DoStart(sc_RowHeightResList, s_NumNodes, 1, 3, OldSelected, &ModeList);
|
||||||
|
|
||||||
for(int i = 0; i < s_NumNodes; ++i)
|
for(int i = 0; i < s_NumNodes; ++i)
|
||||||
{
|
{
|
||||||
|
@ -1542,16 +1551,18 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(&s_aModes[i], OldSelected == i);
|
const CListboxItem Item = s_ListBox.DoNextItem(&s_aModes[i], OldSelected == i);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
int G = std::gcd(s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight);
|
int G = std::gcd(s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight);
|
||||||
str_format(aBuf, sizeof(aBuf), " %dx%d @%dhz %d bit (%d:%d)", s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight, s_aModes[i].m_RefreshRate, Depth, s_aModes[i].m_CanvasWidth / G, s_aModes[i].m_CanvasHeight / G);
|
str_format(aBuf, sizeof(aBuf), " %dx%d @%dhz %d bit (%d:%d)", s_aModes[i].m_CanvasWidth, s_aModes[i].m_CanvasHeight, s_aModes[i].m_RefreshRate, Depth, s_aModes[i].m_CanvasWidth / G, s_aModes[i].m_CanvasHeight / G);
|
||||||
UI()->DoLabel(&Item.m_Rect, aBuf, sc_FontSizeResList, TEXTALIGN_LEFT);
|
SLabelProperties Props;
|
||||||
}
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Item.m_Rect, aBuf, sc_FontSizeResList, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
{
|
{
|
||||||
const int Depth = s_aModes[NewSelected].m_Red + s_aModes[NewSelected].m_Green + s_aModes[NewSelected].m_Blue > 16 ? 24 : 16;
|
const int Depth = s_aModes[NewSelected].m_Red + s_aModes[NewSelected].m_Green + s_aModes[NewSelected].m_Blue > 16 ? 24 : 16;
|
||||||
|
@ -2093,12 +2104,11 @@ void LoadLanguageIndexfile(IStorage *pStorage, IConsole *pConsole, std::vector<C
|
||||||
io_close(File);
|
io_close(File);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMenus::RenderLanguageSelection(CUIRect MainView)
|
bool CMenus::RenderLanguageSelection(CUIRect MainView)
|
||||||
{
|
{
|
||||||
static int s_LanguageList = 0;
|
static int s_SelectedLanguage = -1;
|
||||||
static int s_SelectedLanguage = 0;
|
|
||||||
static std::vector<CLanguage> s_vLanguages;
|
static std::vector<CLanguage> s_vLanguages;
|
||||||
static float s_ScrollValue = 0;
|
static CListBox s_ListBox;
|
||||||
|
|
||||||
if(s_vLanguages.empty())
|
if(s_vLanguages.empty())
|
||||||
{
|
{
|
||||||
|
@ -2113,27 +2123,29 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int OldSelected = s_SelectedLanguage;
|
const int OldSelected = s_SelectedLanguage;
|
||||||
|
|
||||||
UiDoListboxStart(&s_LanguageList, &MainView, 24.0f, Localize("Language"), "", s_vLanguages.size(), 1, s_SelectedLanguage, s_ScrollValue);
|
s_ListBox.DoStart(24.0f, s_vLanguages.size(), 1, 3, s_SelectedLanguage, &MainView, true);
|
||||||
|
|
||||||
for(auto &Language : s_vLanguages)
|
for(auto &Language : s_vLanguages)
|
||||||
{
|
{
|
||||||
CListboxItem Item = UiDoListboxNextItem(&Language.m_Name);
|
const CListboxItem Item = s_ListBox.DoNextItem(&Language.m_Name, s_SelectedLanguage != -1 && !str_comp(s_vLanguages[s_SelectedLanguage].m_Name.c_str(), Language.m_Name.c_str()));
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
CUIRect Rect;
|
|
||||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Rect, &Item.m_Rect);
|
CUIRect FlagRect, Label;
|
||||||
Rect.VMargin(6.0f, &Rect);
|
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &FlagRect, &Label);
|
||||||
Rect.HMargin(3.0f, &Rect);
|
FlagRect.VMargin(6.0f, &FlagRect);
|
||||||
|
FlagRect.HMargin(3.0f, &FlagRect);
|
||||||
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
ColorRGBA Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
m_pClient->m_CountryFlags.Render(Language.m_CountryCode, &Color, Rect.x, Rect.y, Rect.w, Rect.h);
|
m_pClient->m_CountryFlags.Render(Language.m_CountryCode, &Color, FlagRect.x, FlagRect.y, FlagRect.w, FlagRect.h);
|
||||||
Item.m_Rect.HSplitTop(2.0f, 0, &Item.m_Rect);
|
|
||||||
UI()->DoLabel(&Item.m_Rect, Language.m_Name.c_str(), 16.0f, TEXTALIGN_LEFT);
|
SLabelProperties Props;
|
||||||
}
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Label, Language.m_Name.c_str(), 16.0f, TEXTALIGN_LEFT, Props);
|
||||||
}
|
}
|
||||||
|
|
||||||
s_SelectedLanguage = UiDoListboxEnd(&s_ScrollValue, 0);
|
s_SelectedLanguage = s_ListBox.DoEnd();
|
||||||
|
|
||||||
if(OldSelected != s_SelectedLanguage)
|
if(OldSelected != s_SelectedLanguage)
|
||||||
{
|
{
|
||||||
|
@ -2141,6 +2153,8 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
||||||
g_Localization.Load(s_vLanguages[s_SelectedLanguage].m_FileName.c_str(), Storage(), Console());
|
g_Localization.Load(s_vLanguages[s_SelectedLanguage].m_FileName.c_str(), Storage(), Console());
|
||||||
GameClient()->OnLanguageChange();
|
GameClient()->OnLanguageChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return s_ListBox.WasItemActivated();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CMenus::RenderSettings(CUIRect MainView)
|
void CMenus::RenderSettings(CUIRect MainView)
|
||||||
|
|
|
@ -3,7 +3,9 @@
|
||||||
#include <engine/shared/config.h>
|
#include <engine/shared/config.h>
|
||||||
#include <engine/storage.h>
|
#include <engine/storage.h>
|
||||||
#include <engine/textrender.h>
|
#include <engine/textrender.h>
|
||||||
|
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
|
||||||
#include "menus.h"
|
#include "menus.h"
|
||||||
|
@ -457,7 +459,6 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
||||||
|
|
||||||
// skin selector
|
// skin selector
|
||||||
MainView.HSplitTop(MainView.h - 10.0f - ms_ButtonHeight, &CustomList, &MainView);
|
MainView.HSplitTop(MainView.h - 10.0f - ms_ButtonHeight, &CustomList, &MainView);
|
||||||
static float s_ScrollValue = 0.0f;
|
|
||||||
if(gs_aInitCustomList[s_CurCustomTab])
|
if(gs_aInitCustomList[s_CurCustomTab])
|
||||||
{
|
{
|
||||||
int ListSize = 0;
|
int ListSize = 0;
|
||||||
|
@ -533,7 +534,8 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
||||||
SearchListSize = gs_vpSearchExtrasList.size();
|
SearchListSize = gs_vpSearchExtrasList.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
UiDoListboxStart(&gs_aInitCustomList[s_CurCustomTab], &CustomList, TextureHeight + 15.0f + 10.0f + Margin, "", "", SearchListSize, CustomList.w / (Margin + TextureWidth), OldSelected, s_ScrollValue, true);
|
static CListBox s_ListBox;
|
||||||
|
s_ListBox.DoStart(TextureHeight + 15.0f + 10.0f + Margin, SearchListSize, CustomList.w / (Margin + TextureWidth), 1, OldSelected, &CustomList, false);
|
||||||
for(size_t i = 0; i < SearchListSize; ++i)
|
for(size_t i = 0; i < SearchListSize; ++i)
|
||||||
{
|
{
|
||||||
const SCustomItem *pItem = GetCustomItem(s_CurCustomTab, i);
|
const SCustomItem *pItem = GetCustomItem(s_CurCustomTab, i);
|
||||||
|
@ -571,11 +573,12 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
||||||
OldSelected = i;
|
OldSelected = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
CListboxItem Item = UiDoListboxNextItem(pItem, OldSelected >= 0 && (size_t)OldSelected == i);
|
const CListboxItem Item = s_ListBox.DoNextItem(pItem, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||||
CUIRect ItemRect = Item.m_Rect;
|
CUIRect ItemRect = Item.m_Rect;
|
||||||
ItemRect.Margin(Margin / 2, &ItemRect);
|
ItemRect.Margin(Margin / 2, &ItemRect);
|
||||||
if(Item.m_Visible)
|
if(!Item.m_Visible)
|
||||||
{
|
continue;
|
||||||
|
|
||||||
CUIRect TextureRect;
|
CUIRect TextureRect;
|
||||||
ItemRect.HSplitTop(15, &ItemRect, &TextureRect);
|
ItemRect.HSplitTop(15, &ItemRect, &TextureRect);
|
||||||
TextureRect.HSplitTop(10, NULL, &TextureRect);
|
TextureRect.HSplitTop(10, NULL, &TextureRect);
|
||||||
|
@ -592,9 +595,8 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
||||||
Graphics()->WrapNormal();
|
Graphics()->WrapNormal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
const int NewSelected = s_ListBox.DoEnd();
|
||||||
if(OldSelected != NewSelected)
|
if(OldSelected != NewSelected)
|
||||||
{
|
{
|
||||||
if(GetCustomItem(s_CurCustomTab, NewSelected)->m_aName[0] != '\0')
|
if(GetCustomItem(s_CurCustomTab, NewSelected)->m_aName[0] != '\0')
|
||||||
|
|
|
@ -49,7 +49,6 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
||||||
{
|
{
|
||||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||||
}
|
}
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||||
|
@ -62,7 +61,6 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
||||||
{
|
{
|
||||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||||
}
|
}
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||||
|
@ -88,7 +86,6 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
||||||
PopupWarning(Localize("Warning"), Localize("Can't find a Tutorial server"), Localize("Ok"), 10s);
|
PopupWarning(Localize("Warning"), Localize("Can't find a Tutorial server"), Localize("Ok"), 10s);
|
||||||
s_JoinTutorialTime = 0.0f;
|
s_JoinTutorialTime = 0.0f;
|
||||||
}
|
}
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||||
|
@ -101,7 +98,6 @@ void CMenus::RenderStartMenu(CUIRect MainView)
|
||||||
{
|
{
|
||||||
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
dbg_msg("menus", "couldn't open link '%s'", pLink);
|
||||||
}
|
}
|
||||||
m_DoubleClickIndex = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
ExtMenu.HSplitBottom(5.0f, &ExtMenu, 0); // little space
|
||||||
|
|
254
src/game/client/ui_listbox.cpp
Normal file
254
src/game/client/ui_listbox.cpp
Normal file
|
@ -0,0 +1,254 @@
|
||||||
|
/* (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 <base/system.h>
|
||||||
|
#include <base/vmath.h>
|
||||||
|
|
||||||
|
#include <engine/config.h>
|
||||||
|
#include <engine/shared/config.h>
|
||||||
|
|
||||||
|
#include <game/localization.h>
|
||||||
|
|
||||||
|
#include "ui_listbox.h"
|
||||||
|
|
||||||
|
CListBox::CListBox()
|
||||||
|
{
|
||||||
|
m_ScrollOffset = vec2(0.0f, 0.0f);
|
||||||
|
m_ListBoxUpdateScroll = false;
|
||||||
|
m_aFilterString[0] = '\0';
|
||||||
|
m_FilterOffset = 0.0f;
|
||||||
|
m_HasHeader = false;
|
||||||
|
m_AutoSpacing = 0.0f;
|
||||||
|
m_ScrollbarIsShown = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::DoBegin(const CUIRect *pRect)
|
||||||
|
{
|
||||||
|
// setup the variables
|
||||||
|
m_ListBoxView = *pRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::DoHeader(const CUIRect *pRect, const char *pTitle, float HeaderHeight, float Spacing)
|
||||||
|
{
|
||||||
|
CUIRect View = *pRect;
|
||||||
|
CUIRect Header;
|
||||||
|
|
||||||
|
// background
|
||||||
|
View.HSplitTop(HeaderHeight + Spacing, &Header, 0);
|
||||||
|
Header.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), m_BackgroundCorners & IGraphics::CORNER_T, 5.0f);
|
||||||
|
|
||||||
|
// draw header
|
||||||
|
View.HSplitTop(HeaderHeight, &Header, &View);
|
||||||
|
SLabelProperties Props;
|
||||||
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Header, pTitle, Header.h * CUI::ms_FontmodHeight * 0.8f, TEXTALIGN_CENTER, Props);
|
||||||
|
|
||||||
|
View.HSplitTop(Spacing, &Header, &View);
|
||||||
|
|
||||||
|
// setup the variables
|
||||||
|
m_ListBoxView = View;
|
||||||
|
m_HasHeader = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::DoSpacing(float Spacing)
|
||||||
|
{
|
||||||
|
CUIRect View = m_ListBoxView;
|
||||||
|
View.HSplitTop(Spacing, 0, &View);
|
||||||
|
m_ListBoxView = View;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CListBox::DoFilter(float FilterHeight, float Spacing)
|
||||||
|
{
|
||||||
|
CUIRect Filter;
|
||||||
|
CUIRect View = m_ListBoxView;
|
||||||
|
|
||||||
|
// background
|
||||||
|
View.HSplitTop(FilterHeight + Spacing, &Filter, 0);
|
||||||
|
Filter.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), IGraphics::CORNER_NONE, 0.0f);
|
||||||
|
|
||||||
|
// draw filter
|
||||||
|
View.HSplitTop(FilterHeight, &Filter, &View);
|
||||||
|
Filter.Margin(Spacing, &Filter);
|
||||||
|
|
||||||
|
const float FontSize = Filter.h * CUI::ms_FontmodHeight * 0.8f;
|
||||||
|
|
||||||
|
CUIRect Label, EditBox;
|
||||||
|
Filter.VSplitLeft(Filter.w / 5.0f, &Label, &EditBox);
|
||||||
|
Label.y += Spacing;
|
||||||
|
UI()->DoLabel(&Label, Localize("Search:"), FontSize, TEXTALIGN_CENTER);
|
||||||
|
bool Changed = UI()->DoClearableEditBox(m_aFilterString, m_aFilterString + 1, &EditBox, m_aFilterString, sizeof(m_aFilterString), FontSize, &m_FilterOffset);
|
||||||
|
|
||||||
|
View.HSplitTop(Spacing, &Filter, &View);
|
||||||
|
|
||||||
|
m_ListBoxView = View;
|
||||||
|
|
||||||
|
return Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::DoFooter(const char *pBottomText, float FooterHeight)
|
||||||
|
{
|
||||||
|
m_pBottomText = pBottomText;
|
||||||
|
m_FooterHeight = FooterHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CListBox::DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect, bool Background, bool *pActive, int BackgroundCorners)
|
||||||
|
{
|
||||||
|
CUIRect View;
|
||||||
|
if(pRect)
|
||||||
|
View = *pRect;
|
||||||
|
else
|
||||||
|
View = m_ListBoxView;
|
||||||
|
|
||||||
|
// background
|
||||||
|
m_BackgroundCorners = BackgroundCorners;
|
||||||
|
if(Background)
|
||||||
|
View.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.15f), m_BackgroundCorners & (m_HasHeader ? IGraphics::CORNER_B : IGraphics::CORNER_ALL), 5.0f);
|
||||||
|
|
||||||
|
// draw footers
|
||||||
|
if(m_pBottomText)
|
||||||
|
{
|
||||||
|
CUIRect Footer;
|
||||||
|
View.HSplitBottom(m_FooterHeight, &View, &Footer);
|
||||||
|
Footer.VSplitLeft(10.0f, 0, &Footer);
|
||||||
|
SLabelProperties Props;
|
||||||
|
Props.m_AlignVertically = 0;
|
||||||
|
UI()->DoLabel(&Footer, m_pBottomText, Footer.h * CUI::ms_FontmodHeight * 0.8f, TEXTALIGN_CENTER, Props);
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the variables
|
||||||
|
m_ListBoxView = View;
|
||||||
|
m_RowView = {};
|
||||||
|
m_ListBoxSelectedIndex = SelectedIndex;
|
||||||
|
m_ListBoxNewSelected = SelectedIndex;
|
||||||
|
m_ListBoxNewSelOffset = 0;
|
||||||
|
m_ListBoxItemIndex = 0;
|
||||||
|
m_ListBoxRowHeight = RowHeight;
|
||||||
|
m_ListBoxNumItems = NumItems;
|
||||||
|
m_ListBoxItemsPerRow = ItemsPerRow;
|
||||||
|
m_ListBoxDoneEvents = false;
|
||||||
|
m_ListBoxItemActivated = false;
|
||||||
|
m_ListBoxItemSelected = false;
|
||||||
|
|
||||||
|
// handle input
|
||||||
|
if(!pActive || *pActive)
|
||||||
|
{
|
||||||
|
if(UI()->ConsumeHotkey(CUI::HOTKEY_DOWN))
|
||||||
|
m_ListBoxNewSelOffset += 1;
|
||||||
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_UP))
|
||||||
|
m_ListBoxNewSelOffset -= 1;
|
||||||
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_PAGE_UP))
|
||||||
|
m_ListBoxNewSelOffset = -ItemsPerRow * RowsPerScroll * 4;
|
||||||
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_PAGE_DOWN))
|
||||||
|
m_ListBoxNewSelOffset = ItemsPerRow * RowsPerScroll * 4;
|
||||||
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_HOME))
|
||||||
|
m_ListBoxNewSelOffset = 1 - m_ListBoxNumItems;
|
||||||
|
else if(UI()->ConsumeHotkey(CUI::HOTKEY_END))
|
||||||
|
m_ListBoxNewSelOffset = m_ListBoxNumItems - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup the scrollbar
|
||||||
|
m_ScrollOffset = vec2(0.0f, 0.0f);
|
||||||
|
CScrollRegionParams ScrollParams;
|
||||||
|
ScrollParams.m_ScrollbarWidth = ScrollbarWidthMax();
|
||||||
|
ScrollParams.m_ScrollUnit = (m_ListBoxRowHeight + m_AutoSpacing) * RowsPerScroll;
|
||||||
|
m_ScrollRegion.Begin(&m_ListBoxView, &m_ScrollOffset, &ScrollParams);
|
||||||
|
m_ListBoxView.y += m_ScrollOffset.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
CListboxItem CListBox::DoNextRow()
|
||||||
|
{
|
||||||
|
CListboxItem Item = {};
|
||||||
|
|
||||||
|
if(m_ListBoxItemIndex % m_ListBoxItemsPerRow == 0)
|
||||||
|
m_ListBoxView.HSplitTop(m_ListBoxRowHeight, &m_RowView, &m_ListBoxView);
|
||||||
|
m_ScrollRegion.AddRect(m_RowView);
|
||||||
|
if(m_ListBoxUpdateScroll && m_ListBoxSelectedIndex == m_ListBoxItemIndex)
|
||||||
|
{
|
||||||
|
m_ScrollRegion.ScrollHere(CScrollRegion::SCROLLHERE_KEEP_IN_VIEW);
|
||||||
|
m_ListBoxUpdateScroll = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_RowView.VSplitLeft(m_RowView.w / (m_ListBoxItemsPerRow - m_ListBoxItemIndex % m_ListBoxItemsPerRow), &Item.m_Rect, &m_RowView);
|
||||||
|
|
||||||
|
Item.m_Selected = m_ListBoxSelectedIndex == m_ListBoxItemIndex;
|
||||||
|
Item.m_Visible = !m_ScrollRegion.IsRectClipped(Item.m_Rect);
|
||||||
|
|
||||||
|
m_ListBoxItemIndex++;
|
||||||
|
return Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
CListboxItem CListBox::DoNextItem(const void *pId, bool Selected, bool *pActive)
|
||||||
|
{
|
||||||
|
if(m_AutoSpacing > 0.0f && m_ListBoxItemIndex > 0)
|
||||||
|
DoSpacing(m_AutoSpacing);
|
||||||
|
|
||||||
|
const int ThisItemIndex = m_ListBoxItemIndex;
|
||||||
|
if(Selected)
|
||||||
|
{
|
||||||
|
if(m_ListBoxSelectedIndex == m_ListBoxNewSelected)
|
||||||
|
m_ListBoxNewSelected = ThisItemIndex;
|
||||||
|
m_ListBoxSelectedIndex = ThisItemIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
CListboxItem Item = DoNextRow();
|
||||||
|
bool ItemClicked = false;
|
||||||
|
|
||||||
|
if(Item.m_Visible && UI()->DoButtonLogic(pId, 0, &Item.m_Rect))
|
||||||
|
{
|
||||||
|
ItemClicked = true;
|
||||||
|
m_ListBoxNewSelected = ThisItemIndex;
|
||||||
|
m_ListBoxItemSelected = true;
|
||||||
|
if(pActive)
|
||||||
|
*pActive = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ItemClicked = false;
|
||||||
|
|
||||||
|
const bool ProcessInput = !pActive || *pActive;
|
||||||
|
|
||||||
|
// process input, regard selected index
|
||||||
|
if(m_ListBoxSelectedIndex == ThisItemIndex)
|
||||||
|
{
|
||||||
|
if(ProcessInput && !m_ListBoxDoneEvents)
|
||||||
|
{
|
||||||
|
m_ListBoxDoneEvents = true;
|
||||||
|
|
||||||
|
if(UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (ItemClicked && Input()->MouseDoubleClick()))
|
||||||
|
{
|
||||||
|
m_ListBoxItemActivated = true;
|
||||||
|
UI()->SetActiveItem(nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, ProcessInput ? 0.5f : 0.33f), IGraphics::CORNER_ALL, 5.0f);
|
||||||
|
}
|
||||||
|
if(UI()->HotItem() == pId && !m_ScrollRegion.IsAnimating())
|
||||||
|
{
|
||||||
|
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.33f), IGraphics::CORNER_ALL, 5.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
CListboxItem CListBox::DoSubheader()
|
||||||
|
{
|
||||||
|
CListboxItem Item = DoNextRow();
|
||||||
|
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.2f), IGraphics::CORNER_NONE, 0.0f);
|
||||||
|
return Item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CListBox::DoEnd()
|
||||||
|
{
|
||||||
|
m_ScrollRegion.End();
|
||||||
|
m_ScrollbarIsShown = m_ScrollRegion.IsScrollbarShown();
|
||||||
|
if(m_ListBoxNewSelOffset != 0 && m_ListBoxSelectedIndex != -1 && m_ListBoxSelectedIndex == m_ListBoxNewSelected)
|
||||||
|
{
|
||||||
|
m_ListBoxNewSelected = clamp(m_ListBoxNewSelected + m_ListBoxNewSelOffset, 0, m_ListBoxNumItems - 1);
|
||||||
|
ScrollToSelected();
|
||||||
|
}
|
||||||
|
return m_ListBoxNewSelected;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CListBox::FilterMatches(const char *pNeedle) const
|
||||||
|
{
|
||||||
|
return !m_aFilterString[0] || str_find_nocase(pNeedle, m_aFilterString);
|
||||||
|
}
|
68
src/game/client/ui_listbox.h
Normal file
68
src/game/client/ui_listbox.h
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
/* (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. */
|
||||||
|
#ifndef GAME_CLIENT_UI_LISTBOX_H
|
||||||
|
#define GAME_CLIENT_UI_LISTBOX_H
|
||||||
|
|
||||||
|
#include "ui_scrollregion.h"
|
||||||
|
|
||||||
|
struct CListboxItem
|
||||||
|
{
|
||||||
|
bool m_Visible;
|
||||||
|
bool m_Selected;
|
||||||
|
CUIRect m_Rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Instances of CListBox must be static, as member addresses are used as UI item IDs
|
||||||
|
class CListBox : private CUIElementBase
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
CUIRect m_ListBoxView;
|
||||||
|
CUIRect m_RowView;
|
||||||
|
float m_ListBoxRowHeight;
|
||||||
|
int m_ListBoxItemIndex;
|
||||||
|
int m_ListBoxSelectedIndex;
|
||||||
|
int m_ListBoxNewSelected;
|
||||||
|
int m_ListBoxNewSelOffset;
|
||||||
|
bool m_ListBoxUpdateScroll;
|
||||||
|
bool m_ListBoxDoneEvents;
|
||||||
|
int m_ListBoxNumItems;
|
||||||
|
int m_ListBoxItemsPerRow;
|
||||||
|
bool m_ListBoxItemSelected;
|
||||||
|
bool m_ListBoxItemActivated;
|
||||||
|
bool m_ScrollbarIsShown;
|
||||||
|
const char *m_pBottomText;
|
||||||
|
float m_FooterHeight;
|
||||||
|
float m_AutoSpacing;
|
||||||
|
CScrollRegion m_ScrollRegion;
|
||||||
|
vec2 m_ScrollOffset;
|
||||||
|
char m_aFilterString[128];
|
||||||
|
float m_FilterOffset;
|
||||||
|
int m_BackgroundCorners;
|
||||||
|
bool m_HasHeader;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
CListboxItem DoNextRow();
|
||||||
|
|
||||||
|
public:
|
||||||
|
CListBox();
|
||||||
|
|
||||||
|
void DoBegin(const CUIRect *pRect);
|
||||||
|
void DoHeader(const CUIRect *pRect, const char *pTitle, float HeaderHeight = 20.0f, float Spacing = 2.0f);
|
||||||
|
void DoAutoSpacing(float Spacing = 20.0f) { m_AutoSpacing = Spacing; }
|
||||||
|
void DoSpacing(float Spacing = 20.0f);
|
||||||
|
bool DoFilter(float FilterHeight = 20.0f, float Spacing = 2.0f);
|
||||||
|
void DoFooter(const char *pBottomText, float FooterHeight = 20.0f); // call before DoStart to create a footer
|
||||||
|
void DoStart(float RowHeight, int NumItems, int ItemsPerRow, int RowsPerScroll, int SelectedIndex, const CUIRect *pRect = nullptr, bool Background = true, bool *pActive = nullptr, int BackgroundCorners = IGraphics::CORNER_ALL);
|
||||||
|
void ScrollToSelected() { m_ListBoxUpdateScroll = true; }
|
||||||
|
CListboxItem DoNextItem(const void *pID, bool Selected = false, bool *pActive = nullptr);
|
||||||
|
CListboxItem DoSubheader();
|
||||||
|
int DoEnd();
|
||||||
|
bool FilterMatches(const char *pNeedle) const;
|
||||||
|
bool WasItemSelected() const { return m_ListBoxItemSelected; }
|
||||||
|
bool WasItemActivated() const { return m_ListBoxItemActivated; }
|
||||||
|
bool ScrollbarIsShown() const { return m_ScrollbarIsShown; }
|
||||||
|
float ScrollbarWidth() const { return ScrollbarIsShown() ? ScrollbarWidthMax() : 0.0f; }
|
||||||
|
float ScrollbarWidthMax() const { return 20.0f; }
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -24,6 +24,7 @@
|
||||||
#include <game/client/gameclient.h>
|
#include <game/client/gameclient.h>
|
||||||
#include <game/client/render.h>
|
#include <game/client/render.h>
|
||||||
#include <game/client/ui.h>
|
#include <game/client/ui.h>
|
||||||
|
#include <game/client/ui_listbox.h>
|
||||||
#include <game/client/ui_scrollregion.h>
|
#include <game/client/ui_scrollregion.h>
|
||||||
#include <game/generated/client_data.h>
|
#include <game/generated/client_data.h>
|
||||||
#include <game/localization.h>
|
#include <game/localization.h>
|
||||||
|
@ -4244,66 +4245,11 @@ static int EditorListdirCallback(const char *pName, int IsDir, int StorageType,
|
||||||
Item.m_IsDir = IsDir != 0;
|
Item.m_IsDir = IsDir != 0;
|
||||||
Item.m_IsLink = false;
|
Item.m_IsLink = false;
|
||||||
Item.m_StorageType = StorageType;
|
Item.m_StorageType = StorageType;
|
||||||
pEditor->m_vFileList.push_back(Item);
|
pEditor->m_vCompleteFileList.push_back(Item);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEditor::AddFileDialogEntry(int Index, CUIRect *pView)
|
|
||||||
{
|
|
||||||
m_FilesCur++;
|
|
||||||
if(m_FilesCur - 1 < m_FilesStartAt || m_FilesCur >= m_FilesStopAt)
|
|
||||||
return;
|
|
||||||
|
|
||||||
CUIRect Button, FileIcon;
|
|
||||||
pView->HSplitTop(15.0f, &Button, pView);
|
|
||||||
pView->HSplitTop(2.0f, nullptr, pView);
|
|
||||||
Button.VSplitLeft(Button.h, &FileIcon, &Button);
|
|
||||||
Button.VSplitLeft(5.0f, nullptr, &Button);
|
|
||||||
|
|
||||||
const char *pIconType;
|
|
||||||
|
|
||||||
if(!m_vFileList[Index].m_IsDir)
|
|
||||||
{
|
|
||||||
switch(m_FileDialogFileType)
|
|
||||||
{
|
|
||||||
case FILETYPE_MAP:
|
|
||||||
pIconType = "\xEF\x89\xB9";
|
|
||||||
break;
|
|
||||||
case FILETYPE_IMG:
|
|
||||||
pIconType = "\xEF\x80\xBE";
|
|
||||||
break;
|
|
||||||
case FILETYPE_SOUND:
|
|
||||||
pIconType = "\xEF\x80\x81";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
pIconType = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(str_comp(m_vFileList[Index].m_aFilename, "..") == 0)
|
|
||||||
pIconType = "\xEF\xA0\x82";
|
|
||||||
else
|
|
||||||
pIconType = "\xEF\x81\xBB";
|
|
||||||
}
|
|
||||||
|
|
||||||
TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT));
|
|
||||||
UI()->DoLabel(&FileIcon, pIconType, 12.0f, TEXTALIGN_LEFT);
|
|
||||||
TextRender()->SetCurFont(nullptr);
|
|
||||||
|
|
||||||
if(DoButton_File(&m_vFileList[Index], m_vFileList[Index].m_aName, m_FilesSelectedIndex == Index, &Button, 0, nullptr))
|
|
||||||
{
|
|
||||||
if(!m_vFileList[Index].m_IsDir)
|
|
||||||
str_copy(m_aFileDialogFileName, m_vFileList[Index].m_aFilename, sizeof(m_aFileDialogFileName));
|
|
||||||
else
|
|
||||||
m_aFileDialogFileName[0] = 0;
|
|
||||||
m_PreviewImageIsLoaded = false;
|
|
||||||
m_FileDialogActivate |= Index == m_FilesSelectedIndex && Input()->MouseDoubleClick();
|
|
||||||
m_FilesSelectedIndex = Index;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CEditor::RenderFileDialog()
|
void CEditor::RenderFileDialog()
|
||||||
{
|
{
|
||||||
// GUI coordsys
|
// GUI coordsys
|
||||||
|
@ -4318,7 +4264,7 @@ void CEditor::RenderFileDialog()
|
||||||
View.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 5.0f);
|
View.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 5.0f);
|
||||||
View.Margin(10.0f, &View);
|
View.Margin(10.0f, &View);
|
||||||
|
|
||||||
CUIRect Title, FileBox, FileBoxLabel, ButtonBar, Scroll, PathBox;
|
CUIRect Title, FileBox, FileBoxLabel, ButtonBar, PathBox;
|
||||||
View.HSplitTop(18.0f, &Title, &View);
|
View.HSplitTop(18.0f, &Title, &View);
|
||||||
View.HSplitTop(5.0f, nullptr, &View); // some spacing
|
View.HSplitTop(5.0f, nullptr, &View); // some spacing
|
||||||
View.HSplitBottom(14.0f, &View, &ButtonBar);
|
View.HSplitBottom(14.0f, &View, &ButtonBar);
|
||||||
|
@ -4330,7 +4276,6 @@ void CEditor::RenderFileDialog()
|
||||||
View.HSplitBottom(10.0f, &View, nullptr); // some spacing
|
View.HSplitBottom(10.0f, &View, nullptr); // some spacing
|
||||||
if(m_FileDialogFileType == CEditor::FILETYPE_IMG)
|
if(m_FileDialogFileType == CEditor::FILETYPE_IMG)
|
||||||
View.VSplitMid(&View, &Preview);
|
View.VSplitMid(&View, &Preview);
|
||||||
View.VSplitRight(20.0f, &View, &Scroll);
|
|
||||||
|
|
||||||
// title
|
// title
|
||||||
Title.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
Title.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
||||||
|
@ -4340,15 +4285,17 @@ void CEditor::RenderFileDialog()
|
||||||
// pathbox
|
// pathbox
|
||||||
char aPath[128], aBuf[128];
|
char aPath[128], aBuf[128];
|
||||||
if(m_FilesSelectedIndex != -1)
|
if(m_FilesSelectedIndex != -1)
|
||||||
Storage()->GetCompletePath(m_vFileList[m_FilesSelectedIndex].m_StorageType, m_pFileDialogPath, aPath, sizeof(aPath));
|
Storage()->GetCompletePath(m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType, m_pFileDialogPath, aPath, sizeof(aPath));
|
||||||
else
|
else
|
||||||
aPath[0] = 0;
|
aPath[0] = 0;
|
||||||
str_format(aBuf, sizeof(aBuf), "Current path: %s", aPath);
|
str_format(aBuf, sizeof(aBuf), "Current path: %s", aPath);
|
||||||
UI()->DoLabel(&PathBox, aBuf, 10.0f, TEXTALIGN_LEFT);
|
UI()->DoLabel(&PathBox, aBuf, 10.0f, TEXTALIGN_LEFT);
|
||||||
|
|
||||||
|
// filebox
|
||||||
|
static CListBox s_ListBox;
|
||||||
|
|
||||||
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
|
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
|
||||||
{
|
{
|
||||||
// filebox
|
|
||||||
UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, TEXTALIGN_LEFT);
|
UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, TEXTALIGN_LEFT);
|
||||||
static float s_FileBoxID = 0;
|
static float s_FileBoxID = 0;
|
||||||
if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f, &s_FileBoxID))
|
if(DoEditBox(&s_FileBoxID, &FileBox, m_aFileDialogFileName, sizeof(m_aFileDialogFileName), 10.0f, &s_FileBoxID))
|
||||||
|
@ -4358,6 +4305,19 @@ void CEditor::RenderFileDialog()
|
||||||
if(m_aFileDialogFileName[i] == '/' || m_aFileDialogFileName[i] == '\\')
|
if(m_aFileDialogFileName[i] == '/' || m_aFileDialogFileName[i] == '\\')
|
||||||
str_copy(&m_aFileDialogFileName[i], &m_aFileDialogFileName[i + 1], (int)(sizeof(m_aFileDialogFileName)) - i);
|
str_copy(&m_aFileDialogFileName[i], &m_aFileDialogFileName[i + 1], (int)(sizeof(m_aFileDialogFileName)) - i);
|
||||||
m_FilesSelectedIndex = -1;
|
m_FilesSelectedIndex = -1;
|
||||||
|
m_aFilesSelectedName[0] = '\0';
|
||||||
|
// find first valid entry, if it exists
|
||||||
|
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
|
||||||
|
{
|
||||||
|
if(str_comp_nocase(m_vpFilteredFileList[i]->m_aName, m_aFileDialogFileName) == 0)
|
||||||
|
{
|
||||||
|
m_FilesSelectedIndex = i;
|
||||||
|
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[i]->m_aName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m_FilesSelectedIndex >= 0)
|
||||||
|
s_ListBox.ScrollToSelected();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_FileDialogOpening)
|
if(m_FileDialogOpening)
|
||||||
|
@ -4365,119 +4325,73 @@ void CEditor::RenderFileDialog()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//searchbox
|
// render search bar
|
||||||
FileBox.VSplitRight(250, &FileBox, nullptr);
|
FileBox.VSplitRight(250, &FileBox, nullptr);
|
||||||
CUIRect ClearBox;
|
CUIRect ClearBox;
|
||||||
FileBox.VSplitRight(15, &FileBox, &ClearBox);
|
FileBox.VSplitRight(15, &FileBox, &ClearBox);
|
||||||
|
|
||||||
UI()->DoLabel(&FileBoxLabel, "Search:", 10.0f, TEXTALIGN_LEFT);
|
UI()->DoLabel(&FileBoxLabel, "Search:", 10.0f, TEXTALIGN_LEFT);
|
||||||
str_copy(m_aFileDialogPrevSearchText, m_aFileDialogSearchText, sizeof(m_aFileDialogPrevSearchText));
|
|
||||||
static float s_SearchBoxID = 0;
|
static float s_SearchBoxID = 0;
|
||||||
DoEditBox(&s_SearchBoxID, &FileBox, m_aFileDialogSearchText, sizeof(m_aFileDialogSearchText), 10.0f, &s_SearchBoxID, false, IGraphics::CORNER_L);
|
bool SearchUpdated = DoEditBox(&s_SearchBoxID, &FileBox, m_aFileDialogFilterString, sizeof(m_aFileDialogFilterString), 10.0f, &s_SearchBoxID, false, IGraphics::CORNER_L);
|
||||||
if(m_FileDialogOpening)
|
if(m_FileDialogOpening)
|
||||||
UI()->SetActiveItem(&s_SearchBoxID);
|
UI()->SetActiveItem(&s_SearchBoxID);
|
||||||
|
|
||||||
// clearSearchbox button
|
// clear search button
|
||||||
{
|
{
|
||||||
static int s_ClearButton = 0;
|
static int s_ClearButton = 0;
|
||||||
ClearBox.Draw(ColorRGBA(1, 1, 1, 0.33f * UI()->ButtonColorMul(&s_ClearButton)), IGraphics::CORNER_R, 3.0f);
|
ClearBox.Draw(ColorRGBA(1, 1, 1, 0.33f * UI()->ButtonColorMul(&s_ClearButton)), IGraphics::CORNER_R, 3.0f);
|
||||||
UI()->DoLabel(&ClearBox, "×", 10.0f, TEXTALIGN_CENTER);
|
UI()->DoLabel(&ClearBox, "×", 10.0f, TEXTALIGN_CENTER);
|
||||||
if(UI()->DoButtonLogic(&s_ClearButton, 0, &ClearBox))
|
if(UI()->DoButtonLogic(&s_ClearButton, 0, &ClearBox))
|
||||||
{
|
{
|
||||||
m_aFileDialogSearchText[0] = 0;
|
SearchUpdated = true;
|
||||||
|
m_aFileDialogFilterString[0] = 0;
|
||||||
UI()->SetActiveItem(&s_SearchBoxID);
|
UI()->SetActiveItem(&s_SearchBoxID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(str_comp(m_aFileDialogPrevSearchText, m_aFileDialogSearchText))
|
if(SearchUpdated)
|
||||||
m_FileDialogScrollValue = 0.0f;
|
{
|
||||||
|
RefreshFilteredFileList();
|
||||||
|
if(m_vpFilteredFileList.empty())
|
||||||
|
{
|
||||||
|
m_FilesSelectedIndex = -1;
|
||||||
|
}
|
||||||
|
else if(m_FilesSelectedIndex == -1 || (m_aFileDialogFilterString[0] && !str_find_nocase(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName, m_aFileDialogFilterString)))
|
||||||
|
{
|
||||||
|
// we need to refresh selection
|
||||||
|
m_FilesSelectedIndex = -1;
|
||||||
|
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
|
||||||
|
{
|
||||||
|
if(str_find_nocase(m_vpFilteredFileList[i]->m_aName, m_aFileDialogFilterString))
|
||||||
|
{
|
||||||
|
m_FilesSelectedIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m_FilesSelectedIndex == -1)
|
||||||
|
{
|
||||||
|
// select first item
|
||||||
|
m_FilesSelectedIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(m_FilesSelectedIndex >= 0)
|
||||||
|
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||||
|
else
|
||||||
|
m_aFilesSelectedName[0] = '\0';
|
||||||
|
s_ListBox.ScrollToSelected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_FileDialogOpening = false;
|
m_FileDialogOpening = false;
|
||||||
|
|
||||||
int Num = (int)(View.h / 17.0f) + 1;
|
|
||||||
m_FileDialogScrollValue = UI()->DoScrollbarV(&m_FileDialogScrollValue, &Scroll, m_FileDialogScrollValue);
|
|
||||||
|
|
||||||
int ScrollNum = 0;
|
|
||||||
for(size_t i = 0; i < m_vFileList.size(); i++)
|
|
||||||
{
|
|
||||||
m_vFileList[i].m_IsVisible = false;
|
|
||||||
if(!m_aFileDialogSearchText[0] || str_utf8_find_nocase(m_vFileList[i].m_aName, m_aFileDialogSearchText))
|
|
||||||
{
|
|
||||||
AddFileDialogEntry(i, &View);
|
|
||||||
m_vFileList[i].m_IsVisible = true;
|
|
||||||
ScrollNum++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ScrollNum -= Num - 1;
|
|
||||||
|
|
||||||
if(ScrollNum > 0)
|
|
||||||
{
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
|
|
||||||
m_FileDialogScrollValue -= 3.0f / ScrollNum;
|
|
||||||
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
|
|
||||||
m_FileDialogScrollValue += 3.0f / ScrollNum;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ScrollNum = 0;
|
|
||||||
|
|
||||||
if(m_FilesSelectedIndex > -1)
|
if(m_FilesSelectedIndex > -1)
|
||||||
{
|
{
|
||||||
if(!m_vFileList[m_FilesSelectedIndex].m_IsVisible)
|
|
||||||
{
|
|
||||||
m_FilesSelectedIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for(int i = 0; i < Input()->NumEvents(); i++)
|
|
||||||
{
|
|
||||||
int NewIndex = -1;
|
|
||||||
if(Input()->GetEvent(i).m_Flags & IInput::FLAG_PRESS)
|
|
||||||
{
|
|
||||||
if(Input()->GetEvent(i).m_Key == KEY_DOWN)
|
|
||||||
{
|
|
||||||
for(NewIndex = m_FilesSelectedIndex + 1; NewIndex < (int)m_vFileList.size(); NewIndex++)
|
|
||||||
{
|
|
||||||
if(m_vFileList[NewIndex].m_IsVisible)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(Input()->GetEvent(i).m_Key == KEY_UP)
|
|
||||||
{
|
|
||||||
for(NewIndex = m_FilesSelectedIndex - 1; NewIndex >= 0; NewIndex--)
|
|
||||||
{
|
|
||||||
if(m_vFileList[NewIndex].m_IsVisible)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(NewIndex > -1 && NewIndex < (int)m_vFileList.size())
|
|
||||||
{
|
|
||||||
//scroll
|
|
||||||
float IndexY = View.y - m_FileDialogScrollValue * ScrollNum * 17.0f + NewIndex * 17.0f;
|
|
||||||
int ScrollPos = View.y > IndexY ? -1 : View.y + View.h < IndexY + 17.0f ? 1 : 0;
|
|
||||||
if(ScrollPos)
|
|
||||||
{
|
|
||||||
if(ScrollPos < 0)
|
|
||||||
m_FileDialogScrollValue = ((float)(NewIndex) + 0.5f) / ScrollNum;
|
|
||||||
else
|
|
||||||
m_FileDialogScrollValue = ((float)(NewIndex - Num) + 2.5f) / ScrollNum;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!m_vFileList[NewIndex].m_IsDir)
|
|
||||||
str_copy(m_aFileDialogFileName, m_vFileList[NewIndex].m_aFilename, sizeof(m_aFileDialogFileName));
|
|
||||||
else
|
|
||||||
m_aFileDialogFileName[0] = 0;
|
|
||||||
m_FilesSelectedIndex = NewIndex;
|
|
||||||
m_PreviewImageIsLoaded = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(m_FileDialogFileType == CEditor::FILETYPE_IMG && !m_PreviewImageIsLoaded && m_FilesSelectedIndex > -1)
|
if(m_FileDialogFileType == CEditor::FILETYPE_IMG && !m_PreviewImageIsLoaded && m_FilesSelectedIndex > -1)
|
||||||
{
|
{
|
||||||
if(str_endswith(m_vFileList[m_FilesSelectedIndex].m_aFilename, ".png"))
|
if(str_endswith(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, ".png"))
|
||||||
{
|
{
|
||||||
char aBuffer[1024];
|
char aBuffer[1024];
|
||||||
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_pFileDialogPath, m_vFileList[m_FilesSelectedIndex].m_aFilename);
|
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_pFileDialogPath, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
|
||||||
|
|
||||||
if(Graphics()->LoadPNG(&m_FilePreviewImageInfo, aBuffer, IStorage::TYPE_ALL))
|
if(Graphics()->LoadPNG(&m_FilePreviewImageInfo, aBuffer, IStorage::TYPE_ALL))
|
||||||
{
|
{
|
||||||
|
@ -4513,33 +4427,64 @@ void CEditor::RenderFileDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int i = 0; i < Input()->NumEvents(); i++)
|
s_ListBox.DoStart(15.0f, m_vpFilteredFileList.size(), 1, 5, m_FilesSelectedIndex, &View, false);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
|
||||||
{
|
{
|
||||||
if(Input()->GetEvent(i).m_Flags & IInput::FLAG_PRESS && !UiPopupOpen() && !m_PopupEventActivated)
|
const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredFileList[i], m_FilesSelectedIndex >= 0 && (size_t)m_FilesSelectedIndex == i);
|
||||||
|
if(!Item.m_Visible)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
CUIRect Button, FileIcon;
|
||||||
|
Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Button);
|
||||||
|
Button.VSplitLeft(5.0f, nullptr, &Button);
|
||||||
|
|
||||||
|
const char *pIconType;
|
||||||
|
if(!m_vpFilteredFileList[i]->m_IsDir)
|
||||||
{
|
{
|
||||||
if(Input()->GetEvent(i).m_Key == KEY_RETURN || Input()->GetEvent(i).m_Key == KEY_KP_ENTER)
|
switch(m_FileDialogFileType)
|
||||||
m_FileDialogActivate = true;
|
{
|
||||||
|
case FILETYPE_MAP:
|
||||||
|
pIconType = "\xEF\x89\xB9";
|
||||||
|
break;
|
||||||
|
case FILETYPE_IMG:
|
||||||
|
pIconType = "\xEF\x80\xBE";
|
||||||
|
break;
|
||||||
|
case FILETYPE_SOUND:
|
||||||
|
pIconType = "\xEF\x80\x81";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
pIconType = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(str_comp(m_vpFilteredFileList[i]->m_aFilename, "..") == 0)
|
||||||
|
pIconType = "\xEF\xA0\x82";
|
||||||
|
else
|
||||||
|
pIconType = "\xEF\x81\xBB";
|
||||||
|
}
|
||||||
|
|
||||||
if(m_FileDialogScrollValue < 0)
|
TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT));
|
||||||
m_FileDialogScrollValue = 0;
|
UI()->DoLabel(&FileIcon, pIconType, 12.0f, TEXTALIGN_LEFT);
|
||||||
if(m_FileDialogScrollValue > 1)
|
TextRender()->SetCurFont(nullptr);
|
||||||
m_FileDialogScrollValue = 1;
|
|
||||||
|
|
||||||
m_FilesStartAt = (int)(ScrollNum * m_FileDialogScrollValue);
|
SLabelProperties Props;
|
||||||
if(m_FilesStartAt < 0)
|
Props.m_AlignVertically = 0;
|
||||||
m_FilesStartAt = 0;
|
UI()->DoLabel(&Button, m_vpFilteredFileList[i]->m_aName, 10.0f, TEXTALIGN_LEFT, Props);
|
||||||
|
}
|
||||||
|
|
||||||
m_FilesStopAt = m_FilesStartAt + Num;
|
const int NewSelection = s_ListBox.DoEnd();
|
||||||
|
if(NewSelection != m_FilesSelectedIndex)
|
||||||
m_FilesCur = 0;
|
{
|
||||||
|
m_FilesSelectedIndex = NewSelection;
|
||||||
// set clipping
|
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||||
UI()->ClipEnable(&View);
|
if(!m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
|
||||||
|
str_copy(m_aFileDialogFileName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
|
||||||
// disable clipping again
|
else
|
||||||
UI()->ClipDisable();
|
m_aFileDialogFileName[0] = '\0';
|
||||||
|
m_PreviewImageIsLoaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
// the buttons
|
// the buttons
|
||||||
static int s_OkButton = 0;
|
static int s_OkButton = 0;
|
||||||
|
@ -4549,35 +4494,34 @@ void CEditor::RenderFileDialog()
|
||||||
|
|
||||||
CUIRect Button;
|
CUIRect Button;
|
||||||
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
|
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
|
||||||
bool IsDir = m_FilesSelectedIndex >= 0 && m_vFileList[m_FilesSelectedIndex].m_IsDir;
|
bool IsDir = m_FilesSelectedIndex >= 0 && m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir;
|
||||||
if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, nullptr) || m_FileDialogActivate)
|
if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, nullptr) || s_ListBox.WasItemActivated() || UI()->ConsumeHotkey(CUI::HOTKEY_ENTER))
|
||||||
{
|
{
|
||||||
m_FileDialogActivate = false;
|
|
||||||
if(IsDir) // folder
|
if(IsDir) // folder
|
||||||
{
|
{
|
||||||
if(str_comp(m_vFileList[m_FilesSelectedIndex].m_aFilename, "..") == 0) // parent folder
|
if(str_comp(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, "..") == 0) // parent folder
|
||||||
{
|
{
|
||||||
if(fs_parent_dir(m_pFileDialogPath))
|
if(fs_parent_dir(m_pFileDialogPath))
|
||||||
m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link
|
m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link
|
||||||
}
|
}
|
||||||
else // sub folder
|
else // sub folder
|
||||||
{
|
{
|
||||||
if(m_vFileList[m_FilesSelectedIndex].m_IsLink)
|
if(m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsLink)
|
||||||
{
|
{
|
||||||
m_pFileDialogPath = m_aFileDialogCurrentLink; // follow the link
|
m_pFileDialogPath = m_aFileDialogCurrentLink; // follow the link
|
||||||
str_copy(m_aFileDialogCurrentLink, m_vFileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogCurrentLink));
|
str_copy(m_aFileDialogCurrentLink, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, sizeof(m_aFileDialogCurrentLink));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char aTemp[IO_MAX_PATH_LENGTH];
|
char aTemp[IO_MAX_PATH_LENGTH];
|
||||||
str_copy(aTemp, m_pFileDialogPath, sizeof(aTemp));
|
str_copy(aTemp, m_pFileDialogPath, sizeof(aTemp));
|
||||||
str_format(m_pFileDialogPath, IO_MAX_PATH_LENGTH, "%s/%s", aTemp, m_vFileList[m_FilesSelectedIndex].m_aFilename);
|
str_format(m_pFileDialogPath, IO_MAX_PATH_LENGTH, "%s/%s", aTemp, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FilelistPopulate(!str_comp(m_pFileDialogPath, "maps") || !str_comp(m_pFileDialogPath, "mapres") ? m_FileDialogStorageType :
|
FilelistPopulate(!str_comp(m_pFileDialogPath, "maps") || !str_comp(m_pFileDialogPath, "mapres") ? m_FileDialogStorageType :
|
||||||
m_vFileList[m_FilesSelectedIndex].m_StorageType);
|
m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType);
|
||||||
if(m_FilesSelectedIndex >= 0 && !m_vFileList[m_FilesSelectedIndex].m_IsDir)
|
if(m_FilesSelectedIndex >= 0 && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
|
||||||
str_copy(m_aFileDialogFileName, m_vFileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName));
|
str_copy(m_aFileDialogFileName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, sizeof(m_aFileDialogFileName));
|
||||||
else
|
else
|
||||||
m_aFileDialogFileName[0] = 0;
|
m_aFileDialogFileName[0] = 0;
|
||||||
}
|
}
|
||||||
|
@ -4594,10 +4538,10 @@ void CEditor::RenderFileDialog()
|
||||||
m_PopupEventActivated = true;
|
m_PopupEventActivated = true;
|
||||||
}
|
}
|
||||||
else if(m_pfnFileDialogFunc)
|
else if(m_pfnFileDialogFunc)
|
||||||
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vFileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
|
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
|
||||||
}
|
}
|
||||||
else if(m_pfnFileDialogFunc)
|
else if(m_pfnFileDialogFunc)
|
||||||
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vFileList[m_FilesSelectedIndex].m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
|
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4636,9 +4580,42 @@ void CEditor::RenderFileDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CEditor::RefreshFilteredFileList()
|
||||||
|
{
|
||||||
|
m_vpFilteredFileList.clear();
|
||||||
|
for(const CFilelistItem &Item : m_vCompleteFileList)
|
||||||
|
{
|
||||||
|
if(!m_aFileDialogFilterString[0] || str_find_nocase(Item.m_aName, m_aFileDialogFilterString))
|
||||||
|
{
|
||||||
|
m_vpFilteredFileList.push_back(&Item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!m_vpFilteredFileList.empty())
|
||||||
|
{
|
||||||
|
if(m_aFilesSelectedName[0])
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
|
||||||
|
{
|
||||||
|
if(m_aFilesSelectedName[0] && str_comp(m_vpFilteredFileList[i]->m_aName, m_aFilesSelectedName) == 0)
|
||||||
|
{
|
||||||
|
m_FilesSelectedIndex = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_FilesSelectedIndex = clamp<int>(m_FilesSelectedIndex, 0, m_vpFilteredFileList.size() - 1);
|
||||||
|
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_FilesSelectedIndex = -1;
|
||||||
|
m_aFilesSelectedName[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CEditor::FilelistPopulate(int StorageType)
|
void CEditor::FilelistPopulate(int StorageType)
|
||||||
{
|
{
|
||||||
m_vFileList.clear();
|
m_vCompleteFileList.clear();
|
||||||
if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps"))
|
if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps"))
|
||||||
{
|
{
|
||||||
CFilelistItem Item;
|
CFilelistItem Item;
|
||||||
|
@ -4647,18 +4624,17 @@ void CEditor::FilelistPopulate(int StorageType)
|
||||||
Item.m_IsDir = true;
|
Item.m_IsDir = true;
|
||||||
Item.m_IsLink = true;
|
Item.m_IsLink = true;
|
||||||
Item.m_StorageType = IStorage::TYPE_SAVE;
|
Item.m_StorageType = IStorage::TYPE_SAVE;
|
||||||
m_vFileList.push_back(Item);
|
m_vCompleteFileList.push_back(Item);
|
||||||
}
|
}
|
||||||
Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this);
|
Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this);
|
||||||
std::sort(m_vFileList.begin(), m_vFileList.end());
|
std::sort(m_vCompleteFileList.begin(), m_vCompleteFileList.end());
|
||||||
m_FilesSelectedIndex = m_vFileList.empty() ? -1 : 0;
|
RefreshFilteredFileList();
|
||||||
m_PreviewImageIsLoaded = false;
|
m_FilesSelectedIndex = m_vpFilteredFileList.empty() ? -1 : 0;
|
||||||
m_FileDialogActivate = false;
|
if(m_FilesSelectedIndex >= 0)
|
||||||
|
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||||
if(m_FilesSelectedIndex >= 0 && !m_vFileList[m_FilesSelectedIndex].m_IsDir)
|
|
||||||
str_copy(m_aFileDialogFileName, m_vFileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName));
|
|
||||||
else
|
else
|
||||||
m_aFileDialogFileName[0] = 0;
|
m_aFilesSelectedName[0] = '\0';
|
||||||
|
m_PreviewImageIsLoaded = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
|
void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
|
||||||
|
@ -4672,12 +4648,11 @@ void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle
|
||||||
m_pfnFileDialogFunc = pfnFunc;
|
m_pfnFileDialogFunc = pfnFunc;
|
||||||
m_pFileDialogUser = pUser;
|
m_pFileDialogUser = pUser;
|
||||||
m_aFileDialogFileName[0] = 0;
|
m_aFileDialogFileName[0] = 0;
|
||||||
m_aFileDialogSearchText[0] = 0;
|
m_aFileDialogFilterString[0] = 0;
|
||||||
m_aFileDialogCurrentFolder[0] = 0;
|
m_aFileDialogCurrentFolder[0] = 0;
|
||||||
m_aFileDialogCurrentLink[0] = 0;
|
m_aFileDialogCurrentLink[0] = 0;
|
||||||
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
||||||
m_FileDialogFileType = FileType;
|
m_FileDialogFileType = FileType;
|
||||||
m_FileDialogScrollValue = 0.0f;
|
|
||||||
m_PreviewImageIsLoaded = false;
|
m_PreviewImageIsLoaded = false;
|
||||||
m_FileDialogOpening = true;
|
m_FileDialogOpening = true;
|
||||||
|
|
||||||
|
|
|
@ -770,8 +770,8 @@ public:
|
||||||
|
|
||||||
m_BrushColorEnabled = true;
|
m_BrushColorEnabled = true;
|
||||||
|
|
||||||
m_aFileName[0] = 0;
|
m_aFileName[0] = '\0';
|
||||||
m_aFileSaveName[0] = 0;
|
m_aFileSaveName[0] = '\0';
|
||||||
m_ValidSaveFilename = false;
|
m_ValidSaveFilename = false;
|
||||||
|
|
||||||
m_PopupEventActivated = false;
|
m_PopupEventActivated = false;
|
||||||
|
@ -782,17 +782,14 @@ public:
|
||||||
m_pFileDialogTitle = nullptr;
|
m_pFileDialogTitle = nullptr;
|
||||||
m_pFileDialogButtonText = nullptr;
|
m_pFileDialogButtonText = nullptr;
|
||||||
m_pFileDialogUser = nullptr;
|
m_pFileDialogUser = nullptr;
|
||||||
m_aFileDialogFileName[0] = 0;
|
m_aFileDialogFileName[0] = '\0';
|
||||||
m_aFileDialogCurrentFolder[0] = 0;
|
m_aFileDialogCurrentFolder[0] = '\0';
|
||||||
m_aFileDialogCurrentLink[0] = 0;
|
m_aFileDialogCurrentLink[0] = '\0';
|
||||||
|
m_aFilesSelectedName[0] = '\0';
|
||||||
|
m_aFileDialogFilterString[0] = '\0';
|
||||||
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
||||||
m_FileDialogActivate = false;
|
|
||||||
m_FileDialogOpening = false;
|
m_FileDialogOpening = false;
|
||||||
m_FileDialogScrollValue = 0.0f;
|
|
||||||
m_FilesSelectedIndex = -1;
|
m_FilesSelectedIndex = -1;
|
||||||
m_FilesStartAt = 0;
|
|
||||||
m_FilesCur = 0;
|
|
||||||
m_FilesStopAt = 999;
|
|
||||||
|
|
||||||
m_SelectEntitiesImage = "DDNet";
|
m_SelectEntitiesImage = "DDNet";
|
||||||
|
|
||||||
|
@ -867,6 +864,7 @@ public:
|
||||||
|
|
||||||
CLayerGroup *m_apSavedBrushes[10];
|
CLayerGroup *m_apSavedBrushes[10];
|
||||||
|
|
||||||
|
void RefreshFilteredFileList();
|
||||||
void FilelistPopulate(int StorageType);
|
void FilelistPopulate(int StorageType);
|
||||||
void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
|
void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
|
||||||
const char *pBasepath, const char *pDefaultName,
|
const char *pBasepath, const char *pDefaultName,
|
||||||
|
@ -950,12 +948,10 @@ public:
|
||||||
char m_aFileDialogFileName[IO_MAX_PATH_LENGTH];
|
char m_aFileDialogFileName[IO_MAX_PATH_LENGTH];
|
||||||
char m_aFileDialogCurrentFolder[IO_MAX_PATH_LENGTH];
|
char m_aFileDialogCurrentFolder[IO_MAX_PATH_LENGTH];
|
||||||
char m_aFileDialogCurrentLink[IO_MAX_PATH_LENGTH];
|
char m_aFileDialogCurrentLink[IO_MAX_PATH_LENGTH];
|
||||||
char m_aFileDialogSearchText[64];
|
char m_aFilesSelectedName[IO_MAX_PATH_LENGTH];
|
||||||
char m_aFileDialogPrevSearchText[64];
|
char m_aFileDialogFilterString[64];
|
||||||
char *m_pFileDialogPath;
|
char *m_pFileDialogPath;
|
||||||
bool m_FileDialogActivate;
|
|
||||||
int m_FileDialogFileType;
|
int m_FileDialogFileType;
|
||||||
float m_FileDialogScrollValue;
|
|
||||||
int m_FilesSelectedIndex;
|
int m_FilesSelectedIndex;
|
||||||
char m_aFileDialogNewFolderName[64];
|
char m_aFileDialogNewFolderName[64];
|
||||||
char m_aFileDialogErrString[64];
|
char m_aFileDialogErrString[64];
|
||||||
|
@ -971,14 +967,11 @@ public:
|
||||||
bool m_IsDir;
|
bool m_IsDir;
|
||||||
bool m_IsLink;
|
bool m_IsLink;
|
||||||
int m_StorageType;
|
int m_StorageType;
|
||||||
bool m_IsVisible;
|
|
||||||
|
|
||||||
bool operator<(const CFilelistItem &Other) const { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; }
|
bool operator<(const CFilelistItem &Other) const { return !str_comp(m_aFilename, "..") ? true : !str_comp(Other.m_aFilename, "..") ? false : m_IsDir && !Other.m_IsDir ? true : !m_IsDir && Other.m_IsDir ? false : str_comp_filenames(m_aFilename, Other.m_aFilename) < 0; }
|
||||||
};
|
};
|
||||||
std::vector<CFilelistItem> m_vFileList;
|
std::vector<CFilelistItem> m_vCompleteFileList;
|
||||||
int m_FilesStartAt;
|
std::vector<const CFilelistItem *> m_vpFilteredFileList;
|
||||||
int m_FilesCur;
|
|
||||||
int m_FilesStopAt;
|
|
||||||
|
|
||||||
std::vector<std::string> m_vSelectEntitiesFiles;
|
std::vector<std::string> m_vSelectEntitiesFiles;
|
||||||
std::string m_SelectEntitiesImage;
|
std::string m_SelectEntitiesImage;
|
||||||
|
@ -1229,7 +1222,6 @@ public:
|
||||||
void RenderMenubar(CUIRect Menubar);
|
void RenderMenubar(CUIRect Menubar);
|
||||||
void RenderFileDialog();
|
void RenderFileDialog();
|
||||||
|
|
||||||
void AddFileDialogEntry(int Index, CUIRect *pView);
|
|
||||||
void SelectGameLayer();
|
void SelectGameLayer();
|
||||||
void SortImages();
|
void SortImages();
|
||||||
bool SelectLayerByTile();
|
bool SelectLayerByTile();
|
||||||
|
|
Loading…
Reference in a new issue