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
|
||||
ui.cpp
|
||||
ui.h
|
||||
ui_listbox.cpp
|
||||
ui_listbox.h
|
||||
ui_rect.cpp
|
||||
ui_rect.h
|
||||
ui_scrollregion.cpp
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <game/client/components/menu_background.h>
|
||||
#include <game/client/components/sounds.h>
|
||||
#include <game/client/gameclient.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/generated/client_data.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
|
@ -79,7 +80,6 @@ CMenus::CMenus()
|
|||
m_aCallvoteReason[0] = 0;
|
||||
|
||||
m_FriendlistSelectedIndex = -1;
|
||||
m_DoubleClickIndex = -1;
|
||||
|
||||
m_DemoPlayerState = DEMOPLAYER_NONE;
|
||||
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))
|
||||
{
|
||||
m_ShowStart = true;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
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]))
|
||||
{
|
||||
NewPage = PAGE_NEWS;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
}
|
||||
else if(m_ActivePage == PAGE_DEMOS)
|
||||
|
@ -732,7 +730,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
{
|
||||
DemolistPopulate();
|
||||
NewPage = PAGE_DEMOS;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -744,7 +741,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_INTERNET)
|
||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
||||
NewPage = PAGE_INTERNET;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
Box.VSplitLeft(100.0f, &Button, &Box);
|
||||
|
@ -754,7 +750,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_LAN)
|
||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_LAN);
|
||||
NewPage = PAGE_LAN;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
Box.VSplitLeft(100.0f, &Button, &Box);
|
||||
|
@ -764,7 +759,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_FAVORITES)
|
||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_FAVORITES);
|
||||
NewPage = PAGE_FAVORITES;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
Box.VSplitLeft(90.0f, &Button, &Box);
|
||||
|
@ -777,7 +771,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET);
|
||||
}
|
||||
NewPage = PAGE_DDNET;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
Box.VSplitLeft(90.0f, &Button, &Box);
|
||||
|
@ -790,7 +783,6 @@ int CMenus::RenderMenubar(CUIRect r)
|
|||
ServerBrowser()->Refresh(IServerBrowser::TYPE_KOG);
|
||||
}
|
||||
NewPage = PAGE_KOG;
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1323,7 +1315,6 @@ int CMenus::Render()
|
|||
{
|
||||
UpdateMusicState();
|
||||
s_Frame++;
|
||||
m_DoubleClickIndex = -1;
|
||||
|
||||
RefreshBrowserTab(g_Config.m_UiPage);
|
||||
if(g_Config.m_UiPage == PAGE_INTERNET)
|
||||
|
@ -1397,7 +1388,6 @@ int CMenus::Render()
|
|||
{
|
||||
ServerBrowser()->Refresh(IServerBrowser::TYPE_INTERNET);
|
||||
SetMenuPage(PAGE_INTERNET);
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
// render current page
|
||||
|
@ -1837,36 +1827,38 @@ int CMenus::Render()
|
|||
}
|
||||
else if(m_Popup == POPUP_LANGUAGE)
|
||||
{
|
||||
Box = Screen;
|
||||
Box.Margin(150.0f, &Box);
|
||||
Box.HSplitTop(20.f, &Part, &Box);
|
||||
Box.HSplitBottom(20.f, &Box, &Part);
|
||||
Box.HSplitBottom(24.f, &Box, &Part);
|
||||
Box.HSplitBottom(20.f, &Box, 0);
|
||||
CUIRect Button;
|
||||
Screen.Margin(150.0f, &Box);
|
||||
Box.HSplitTop(20.0f, nullptr, &Box);
|
||||
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||
Box.HSplitBottom(24.0f, &Box, &Button);
|
||||
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||
Box.VMargin(20.0f, &Box);
|
||||
RenderLanguageSelection(Box);
|
||||
Part.VMargin(120.0f, &Part);
|
||||
const bool Activated = RenderLanguageSelection(Box);
|
||||
Button.VMargin(120.0f, &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;
|
||||
}
|
||||
else if(m_Popup == POPUP_COUNTRY)
|
||||
{
|
||||
Box = Screen;
|
||||
Box.Margin(150.0f, &Box);
|
||||
Box.HSplitTop(20.f, &Part, &Box);
|
||||
Box.HSplitBottom(20.f, &Box, &Part);
|
||||
Box.HSplitBottom(24.f, &Box, &Part);
|
||||
Box.HSplitBottom(20.f, &Box, 0);
|
||||
CUIRect ButtonBar;
|
||||
Screen.Margin(150.0f, &Box);
|
||||
Box.HSplitTop(20.0f, nullptr, &Box);
|
||||
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||
Box.HSplitBottom(24.0f, &Box, &ButtonBar);
|
||||
Box.HSplitBottom(20.0f, &Box, nullptr);
|
||||
Box.VMargin(20.0f, &Box);
|
||||
ButtonBar.VMargin(100.0f, &ButtonBar);
|
||||
|
||||
static int s_CurSelection = -2;
|
||||
if(s_CurSelection == -2)
|
||||
s_CurSelection = g_Config.m_BrFilterCountryIndex;
|
||||
static float s_ScrollValue = 0.0f;
|
||||
|
||||
static CListBox s_ListBox;
|
||||
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)
|
||||
{
|
||||
|
@ -1874,29 +1866,31 @@ int CMenus::Render()
|
|||
if(pEntry->m_CountryCode == s_CurSelection)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
CUIRect Label;
|
||||
Item.m_Rect.Margin(5.0f, &Item.m_Rect);
|
||||
Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
|
||||
float OldWidth = Item.m_Rect.w;
|
||||
Item.m_Rect.w = Item.m_Rect.h * 2;
|
||||
Item.m_Rect.x += (OldWidth - Item.m_Rect.w) / 2.0f;
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(pEntry, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect FlagRect, Label;
|
||||
Item.m_Rect.Margin(5.0f, &FlagRect);
|
||||
FlagRect.HSplitBottom(12.0f, &FlagRect, &Label);
|
||||
Label.HSplitTop(2.0f, nullptr, &Label);
|
||||
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);
|
||||
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);
|
||||
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER);
|
||||
}
|
||||
m_pClient->m_CountryFlags.Render(pEntry->m_CountryCode, &Color, FlagRect.x, FlagRect.y, FlagRect.w, FlagRect.h);
|
||||
|
||||
SLabelProperties ItemLabelProps;
|
||||
ItemLabelProps.m_AlignVertically = 0;
|
||||
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER, ItemLabelProps);
|
||||
}
|
||||
|
||||
bool Activated = false;
|
||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, &Activated);
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(OldSelected != NewSelected)
|
||||
s_CurSelection = m_pClient->m_CountryFlags.GetByIndex(NewSelected)->m_CountryCode;
|
||||
|
||||
CUIRect CancelButton, OkButton;
|
||||
Part.VMargin(100.0f, &Part);
|
||||
Part.VSplitMid(&CancelButton, &OkButton, 40.0f);
|
||||
ButtonBar.VSplitMid(&CancelButton, &OkButton, 40.0f);
|
||||
|
||||
static CButtonContainer s_CancelButton;
|
||||
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;
|
||||
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;
|
||||
Client()->ServerBrowserUpdate();
|
||||
|
@ -2195,35 +2189,35 @@ void CMenus::PopupConfirmDemoReplaceVideo()
|
|||
}
|
||||
#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;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const int OldSelected = SelectedTheme;
|
||||
|
||||
static int s_ListBox = 0;
|
||||
static float s_ScrollValue = 0.0f;
|
||||
UiDoListboxStart(&s_ListBox, &MainView, 26.0f, Localize("Theme"), "", vThemesRef.size(), 1, -1, s_ScrollValue);
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoHeader(&MainView, Localize("Theme"), 20.0f);
|
||||
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);
|
||||
|
||||
CTheme &Theme = vThemesRef[i];
|
||||
const CTheme &Theme = vThemes[i];
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(&Theme.m_Name, i == SelectedTheme);
|
||||
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect Icon;
|
||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Icon, &Item.m_Rect);
|
||||
CUIRect Icon, Label;
|
||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Icon, &Label);
|
||||
|
||||
// draw icon if it exists
|
||||
if(Theme.m_IconTexture.IsValid())
|
||||
|
@ -2254,16 +2248,18 @@ void CMenus::RenderThemeSelection(CUIRect MainView, bool Header)
|
|||
else // generic
|
||||
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;
|
||||
int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0, &ItemActive);
|
||||
SelectedTheme = s_ListBox.DoEnd();
|
||||
|
||||
if(ItemActive && NewSelected != SelectedTheme)
|
||||
if(OldSelected != SelectedTheme)
|
||||
{
|
||||
str_copy(g_Config.m_ClMenuMap, vThemesRef[NewSelected].m_Name.c_str());
|
||||
m_pBackground->LoadMenuBackground(vThemesRef[NewSelected].m_HasDay, vThemesRef[NewSelected].m_HasNight);
|
||||
const CTheme &Theme = vThemes[SelectedTheme];
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
* 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
|
||||
int m_SelectedIndex;
|
||||
int m_DoubleClickIndex;
|
||||
int m_ScrollOffset;
|
||||
void RenderServerbrowserServerList(CUIRect View);
|
||||
void Connect(const char *pAddress);
|
||||
void PopupConfirmSwitchServer();
|
||||
|
@ -565,8 +547,8 @@ protected:
|
|||
void OnConfigSave(IConfigManager *pConfigManager);
|
||||
|
||||
// found in menus_settings.cpp
|
||||
void RenderLanguageSelection(CUIRect MainView);
|
||||
void RenderThemeSelection(CUIRect MainView, bool Header = true);
|
||||
bool RenderLanguageSelection(CUIRect MainView);
|
||||
void RenderThemeSelection(CUIRect MainView);
|
||||
void RenderSettingsGeneral(CUIRect MainView);
|
||||
void RenderSettingsPlayer(CUIRect MainView);
|
||||
void RenderSettingsDummyPlayer(CUIRect MainView);
|
||||
|
@ -746,7 +728,6 @@ private:
|
|||
static int GhostlistFetchCallback(const char *pName, int IsDir, int StorageType, void *pUser);
|
||||
void SetMenuPage(int NewPage);
|
||||
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
|
||||
void RenderInGameNetwork(CUIRect MainView);
|
||||
|
|
|
@ -12,12 +12,12 @@
|
|||
|
||||
#include <game/client/components/console.h>
|
||||
#include <game/client/components/countryflags.h>
|
||||
#include <game/client/gameclient.h>
|
||||
#include <game/client/render.h>
|
||||
#include <game/client/ui.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include <game/client/gameclient.h>
|
||||
|
||||
#include "menus.h"
|
||||
|
||||
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);
|
||||
|
||||
CUIRect Scroll;
|
||||
View.VSplitRight(20.0f, &View, &Scroll);
|
||||
|
||||
int NumServers = ServerBrowser()->NumSortedServers();
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
static float s_ScrollValue = 0;
|
||||
|
||||
s_ScrollValue = UI()->DoScrollbarV(&s_ScrollValue, &Scroll, s_ScrollValue);
|
||||
|
||||
if(UI()->ConsumeHotkey(CUI::HOTKEY_TAB))
|
||||
{
|
||||
const int Direction = Input()->ShiftIsPressed() ? -1 : 1;
|
||||
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))
|
||||
{
|
||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(m_SelectedIndex);
|
||||
str_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
||||
}
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoStart(ms_ListheaderHeight, NumServers, 1, 3, m_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(NumServers - Num + 1, 0);
|
||||
View.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
||||
|
||||
int NewSelected = -1;
|
||||
bool DoubleClicked = false;
|
||||
int NumPlayers = 0;
|
||||
|
||||
static int s_PrevSelectedIndex = -1;
|
||||
if(s_PrevSelectedIndex != m_SelectedIndex)
|
||||
{
|
||||
s_ListBox.ScrollToSelected();
|
||||
s_PrevSelectedIndex = m_SelectedIndex;
|
||||
}
|
||||
m_SelectedIndex = -1;
|
||||
|
||||
// reset friend counter
|
||||
|
@ -229,23 +214,17 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
|
||||
for(int i = 0; i < NumServers; i++)
|
||||
{
|
||||
int ItemIndex = i;
|
||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(ItemIndex);
|
||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(i);
|
||||
NumPlayers += pItem->m_NumFilteredPlayers;
|
||||
CUIRect Row;
|
||||
|
||||
const int UIRectCount = 2 + (COL_VERSION + 1) * 3;
|
||||
//initialize
|
||||
if(pItem->m_pUIElement == NULL)
|
||||
if(pItem->m_pUIElement == nullptr)
|
||||
{
|
||||
const int UIRectCount = 2 + (COL_VERSION + 1) * 3;
|
||||
pItem->m_pUIElement = UI()->GetNewUIElement(UIRectCount);
|
||||
}
|
||||
|
||||
int Selected = str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0; //selected_index==ItemIndex;
|
||||
|
||||
View.HSplitTop(ms_ListheaderHeight, &Row, &View);
|
||||
|
||||
if(Selected)
|
||||
const CListboxItem ListItem = s_ListBox.DoNextItem(pItem, str_comp(pItem->m_aAddress, g_Config.m_UiServerAddress) == 0);
|
||||
if(ListItem.m_Selected)
|
||||
m_SelectedIndex = i;
|
||||
|
||||
// update friend counter
|
||||
|
@ -273,31 +252,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
}
|
||||
}
|
||||
|
||||
// make sure that only those in view can be selected
|
||||
if(Row.y + Row.h > OriginalView.y && Row.y < OriginalView.y + OriginalView.h)
|
||||
{
|
||||
if(Selected)
|
||||
{
|
||||
CUIRect r = Row;
|
||||
r.Margin(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
|
||||
if(!ListItem.m_Visible)
|
||||
{
|
||||
// reset active item, if not visible
|
||||
if(UI()->CheckActiveItem(pItem))
|
||||
|
@ -312,8 +267,8 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
CUIRect Button;
|
||||
char aTemp[64];
|
||||
Button.x = s_aCols[c].m_Rect.x;
|
||||
Button.y = Row.y;
|
||||
Button.h = Row.h;
|
||||
Button.y = ListItem.m_Rect.y;
|
||||
Button.h = ListItem.m_Rect.h;
|
||||
Button.w = s_aCols[c].m_Rect.w;
|
||||
|
||||
int ID = s_aCols[c].m_ID;
|
||||
|
@ -469,16 +424,22 @@ void CMenus::RenderServerbrowserServerList(CUIRect View)
|
|||
}
|
||||
}
|
||||
|
||||
UI()->ClipDisable();
|
||||
|
||||
if(NewSelected != -1)
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(NewSelected != m_SelectedIndex)
|
||||
{
|
||||
m_SelectedIndex = NewSelected;
|
||||
if(m_SelectedIndex >= 0)
|
||||
{
|
||||
// select the new server
|
||||
const CServerInfo *pItem = ServerBrowser()->SortedGet(NewSelected);
|
||||
if(pItem)
|
||||
{
|
||||
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.
|
||||
// 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)
|
||||
{
|
||||
static int s_VoteList = 0;
|
||||
static float s_ScrollValue = 0;
|
||||
UiDoListboxStart(&s_VoteList, &ServerScoreBoard, 26.0f, Localize("Scoreboard"), "", pSelectedServer->m_NumReceivedClients, 1, -1, s_ScrollValue);
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoAutoSpacing(1.0f);
|
||||
s_ListBox.DoStart(25.0f, pSelectedServer->m_NumReceivedClients, 1, 3, -1, &ServerScoreBoard);
|
||||
|
||||
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)
|
||||
continue;
|
||||
|
||||
CUIRect Name, Clan, Score, Flag;
|
||||
Item.m_Rect.HSplitTop(25.0f, &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();
|
||||
}
|
||||
Name = Item.m_Rect;
|
||||
|
||||
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(0.5f, 1.0f, 0.5f, 0.15f + (i % 2 + 1) * 0.05f);
|
||||
Name.Draw(Color, IGraphics::CORNER_ALL, 4.0f);
|
||||
|
@ -1159,17 +1112,17 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
|||
// score
|
||||
char aTemp[16];
|
||||
|
||||
if(!pSelectedServer->m_aClients[i].m_Player)
|
||||
if(!CurrentClient.m_Player)
|
||||
str_copy(aTemp, "SPEC");
|
||||
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;
|
||||
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
|
||||
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;
|
||||
while(ScoreFontSize >= 4.0f && TextRender()->TextWidth(0, ScoreFontSize, aTemp, -1, -1.0f) > Score.w)
|
||||
|
@ -1182,7 +1135,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
|||
// name
|
||||
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;
|
||||
const char *pName = pSelectedServer->m_aClients[i].m_aName;
|
||||
const char *pName = CurrentClient.m_aName;
|
||||
bool Printed = false;
|
||||
if(g_Config.m_BrFilterString[0])
|
||||
Printed = PrintHighlighted(pName, [this, &Cursor, pName](const char *pFilteredStr, const int FilterLen) {
|
||||
|
@ -1198,7 +1151,7 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
|||
// clan
|
||||
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;
|
||||
const char *pClan = pSelectedServer->m_aClients[i].m_aClan;
|
||||
const char *pClan = CurrentClient.m_aClan;
|
||||
Printed = false;
|
||||
if(g_Config.m_BrFilterString[0])
|
||||
Printed = PrintHighlighted(pClan, [this, &Cursor, pClan](const char *pFilteredStr, const int FilterLen) {
|
||||
|
@ -1213,10 +1166,20 @@ void CMenus::RenderServerbrowserServerDetail(CUIRect View)
|
|||
|
||||
// flag
|
||||
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);
|
||||
ServerFriends.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 4.0f);
|
||||
UI()->DoLabel(&FilterHeader, Localize("Friends"), FontSize + 4.0f, TEXTALIGN_CENTER);
|
||||
CUIRect Button, List;
|
||||
|
||||
CUIRect List;
|
||||
ServerFriends.Margin(3.0f, &ServerFriends);
|
||||
ServerFriends.VMargin(3.0f, &ServerFriends);
|
||||
ServerFriends.HSplitBottom(100.0f, &List, &ServerFriends);
|
||||
|
||||
// friends list(remove friend)
|
||||
static float s_ScrollValue = 0;
|
||||
static CListBox s_ListBox;
|
||||
if(m_FriendlistSelectedIndex >= (int)m_vFriends.size())
|
||||
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());
|
||||
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)
|
||||
{
|
||||
Item.m_Rect.Margin(1.5f, &Item.m_Rect);
|
||||
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);
|
||||
CUIRect NameClanLabels, NameLabel, ClanLabel, OnState;
|
||||
Item.m_Rect.VSplitRight(30.0f, &NameClanLabels, &OnState);
|
||||
NameClanLabels.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.1f), IGraphics::CORNER_L, 4.0f);
|
||||
|
||||
Item.m_Rect.VMargin(2.5f, &Item.m_Rect);
|
||||
Item.m_Rect.HSplitTop(12.0f, &Item.m_Rect, &Button);
|
||||
UI()->DoLabel(&Item.m_Rect, Friend.m_pFriendInfo->m_aName, FontSize, TEXTALIGN_LEFT);
|
||||
UI()->DoLabel(&Button, Friend.m_pFriendInfo->m_aClan, FontSize, TEXTALIGN_LEFT);
|
||||
NameClanLabels.VMargin(2.5f, &NameClanLabels);
|
||||
NameClanLabels.HSplitTop(12.0f, &NameLabel, &ClanLabel);
|
||||
UI()->DoLabel(&NameLabel, Friend.m_pFriendInfo->m_aName, 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.HMargin((OnState.h - FontSize) / 3, &OnState);
|
||||
|
@ -1312,13 +1276,11 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
|||
str_format(aBuf, sizeof(aBuf), "%i", Friend.m_NumFound);
|
||||
UI()->DoLabel(&OnState, aBuf, FontSize + 2, TEXTALIGN_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
bool Activated = false;
|
||||
m_FriendlistSelectedIndex = UiDoListboxEnd(&s_ScrollValue, &Activated);
|
||||
m_FriendlistSelectedIndex = s_ListBox.DoEnd();
|
||||
|
||||
// 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;
|
||||
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_copy(g_Config.m_UiServerAddress, pItem->m_aAddress);
|
||||
m_ScrollOffset = ItemIndex;
|
||||
m_SelectedIndex = ItemIndex;
|
||||
Found = true;
|
||||
}
|
||||
|
@ -1345,6 +1306,7 @@ void CMenus::RenderServerbrowserFriends(CUIRect View)
|
|||
}
|
||||
}
|
||||
|
||||
CUIRect Button;
|
||||
ServerFriends.HSplitTop(2.5f, 0, &ServerFriends);
|
||||
ServerFriends.HSplitTop(20.0f, &Button, &ServerFriends);
|
||||
if(m_FriendlistSelectedIndex != -1)
|
||||
|
|
|
@ -14,11 +14,10 @@
|
|||
#include <game/client/components/console.h>
|
||||
#include <game/client/gameclient.h>
|
||||
#include <game/client/render.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include <game/client/ui.h>
|
||||
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/generated/client_data.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include "maplayers.h"
|
||||
#include "menus.h"
|
||||
|
@ -636,246 +635,6 @@ void CMenus::RenderDemoPlayer(CUIRect MainView)
|
|||
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)
|
||||
{
|
||||
CMenus *pSelf = (CMenus *)pUser;
|
||||
|
@ -1206,78 +965,26 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
}
|
||||
}
|
||||
|
||||
// scrollbar
|
||||
CUIRect Scroll;
|
||||
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;
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoStart(ms_ListheaderHeight, m_vDemos.size(), 1, 3, m_DemolistSelectedIndex, &ListBox, false);
|
||||
|
||||
int ItemIndex = -1;
|
||||
bool DoubleClicked = false;
|
||||
|
||||
for(auto &Item : m_vDemos)
|
||||
{
|
||||
ItemIndex++;
|
||||
|
||||
CUIRect Row;
|
||||
ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox);
|
||||
|
||||
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
|
||||
const CListboxItem ListItem = s_ListBox.DoNextItem(&Item, ItemIndex == m_DemolistSelectedIndex);
|
||||
if(!ListItem.m_Visible)
|
||||
continue;
|
||||
}
|
||||
|
||||
CUIRect Row = ListItem.m_Rect;
|
||||
CUIRect FileIcon;
|
||||
Row.VSplitLeft(Row.h, &FileIcon, &Row);
|
||||
Row.VSplitLeft(5.0f, 0, &Row);
|
||||
FileIcon.Margin(1.0f, &FileIcon);
|
||||
FileIcon.x += 2.0f;
|
||||
const char *pIconType;
|
||||
|
||||
const char *pIconType;
|
||||
if(str_comp(Item.m_aFilename, "..") == 0)
|
||||
pIconType = "\xEF\xA0\x82";
|
||||
else if(Item.m_IsDir)
|
||||
|
@ -1338,13 +1045,13 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
}
|
||||
}
|
||||
|
||||
UI()->ClipDisable();
|
||||
|
||||
bool Activated = false;
|
||||
if(UI()->ConsumeHotkey(CUI::HOTKEY_ENTER) || (DoubleClicked && Input()->MouseDoubleClick()))
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(NewSelected != m_DemolistSelectedIndex)
|
||||
{
|
||||
UI()->SetActiveItem(nullptr);
|
||||
Activated = true;
|
||||
m_DemolistSelectedIndex = NewSelected;
|
||||
if(m_DemolistSelectedIndex >= 0)
|
||||
str_copy(g_Config.m_UiDemoSelected, m_vDemos[m_DemolistSelectedIndex].m_aName);
|
||||
DemolistOnUpdate(false);
|
||||
}
|
||||
|
||||
static CButtonContainer s_RefreshButton;
|
||||
|
@ -1362,7 +1069,7 @@ void CMenus::RenderDemoList(CUIRect MainView)
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <game/client/gameclient.h>
|
||||
#include <game/client/render.h>
|
||||
#include <game/client/ui.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/client/ui_scrollregion.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
|
@ -242,16 +243,15 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
|||
ButtonBar.VSplitLeft(Width, &Button, &ButtonBar);
|
||||
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);
|
||||
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);
|
||||
RenderTools()->RenderIcon(IMAGE_GUIICONS, SPRITE_GUIICON_FRIEND, &Button);
|
||||
|
||||
int TotalPlayers = 0;
|
||||
|
||||
for(const auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName)
|
||||
{
|
||||
if(!pInfoByName)
|
||||
|
@ -265,14 +265,11 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
|||
TotalPlayers++;
|
||||
}
|
||||
|
||||
static int s_VoteList = 0;
|
||||
static float s_ScrollValue = 0;
|
||||
CUIRect List = Options;
|
||||
// List.HSplitTop(28.0f, 0, &List);
|
||||
UiDoListboxStart(&s_VoteList, &List, 24.0f, "", "", TotalPlayers, 1, -1, s_ScrollValue);
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoStart(24.0f, TotalPlayers, 1, 3, -1, &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)
|
||||
{
|
||||
|
@ -280,25 +277,27 @@ void CMenus::RenderPlayers(CUIRect MainView)
|
|||
continue;
|
||||
|
||||
int Index = m_pClient->m_Snap.m_apInfoByName[i]->m_ClientID;
|
||||
|
||||
if(Index == m_pClient->m_Snap.m_LocalClientID)
|
||||
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++;
|
||||
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect Row = Item.m_Rect;
|
||||
if(Count % 2 == 1)
|
||||
Item.m_Rect.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 10.0f);
|
||||
Item.m_Rect.VSplitRight(300.0f, &Player, &Item.m_Rect);
|
||||
Row.Draw(ColorRGBA(1.0f, 1.0f, 1.0f, 0.25f), IGraphics::CORNER_ALL, 5.0f);
|
||||
Row.VSplitRight(s_ListBox.ScrollbarWidthMax() - s_ListBox.ScrollbarWidth(), &Row, nullptr);
|
||||
Row.VSplitRight(300.0f, &Player, &Row);
|
||||
|
||||
// player info
|
||||
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;
|
||||
|
||||
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);
|
||||
|
||||
Player.HSplitTop(1.5f, 0, &Player);
|
||||
Player.HSplitTop(1.5f, nullptr, &Player);
|
||||
Player.VSplitMid(&Player, &Button);
|
||||
Item.m_Rect.VSplitRight(200.0f, &Button2, &Item.m_Rect);
|
||||
Row.VSplitRight(210.0f, &Button2, &Row);
|
||||
CTextCursor Cursor;
|
||||
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;
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
// ignore chat button
|
||||
Item.m_Rect.HMargin(2.0f, &Item.m_Rect);
|
||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, 0);
|
||||
if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
|
||||
Row.HMargin(2.0f, &Row);
|
||||
Row.VSplitLeft(Width, &Button, &Row);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||
if(g_Config.m_ClShowChatFriends && !CurrentClient.m_Friend)
|
||||
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))
|
||||
m_pClient->m_aClients[Index].m_ChatIgnore ^= 1;
|
||||
else if(DoButton_Toggle(&s_aPlayerIDs[Index][0], CurrentClient.m_ChatIgnore, &Button, true))
|
||||
CurrentClient.m_ChatIgnore ^= 1;
|
||||
|
||||
// ignore emoticon button
|
||||
Item.m_Rect.VSplitLeft(20.0f, &Button, &Item.m_Rect);
|
||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, 0);
|
||||
if(g_Config.m_ClShowChatFriends && !m_pClient->m_aClients[Index].m_Friend)
|
||||
Row.VSplitLeft(30.0f, nullptr, &Row);
|
||||
Row.VSplitLeft(Width, &Button, &Row);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||
if(g_Config.m_ClShowChatFriends && !CurrentClient.m_Friend)
|
||||
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))
|
||||
m_pClient->m_aClients[Index].m_EmoticonIgnore ^= 1;
|
||||
else if(DoButton_Toggle(&s_aPlayerIDs[Index][1], CurrentClient.m_EmoticonIgnore, &Button, true))
|
||||
CurrentClient.m_EmoticonIgnore ^= 1;
|
||||
|
||||
// friend button
|
||||
Item.m_Rect.VSplitLeft(20.0f, &Button, &Item.m_Rect);
|
||||
Item.m_Rect.VSplitLeft(Width, &Button, &Item.m_Rect);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, 0, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, 0);
|
||||
if(DoButton_Toggle(&s_aPlayerIDs[Index][2], m_pClient->m_aClients[Index].m_Friend, &Button, true))
|
||||
Row.VSplitLeft(10.0f, nullptr, &Row);
|
||||
Row.VSplitLeft(Width, &Button, &Row);
|
||||
Button.VSplitLeft((Width - Button.h) / 4.0f, nullptr, &Button);
|
||||
Button.VSplitLeft(Button.h, &Button, nullptr);
|
||||
if(DoButton_Toggle(&s_aPlayerIDs[Index][2], CurrentClient.m_Friend, &Button, true))
|
||||
{
|
||||
if(m_pClient->m_aClients[Index].m_Friend)
|
||||
m_pClient->Friends()->RemoveFriend(m_pClient->m_aClients[Index].m_aName, m_pClient->m_aClients[Index].m_aClan);
|
||||
if(CurrentClient.m_Friend)
|
||||
m_pClient->Friends()->RemoveFriend(CurrentClient.m_aName, CurrentClient.m_aClan);
|
||||
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)
|
||||
|
@ -492,8 +489,6 @@ void CMenus::RenderServerInfo(CUIRect MainView)
|
|||
|
||||
bool CMenus::RenderServerControlServer(CUIRect MainView)
|
||||
{
|
||||
static int s_VoteList = 0;
|
||||
static float s_ScrollValue = 0;
|
||||
CUIRect List = MainView;
|
||||
int Total = m_pClient->m_Voting.m_NumVoteOptions;
|
||||
int NumVoteOptions = 0;
|
||||
|
@ -508,7 +503,8 @@ bool CMenus::RenderServerControlServer(CUIRect MainView)
|
|||
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;
|
||||
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))
|
||||
continue;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(pOption);
|
||||
|
||||
if(Item.m_Visible)
|
||||
UI()->DoLabel(&Item.m_Rect, pOption->m_aDescription, 13.0f, TEXTALIGN_LEFT);
|
||||
|
||||
if(NumVoteOptions < Total)
|
||||
aIndices[NumVoteOptions] = i;
|
||||
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 = UiDoListboxEnd(&s_ScrollValue, &Call);
|
||||
s_CurVoteOption = s_ListBox.DoEnd();
|
||||
if(s_CurVoteOption < Total)
|
||||
m_CallvoteSelectedOption = aIndices[s_CurVoteOption];
|
||||
return Call;
|
||||
return s_ListBox.WasItemActivated();
|
||||
}
|
||||
|
||||
bool CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
|
||||
|
@ -556,36 +554,36 @@ bool CMenus::RenderServerControlKick(CUIRect MainView, bool FilterSpectators)
|
|||
aPlayerIDs[NumOptions++] = Index;
|
||||
}
|
||||
|
||||
static int s_VoteList = 0;
|
||||
static float s_ScrollValue = 0;
|
||||
CUIRect List = MainView;
|
||||
UiDoListboxStart(&s_VoteList, &List, 24.0f, "", "", NumOptions, 1, Selected, s_ScrollValue);
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoStart(24.0f, NumOptions, 1, 3, Selected, &MainView);
|
||||
|
||||
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;
|
||||
TeeInfo.m_Size = Item.m_Rect.h;
|
||||
TeeInfo.m_Size = TeeRect.h;
|
||||
|
||||
CAnimState *pIdleState = CAnimState::GetIdle();
|
||||
vec2 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);
|
||||
|
||||
Item.m_Rect.x += TeeInfo.m_Size;
|
||||
UI()->DoLabel(&Item.m_Rect, m_pClient->m_aClients[aPlayerIDs[i]].m_aName, 16.0f, TEXTALIGN_LEFT);
|
||||
}
|
||||
SLabelProperties Props;
|
||||
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 = UiDoListboxEnd(&s_ScrollValue, &Call);
|
||||
Selected = s_ListBox.DoEnd();
|
||||
m_CallvoteSelectedPlayer = Selected != -1 ? aPlayerIDs[Selected] : -1;
|
||||
return Call;
|
||||
return s_ListBox.WasItemActivated();
|
||||
}
|
||||
|
||||
void CMenus::RenderServerControl(CUIRect MainView)
|
||||
|
@ -1007,70 +1005,37 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
|
||||
View.Draw(ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
||||
|
||||
CUIRect Scroll;
|
||||
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();
|
||||
const int NumGhosts = m_vGhosts.size();
|
||||
static int s_SelectedIndex = 0;
|
||||
HandleListInputs(View, s_ScrollValue, 1.0f, nullptr, s_aCols[0].m_Rect.h, s_SelectedIndex, NumGhosts);
|
||||
|
||||
// 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;
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoStart(17.0f, NumGhosts, 1, 3, s_SelectedIndex, &View, false);
|
||||
|
||||
for(int i = 0; i < NumGhosts; i++)
|
||||
{
|
||||
const CGhostItem *pItem = &m_vGhosts[i];
|
||||
CUIRect Row;
|
||||
View.HSplitTop(17.0f, &Row, &View);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
const CGhostItem *pGhost = &m_vGhosts[i];
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(pGhost);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
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));
|
||||
|
||||
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++)
|
||||
{
|
||||
CUIRect Button;
|
||||
Button.x = s_aCols[c].m_Rect.x;
|
||||
Button.y = Row.y;
|
||||
Button.h = Row.h;
|
||||
Button.y = Item.m_Rect.y;
|
||||
Button.h = Item.m_Rect.h;
|
||||
Button.w = s_aCols[c].m_Rect.w;
|
||||
|
||||
int Id = s_aCols[c].m_Id;
|
||||
|
||||
if(Id == COL_ACTIVE)
|
||||
{
|
||||
if(pItem->Active())
|
||||
if(pGhost->Active())
|
||||
{
|
||||
Graphics()->WrapClamp();
|
||||
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);
|
||||
Cursor.m_LineWidth = Button.w;
|
||||
|
||||
TextRender()->TextEx(&Cursor, pItem->m_aPlayer, -1);
|
||||
TextRender()->TextEx(&Cursor, pGhost->m_aPlayer, -1);
|
||||
}
|
||||
else if(Id == COL_TIME)
|
||||
{
|
||||
|
@ -1097,7 +1062,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
Cursor.m_LineWidth = Button.w;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1105,10 +1070,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
UI()->ClipDisable();
|
||||
|
||||
if(NewSelected != -1)
|
||||
s_SelectedIndex = NewSelected;
|
||||
s_SelectedIndex = s_ListBox.DoEnd();
|
||||
|
||||
Status.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_B, 5.0f);
|
||||
Status.Margin(5.0f, &Status);
|
||||
|
@ -1136,7 +1098,7 @@ void CMenus::RenderGhost(CUIRect MainView)
|
|||
|
||||
static CButtonContainer s_GhostButton;
|
||||
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())
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <game/client/render.h>
|
||||
#include <game/client/skin.h>
|
||||
#include <game/client/ui.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/client/ui_scrollregion.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
|
@ -366,9 +367,9 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
|
|||
|
||||
// country flag selector
|
||||
MainView.HSplitTop(20.0f, 0, &MainView);
|
||||
static float s_ScrollValue = 0.0f;
|
||||
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)
|
||||
{
|
||||
|
@ -376,26 +377,29 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
|
|||
if(pEntry->m_CountryCode == *pCountry)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, s_ListBoxUsed);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
Item.m_Rect.Margin(5.0f, &Item.m_Rect);
|
||||
Item.m_Rect.HSplitBottom(10.0f, &Item.m_Rect, &Label);
|
||||
float OldWidth = Item.m_Rect.w;
|
||||
Item.m_Rect.w = Item.m_Rect.h * 2;
|
||||
Item.m_Rect.x += (OldWidth - Item.m_Rect.w) / 2.0f;
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(&pEntry->m_CountryCode, OldSelected >= 0 && (size_t)OldSelected == i, &s_ListBoxUsed);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect FlagRect;
|
||||
Item.m_Rect.Margin(5.0f, &FlagRect);
|
||||
FlagRect.HSplitBottom(12.0f, &FlagRect, &Label);
|
||||
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);
|
||||
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())
|
||||
{
|
||||
SLabelProperties ItemLabelProps;
|
||||
ItemLabelProps.m_AlignVertically = 0;
|
||||
UI()->DoLabel(&Label, pEntry->m_aCountryCodeString, 10.0f, TEXTALIGN_CENTER);
|
||||
}
|
||||
}
|
||||
|
||||
bool Clicked = false;
|
||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0, &Clicked);
|
||||
if(Clicked)
|
||||
s_ListBoxUsed = true;
|
||||
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(OldSelected != NewSelected)
|
||||
{
|
||||
*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_vFavoriteSkinListHelper;
|
||||
static int s_SkinCount = 0;
|
||||
static float s_ScrollValue = 0.0f;
|
||||
static CListBox s_ListBox;
|
||||
|
||||
// be nice to the CPU
|
||||
static auto s_SkinLastRebuildTime = time_get_nanoseconds();
|
||||
const auto CurTime = time_get_nanoseconds();
|
||||
|
@ -780,7 +785,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
};
|
||||
|
||||
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)
|
||||
{
|
||||
const CSkin *pSkinToBeDraw = s_vSkinList[i].m_pSkin;
|
||||
|
@ -788,10 +793,11 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
if(str_comp(pSkinToBeDraw->GetName(), pSkinName) == 0)
|
||||
OldSelected = i;
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
auto OriginalRect = Item.m_Rect;
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(pSkinToBeDraw, OldSelected >= 0 && (size_t)OldSelected == i);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
const CUIRect OriginalRect = Item.m_Rect;
|
||||
|
||||
CTeeRenderInfo Info = OwnSkinInfo;
|
||||
Info.m_CustomColoredSkin = *pUseCustomColor;
|
||||
|
@ -801,14 +807,15 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
Info.m_SkinMetrics = pSkinToBeDraw->m_Metrics;
|
||||
|
||||
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);
|
||||
|
||||
Item.m_Rect.VSplitLeft(60.0f, 0, &Item.m_Rect);
|
||||
OriginalRect.VSplitLeft(60.0f, 0, &Label);
|
||||
{
|
||||
SLabelProperties Props;
|
||||
Props.m_MaxWidth = Item.m_Rect.w;
|
||||
UI()->DoLabel(&Item.m_Rect, pSkinToBeDraw->GetName(), 12.0f, TEXTALIGN_LEFT, Props);
|
||||
Props.m_MaxWidth = Label.w;
|
||||
Props.m_AlignVertically = 0;
|
||||
UI()->DoLabel(&Label, pSkinToBeDraw->GetName(), 12.0f, TEXTALIGN_LEFT, Props);
|
||||
}
|
||||
if(g_Config.m_Debug)
|
||||
{
|
||||
|
@ -816,7 +823,7 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
|
|||
Graphics()->TextureClear();
|
||||
Graphics()->QuadsBegin();
|
||||
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()->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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
const float RowHeight = 24.0f;
|
||||
const float RowSpacing = 3.0f;
|
||||
CUIRect ListRect;
|
||||
pRect->HSplitTop(24.0f * PickNum, &ListRect, pRect);
|
||||
char aBuf[1024];
|
||||
UiDoListboxStart(&pButtonContainer, &ListRect, 24.0f, "", aBuf, PickNum, 1, CurSelection, ScrollVal);
|
||||
pRect->HSplitTop((RowHeight + RowSpacing) * PickNum, &ListRect, pRect);
|
||||
static CListBox s_ListBox;
|
||||
s_ListBox.DoAutoSpacing(RowSpacing);
|
||||
s_ListBox.DoStart(RowHeight, PickNum, 1, 3, CurSelection, &ListRect);
|
||||
for(int i = 0; i < PickNum; ++i)
|
||||
{
|
||||
CListboxItem Item = UiDoListboxNextItem(pIDs[i], CurSelection == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
str_copy(aBuf, pStr[i]);
|
||||
UI()->DoLabel(&Item.m_Rect, aBuf, 16.0f, TEXTALIGN_CENTER);
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(pIDs[i], CurSelection == i);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
SLabelProperties Props;
|
||||
Props.m_AlignVertically = 0;
|
||||
UI()->DoLabel(&Item.m_Rect, pStr[i], 16.0f, TEXTALIGN_CENTER, Props);
|
||||
}
|
||||
}
|
||||
bool ClickedItem = false;
|
||||
int NewIndex = UiDoListboxEnd(&ScrollVal, NULL, &ClickedItem);
|
||||
if(ClickedItem)
|
||||
int NewIndex = s_ListBox.DoEnd();
|
||||
if(s_ListBox.WasItemSelected() || s_ListBox.WasItemActivated())
|
||||
{
|
||||
CurDropDownState = 0;
|
||||
return NewIndex;
|
||||
|
@ -1518,7 +1527,7 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
MainView.VSplitLeft(340.0f, &MainView, 0);
|
||||
|
||||
// display mode list
|
||||
static float s_ScrollValue = 0;
|
||||
static CListBox s_ListBox;
|
||||
static const float sc_RowHeightResList = 22.0f;
|
||||
static const float sc_FontSizeResListHeader = 12.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);
|
||||
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)
|
||||
{
|
||||
|
@ -1542,16 +1551,18 @@ void CMenus::RenderSettingsGraphics(CUIRect MainView)
|
|||
OldSelected = i;
|
||||
}
|
||||
|
||||
CListboxItem Item = UiDoListboxNextItem(&s_aModes[i], OldSelected == i);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
const CListboxItem Item = s_ListBox.DoNextItem(&s_aModes[i], OldSelected == i);
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
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);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
void CMenus::RenderLanguageSelection(CUIRect MainView)
|
||||
bool CMenus::RenderLanguageSelection(CUIRect MainView)
|
||||
{
|
||||
static int s_LanguageList = 0;
|
||||
static int s_SelectedLanguage = 0;
|
||||
static int s_SelectedLanguage = -1;
|
||||
static std::vector<CLanguage> s_vLanguages;
|
||||
static float s_ScrollValue = 0;
|
||||
static CListBox s_ListBox;
|
||||
|
||||
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)
|
||||
{
|
||||
CListboxItem Item = UiDoListboxNextItem(&Language.m_Name);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
CUIRect Rect;
|
||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &Rect, &Item.m_Rect);
|
||||
Rect.VMargin(6.0f, &Rect);
|
||||
Rect.HMargin(3.0f, &Rect);
|
||||
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)
|
||||
continue;
|
||||
|
||||
CUIRect FlagRect, Label;
|
||||
Item.m_Rect.VSplitLeft(Item.m_Rect.h * 2.0f, &FlagRect, &Label);
|
||||
FlagRect.VMargin(6.0f, &FlagRect);
|
||||
FlagRect.HMargin(3.0f, &FlagRect);
|
||||
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);
|
||||
Item.m_Rect.HSplitTop(2.0f, 0, &Item.m_Rect);
|
||||
UI()->DoLabel(&Item.m_Rect, Language.m_Name.c_str(), 16.0f, TEXTALIGN_LEFT);
|
||||
}
|
||||
m_pClient->m_CountryFlags.Render(Language.m_CountryCode, &Color, FlagRect.x, FlagRect.y, FlagRect.w, FlagRect.h);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -2141,6 +2153,8 @@ void CMenus::RenderLanguageSelection(CUIRect MainView)
|
|||
g_Localization.Load(s_vLanguages[s_SelectedLanguage].m_FileName.c_str(), Storage(), Console());
|
||||
GameClient()->OnLanguageChange();
|
||||
}
|
||||
|
||||
return s_ListBox.WasItemActivated();
|
||||
}
|
||||
|
||||
void CMenus::RenderSettings(CUIRect MainView)
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
#include <engine/shared/config.h>
|
||||
#include <engine/storage.h>
|
||||
#include <engine/textrender.h>
|
||||
|
||||
#include <game/client/gameclient.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/localization.h>
|
||||
|
||||
#include "menus.h"
|
||||
|
@ -457,7 +459,6 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
|
||||
// skin selector
|
||||
MainView.HSplitTop(MainView.h - 10.0f - ms_ButtonHeight, &CustomList, &MainView);
|
||||
static float s_ScrollValue = 0.0f;
|
||||
if(gs_aInitCustomList[s_CurCustomTab])
|
||||
{
|
||||
int ListSize = 0;
|
||||
|
@ -533,7 +534,8 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
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)
|
||||
{
|
||||
const SCustomItem *pItem = GetCustomItem(s_CurCustomTab, i);
|
||||
|
@ -571,11 +573,12 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
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;
|
||||
ItemRect.Margin(Margin / 2, &ItemRect);
|
||||
if(Item.m_Visible)
|
||||
{
|
||||
if(!Item.m_Visible)
|
||||
continue;
|
||||
|
||||
CUIRect TextureRect;
|
||||
ItemRect.HSplitTop(15, &ItemRect, &TextureRect);
|
||||
TextureRect.HSplitTop(10, NULL, &TextureRect);
|
||||
|
@ -592,9 +595,8 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
|
|||
Graphics()->WrapNormal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int NewSelected = UiDoListboxEnd(&s_ScrollValue, 0);
|
||||
const int NewSelected = s_ListBox.DoEnd();
|
||||
if(OldSelected != NewSelected)
|
||||
{
|
||||
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);
|
||||
}
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
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);
|
||||
s_JoinTutorialTime = 0.0f;
|
||||
}
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
m_DoubleClickIndex = -1;
|
||||
}
|
||||
|
||||
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/render.h>
|
||||
#include <game/client/ui.h>
|
||||
#include <game/client/ui_listbox.h>
|
||||
#include <game/client/ui_scrollregion.h>
|
||||
#include <game/generated/client_data.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_IsLink = false;
|
||||
Item.m_StorageType = StorageType;
|
||||
pEditor->m_vFileList.push_back(Item);
|
||||
pEditor->m_vCompleteFileList.push_back(Item);
|
||||
|
||||
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()
|
||||
{
|
||||
// GUI coordsys
|
||||
|
@ -4318,7 +4264,7 @@ void CEditor::RenderFileDialog()
|
|||
View.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 5.0f);
|
||||
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(5.0f, nullptr, &View); // some spacing
|
||||
View.HSplitBottom(14.0f, &View, &ButtonBar);
|
||||
|
@ -4330,7 +4276,6 @@ void CEditor::RenderFileDialog()
|
|||
View.HSplitBottom(10.0f, &View, nullptr); // some spacing
|
||||
if(m_FileDialogFileType == CEditor::FILETYPE_IMG)
|
||||
View.VSplitMid(&View, &Preview);
|
||||
View.VSplitRight(20.0f, &View, &Scroll);
|
||||
|
||||
// title
|
||||
Title.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
|
||||
|
@ -4340,15 +4285,17 @@ void CEditor::RenderFileDialog()
|
|||
// pathbox
|
||||
char aPath[128], aBuf[128];
|
||||
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
|
||||
aPath[0] = 0;
|
||||
str_format(aBuf, sizeof(aBuf), "Current path: %s", aPath);
|
||||
UI()->DoLabel(&PathBox, aBuf, 10.0f, TEXTALIGN_LEFT);
|
||||
|
||||
// filebox
|
||||
static CListBox s_ListBox;
|
||||
|
||||
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
|
||||
{
|
||||
// filebox
|
||||
UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, TEXTALIGN_LEFT);
|
||||
static float s_FileBoxID = 0;
|
||||
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] == '\\')
|
||||
str_copy(&m_aFileDialogFileName[i], &m_aFileDialogFileName[i + 1], (int)(sizeof(m_aFileDialogFileName)) - i);
|
||||
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)
|
||||
|
@ -4365,119 +4325,73 @@ void CEditor::RenderFileDialog()
|
|||
}
|
||||
else
|
||||
{
|
||||
//searchbox
|
||||
// render search bar
|
||||
FileBox.VSplitRight(250, &FileBox, nullptr);
|
||||
CUIRect ClearBox;
|
||||
FileBox.VSplitRight(15, &FileBox, &ClearBox);
|
||||
|
||||
UI()->DoLabel(&FileBoxLabel, "Search:", 10.0f, TEXTALIGN_LEFT);
|
||||
str_copy(m_aFileDialogPrevSearchText, m_aFileDialogSearchText, sizeof(m_aFileDialogPrevSearchText));
|
||||
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)
|
||||
UI()->SetActiveItem(&s_SearchBoxID);
|
||||
|
||||
// clearSearchbox button
|
||||
// clear search button
|
||||
{
|
||||
static int s_ClearButton = 0;
|
||||
ClearBox.Draw(ColorRGBA(1, 1, 1, 0.33f * UI()->ButtonColorMul(&s_ClearButton)), IGraphics::CORNER_R, 3.0f);
|
||||
UI()->DoLabel(&ClearBox, "×", 10.0f, TEXTALIGN_CENTER);
|
||||
if(UI()->DoButtonLogic(&s_ClearButton, 0, &ClearBox))
|
||||
{
|
||||
m_aFileDialogSearchText[0] = 0;
|
||||
SearchUpdated = true;
|
||||
m_aFileDialogFilterString[0] = 0;
|
||||
UI()->SetActiveItem(&s_SearchBoxID);
|
||||
}
|
||||
}
|
||||
|
||||
if(str_comp(m_aFileDialogPrevSearchText, m_aFileDialogSearchText))
|
||||
m_FileDialogScrollValue = 0.0f;
|
||||
if(SearchUpdated)
|
||||
{
|
||||
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;
|
||||
|
||||
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_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(str_endswith(m_vFileList[m_FilesSelectedIndex].m_aFilename, ".png"))
|
||||
if(str_endswith(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, ".png"))
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
@ -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)
|
||||
m_FileDialogActivate = true;
|
||||
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_vpFilteredFileList[i]->m_aFilename, "..") == 0)
|
||||
pIconType = "\xEF\xA0\x82";
|
||||
else
|
||||
pIconType = "\xEF\x81\xBB";
|
||||
}
|
||||
|
||||
if(m_FileDialogScrollValue < 0)
|
||||
m_FileDialogScrollValue = 0;
|
||||
if(m_FileDialogScrollValue > 1)
|
||||
m_FileDialogScrollValue = 1;
|
||||
TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT));
|
||||
UI()->DoLabel(&FileIcon, pIconType, 12.0f, TEXTALIGN_LEFT);
|
||||
TextRender()->SetCurFont(nullptr);
|
||||
|
||||
m_FilesStartAt = (int)(ScrollNum * m_FileDialogScrollValue);
|
||||
if(m_FilesStartAt < 0)
|
||||
m_FilesStartAt = 0;
|
||||
SLabelProperties Props;
|
||||
Props.m_AlignVertically = 0;
|
||||
UI()->DoLabel(&Button, m_vpFilteredFileList[i]->m_aName, 10.0f, TEXTALIGN_LEFT, Props);
|
||||
}
|
||||
|
||||
m_FilesStopAt = m_FilesStartAt + Num;
|
||||
|
||||
m_FilesCur = 0;
|
||||
|
||||
// set clipping
|
||||
UI()->ClipEnable(&View);
|
||||
|
||||
// disable clipping again
|
||||
UI()->ClipDisable();
|
||||
const int NewSelection = s_ListBox.DoEnd();
|
||||
if(NewSelection != m_FilesSelectedIndex)
|
||||
{
|
||||
m_FilesSelectedIndex = NewSelection;
|
||||
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||
if(!m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
|
||||
str_copy(m_aFileDialogFileName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
|
||||
else
|
||||
m_aFileDialogFileName[0] = '\0';
|
||||
m_PreviewImageIsLoaded = false;
|
||||
}
|
||||
|
||||
// the buttons
|
||||
static int s_OkButton = 0;
|
||||
|
@ -4549,35 +4494,34 @@ void CEditor::RenderFileDialog()
|
|||
|
||||
CUIRect Button;
|
||||
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
|
||||
bool IsDir = m_FilesSelectedIndex >= 0 && m_vFileList[m_FilesSelectedIndex].m_IsDir;
|
||||
if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, nullptr) || m_FileDialogActivate)
|
||||
bool IsDir = m_FilesSelectedIndex >= 0 && m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir;
|
||||
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(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))
|
||||
m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link
|
||||
}
|
||||
else // sub folder
|
||||
{
|
||||
if(m_vFileList[m_FilesSelectedIndex].m_IsLink)
|
||||
if(m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsLink)
|
||||
{
|
||||
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
|
||||
{
|
||||
char aTemp[IO_MAX_PATH_LENGTH];
|
||||
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 :
|
||||
m_vFileList[m_FilesSelectedIndex].m_StorageType);
|
||||
if(m_FilesSelectedIndex >= 0 && !m_vFileList[m_FilesSelectedIndex].m_IsDir)
|
||||
str_copy(m_aFileDialogFileName, m_vFileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName));
|
||||
m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType);
|
||||
if(m_FilesSelectedIndex >= 0 && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
|
||||
str_copy(m_aFileDialogFileName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, sizeof(m_aFileDialogFileName));
|
||||
else
|
||||
m_aFileDialogFileName[0] = 0;
|
||||
}
|
||||
|
@ -4594,10 +4538,10 @@ void CEditor::RenderFileDialog()
|
|||
m_PopupEventActivated = true;
|
||||
}
|
||||
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)
|
||||
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)
|
||||
{
|
||||
m_vFileList.clear();
|
||||
m_vCompleteFileList.clear();
|
||||
if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps"))
|
||||
{
|
||||
CFilelistItem Item;
|
||||
|
@ -4647,18 +4624,17 @@ void CEditor::FilelistPopulate(int StorageType)
|
|||
Item.m_IsDir = true;
|
||||
Item.m_IsLink = true;
|
||||
Item.m_StorageType = IStorage::TYPE_SAVE;
|
||||
m_vFileList.push_back(Item);
|
||||
m_vCompleteFileList.push_back(Item);
|
||||
}
|
||||
Storage()->ListDirectory(StorageType, m_pFileDialogPath, EditorListdirCallback, this);
|
||||
std::sort(m_vFileList.begin(), m_vFileList.end());
|
||||
m_FilesSelectedIndex = m_vFileList.empty() ? -1 : 0;
|
||||
m_PreviewImageIsLoaded = false;
|
||||
m_FileDialogActivate = false;
|
||||
|
||||
if(m_FilesSelectedIndex >= 0 && !m_vFileList[m_FilesSelectedIndex].m_IsDir)
|
||||
str_copy(m_aFileDialogFileName, m_vFileList[m_FilesSelectedIndex].m_aFilename, sizeof(m_aFileDialogFileName));
|
||||
std::sort(m_vCompleteFileList.begin(), m_vCompleteFileList.end());
|
||||
RefreshFilteredFileList();
|
||||
m_FilesSelectedIndex = m_vpFilteredFileList.empty() ? -1 : 0;
|
||||
if(m_FilesSelectedIndex >= 0)
|
||||
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
|
||||
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,
|
||||
|
@ -4672,12 +4648,11 @@ void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle
|
|||
m_pfnFileDialogFunc = pfnFunc;
|
||||
m_pFileDialogUser = pUser;
|
||||
m_aFileDialogFileName[0] = 0;
|
||||
m_aFileDialogSearchText[0] = 0;
|
||||
m_aFileDialogFilterString[0] = 0;
|
||||
m_aFileDialogCurrentFolder[0] = 0;
|
||||
m_aFileDialogCurrentLink[0] = 0;
|
||||
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
||||
m_FileDialogFileType = FileType;
|
||||
m_FileDialogScrollValue = 0.0f;
|
||||
m_PreviewImageIsLoaded = false;
|
||||
m_FileDialogOpening = true;
|
||||
|
||||
|
|
|
@ -770,8 +770,8 @@ public:
|
|||
|
||||
m_BrushColorEnabled = true;
|
||||
|
||||
m_aFileName[0] = 0;
|
||||
m_aFileSaveName[0] = 0;
|
||||
m_aFileName[0] = '\0';
|
||||
m_aFileSaveName[0] = '\0';
|
||||
m_ValidSaveFilename = false;
|
||||
|
||||
m_PopupEventActivated = false;
|
||||
|
@ -782,17 +782,14 @@ public:
|
|||
m_pFileDialogTitle = nullptr;
|
||||
m_pFileDialogButtonText = nullptr;
|
||||
m_pFileDialogUser = nullptr;
|
||||
m_aFileDialogFileName[0] = 0;
|
||||
m_aFileDialogCurrentFolder[0] = 0;
|
||||
m_aFileDialogCurrentLink[0] = 0;
|
||||
m_aFileDialogFileName[0] = '\0';
|
||||
m_aFileDialogCurrentFolder[0] = '\0';
|
||||
m_aFileDialogCurrentLink[0] = '\0';
|
||||
m_aFilesSelectedName[0] = '\0';
|
||||
m_aFileDialogFilterString[0] = '\0';
|
||||
m_pFileDialogPath = m_aFileDialogCurrentFolder;
|
||||
m_FileDialogActivate = false;
|
||||
m_FileDialogOpening = false;
|
||||
m_FileDialogScrollValue = 0.0f;
|
||||
m_FilesSelectedIndex = -1;
|
||||
m_FilesStartAt = 0;
|
||||
m_FilesCur = 0;
|
||||
m_FilesStopAt = 999;
|
||||
|
||||
m_SelectEntitiesImage = "DDNet";
|
||||
|
||||
|
@ -867,6 +864,7 @@ public:
|
|||
|
||||
CLayerGroup *m_apSavedBrushes[10];
|
||||
|
||||
void RefreshFilteredFileList();
|
||||
void FilelistPopulate(int StorageType);
|
||||
void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
|
||||
const char *pBasepath, const char *pDefaultName,
|
||||
|
@ -950,12 +948,10 @@ public:
|
|||
char m_aFileDialogFileName[IO_MAX_PATH_LENGTH];
|
||||
char m_aFileDialogCurrentFolder[IO_MAX_PATH_LENGTH];
|
||||
char m_aFileDialogCurrentLink[IO_MAX_PATH_LENGTH];
|
||||
char m_aFileDialogSearchText[64];
|
||||
char m_aFileDialogPrevSearchText[64];
|
||||
char m_aFilesSelectedName[IO_MAX_PATH_LENGTH];
|
||||
char m_aFileDialogFilterString[64];
|
||||
char *m_pFileDialogPath;
|
||||
bool m_FileDialogActivate;
|
||||
int m_FileDialogFileType;
|
||||
float m_FileDialogScrollValue;
|
||||
int m_FilesSelectedIndex;
|
||||
char m_aFileDialogNewFolderName[64];
|
||||
char m_aFileDialogErrString[64];
|
||||
|
@ -971,14 +967,11 @@ public:
|
|||
bool m_IsDir;
|
||||
bool m_IsLink;
|
||||
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; }
|
||||
};
|
||||
std::vector<CFilelistItem> m_vFileList;
|
||||
int m_FilesStartAt;
|
||||
int m_FilesCur;
|
||||
int m_FilesStopAt;
|
||||
std::vector<CFilelistItem> m_vCompleteFileList;
|
||||
std::vector<const CFilelistItem *> m_vpFilteredFileList;
|
||||
|
||||
std::vector<std::string> m_vSelectEntitiesFiles;
|
||||
std::string m_SelectEntitiesImage;
|
||||
|
@ -1229,7 +1222,6 @@ public:
|
|||
void RenderMenubar(CUIRect Menubar);
|
||||
void RenderFileDialog();
|
||||
|
||||
void AddFileDialogEntry(int Index, CUIRect *pView);
|
||||
void SelectGameLayer();
|
||||
void SortImages();
|
||||
bool SelectLayerByTile();
|
||||
|
|
Loading…
Reference in a new issue