2010-11-20 10:37:14 +00:00
|
|
|
|
/* (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. */
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2011-08-31 11:56:04 +00:00
|
|
|
|
#include <base/tl/string.h>
|
|
|
|
|
|
2019-10-14 00:27:08 +00:00
|
|
|
|
#include <base/hash.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <base/math.h>
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include <engine/demo.h>
|
2010-07-27 20:25:36 +00:00
|
|
|
|
#include <engine/graphics.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <engine/keys.h>
|
2010-09-03 18:05:22 +00:00
|
|
|
|
#include <engine/storage.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <engine/textrender.h>
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2019-04-23 12:52:32 +00:00
|
|
|
|
#include <game/client/components/console.h>
|
2020-09-26 19:41:58 +00:00
|
|
|
|
#include <game/client/gameclient.h>
|
|
|
|
|
#include <game/client/render.h>
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include <game/localization.h>
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include <game/client/ui.h>
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2010-07-27 20:25:36 +00:00
|
|
|
|
#include <game/generated/client_data.h>
|
|
|
|
|
|
2011-12-04 13:04:12 +00:00
|
|
|
|
#include "maplayers.h"
|
2010-05-29 07:25:38 +00:00
|
|
|
|
#include "menus.h"
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
int CMenus::DoButton_DemoPlayer(const void *pID, const char *pText, int Checked, const CUIRect *pRect)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(pRect, ColorRGBA(1, 1, 1, (Checked ? 0.10f : 0.5f) * ButtonColorMul(pID)), CUI::CORNER_ALL, 5.0f);
|
2009-10-27 14:38:53 +00:00
|
|
|
|
UI()->DoLabel(pRect, pText, 14.0f, 0);
|
|
|
|
|
return UI()->DoButtonLogic(pID, pText, Checked, pRect);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-03-28 22:48:36 +00:00
|
|
|
|
int CMenus::DoButton_Sprite(const void *pID, int ImageID, int SpriteID, int Checked, const CUIRect *pRect, int Corners)
|
2010-07-27 20:25:36 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(pRect, ColorRGBA(1.0f, 1.0f, 1.0f, (Checked ? 0.10f : 0.5f) * ButtonColorMul(pID)), Corners, 5.0f);
|
2011-03-28 19:10:37 +00:00
|
|
|
|
Graphics()->TextureSet(g_pData->m_aImages[ImageID].m_Id);
|
2010-07-27 20:25:36 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
2011-03-28 22:48:36 +00:00
|
|
|
|
if(!Checked)
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.5f);
|
2011-02-12 10:40:36 +00:00
|
|
|
|
RenderTools()->SelectSprite(SpriteID);
|
2010-07-27 20:25:36 +00:00
|
|
|
|
IGraphics::CQuadItem QuadItem(pRect->x, pRect->y, pRect->w, pRect->h);
|
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
|
Graphics()->QuadsEnd();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-07-27 20:25:36 +00:00
|
|
|
|
return UI()->DoButtonLogic(pID, "", Checked, pRect);
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-28 09:08:14 +00:00
|
|
|
|
bool CMenus::DemoFilterChat(const void *pData, int Size, void *pUser)
|
|
|
|
|
{
|
|
|
|
|
bool DoFilterChat = *(bool *)pUser;
|
|
|
|
|
if(!DoFilterChat)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CUnpacker Unpacker;
|
|
|
|
|
Unpacker.Reset(pData, Size);
|
|
|
|
|
|
|
|
|
|
int Msg = Unpacker.GetInt();
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int Sys = Msg & 1;
|
2017-02-28 09:08:14 +00:00
|
|
|
|
Msg >>= 1;
|
|
|
|
|
|
|
|
|
|
return !Unpacker.Error() && !Sys && Msg == NETMSGTYPE_SV_CHAT;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CMenus::RenderDemoPlayer(CUIRect MainView)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
const IDemoPlayer::CInfo *pInfo = DemoPlayer()->BaseInfo();
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
const float SeekBarHeight = 15.0f;
|
|
|
|
|
const float ButtonbarHeight = 20.0f;
|
2010-09-06 19:36:39 +00:00
|
|
|
|
const float NameBarHeight = 20.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
const float Margins = 5.0f;
|
|
|
|
|
float TotalHeight;
|
2014-08-22 08:00:48 +00:00
|
|
|
|
static int64 LastSpeedChange = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2014-08-23 15:48:04 +00:00
|
|
|
|
// render popups
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(m_DemoPlayerState == DEMOPLAYER_SLICE_SAVE)
|
2014-08-23 15:48:04 +00:00
|
|
|
|
{
|
|
|
|
|
CUIRect Screen = *UI()->Screen();
|
2016-04-27 15:05:30 +00:00
|
|
|
|
CUIRect Box, Part, Part2;
|
2014-08-23 15:48:04 +00:00
|
|
|
|
Box = Screen;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Box.VMargin(150.0f / UI()->Scale(), &Box);
|
|
|
|
|
Box.HMargin(150.0f / UI()->Scale(), &Box);
|
2014-08-23 15:48:04 +00:00
|
|
|
|
|
|
|
|
|
// render the box
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&Box, ColorRGBA(0, 0, 0, 0.5f), CUI::CORNER_ALL, 15.0f);
|
2014-08-23 15:48:04 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Box.HSplitTop(20.f / UI()->Scale(), &Part, &Box);
|
|
|
|
|
Box.HSplitTop(24.f / UI()->Scale(), &Part, &Box);
|
2015-07-14 11:43:24 +00:00
|
|
|
|
UI()->DoLabelScaled(&Part, Localize("Select a name"), 24.f, 0);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Box.HSplitTop(20.f / UI()->Scale(), &Part, &Box);
|
|
|
|
|
Box.HSplitTop(24.f / UI()->Scale(), &Part, &Box);
|
|
|
|
|
Part.VMargin(20.f / UI()->Scale(), &Part);
|
2014-08-25 09:19:00 +00:00
|
|
|
|
UI()->DoLabelScaled(&Part, m_aDemoPlayerPopupHint, 24.f, 0);
|
2014-08-23 15:48:04 +00:00
|
|
|
|
|
|
|
|
|
CUIRect Label, TextBox, Ok, Abort;
|
|
|
|
|
|
|
|
|
|
Box.HSplitBottom(20.f, &Box, &Part);
|
|
|
|
|
Box.HSplitBottom(24.f, &Box, &Part);
|
|
|
|
|
Part.VMargin(80.0f, &Part);
|
|
|
|
|
|
|
|
|
|
Part.VSplitMid(&Abort, &Ok);
|
|
|
|
|
|
|
|
|
|
Ok.VMargin(20.0f, &Ok);
|
|
|
|
|
Abort.VMargin(20.0f, &Abort);
|
|
|
|
|
|
2016-04-27 15:05:30 +00:00
|
|
|
|
static int s_RemoveChat = 0;
|
|
|
|
|
|
2014-08-23 15:48:04 +00:00
|
|
|
|
static int s_ButtonAbort = 0;
|
|
|
|
|
if(DoButton_Menu(&s_ButtonAbort, Localize("Abort"), 0, &Abort) || m_EscapePressed)
|
|
|
|
|
m_DemoPlayerState = DEMOPLAYER_NONE;
|
|
|
|
|
|
|
|
|
|
static int s_ButtonOk = 0;
|
|
|
|
|
if(DoButton_Menu(&s_ButtonOk, Localize("Ok"), 0, &Ok) || m_EnterPressed)
|
|
|
|
|
{
|
2017-07-24 16:33:11 +00:00
|
|
|
|
if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, m_aCurrentDemoFile) == 0)
|
2015-07-14 11:43:44 +00:00
|
|
|
|
str_copy(m_aDemoPlayerPopupHint, Localize("Please use a different name"), sizeof(m_aDemoPlayerPopupHint));
|
2014-08-25 09:19:00 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2018-07-25 08:29:05 +00:00
|
|
|
|
if(!str_endswith(m_aCurrentDemoFile, ".demo"))
|
2015-07-14 11:43:44 +00:00
|
|
|
|
str_append(m_aCurrentDemoFile, ".demo", sizeof(m_aCurrentDemoFile));
|
|
|
|
|
|
2014-08-25 09:19:00 +00:00
|
|
|
|
char aPath[512];
|
|
|
|
|
str_format(aPath, sizeof(aPath), "%s/%s", m_aCurrentDemoFolder, m_aCurrentDemoFile);
|
2017-07-24 16:33:11 +00:00
|
|
|
|
|
|
|
|
|
IOHANDLE DemoFile = Storage()->OpenFile(aPath, IOFLAG_READ, IStorage::TYPE_SAVE);
|
2018-07-25 08:29:05 +00:00
|
|
|
|
const char *pStr = Localize("File already exists, do you want to overwrite it?");
|
|
|
|
|
if(DemoFile && str_comp(m_aDemoPlayerPopupHint, pStr) != 0)
|
2017-07-24 16:33:11 +00:00
|
|
|
|
{
|
|
|
|
|
io_close(DemoFile);
|
|
|
|
|
str_copy(m_aDemoPlayerPopupHint, pStr, sizeof(m_aDemoPlayerPopupHint));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_DemoPlayerState = DEMOPLAYER_NONE;
|
|
|
|
|
Client()->DemoSlice(aPath, CMenus::DemoFilterChat, &s_RemoveChat);
|
|
|
|
|
}
|
2014-08-25 09:19:00 +00:00
|
|
|
|
}
|
2014-08-23 15:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Box.HSplitBottom(60.f, &Box, &Part);
|
2016-04-27 15:05:30 +00:00
|
|
|
|
Box.HSplitBottom(60.f, &Box, &Part2);
|
|
|
|
|
Box.HSplitBottom(24.f, &Box, &Part2);
|
2014-08-23 15:48:04 +00:00
|
|
|
|
Box.HSplitBottom(24.f, &Box, &Part);
|
|
|
|
|
|
2016-04-27 15:05:30 +00:00
|
|
|
|
Part2.VSplitLeft(60.0f, 0, &Label);
|
|
|
|
|
if(DoButton_CheckBox(&s_RemoveChat, Localize("Remove chat"), s_RemoveChat, &Label))
|
|
|
|
|
{
|
|
|
|
|
s_RemoveChat ^= 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-23 15:48:04 +00:00
|
|
|
|
Part.VSplitLeft(60.0f, 0, &Label);
|
|
|
|
|
Label.VSplitLeft(120.0f, 0, &TextBox);
|
|
|
|
|
TextBox.VSplitLeft(20.0f, 0, &TextBox);
|
|
|
|
|
TextBox.VSplitRight(60.0f, &TextBox, 0);
|
|
|
|
|
UI()->DoLabel(&Label, Localize("New name:"), 18.0f, -1);
|
|
|
|
|
static float Offset = 0.0f;
|
2017-07-24 16:33:11 +00:00
|
|
|
|
if(DoEditBox(&Offset, &TextBox, m_aCurrentDemoFile, sizeof(m_aCurrentDemoFile), 12.0f, &Offset))
|
|
|
|
|
{
|
|
|
|
|
m_aDemoPlayerPopupHint[0] = '\0';
|
|
|
|
|
}
|
2014-08-23 15:48:04 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-15 18:39:39 +00:00
|
|
|
|
// handle keyboard shortcuts independent of active menu
|
2019-10-05 16:04:43 +00:00
|
|
|
|
if(m_pClient->m_pGameConsole->IsClosed() && m_DemoPlayerState == DEMOPLAYER_NONE && g_Config.m_ClDemoKeyboardShortcuts)
|
2019-04-15 18:39:39 +00:00
|
|
|
|
{
|
2019-04-23 12:52:32 +00:00
|
|
|
|
// increase/decrease speed
|
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) || Input()->KeyPress(KEY_UP))
|
2019-04-15 18:39:39 +00:00
|
|
|
|
{
|
2019-04-23 12:52:32 +00:00
|
|
|
|
DemoPlayer()->SetSpeedIndex(+1);
|
|
|
|
|
LastSpeedChange = time_get();
|
2019-04-15 18:39:39 +00:00
|
|
|
|
}
|
2019-04-23 12:52:32 +00:00
|
|
|
|
else if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) || Input()->KeyPress(KEY_DOWN))
|
2019-04-15 18:39:39 +00:00
|
|
|
|
{
|
2019-04-23 12:52:32 +00:00
|
|
|
|
DemoPlayer()->SetSpeedIndex(-1);
|
|
|
|
|
LastSpeedChange = time_get();
|
2019-04-15 18:39:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 12:52:32 +00:00
|
|
|
|
// pause/unpause
|
|
|
|
|
if(Input()->KeyPress(KEY_SPACE) || Input()->KeyPress(KEY_RETURN) || Input()->KeyPress(KEY_K))
|
|
|
|
|
{
|
|
|
|
|
if(pInfo->m_Paused)
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->Unpause();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->Pause();
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-15 18:39:39 +00:00
|
|
|
|
|
2019-04-23 12:52:32 +00:00
|
|
|
|
// seek backward/forward 10/5 seconds
|
|
|
|
|
if(Input()->KeyPress(KEY_J))
|
2019-04-15 18:39:39 +00:00
|
|
|
|
{
|
2019-04-23 12:52:32 +00:00
|
|
|
|
DemoPlayer()->SeekTime(-10.0f);
|
|
|
|
|
}
|
|
|
|
|
else if(Input()->KeyPress(KEY_L))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekTime(10.0f);
|
|
|
|
|
}
|
|
|
|
|
else if(Input()->KeyPress(KEY_LEFT))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekTime(-5.0f);
|
|
|
|
|
}
|
|
|
|
|
else if(Input()->KeyPress(KEY_RIGHT))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekTime(5.0f);
|
2019-04-15 18:39:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 12:52:32 +00:00
|
|
|
|
// seek to 0-90%
|
|
|
|
|
const int SeekPercentKeys[] = {KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9};
|
|
|
|
|
for(unsigned i = 0; i < sizeof(SeekPercentKeys) / sizeof(SeekPercentKeys[0]); i++)
|
|
|
|
|
{
|
|
|
|
|
if(Input()->KeyPress(SeekPercentKeys[i]))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekPercent(i * 0.1f);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// seek to the beginning/end
|
|
|
|
|
if(Input()->KeyPress(KEY_HOME))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekPercent(0.0f);
|
|
|
|
|
}
|
|
|
|
|
else if(Input()->KeyPress(KEY_END))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->SeekPercent(1.0f);
|
|
|
|
|
}
|
2019-04-15 18:39:39 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TotalHeight = SeekBarHeight + ButtonbarHeight + NameBarHeight + Margins * 3;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2014-08-22 08:00:48 +00:00
|
|
|
|
// render speed info
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(g_Config.m_ClDemoShowSpeed && time_get() - LastSpeedChange < time_freq() * 1)
|
2014-08-22 08:00:48 +00:00
|
|
|
|
{
|
|
|
|
|
CUIRect Screen = *UI()->Screen();
|
|
|
|
|
|
|
|
|
|
char aSpeedBuf[256];
|
2014-08-29 14:13:28 +00:00
|
|
|
|
str_format(aSpeedBuf, sizeof(aSpeedBuf), "×%.2f", pInfo->m_Speed);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->Text(0, 120.0f, Screen.y + Screen.h - 120.0f - TotalHeight, 60.0f, aSpeedBuf, -1.0f);
|
2014-08-22 08:00:48 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!m_MenuActive)
|
|
|
|
|
return;
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
MainView.HSplitBottom(TotalHeight, 0, &MainView);
|
2011-03-12 17:07:57 +00:00
|
|
|
|
MainView.VSplitLeft(50.0f, 0, &MainView);
|
2015-05-08 10:31:55 +00:00
|
|
|
|
MainView.VSplitLeft(450.0f, &MainView, 0);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_T, 10.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
MainView.Margin(5.0f, &MainView);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-09-06 19:36:39 +00:00
|
|
|
|
CUIRect SeekBar, ButtonBar, NameBar;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-09-03 20:30:46 +00:00
|
|
|
|
int CurrentTick = pInfo->m_CurrentTick - pInfo->m_FirstTick;
|
|
|
|
|
int TotalTicks = pInfo->m_LastTick - pInfo->m_FirstTick;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
MainView.HSplitTop(SeekBarHeight, &SeekBar, &ButtonBar);
|
|
|
|
|
ButtonBar.HSplitTop(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.HSplitBottom(NameBarHeight, &ButtonBar, &NameBar);
|
|
|
|
|
NameBar.HSplitTop(4.0f, 0, &NameBar);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
|
|
|
|
// do seekbar
|
|
|
|
|
{
|
2011-02-12 10:40:36 +00:00
|
|
|
|
static int s_SeekBarID = 0;
|
|
|
|
|
void *id = &s_SeekBarID;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
char aBuffer[128];
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2012-01-10 22:13:19 +00:00
|
|
|
|
// draw seek bar
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&SeekBar, ColorRGBA(0, 0, 0, 0.5f), CUI::CORNER_ALL, 5.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2012-01-10 22:13:19 +00:00
|
|
|
|
// draw filled bar
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Amount = CurrentTick / (float)TotalTicks;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CUIRect FilledBar = SeekBar;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
FilledBar.w = 10.0f + (FilledBar.w - 10.0f) * Amount;
|
|
|
|
|
RenderTools()->DrawUIRect(&FilledBar, ColorRGBA(1, 1, 1, 0.5f), CUI::CORNER_ALL, 5.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2012-01-10 22:13:19 +00:00
|
|
|
|
// draw markers
|
|
|
|
|
for(int i = 0; i < pInfo->m_NumTimelineMarkers; i++)
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Ratio = (pInfo->m_aTimelineMarkers[i] - pInfo->m_FirstTick) / (float)TotalTicks;
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2012-01-10 22:13:19 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
IGraphics::CQuadItem QuadItem(SeekBar.x + (SeekBar.w - 10.0f) * Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h);
|
2012-01-10 22:13:19 +00:00
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-13 15:32:03 +00:00
|
|
|
|
// draw slice markers
|
|
|
|
|
// begin
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(g_Config.m_ClDemoSliceBegin != -1)
|
2014-08-13 15:32:03 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Ratio = (g_Config.m_ClDemoSliceBegin - pInfo->m_FirstTick) / (float)TotalTicks;
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2014-08-13 15:32:03 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
IGraphics::CQuadItem QuadItem(10.0f + SeekBar.x + (SeekBar.w - 10.0f) * Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h);
|
2014-08-13 15:32:03 +00:00
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// end
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(g_Config.m_ClDemoSliceEnd != -1)
|
2014-08-13 15:32:03 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Ratio = (g_Config.m_ClDemoSliceEnd - pInfo->m_FirstTick) / (float)TotalTicks;
|
2012-08-12 10:41:50 +00:00
|
|
|
|
Graphics()->TextureClear();
|
2014-08-13 15:32:03 +00:00
|
|
|
|
Graphics()->QuadsBegin();
|
|
|
|
|
Graphics()->SetColor(1.0f, 0.0f, 0.0f, 1.0f);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
IGraphics::CQuadItem QuadItem(10.0f + SeekBar.x + (SeekBar.w - 10.0f) * Ratio, SeekBar.y, UI()->PixelSize(), SeekBar.h);
|
2014-08-13 15:32:03 +00:00
|
|
|
|
Graphics()->QuadsDrawTL(&QuadItem, 1);
|
|
|
|
|
Graphics()->QuadsEnd();
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-10 22:13:19 +00:00
|
|
|
|
// draw time
|
2010-05-29 07:25:38 +00:00
|
|
|
|
str_format(aBuffer, sizeof(aBuffer), "%d:%02d / %d:%02d",
|
2020-09-26 19:41:58 +00:00
|
|
|
|
CurrentTick / SERVER_TICK_SPEED / 60, (CurrentTick / SERVER_TICK_SPEED) % 60,
|
|
|
|
|
TotalTicks / SERVER_TICK_SPEED / 60, (TotalTicks / SERVER_TICK_SPEED) % 60);
|
|
|
|
|
UI()->DoLabel(&SeekBar, aBuffer, SeekBar.h * 0.70f, 0);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
|
|
|
|
// do the logic
|
2011-04-13 18:37:12 +00:00
|
|
|
|
int Inside = UI()->MouseInside(&SeekBar);
|
|
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
|
if(UI()->ActiveItem() == id)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2009-10-27 14:38:53 +00:00
|
|
|
|
if(!UI()->MouseButton(0))
|
|
|
|
|
UI()->SetActiveItem(0);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
static float PrevAmount = 0.0f;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float Amount = (UI()->MouseX() - SeekBar.x) / SeekBar.w;
|
2014-01-22 16:14:47 +00:00
|
|
|
|
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(Input()->KeyIsPressed(KEY_LSHIFT) || Input()->KeyIsPressed(KEY_RSHIFT))
|
2014-01-22 16:14:47 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Amount = PrevAmount + (Amount - PrevAmount) * 0.05f;
|
2014-01-22 16:14:47 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount - Amount) >= 0.0001f)
|
2014-01-22 16:14:47 +00:00
|
|
|
|
{
|
2014-01-22 16:19:21 +00:00
|
|
|
|
//PrevAmount = Amount;
|
2014-01-22 16:14:47 +00:00
|
|
|
|
m_pClient->m_SuppressEvents = true;
|
2019-04-15 18:39:39 +00:00
|
|
|
|
DemoPlayer()->SeekPercent(Amount);
|
2014-01-22 16:14:47 +00:00
|
|
|
|
m_pClient->m_SuppressEvents = false;
|
|
|
|
|
m_pClient->m_pMapLayersBackGround->EnvelopeUpdate();
|
|
|
|
|
m_pClient->m_pMapLayersForeGround->EnvelopeUpdate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(Amount > 0.0f && Amount < 1.0f && absolute(PrevAmount - Amount) >= 0.001f)
|
2014-01-22 16:14:47 +00:00
|
|
|
|
{
|
|
|
|
|
PrevAmount = Amount;
|
|
|
|
|
m_pClient->m_SuppressEvents = true;
|
2019-04-15 18:39:39 +00:00
|
|
|
|
DemoPlayer()->SeekPercent(Amount);
|
2014-01-22 16:14:47 +00:00
|
|
|
|
m_pClient->m_SuppressEvents = false;
|
|
|
|
|
m_pClient->m_pMapLayersBackGround->EnvelopeUpdate();
|
|
|
|
|
m_pClient->m_pMapLayersForeGround->EnvelopeUpdate();
|
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2009-10-27 14:38:53 +00:00
|
|
|
|
else if(UI()->HotItem() == id)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2009-10-27 14:38:53 +00:00
|
|
|
|
if(UI()->MouseButton(0))
|
|
|
|
|
UI()->SetActiveItem(id);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(Inside)
|
2009-10-27 14:38:53 +00:00
|
|
|
|
UI()->SetHotItem(id);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
}
|
2010-09-03 20:30:46 +00:00
|
|
|
|
|
|
|
|
|
if(CurrentTick == TotalTicks)
|
|
|
|
|
{
|
2011-01-09 22:42:37 +00:00
|
|
|
|
DemoPlayer()->Pause();
|
2019-04-15 18:39:39 +00:00
|
|
|
|
DemoPlayer()->SeekPercent(0.0f);
|
2010-09-03 20:30:46 +00:00
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2011-03-27 14:26:50 +00:00
|
|
|
|
bool IncreaseDemoSpeed = false, DecreaseDemoSpeed = false;
|
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
// do buttons
|
|
|
|
|
CUIRect Button;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
// combined play and pause button
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_PlayPauseButton = 0;
|
2019-05-11 01:02:00 +00:00
|
|
|
|
if(DoButton_Sprite(&s_PlayPauseButton, IMAGE_DEMOBUTTONS, pInfo->m_Paused ? SPRITE_DEMOBUTTON_PLAY : SPRITE_DEMOBUTTON_PAUSE, false, &Button, CUI::CORNER_ALL))
|
2014-01-15 14:08:00 +00:00
|
|
|
|
{
|
2019-04-15 18:39:39 +00:00
|
|
|
|
if(pInfo->m_Paused)
|
|
|
|
|
{
|
2014-01-15 14:08:00 +00:00
|
|
|
|
DemoPlayer()->Unpause();
|
2019-04-15 18:39:39 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->Pause();
|
|
|
|
|
}
|
2014-01-15 14:08:00 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// stop button
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_ResetButton = 0;
|
|
|
|
|
if(DoButton_Sprite(&s_ResetButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_STOP, false, &Button, CUI::CORNER_ALL))
|
|
|
|
|
{
|
|
|
|
|
DemoPlayer()->Pause();
|
2019-04-15 18:39:39 +00:00
|
|
|
|
DemoPlayer()->SeekPercent(0.0f);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
2011-03-27 14:26:50 +00:00
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
// slowdown
|
|
|
|
|
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_SlowDownButton = 0;
|
2017-03-22 18:11:46 +00:00
|
|
|
|
if(DoButton_Sprite(&s_SlowDownButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_SLOWER, 0, &Button, CUI::CORNER_ALL))
|
2014-01-15 14:08:00 +00:00
|
|
|
|
DecreaseDemoSpeed = true;
|
|
|
|
|
|
|
|
|
|
// fastforward
|
|
|
|
|
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_FastForwardButton = 0;
|
|
|
|
|
if(DoButton_Sprite(&s_FastForwardButton, IMAGE_DEMOBUTTONS, SPRITE_DEMOBUTTON_FASTER, 0, &Button, CUI::CORNER_ALL))
|
|
|
|
|
IncreaseDemoSpeed = true;
|
|
|
|
|
|
|
|
|
|
// speed meter
|
2020-09-26 19:41:58 +00:00
|
|
|
|
ButtonBar.VSplitLeft(Margins * 3, 0, &ButtonBar);
|
2014-01-15 14:08:00 +00:00
|
|
|
|
char aBuffer[64];
|
2017-03-22 20:10:53 +00:00
|
|
|
|
str_format(aBuffer, sizeof(aBuffer), "×%g", pInfo->m_Speed);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
UI()->DoLabel(&ButtonBar, aBuffer, Button.h * 0.7f, -1);
|
2014-01-15 14:08:00 +00:00
|
|
|
|
|
2014-08-13 14:35:15 +00:00
|
|
|
|
// slice begin button
|
2020-09-26 19:41:58 +00:00
|
|
|
|
ButtonBar.VSplitLeft(Margins * 10, 0, &ButtonBar);
|
2014-08-13 14:35:15 +00:00
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_SliceBeginButton = 0;
|
|
|
|
|
if(DoButton_Sprite(&s_SliceBeginButton, IMAGE_DEMOBUTTONS2, SPRITE_DEMOBUTTON_SLICE_BEGIN, 0, &Button, CUI::CORNER_ALL))
|
|
|
|
|
Client()->DemoSliceBegin();
|
|
|
|
|
|
|
|
|
|
// slice end button
|
|
|
|
|
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_SliceEndButton = 0;
|
|
|
|
|
if(DoButton_Sprite(&s_SliceEndButton, IMAGE_DEMOBUTTONS2, SPRITE_DEMOBUTTON_SLICE_END, 0, &Button, CUI::CORNER_ALL))
|
|
|
|
|
Client()->DemoSliceEnd();
|
|
|
|
|
|
|
|
|
|
// slice save button
|
|
|
|
|
ButtonBar.VSplitLeft(Margins, 0, &ButtonBar);
|
|
|
|
|
ButtonBar.VSplitLeft(ButtonbarHeight, &Button, &ButtonBar);
|
|
|
|
|
static int s_SliceSaveButton = 0;
|
|
|
|
|
if(DoButton_Sprite(&s_SliceSaveButton, IMAGE_FILEICONS, SPRITE_FILE_DEMO2, 0, &Button, CUI::CORNER_ALL))
|
2014-08-23 15:48:04 +00:00
|
|
|
|
{
|
|
|
|
|
str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile));
|
2014-08-25 09:19:00 +00:00
|
|
|
|
m_aDemoPlayerPopupHint[0] = '\0';
|
2014-08-23 15:48:04 +00:00
|
|
|
|
m_DemoPlayerState = DEMOPLAYER_SLICE_SAVE;
|
|
|
|
|
}
|
2014-08-13 14:35:15 +00:00
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
// close button
|
2020-09-26 19:41:58 +00:00
|
|
|
|
ButtonBar.VSplitRight(ButtonbarHeight * 3, &ButtonBar, &Button);
|
2014-01-15 14:08:00 +00:00
|
|
|
|
static int s_ExitButton = 0;
|
2020-09-18 05:57:36 +00:00
|
|
|
|
if(DoButton_DemoPlayer(&s_ExitButton, Localize("Close"), 0, &Button) || (Input()->KeyPress(KEY_C) && m_pClient->m_pGameConsole->IsClosed() && m_DemoPlayerState == DEMOPLAYER_NONE))
|
2014-09-05 19:17:04 +00:00
|
|
|
|
{
|
2014-01-15 14:08:00 +00:00
|
|
|
|
Client()->Disconnect();
|
2014-09-05 19:17:04 +00:00
|
|
|
|
DemolistOnUpdate(false);
|
|
|
|
|
}
|
2014-01-15 14:08:00 +00:00
|
|
|
|
|
2019-10-05 16:04:43 +00:00
|
|
|
|
// toggle keyboard shortcuts button
|
2020-09-26 19:41:58 +00:00
|
|
|
|
ButtonBar.VSplitRight(Margins * 3, &ButtonBar, 0);
|
2019-10-05 16:04:43 +00:00
|
|
|
|
ButtonBar.VSplitRight(ButtonbarHeight, &ButtonBar, &Button);
|
|
|
|
|
static int s_KeyboardShortcutsButton = 0;
|
|
|
|
|
int Sprite = g_Config.m_ClDemoKeyboardShortcuts ? SPRITE_DEMOBUTTON_SHORTCUTS_ENABLED : SPRITE_DEMOBUTTON_SHORTCUTS_DISABLED;
|
|
|
|
|
if(DoButton_Sprite(&s_KeyboardShortcutsButton, IMAGE_DEMOBUTTONS2, Sprite, 0, &Button, CUI::CORNER_ALL))
|
|
|
|
|
{
|
|
|
|
|
g_Config.m_ClDemoKeyboardShortcuts ^= 1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-15 14:08:00 +00:00
|
|
|
|
// demo name
|
|
|
|
|
char aDemoName[64] = {0};
|
|
|
|
|
DemoPlayer()->GetDemoName(aDemoName, sizeof(aDemoName));
|
|
|
|
|
char aBuf[128];
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("Demofile: %s"), aDemoName);
|
|
|
|
|
CTextCursor Cursor;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, NameBar.x, NameBar.y + (NameBar.h - (Button.h * 0.5f)) / 2.f, Button.h * 0.5f, TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
2014-01-15 14:08:00 +00:00
|
|
|
|
Cursor.m_LineWidth = MainView.w;
|
|
|
|
|
TextRender()->TextEx(&Cursor, aBuf, -1);
|
|
|
|
|
|
2014-08-22 08:00:48 +00:00
|
|
|
|
if(IncreaseDemoSpeed)
|
2011-03-27 14:26:50 +00:00
|
|
|
|
{
|
2016-10-28 07:31:22 +00:00
|
|
|
|
DemoPlayer()->SetSpeedIndex(+1);
|
2014-08-22 08:00:48 +00:00
|
|
|
|
LastSpeedChange = time_get();
|
2011-03-27 14:26:50 +00:00
|
|
|
|
}
|
2014-08-22 08:00:48 +00:00
|
|
|
|
else if(DecreaseDemoSpeed)
|
2011-03-27 14:26:50 +00:00
|
|
|
|
{
|
2016-10-28 07:31:22 +00:00
|
|
|
|
DemoPlayer()->SetSpeedIndex(-1);
|
2014-08-22 08:00:48 +00:00
|
|
|
|
LastSpeedChange = time_get();
|
2011-03-27 14:26:50 +00:00
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
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;
|
2018-02-13 02:44:43 +00:00
|
|
|
|
static bool gs_ListBoxClicked;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
2011-03-16 20:31:55 +00:00
|
|
|
|
void CMenus::UiDoListboxStart(const void *pID, const CUIRect *pRect, float RowHeight, const char *pTitle, const char *pBottomText, int NumItems,
|
2020-09-26 07:37:35 +00:00
|
|
|
|
int ItemsPerRow, int SelectedIndex, float ScrollValue, bool LogicOnly)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CUIRect Scroll, Row;
|
|
|
|
|
CUIRect View = *pRect;
|
|
|
|
|
CUIRect Header, Footer;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2020-09-26 07:37:35 +00:00
|
|
|
|
if(!LogicOnly)
|
|
|
|
|
{
|
|
|
|
|
// draw header
|
|
|
|
|
View.HSplitTop(ms_ListheaderHeight, &Header, &View);
|
|
|
|
|
RenderTools()->DrawUIRect(&Header, ColorRGBA(1, 1, 1, 0.25f), CUI::CORNER_T, 5.0f);
|
|
|
|
|
UI()->DoLabel(&Header, pTitle, Header.h * ms_FontmodHeight, 0);
|
|
|
|
|
|
|
|
|
|
// draw footers
|
|
|
|
|
View.HSplitBottom(ms_ListheaderHeight, &View, &Footer);
|
|
|
|
|
RenderTools()->DrawUIRect(&Footer, ColorRGBA(1, 1, 1, 0.25f), CUI::CORNER_B, 5.0f);
|
|
|
|
|
Footer.VSplitLeft(10.0f, 0, &Footer);
|
|
|
|
|
UI()->DoLabel(&Footer, pBottomText, Header.h * ms_FontmodHeight, 0);
|
|
|
|
|
|
|
|
|
|
// background
|
|
|
|
|
RenderTools()->DrawUIRect(&View, ColorRGBA(0, 0, 0, 0.15f), 0, 0);
|
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
|
|
|
|
// prepare the scroll
|
2010-05-29 07:25:38 +00:00
|
|
|
|
View.VSplitRight(15, &View, &Scroll);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2011-04-13 18:37:12 +00:00
|
|
|
|
// setup the variables
|
2010-05-29 07:25:38 +00:00
|
|
|
|
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;
|
2018-02-13 02:44:43 +00:00
|
|
|
|
gs_ListBoxClicked = false;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
|
|
|
|
// do the scrollbar
|
2010-05-29 07:25:38 +00:00
|
|
|
|
View.HSplitTop(gs_ListBoxRowHeight, &Row, 0);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int NumViewable = (int)(gs_ListBoxOriginalView.h / Row.h) + 1;
|
|
|
|
|
int Num = (NumItems + gs_ListBoxItemsPerRow - 1) / gs_ListBoxItemsPerRow - NumViewable + 1;
|
2017-07-22 11:41:18 +00:00
|
|
|
|
if(Num <= 0)
|
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Num = 0;
|
2017-07-22 11:41:18 +00:00
|
|
|
|
}
|
|
|
|
|
else if(Num == 1)
|
|
|
|
|
{
|
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View))
|
|
|
|
|
gs_ListBoxScrollValue -= 0.1f;
|
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View))
|
|
|
|
|
gs_ListBoxScrollValue += 0.1f;
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(gs_ListBoxScrollValue < 0.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 0.0f;
|
|
|
|
|
if(gs_ListBoxScrollValue > 1.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 1.0f;
|
2017-07-22 11:41:18 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
|
{
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&View))
|
2020-09-26 19:41:58 +00:00
|
|
|
|
gs_ListBoxScrollValue -= 3.0f / Num;
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&View))
|
2020-09-26 19:41:58 +00:00
|
|
|
|
gs_ListBoxScrollValue += 3.0f / Num;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(gs_ListBoxScrollValue < 0.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 0.0f;
|
|
|
|
|
if(gs_ListBoxScrollValue > 1.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 1.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Scroll.HMargin(5.0f, &Scroll);
|
2011-02-12 10:40:36 +00:00
|
|
|
|
gs_ListBoxScrollValue = DoScrollbarV(pID, &Scroll, gs_ListBoxScrollValue);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2008-10-06 18:05:01 +00:00
|
|
|
|
// the list
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxView = gs_ListBoxOriginalView;
|
|
|
|
|
gs_ListBoxView.VMargin(5.0f, &gs_ListBoxView);
|
|
|
|
|
UI()->ClipEnable(&gs_ListBoxView);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
gs_ListBoxView.y -= gs_ListBoxScrollValue * Num * Row.h;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CMenus::CListboxItem CMenus::UiDoListboxNextRow()
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
static CUIRect s_RowView;
|
|
|
|
|
CListboxItem Item = {0};
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(gs_ListBoxItemIndex % gs_ListBoxItemsPerRow == 0)
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxView.HSplitTop(gs_ListBoxRowHeight /*-2.0f*/, &s_RowView, &gs_ListBoxView);
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
s_RowView.VSplitLeft(s_RowView.w / (gs_ListBoxItemsPerRow - gs_ListBoxItemIndex % gs_ListBoxItemsPerRow) / (UI()->Scale()), &Item.m_Rect, &s_RowView);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
|
|
|
|
|
Item.m_Visible = 1;
|
2009-10-27 14:38:53 +00:00
|
|
|
|
//item.rect = row;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Item.m_HitRect = Item.m_Rect;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
|
//CUIRect select_hit_box = item.rect;
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(gs_ListBoxSelectedIndex == gs_ListBoxItemIndex)
|
|
|
|
|
Item.m_Selected = 1;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
|
// make sure that only those in view can be selected
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(Item.m_Rect.y + Item.m_Rect.h > gs_ListBoxOriginalView.y)
|
2009-10-27 14:38:53 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(Item.m_HitRect.y < Item.m_HitRect.y) // clip the selection
|
2009-10-27 14:38:53 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
Item.m_HitRect.h -= gs_ListBoxOriginalView.y - Item.m_HitRect.y;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Item.m_HitRect.y = gs_ListBoxOriginalView.y;
|
2009-10-27 14:38:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Item.m_Visible = 0;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2009-10-27 14:38:53 +00:00
|
|
|
|
// check if we need to do more
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(Item.m_Rect.y > gs_ListBoxOriginalView.y + gs_ListBoxOriginalView.h)
|
2010-05-29 07:25:38 +00:00
|
|
|
|
Item.m_Visible = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxItemIndex++;
|
|
|
|
|
return Item;
|
2009-10-27 14:38:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-09-16 01:30:03 +00:00
|
|
|
|
CMenus::CListboxItem CMenus::UiDoListboxNextItem(const void *pId, bool Selected, bool KeyEvents, bool NoHoverEffects)
|
2009-10-27 14:38:53 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
int ThisItemIndex = gs_ListBoxItemIndex;
|
|
|
|
|
if(Selected)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(gs_ListBoxSelectedIndex == gs_ListBoxNewSelected)
|
|
|
|
|
gs_ListBoxNewSelected = ThisItemIndex;
|
|
|
|
|
gs_ListBoxSelectedIndex = ThisItemIndex;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CListboxItem Item = UiDoListboxNextRow();
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2018-02-13 16:15:16 +00:00
|
|
|
|
if(Item.m_Visible && UI()->DoButtonLogic(pId, "", gs_ListBoxSelectedIndex == gs_ListBoxItemIndex, &Item.m_HitRect))
|
|
|
|
|
{
|
2018-02-13 02:44:43 +00:00
|
|
|
|
gs_ListBoxClicked = true;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxNewSelected = ThisItemIndex;
|
2018-02-13 02:44:43 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
// process input, regard selected index
|
|
|
|
|
if(gs_ListBoxSelectedIndex == ThisItemIndex)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(!gs_ListBoxDoneEvents)
|
2009-06-15 14:01:36 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxDoneEvents = 1;
|
|
|
|
|
|
2011-05-04 23:56:31 +00:00
|
|
|
|
if(m_EnterPressed || (UI()->ActiveItem() == pId && Input()->MouseDoubleClick()))
|
2009-06-15 14:01:36 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxItemActivated = true;
|
2010-09-03 17:39:20 +00:00
|
|
|
|
UI()->SetActiveItem(0);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
}
|
2016-04-27 18:26:33 +00:00
|
|
|
|
else if(KeyEvents)
|
2011-04-13 18:37:12 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
for(int i = 0; i < m_NumInputEvents; i++)
|
2009-06-15 14:01:36 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
int NewIndex = -1;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_aInputEvents[i].m_Flags & IInput::FLAG_PRESS)
|
2010-05-29 07:25:38 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
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;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
}
|
|
|
|
|
if(NewIndex > -1 && NewIndex < gs_ListBoxNumItems)
|
|
|
|
|
{
|
|
|
|
|
// scroll
|
2020-09-26 19:41:58 +00:00
|
|
|
|
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;
|
2010-09-29 23:13:12 +00:00
|
|
|
|
if(Scroll)
|
2010-05-29 07:25:38 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int NumViewable = (int)(gs_ListBoxOriginalView.h / gs_ListBoxRowHeight) + 1;
|
|
|
|
|
int ScrollNum = (gs_ListBoxNumItems + gs_ListBoxItemsPerRow - 1) / gs_ListBoxItemsPerRow - NumViewable + 1;
|
2010-09-29 23:13:12 +00:00
|
|
|
|
if(Scroll < 0)
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int Num = (gs_ListBoxOriginalView.y - Item.m_Rect.y - Offset + gs_ListBoxRowHeight - 1.0f) / gs_ListBoxRowHeight;
|
|
|
|
|
gs_ListBoxScrollValue -= (1.0f / ScrollNum) * Num;
|
2010-09-29 23:13:12 +00:00
|
|
|
|
}
|
2010-05-29 07:25:38 +00:00
|
|
|
|
else
|
2010-09-29 23:13:12 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
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;
|
2010-09-29 23:13:12 +00:00
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(gs_ListBoxScrollValue < 0.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 0.0f;
|
|
|
|
|
if(gs_ListBoxScrollValue > 1.0f)
|
|
|
|
|
gs_ListBoxScrollValue = 1.0f;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
gs_ListBoxNewSelected = NewIndex;
|
|
|
|
|
}
|
2009-06-15 14:01:36 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2008-10-06 18:05:01 +00:00
|
|
|
|
//selected_index = i;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CUIRect r = Item.m_Rect;
|
2009-10-27 14:38:53 +00:00
|
|
|
|
r.Margin(1.5f, &r);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&r, ColorRGBA(1, 1, 1, 0.5f), CUI::CORNER_ALL, 4.0f);
|
2020-09-16 01:30:03 +00:00
|
|
|
|
}
|
|
|
|
|
else if(UI()->MouseInside(&Item.m_Rect) && !NoHoverEffects)
|
|
|
|
|
{
|
|
|
|
|
CUIRect r = Item.m_Rect;
|
|
|
|
|
r.Margin(1.5f, &r);
|
|
|
|
|
RenderTools()->DrawUIRect(&r, ColorRGBA(1, 1, 1, 0.25f), CUI::CORNER_ALL, 4.0f);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
return Item;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 02:44:43 +00:00
|
|
|
|
int CMenus::UiDoListboxEnd(float *pScrollValue, bool *pItemActivated, bool *pListBoxActive)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2009-10-27 14:38:53 +00:00
|
|
|
|
UI()->ClipDisable();
|
2010-05-29 07:25:38 +00:00
|
|
|
|
if(pScrollValue)
|
|
|
|
|
*pScrollValue = gs_ListBoxScrollValue;
|
|
|
|
|
if(pItemActivated)
|
|
|
|
|
*pItemActivated = gs_ListBoxItemActivated;
|
2018-02-13 02:44:43 +00:00
|
|
|
|
if(pListBoxActive)
|
|
|
|
|
*pListBoxActive = gs_ListBoxClicked;
|
2010-05-29 07:25:38 +00:00
|
|
|
|
return gs_ListBoxNewSelected;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2015-08-27 12:57:56 +00:00
|
|
|
|
int CMenus::DemolistFetchCallback(const char *pName, time_t Date, int IsDir, int StorageType, void *pUser)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-09-18 13:08:57 +00:00
|
|
|
|
CMenus *pSelf = (CMenus *)pUser;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(str_comp(pName, ".") == 0 || (str_comp(pName, "..") == 0 && str_comp(pSelf->m_aCurrentDemoFolder, "demos") == 0) || (!IsDir && !str_endswith(pName, ".demo")))
|
2018-07-25 08:29:05 +00:00
|
|
|
|
{
|
2011-02-21 10:23:30 +00:00
|
|
|
|
return 0;
|
2018-07-25 08:29:05 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
CDemoItem Item;
|
2010-09-28 22:53:53 +00:00
|
|
|
|
str_copy(Item.m_aFilename, pName, sizeof(Item.m_aFilename));
|
|
|
|
|
if(IsDir)
|
2010-10-09 11:27:21 +00:00
|
|
|
|
{
|
2010-09-28 22:53:53 +00:00
|
|
|
|
str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pName);
|
2019-04-08 20:13:47 +00:00
|
|
|
|
Item.m_InfosLoaded = false;
|
2010-10-09 11:27:21 +00:00
|
|
|
|
Item.m_Valid = false;
|
|
|
|
|
}
|
2010-09-28 22:53:53 +00:00
|
|
|
|
else
|
2010-10-09 11:27:21 +00:00
|
|
|
|
{
|
2019-04-26 19:36:49 +00:00
|
|
|
|
str_copy(Item.m_aName, pName, minimum(static_cast<int>(sizeof(Item.m_aName)), str_length(pName) - 4));
|
2010-11-20 13:45:09 +00:00
|
|
|
|
Item.m_InfosLoaded = false;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
Item.m_Date = Date;
|
2010-10-09 11:27:21 +00:00
|
|
|
|
}
|
2010-09-28 22:53:53 +00:00
|
|
|
|
Item.m_IsDir = IsDir != 0;
|
2010-10-06 21:07:35 +00:00
|
|
|
|
Item.m_StorageType = StorageType;
|
2011-03-27 14:42:47 +00:00
|
|
|
|
pSelf->m_lDemos.add_unsorted(Item);
|
2011-02-21 10:23:30 +00:00
|
|
|
|
|
|
|
|
|
return 0;
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CMenus::DemolistPopulate()
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
m_lDemos.clear();
|
2010-10-07 22:13:05 +00:00
|
|
|
|
if(!str_comp(m_aCurrentDemoFolder, "demos"))
|
|
|
|
|
m_DemolistStorageType = IStorage::TYPE_ALL;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
Storage()->ListDirectoryInfo(m_DemolistStorageType, m_aCurrentDemoFolder, DemolistFetchCallback, this);
|
2019-03-19 17:28:09 +00:00
|
|
|
|
|
|
|
|
|
if(g_Config.m_BrDemoFetchInfo)
|
|
|
|
|
FetchAllHeaders();
|
|
|
|
|
|
2011-03-27 14:42:47 +00:00
|
|
|
|
m_lDemos.sort_range();
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-28 22:53:53 +00:00
|
|
|
|
void CMenus::DemolistOnUpdate(bool Reset)
|
|
|
|
|
{
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(Reset)
|
2015-08-27 12:57:56 +00:00
|
|
|
|
g_Config.m_UiDemoSelected[0] = '\0';
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
bool Found = false;
|
|
|
|
|
int SelectedIndex = -1;
|
|
|
|
|
// search for selected index
|
|
|
|
|
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
|
|
|
|
{
|
|
|
|
|
SelectedIndex++;
|
|
|
|
|
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(str_comp(g_Config.m_UiDemoSelected, r.front().m_aName) == 0)
|
2015-08-27 12:57:56 +00:00
|
|
|
|
{
|
|
|
|
|
Found = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(Found)
|
2015-08-27 12:57:56 +00:00
|
|
|
|
m_DemolistSelectedIndex = SelectedIndex;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-28 22:53:53 +00:00
|
|
|
|
m_DemolistSelectedIndex = Reset ? m_lDemos.size() > 0 ? 0 : -1 :
|
2020-09-26 19:41:58 +00:00
|
|
|
|
m_DemolistSelectedIndex >= m_lDemos.size() ? m_lDemos.size() - 1 : m_DemolistSelectedIndex;
|
2010-09-28 22:53:53 +00:00
|
|
|
|
m_DemolistSelectedIsDir = m_DemolistSelectedIndex < 0 ? false : m_lDemos[m_DemolistSelectedIndex].m_IsDir;
|
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
|
2019-01-08 19:12:21 +00:00
|
|
|
|
bool CMenus::FetchHeader(CDemoItem &Item)
|
|
|
|
|
{
|
|
|
|
|
if(!Item.m_InfosLoaded)
|
|
|
|
|
{
|
|
|
|
|
char aBuffer[512];
|
|
|
|
|
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_aCurrentDemoFolder, Item.m_aFilename);
|
2019-10-14 00:27:08 +00:00
|
|
|
|
Item.m_Valid = DemoPlayer()->GetDemoInfo(Storage(), aBuffer, Item.m_StorageType, &Item.m_Info, &Item.m_TimelineMarkers, &Item.m_MapInfo);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Item.m_InfosLoaded = true;
|
|
|
|
|
}
|
|
|
|
|
return Item.m_Valid;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 17:28:09 +00:00
|
|
|
|
void CMenus::FetchAllHeaders()
|
|
|
|
|
{
|
|
|
|
|
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
|
|
|
|
{
|
|
|
|
|
FetchHeader(r.front());
|
|
|
|
|
}
|
|
|
|
|
m_lDemos.sort_range();
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
void CMenus::RenderDemoList(CUIRect MainView)
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
static int s_Inited = 0;
|
|
|
|
|
if(!s_Inited)
|
2010-09-05 12:28:08 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
DemolistPopulate();
|
2010-09-28 22:53:53 +00:00
|
|
|
|
DemolistOnUpdate(true);
|
2010-09-05 12:28:08 +00:00
|
|
|
|
s_Inited = 1;
|
2010-09-05 17:06:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-10-13 10:59:30 +00:00
|
|
|
|
char aFooterLabel[128] = {0};
|
|
|
|
|
if(m_DemolistSelectedIndex >= 0)
|
|
|
|
|
{
|
2019-01-08 19:12:21 +00:00
|
|
|
|
CDemoItem &Item = m_lDemos[m_DemolistSelectedIndex];
|
|
|
|
|
if(str_comp(Item.m_aFilename, "..") == 0)
|
2010-10-13 10:59:30 +00:00
|
|
|
|
str_copy(aFooterLabel, Localize("Parent Folder"), sizeof(aFooterLabel));
|
|
|
|
|
else if(m_DemolistSelectedIsDir)
|
|
|
|
|
str_copy(aFooterLabel, Localize("Folder"), sizeof(aFooterLabel));
|
2019-01-08 19:12:21 +00:00
|
|
|
|
else if(!FetchHeader(Item))
|
|
|
|
|
str_copy(aFooterLabel, Localize("Invalid Demo"), sizeof(aFooterLabel));
|
2010-10-13 10:59:30 +00:00
|
|
|
|
else
|
2019-01-08 19:12:21 +00:00
|
|
|
|
str_copy(aFooterLabel, Localize("Demo details"), sizeof(aFooterLabel));
|
2010-10-09 11:27:21 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2008-10-06 18:05:01 +00:00
|
|
|
|
// render background
|
2019-03-24 22:15:38 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&MainView, ms_ColorTabbarActive, CUI::CORNER_B, 10.0f);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
MainView.Margin(10.0f, &MainView);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
2019-09-26 15:28:29 +00:00
|
|
|
|
CUIRect ButtonBar, RefreshRect, FetchRect, PlayRect, DeleteRect, RenameRect, RenderRect, LabelRect, ListBox;
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#else
|
|
|
|
|
CUIRect ButtonBar, RefreshRect, FetchRect, PlayRect, DeleteRect, RenameRect, LabelRect, ListBox;
|
|
|
|
|
#endif
|
2020-09-26 19:41:58 +00:00
|
|
|
|
MainView.HSplitBottom(ms_ButtonHeight + 5.0f, &MainView, &ButtonBar);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
ButtonBar.HSplitTop(5.0f, 0, &ButtonBar);
|
2019-03-19 17:28:09 +00:00
|
|
|
|
ButtonBar.VSplitRight(110.0f, &ButtonBar, &PlayRect);
|
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &RefreshRect, &ButtonBar);
|
2011-03-12 18:08:44 +00:00
|
|
|
|
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
|
2019-03-19 17:28:09 +00:00
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &FetchRect, &ButtonBar);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
|
2019-03-19 17:28:09 +00:00
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &DeleteRect, &ButtonBar);
|
2011-03-12 18:08:44 +00:00
|
|
|
|
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
|
2019-03-19 17:28:09 +00:00
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &RenameRect, &ButtonBar);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
2019-09-26 15:28:29 +00:00
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &RenderRect, &ButtonBar);
|
2019-09-30 13:03:37 +00:00
|
|
|
|
ButtonBar.VSplitLeft(10.0f, 0, &ButtonBar);
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#endif
|
2019-09-30 13:03:37 +00:00
|
|
|
|
ButtonBar.VSplitLeft(110.0f, &LabelRect, &ButtonBar);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
MainView.HSplitBottom(140.0f, &ListBox, &MainView);
|
|
|
|
|
|
|
|
|
|
// render demo info
|
|
|
|
|
MainView.VMargin(5.0f, &MainView);
|
|
|
|
|
MainView.HSplitBottom(5.0f, &MainView, 0);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&MainView, ColorRGBA(0, 0, 0, 0.15f), CUI::CORNER_B, 4.0f);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
if(!m_DemolistSelectedIsDir && m_DemolistSelectedIndex >= 0 && m_lDemos[m_DemolistSelectedIndex].m_Valid)
|
|
|
|
|
{
|
|
|
|
|
CUIRect Left, Right, Labels;
|
2019-01-08 19:12:21 +00:00
|
|
|
|
MainView.VMargin(20.0f, &MainView);
|
|
|
|
|
MainView.HMargin(10.0f, &MainView);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
MainView.VSplitMid(&Labels, &MainView);
|
|
|
|
|
|
|
|
|
|
// left side
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Created:"), 14.0f, -1);
|
2015-08-27 13:02:55 +00:00
|
|
|
|
|
|
|
|
|
char aTimestamp[256];
|
2017-08-04 20:38:22 +00:00
|
|
|
|
str_timestamp_ex(m_lDemos[m_DemolistSelectedIndex].m_Date, aTimestamp, sizeof(aTimestamp), FORMAT_SPACE);
|
2015-08-27 13:02:55 +00:00
|
|
|
|
|
|
|
|
|
UI()->DoLabelScaled(&Right, aTimestamp, 14.0f, -1);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Type:"), 14.0f, -1);
|
|
|
|
|
UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aType, 14.0f, -1);
|
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Length:"), 14.0f, -1);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
int Length = m_lDemos[m_DemolistSelectedIndex].Length();
|
2011-03-13 09:41:10 +00:00
|
|
|
|
char aBuf[64];
|
2020-09-26 19:41:58 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d:%02d", Length / 60, Length % 60);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Version:"), 14.0f, -1);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].m_Info.m_Version);
|
|
|
|
|
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Markers:"), 14.0f, -1);
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", m_lDemos[m_DemolistSelectedIndex].NumMarkers());
|
|
|
|
|
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
|
|
|
|
|
// right side
|
|
|
|
|
Labels = MainView;
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Map:"), 14.0f, -1);
|
|
|
|
|
UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapName, 14.0f, -1);
|
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Size:"), 14.0f, -1);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
unsigned Size = (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[0] << 24) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[1] << 16) |
|
|
|
|
|
(m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[2] << 8) | (m_lDemos[m_DemolistSelectedIndex].m_Info.m_aMapSize[3]);
|
|
|
|
|
if(Size > 1024 * 1024)
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("%.2f MiB"), float(Size) / (1024 * 1024));
|
2014-07-08 18:35:27 +00:00
|
|
|
|
else
|
2020-09-26 19:41:58 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), Localize("%.2f KiB"), float(Size) / 1024);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Crc:"), 14.0f, -1);
|
2019-10-14 00:27:08 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%08x", m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Crc);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Right, aBuf, 14.0f, -1);
|
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
2019-12-17 14:44:54 +00:00
|
|
|
|
|
|
|
|
|
if(m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Sha256 != SHA256_ZEROED)
|
|
|
|
|
{
|
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2020-06-26 16:17:20 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, "SHA256:", 14.0f, -1);
|
2019-12-17 14:44:54 +00:00
|
|
|
|
char aSha[SHA256_MAXSTRSIZE];
|
2020-09-26 19:41:58 +00:00
|
|
|
|
sha256_str(m_lDemos[m_DemolistSelectedIndex].m_MapInfo.m_Sha256, aSha, sizeof(aSha) / 2);
|
2020-09-08 09:31:45 +00:00
|
|
|
|
UI()->DoLabelScaled(&Right, aSha, Right.w > 235 ? 14.0f : 11.0f, -1);
|
2019-12-17 14:44:54 +00:00
|
|
|
|
Labels.HSplitTop(5.0f, 0, &Labels);
|
|
|
|
|
Labels.HSplitTop(20.0f, &Left, &Labels);
|
|
|
|
|
}
|
|
|
|
|
|
2011-04-03 21:33:43 +00:00
|
|
|
|
Left.VSplitLeft(150.0f, &Left, &Right);
|
2011-03-13 09:41:10 +00:00
|
|
|
|
UI()->DoLabelScaled(&Left, Localize("Netversion:"), 14.0f, -1);
|
|
|
|
|
UI()->DoLabelScaled(&Right, m_lDemos[m_DemolistSelectedIndex].m_Info.m_aNetversion, 14.0f, -1);
|
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2015-08-25 13:55:15 +00:00
|
|
|
|
// demo list
|
|
|
|
|
|
|
|
|
|
CUIRect Headers;
|
|
|
|
|
|
|
|
|
|
ListBox.HSplitTop(ms_ListheaderHeight, &Headers, &ListBox);
|
|
|
|
|
|
|
|
|
|
struct CColumn
|
|
|
|
|
{
|
|
|
|
|
int m_ID;
|
|
|
|
|
int m_Sort;
|
|
|
|
|
CLocConstString m_Caption;
|
|
|
|
|
int m_Direction;
|
|
|
|
|
float m_Width;
|
|
|
|
|
int m_Flags;
|
|
|
|
|
CUIRect m_Rect;
|
|
|
|
|
CUIRect m_Spacer;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
COL_ICON = 0,
|
2015-08-27 12:57:56 +00:00
|
|
|
|
COL_DEMONAME,
|
2019-01-08 19:12:21 +00:00
|
|
|
|
COL_MARKERS,
|
|
|
|
|
COL_LENGTH,
|
2015-08-25 13:55:15 +00:00
|
|
|
|
COL_DATE,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static CColumn s_aCols[] = {
|
2020-09-18 21:27:24 +00:00
|
|
|
|
{COL_ICON, -1, " ", -1, 14.0f, 0, {0}, {0}},
|
|
|
|
|
{COL_DEMONAME, SORT_DEMONAME, "Demo", 0, 0.0f, 0, {0}, {0}},
|
|
|
|
|
{COL_MARKERS, SORT_MARKERS, "Markers", 1, 75.0f, 0, {0}, {0}},
|
|
|
|
|
{COL_LENGTH, SORT_LENGTH, "Length", 1, 75.0f, 0, {0}, {0}},
|
|
|
|
|
{COL_DATE, SORT_DATE, "Date", 1, 160.0f, 1, {0}, {0}},
|
2015-08-25 13:55:15 +00:00
|
|
|
|
};
|
2020-09-18 21:27:24 +00:00
|
|
|
|
/* This is just for scripts/update_localization.py to work correctly. Don't remove!
|
|
|
|
|
Localize("Demo");Localize("Markers");Localize("Length");Localize("Date");
|
|
|
|
|
*/
|
2015-08-25 13:55:15 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
RenderTools()->DrawUIRect(&Headers, ColorRGBA(0.0f, 0, 0, 0.15f), 0, 0);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int NumCols = sizeof(s_aCols) / sizeof(CColumn);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
|
|
|
|
|
// do layout
|
|
|
|
|
for(int i = 0; i < NumCols; i++)
|
|
|
|
|
{
|
|
|
|
|
if(s_aCols[i].m_Direction == -1)
|
|
|
|
|
{
|
|
|
|
|
Headers.VSplitLeft(s_aCols[i].m_Width, &s_aCols[i].m_Rect, &Headers);
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(i + 1 < NumCols)
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
|
|
|
|
//Cols[i].flags |= SPACER;
|
|
|
|
|
Headers.VSplitLeft(2, &s_aCols[i].m_Spacer, &Headers);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
for(int i = NumCols - 1; i >= 0; i--)
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
|
|
|
|
if(s_aCols[i].m_Direction == 1)
|
|
|
|
|
{
|
|
|
|
|
Headers.VSplitRight(s_aCols[i].m_Width, &Headers, &s_aCols[i].m_Rect);
|
|
|
|
|
Headers.VSplitRight(2, &Headers, &s_aCols[i].m_Spacer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < NumCols; i++)
|
|
|
|
|
{
|
|
|
|
|
if(s_aCols[i].m_Direction == 0)
|
|
|
|
|
s_aCols[i].m_Rect = Headers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// do headers
|
|
|
|
|
for(int i = 0; i < NumCols; i++)
|
|
|
|
|
{
|
2020-09-18 21:27:24 +00:00
|
|
|
|
if(DoButton_GridHeader(s_aCols[i].m_Caption, Localize(s_aCols[i].m_Caption), g_Config.m_BrDemoSort == s_aCols[i].m_Sort, &s_aCols[i].m_Rect))
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
|
|
|
|
if(s_aCols[i].m_Sort != -1)
|
|
|
|
|
{
|
2015-08-27 12:57:56 +00:00
|
|
|
|
if(g_Config.m_BrDemoSort == s_aCols[i].m_Sort)
|
|
|
|
|
g_Config.m_BrDemoSortOrder ^= 1;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
else
|
2015-08-27 12:57:56 +00:00
|
|
|
|
g_Config.m_BrDemoSortOrder = 0;
|
|
|
|
|
g_Config.m_BrDemoSort = s_aCols[i].m_Sort;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
}
|
2015-08-27 12:57:56 +00:00
|
|
|
|
|
2019-01-08 19:12:21 +00:00
|
|
|
|
// Don't rescan in order to keep fetched headers, just resort
|
|
|
|
|
m_lDemos.sort_range();
|
2015-08-27 12:57:56 +00:00
|
|
|
|
DemolistOnUpdate(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// scrollbar
|
|
|
|
|
CUIRect Scroll;
|
|
|
|
|
ListBox.VSplitRight(15, &ListBox, &Scroll);
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int Num = (int)(ListBox.h / s_aCols[0].m_Rect.h) + 1;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
static int s_ScrollBar = 0;
|
|
|
|
|
static float s_ScrollValue = 0;
|
|
|
|
|
|
|
|
|
|
Scroll.HMargin(5.0f, &Scroll);
|
|
|
|
|
s_ScrollValue = DoScrollbarV(&s_ScrollBar, &Scroll, s_ScrollValue);
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int ScrollNum = m_lDemos.size() - Num + 1;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
if(ScrollNum > 0)
|
|
|
|
|
{
|
|
|
|
|
if(m_ScrollOffset)
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
s_ScrollValue = (float)(m_ScrollOffset) / ScrollNum;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
m_ScrollOffset = 0;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
}
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP) && UI()->MouseInside(&ListBox))
|
2020-09-26 19:41:58 +00:00
|
|
|
|
s_ScrollValue -= 3.0f / ScrollNum;
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN) && UI()->MouseInside(&ListBox))
|
2020-09-26 19:41:58 +00:00
|
|
|
|
s_ScrollValue += 3.0f / ScrollNum;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
}
|
2015-08-27 12:57:56 +00:00
|
|
|
|
else
|
|
|
|
|
ScrollNum = 0;
|
|
|
|
|
|
2015-08-27 14:59:25 +00:00
|
|
|
|
if(m_DemolistSelectedIndex > -1)
|
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < m_NumInputEvents; i++)
|
|
|
|
|
{
|
|
|
|
|
int NewIndex = -1;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_aInputEvents[i].m_Flags & IInput::FLAG_PRESS)
|
2015-08-27 14:59:25 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_aInputEvents[i].m_Key == KEY_DOWN)
|
|
|
|
|
NewIndex = m_DemolistSelectedIndex + 1;
|
|
|
|
|
else if(m_aInputEvents[i].m_Key == KEY_UP)
|
|
|
|
|
NewIndex = m_DemolistSelectedIndex - 1;
|
|
|
|
|
else if(m_aInputEvents[i].m_Key == KEY_PAGEUP)
|
|
|
|
|
NewIndex = maximum(m_DemolistSelectedIndex - 20, 0);
|
|
|
|
|
else if(m_aInputEvents[i].m_Key == KEY_PAGEDOWN)
|
|
|
|
|
NewIndex = minimum(m_DemolistSelectedIndex + 20, m_lDemos.size() - 1);
|
|
|
|
|
else if(m_aInputEvents[i].m_Key == KEY_HOME)
|
|
|
|
|
NewIndex = 0;
|
|
|
|
|
else if(m_aInputEvents[i].m_Key == KEY_END)
|
|
|
|
|
NewIndex = m_lDemos.size() - 1;
|
2015-08-27 14:59:25 +00:00
|
|
|
|
}
|
|
|
|
|
if(NewIndex > -1 && NewIndex < m_lDemos.size())
|
|
|
|
|
{
|
|
|
|
|
//scroll
|
2020-09-26 19:41:58 +00:00
|
|
|
|
float IndexY = ListBox.y - s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h + NewIndex * s_aCols[0].m_Rect.h;
|
|
|
|
|
int Scroll = ListBox.y > IndexY ? -1 : ListBox.y + ListBox.h < IndexY + s_aCols[0].m_Rect.h ? 1 : 0;
|
2015-08-27 14:59:25 +00:00
|
|
|
|
if(Scroll)
|
|
|
|
|
{
|
|
|
|
|
if(Scroll < 0)
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int NumScrolls = (ListBox.y - IndexY + s_aCols[0].m_Rect.h - 1.0f) / s_aCols[0].m_Rect.h;
|
|
|
|
|
s_ScrollValue -= (1.0f / ScrollNum) * NumScrolls;
|
2015-08-27 14:59:25 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
int NumScrolls = (IndexY + s_aCols[0].m_Rect.h - (ListBox.y + ListBox.h) + s_aCols[0].m_Rect.h - 1.0f) / s_aCols[0].m_Rect.h;
|
|
|
|
|
s_ScrollValue += (1.0f / ScrollNum) * NumScrolls;
|
2015-08-27 14:59:25 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_DemolistSelectedIndex = NewIndex;
|
|
|
|
|
|
|
|
|
|
str_copy(g_Config.m_UiDemoSelected, m_lDemos[NewIndex].m_aName, sizeof(g_Config.m_UiDemoSelected));
|
|
|
|
|
DemolistOnUpdate(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(s_ScrollValue < 0)
|
|
|
|
|
s_ScrollValue = 0;
|
|
|
|
|
if(s_ScrollValue > 1)
|
|
|
|
|
s_ScrollValue = 1;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
|
|
|
|
|
// set clipping
|
|
|
|
|
UI()->ClipEnable(&ListBox);
|
|
|
|
|
|
2015-08-25 13:55:15 +00:00
|
|
|
|
CUIRect OriginalView = ListBox;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
ListBox.y -= s_ScrollValue * ScrollNum * s_aCols[0].m_Rect.h;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
|
2015-08-25 13:55:15 +00:00
|
|
|
|
int NewSelected = -1;
|
|
|
|
|
int ItemIndex = -1;
|
|
|
|
|
|
|
|
|
|
for(sorted_array<CDemoItem>::range r = m_lDemos.all(); !r.empty(); r.pop_front())
|
|
|
|
|
{
|
|
|
|
|
ItemIndex++;
|
|
|
|
|
|
|
|
|
|
CUIRect Row;
|
|
|
|
|
CUIRect SelectHitBox;
|
|
|
|
|
|
|
|
|
|
ListBox.HSplitTop(ms_ListheaderHeight, &Row, &ListBox);
|
|
|
|
|
SelectHitBox = Row;
|
|
|
|
|
|
2015-08-27 12:57:56 +00:00
|
|
|
|
int Selected = ItemIndex == m_DemolistSelectedIndex;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
|
|
|
|
|
// make sure that only those in view can be selected
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(Row.y + Row.h > OriginalView.y && Row.y < OriginalView.y + OriginalView.h)
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
|
|
|
|
if(Selected)
|
|
|
|
|
{
|
|
|
|
|
CUIRect r = Row;
|
2020-09-22 16:41:47 +00:00
|
|
|
|
r.Margin(0.5f, &r);
|
|
|
|
|
RenderTools()->DrawUIRect(&r, ColorRGBA(1, 1, 1, 0.5f), CUI::CORNER_ALL, 4.0f);
|
|
|
|
|
}
|
|
|
|
|
else if(UI()->MouseInside(&SelectHitBox))
|
|
|
|
|
{
|
|
|
|
|
CUIRect r = Row;
|
|
|
|
|
r.Margin(0.5f, &r);
|
|
|
|
|
RenderTools()->DrawUIRect(&r, ColorRGBA(1, 1, 1, 0.25f), CUI::CORNER_ALL, 4.0f);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clip the selection
|
|
|
|
|
if(SelectHitBox.y < OriginalView.y) // top
|
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
SelectHitBox.h -= OriginalView.y - SelectHitBox.y;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
SelectHitBox.y = OriginalView.y;
|
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
|
else if(SelectHitBox.y + SelectHitBox.h > OriginalView.y + OriginalView.h) // bottom
|
|
|
|
|
SelectHitBox.h = OriginalView.y + OriginalView.h - SelectHitBox.y;
|
2015-08-25 13:55:15 +00:00
|
|
|
|
|
|
|
|
|
if(UI()->DoButtonLogic(r.front().m_aName /* TODO: */, "", Selected, &SelectHitBox))
|
|
|
|
|
{
|
|
|
|
|
NewSelected = ItemIndex;
|
|
|
|
|
str_copy(g_Config.m_UiDemoSelected, r.front().m_aName, sizeof(g_Config.m_UiDemoSelected));
|
2015-08-27 12:57:56 +00:00
|
|
|
|
DemolistOnUpdate(false);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
m_DoubleClickIndex = NewSelected;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// don't render invisible items
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(int c = 0; c < NumCols; c++)
|
|
|
|
|
{
|
|
|
|
|
CUIRect Button;
|
|
|
|
|
Button.x = s_aCols[c].m_Rect.x;
|
|
|
|
|
Button.y = Row.y;
|
|
|
|
|
Button.h = Row.h;
|
|
|
|
|
Button.w = s_aCols[c].m_Rect.w;
|
|
|
|
|
|
|
|
|
|
int ID = s_aCols[c].m_ID;
|
|
|
|
|
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(ID == COL_ICON)
|
2015-08-27 12:57:56 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
DoButton_Icon(IMAGE_FILEICONS, r.front().m_IsDir ? SPRITE_FILE_FOLDER : SPRITE_FILE_DEMO1, &Button);
|
2015-08-27 12:57:56 +00:00
|
|
|
|
}
|
|
|
|
|
else if(ID == COL_DEMONAME)
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
|
|
|
|
CTextCursor Cursor;
|
2020-09-26 19:41:58 +00:00
|
|
|
|
TextRender()->SetCursor(&Cursor, Button.x, Button.y + (Button.h - 12.0f * UI()->Scale()) / 2.f, 12.0f * UI()->Scale(), TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
Cursor.m_LineWidth = Button.w;
|
|
|
|
|
|
|
|
|
|
TextRender()->TextEx(&Cursor, r.front().m_aName, -1);
|
|
|
|
|
}
|
2019-01-08 19:12:21 +00:00
|
|
|
|
else if(ID == COL_MARKERS && !r.front().m_IsDir && r.front().m_InfosLoaded)
|
|
|
|
|
{
|
|
|
|
|
char aBuf[3];
|
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d", r.front().NumMarkers());
|
|
|
|
|
Button.VMargin(4.0f, &Button);
|
|
|
|
|
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
|
|
|
|
|
}
|
|
|
|
|
else if(ID == COL_LENGTH && !r.front().m_IsDir && r.front().m_InfosLoaded)
|
|
|
|
|
{
|
|
|
|
|
int Length = r.front().Length();
|
|
|
|
|
char aBuf[32];
|
2020-09-26 19:41:58 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%d:%02d", Length / 60, Length % 60);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Button.VMargin(4.0f, &Button);
|
|
|
|
|
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
|
|
|
|
|
}
|
2018-03-13 20:59:07 +00:00
|
|
|
|
else if(ID == COL_DATE && !r.front().m_IsDir)
|
2015-08-25 13:55:15 +00:00
|
|
|
|
{
|
2019-01-08 19:12:21 +00:00
|
|
|
|
char aBuf[64];
|
2017-08-04 20:38:22 +00:00
|
|
|
|
str_timestamp_ex(r.front().m_Date, aBuf, sizeof(aBuf), FORMAT_SPACE);
|
2019-01-08 19:12:21 +00:00
|
|
|
|
Button.VSplitRight(24.0f, &Button, 0);
|
|
|
|
|
UI()->DoLabelScaled(&Button, aBuf, 12.0f, 1);
|
2015-08-25 13:55:15 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-27 12:57:56 +00:00
|
|
|
|
UI()->ClipDisable();
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
bool Activated = false;
|
2015-08-27 12:57:56 +00:00
|
|
|
|
|
2018-03-13 20:59:07 +00:00
|
|
|
|
if(m_EnterPressed || (Input()->MouseDoubleClick() && UI()->HotItem() == m_lDemos[m_DemolistSelectedIndex].m_aName))
|
2015-08-27 12:57:56 +00:00
|
|
|
|
{
|
|
|
|
|
UI()->SetActiveItem(0);
|
|
|
|
|
Activated = true;
|
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
static int s_RefreshButton = 0;
|
2016-04-30 18:11:26 +00:00
|
|
|
|
if(DoButton_Menu(&s_RefreshButton, Localize("Refresh"), 0, &RefreshRect) || Input()->KeyPress(KEY_F5) || (Input()->KeyPress(KEY_R) && (Input()->KeyIsPressed(KEY_LCTRL) || Input()->KeyIsPressed(KEY_RCTRL))))
|
2008-10-06 18:05:01 +00:00
|
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
|
DemolistPopulate();
|
2010-09-28 22:53:53 +00:00
|
|
|
|
DemolistOnUpdate(false);
|
2010-05-29 07:25:38 +00:00
|
|
|
|
}
|
2010-10-09 11:27:21 +00:00
|
|
|
|
|
2019-03-19 17:28:09 +00:00
|
|
|
|
if(DoButton_CheckBox(&g_Config.m_BrDemoFetchInfo, Localize("Fetch Info"), g_Config.m_BrDemoFetchInfo, &FetchRect))
|
2019-01-08 19:12:21 +00:00
|
|
|
|
{
|
2019-03-19 17:28:09 +00:00
|
|
|
|
g_Config.m_BrDemoFetchInfo ^= 1;
|
|
|
|
|
if(g_Config.m_BrDemoFetchInfo)
|
|
|
|
|
FetchAllHeaders();
|
2019-01-08 19:12:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
|
static int s_PlayButton = 0;
|
2020-09-18 05:57:36 +00:00
|
|
|
|
if(DoButton_Menu(&s_PlayButton, m_DemolistSelectedIsDir ? Localize("Open") : Localize("Play", "Demo browser"), 0, &PlayRect) || Activated || (Input()->KeyPress(KEY_P) && m_pClient->m_pGameConsole->IsClosed() && m_DemoPlayerState == DEMOPLAYER_NONE))
|
2010-09-03 19:41:37 +00:00
|
|
|
|
{
|
2010-09-28 22:53:53 +00:00
|
|
|
|
if(m_DemolistSelectedIndex >= 0)
|
2009-06-15 13:16:33 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(m_DemolistSelectedIsDir) // folder
|
2010-06-04 20:14:02 +00:00
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
|
if(str_comp(m_lDemos[m_DemolistSelectedIndex].m_aFilename, "..") == 0) // parent folder
|
2010-09-28 22:53:53 +00:00
|
|
|
|
fs_parent_dir(m_aCurrentDemoFolder);
|
2020-09-26 19:41:58 +00:00
|
|
|
|
else // sub folder
|
2010-09-28 22:53:53 +00:00
|
|
|
|
{
|
|
|
|
|
char aTemp[256];
|
|
|
|
|
str_copy(aTemp, m_aCurrentDemoFolder, sizeof(aTemp));
|
|
|
|
|
str_format(m_aCurrentDemoFolder, sizeof(m_aCurrentDemoFolder), "%s/%s", aTemp, m_lDemos[m_DemolistSelectedIndex].m_aFilename);
|
2010-10-07 22:13:05 +00:00
|
|
|
|
m_DemolistStorageType = m_lDemos[m_DemolistSelectedIndex].m_StorageType;
|
2010-09-28 22:53:53 +00:00
|
|
|
|
}
|
2010-06-04 20:14:02 +00:00
|
|
|
|
DemolistPopulate();
|
2010-09-28 22:53:53 +00:00
|
|
|
|
DemolistOnUpdate(true);
|
2010-06-04 20:14:02 +00:00
|
|
|
|
}
|
2010-09-28 22:53:53 +00:00
|
|
|
|
else // file
|
2010-06-04 20:14:02 +00:00
|
|
|
|
{
|
2010-09-28 22:53:53 +00:00
|
|
|
|
char aBuf[512];
|
2010-10-06 21:07:35 +00:00
|
|
|
|
str_format(aBuf, sizeof(aBuf), "%s/%s", m_aCurrentDemoFolder, m_lDemos[m_DemolistSelectedIndex].m_aFilename);
|
2019-09-27 03:06:02 +00:00
|
|
|
|
const char *pError = Client()->DemoPlayer_Play(aBuf, m_lDemos[m_DemolistSelectedIndex].m_StorageType);
|
2010-06-04 20:14:02 +00:00
|
|
|
|
if(pError)
|
2010-11-20 22:46:49 +00:00
|
|
|
|
PopupMessage(Localize("Error"), str_comp(pError, "error loading demo") ? pError : Localize("Error loading demo"), Localize("Ok"));
|
2010-09-08 00:27:48 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
UI()->SetActiveItem(0);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2010-06-04 20:14:02 +00:00
|
|
|
|
}
|
2009-06-15 13:16:33 +00:00
|
|
|
|
}
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
|
2010-09-28 22:53:53 +00:00
|
|
|
|
if(!m_DemolistSelectedIsDir)
|
2010-09-03 18:05:22 +00:00
|
|
|
|
{
|
2010-09-05 15:53:31 +00:00
|
|
|
|
static int s_DeleteButton = 0;
|
2020-09-18 05:57:36 +00:00
|
|
|
|
if(DoButton_Menu(&s_DeleteButton, Localize("Delete"), 0, &DeleteRect) || m_DeletePressed || (Input()->KeyPress(KEY_D) && m_pClient->m_pGameConsole->IsClosed()))
|
2010-09-03 18:05:22 +00:00
|
|
|
|
{
|
2010-09-28 22:53:53 +00:00
|
|
|
|
if(m_DemolistSelectedIndex >= 0)
|
2010-09-08 00:27:48 +00:00
|
|
|
|
{
|
|
|
|
|
UI()->SetActiveItem(0);
|
2010-09-05 15:53:31 +00:00
|
|
|
|
m_Popup = POPUP_DELETE_DEMO;
|
2011-03-12 18:08:44 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int s_RenameButton = 0;
|
|
|
|
|
if(DoButton_Menu(&s_RenameButton, Localize("Rename"), 0, &RenameRect))
|
|
|
|
|
{
|
|
|
|
|
if(m_DemolistSelectedIndex >= 0)
|
|
|
|
|
{
|
|
|
|
|
UI()->SetActiveItem(0);
|
|
|
|
|
m_Popup = POPUP_RENAME_DEMO;
|
|
|
|
|
str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile));
|
|
|
|
|
return;
|
2010-09-08 00:27:48 +00:00
|
|
|
|
}
|
2010-09-03 18:05:22 +00:00
|
|
|
|
}
|
2019-09-26 15:28:29 +00:00
|
|
|
|
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
2019-09-26 15:28:29 +00:00
|
|
|
|
static int s_RenderButton = 0;
|
2020-09-18 05:57:36 +00:00
|
|
|
|
if(DoButton_Menu(&s_RenderButton, Localize("Render"), 0, &RenderRect) || (Input()->KeyPress(KEY_R) && m_pClient->m_pGameConsole->IsClosed()))
|
2019-09-26 15:28:29 +00:00
|
|
|
|
{
|
2019-09-27 03:06:02 +00:00
|
|
|
|
if(m_DemolistSelectedIndex >= 0)
|
2019-09-26 15:28:29 +00:00
|
|
|
|
{
|
|
|
|
|
UI()->SetActiveItem(0);
|
2019-09-27 03:06:02 +00:00
|
|
|
|
m_Popup = POPUP_RENDER_DEMO;
|
|
|
|
|
str_copy(m_aCurrentDemoFile, m_lDemos[m_DemolistSelectedIndex].m_aFilename, sizeof(m_aCurrentDemoFile));
|
2019-09-26 15:28:29 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-09-27 07:22:50 +00:00
|
|
|
|
#endif
|
2010-09-03 18:05:22 +00:00
|
|
|
|
}
|
2019-01-08 19:12:21 +00:00
|
|
|
|
|
2020-09-08 09:31:45 +00:00
|
|
|
|
#if defined(CONF_VIDEORECORDER)
|
|
|
|
|
// Doesn't always fit, not so important to show
|
|
|
|
|
if(PlayRect.x > 725)
|
|
|
|
|
#endif
|
|
|
|
|
UI()->DoLabelScaled(&LabelRect, aFooterLabel, 14.0f, -1);
|
2008-10-06 18:05:01 +00:00
|
|
|
|
}
|