Skip to content

Commit 166ccfc

Browse files
committed
NeoUI - Refactor root NeoUI usages, sound within NeoUI
* Refactor neo_root to not loop around buttons, instead just directly place and use the buttons like the rest of the menus * Put sound rollover into within the NeoUI API and remove manual handling within neo_root. Off by default, just add the new flag to per section and can customize to point to different paths from external to the NeoUI API. * fixes #1468
1 parent f9b2c36 commit 166ccfc

File tree

4 files changed

+113
-118
lines changed

4 files changed

+113
-118
lines changed

src/game/client/neo/ui/neo_root.cpp

Lines changed: 75 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -336,18 +336,16 @@ void CNeoRootInput::OnThink()
336336
}
337337
}
338338

339-
constexpr WidgetInfo BTNS_INFO[BTNS_TOTAL] = {
340-
{ "#GameUI_GameMenu_ResumeGame", false, "ResumeGame", true, STATE__TOTAL, FLAG_SHOWINGAME },
341-
{ "#GameUI_GameMenu_FindServers", false, nullptr, true, STATE_SERVERBROWSER, FLAG_SHOWINGAME | FLAG_SHOWINMAIN },
342-
{ "#GameUI_GameMenu_CreateServer", false, nullptr, true, STATE_NEWGAME, FLAG_SHOWINGAME | FLAG_SHOWINMAIN },
343-
{ "#GameUI_GameMenu_Disconnect", false, "Disconnect", true, STATE__TOTAL, FLAG_SHOWINGAME },
344-
{ "#GameUI_GameMenu_PlayerList", false, nullptr, true, STATE_PLAYERLIST, FLAG_SHOWINGAME },
345-
{ "", true, nullptr, true, STATE__TOTAL, FLAG_SHOWINMAIN },
346-
{ "#GameUI_GameMenu_Tutorial", false, "sv_use_steam_networking 0; map " TUTORIAL_MAP_CLASSES, false, STATE__TOTAL, FLAG_SHOWINMAIN},
347-
{ "#GameUI_GameMenu_FiringRange", false, "sv_use_steam_networking 0; map " TUTORIAL_MAP_SHOOTING, false, STATE__TOTAL, FLAG_SHOWINMAIN},
348-
{ "", true, nullptr, true, STATE__TOTAL, FLAG_SHOWINGAME | FLAG_SHOWINMAIN },
349-
{ "#GameUI_GameMenu_Options", false, nullptr, true, STATE_SETTINGS, FLAG_SHOWINGAME | FLAG_SHOWINMAIN },
350-
{ "#GameUI_GameMenu_Quit", false, nullptr, true, STATE_QUIT, FLAG_SHOWINGAME | FLAG_SHOWINMAIN },
339+
constexpr const char *BTNS_LOCALIZE[MMBTN__TOTAL] = {
340+
"#GameUI_GameMenu_ResumeGame",
341+
"#GameUI_GameMenu_FindServers",
342+
"#GameUI_GameMenu_CreateServer",
343+
"#GameUI_GameMenu_Disconnect",
344+
"#GameUI_GameMenu_PlayerList",
345+
"#GameUI_GameMenu_Tutorial",
346+
"#GameUI_GameMenu_FiringRange",
347+
"#GameUI_GameMenu_Options",
348+
"#GameUI_GameMenu_Quit",
351349
};
352350

353351
CNeoRoot::CNeoRoot(VPANEL parent)
@@ -364,18 +362,19 @@ CNeoRoot::CNeoRoot(VPANEL parent)
364362
enginevgui->GetPanel(PANEL_CLIENTDLL), "resource/ClientScheme.res", "ClientScheme");
365363
SetScheme(neoscheme);
366364

367-
for (int i = 0; i < BTNS_TOTAL; ++i)
365+
for (int i = 0; i < MMBTN__TOTAL; ++i)
368366
{
369-
const char *label = BTNS_INFO[i].label;
370-
if (wchar_t *localizedWszStr = g_pVGuiLocalize->Find(label))
367+
const char *label = BTNS_LOCALIZE[i];
368+
wchar_t *localizedWszStr = g_pVGuiLocalize->Find(label);
369+
Assert(localizedWszStr);
370+
if (localizedWszStr)
371371
{
372-
V_wcsncpy(m_wszDispBtnTexts[i], localizedWszStr, sizeof(m_wszDispBtnTexts[i]));
372+
V_wcsncpy(m_wszCachedTexts[i], localizedWszStr, sizeof(m_wszCachedTexts[i]));
373373
}
374374
else
375375
{
376-
g_pVGuiLocalize->ConvertANSIToUnicode(label, m_wszDispBtnTexts[i], sizeof(m_wszDispBtnTexts[i]));
376+
g_pVGuiLocalize->ConvertANSIToUnicode(label, m_wszCachedTexts[i], sizeof(m_wszCachedTexts[i]));
377377
}
378-
m_iWszDispBtnTextsSizes[i] = V_wcslen(m_wszDispBtnTexts[i]);
379378
}
380379

381380
NeoSettingsInit(&m_ns);
@@ -746,7 +745,7 @@ void CNeoRoot::MainLoopRoot(const MainLoopParam param)
746745
const int iMarginHalf = iMargin * 0.5;
747746
const int iTitleMarginTop = (param.tall * 0.2);
748747
surface()->GetTextSize(g_uiCtx.fonts[NeoUI::FONT_LOGO].hdl, L"n", iTitleNWidth, iTitleNHeight);
749-
g_uiCtx.dPanel.wide = (m_iTitleWidth) +iMargin;
748+
g_uiCtx.dPanel.wide = (m_iTitleWidth) + iMargin;
750749
g_uiCtx.dPanel.tall = param.tall;
751750
g_uiCtx.dPanel.x = iBtnPlaceXMid - (m_iTitleWidth * 0.5) + (iTitleNWidth * 1.16) - iMarginHalf;
752751
g_uiCtx.dPanel.y = iTitleMarginTop + (2 * iTitleNHeight);
@@ -757,60 +756,60 @@ void CNeoRoot::MainLoopRoot(const MainLoopParam param)
757756
g_uiCtx.dPanel.x + g_uiCtx.dPanel.wide, param.tall);
758757

759758
NeoUI::BeginContext(&g_uiCtx, param.eMode, nullptr, "CtxRoot");
760-
NeoUI::BeginSection(NeoUI::SECTIONFLAG_DEFAULTFOCUS);
759+
NeoUI::BeginSection(NeoUI::SECTIONFLAG_DEFAULTFOCUS | NeoUI::SECTIONFLAG_PLAYBUTTONSOUNDS);
761760
{
762761
g_uiCtx.eButtonTextStyle = NeoUI::TEXTSTYLE_CENTER;
763762
const int iFlagToMatch = IsInGame() ? FLAG_SHOWINGAME : FLAG_SHOWINMAIN;
764763
bool mouseOverButton = false;
765-
for (int i = 0; i < BTNS_TOTAL; ++i)
764+
const bool bIsInGame = IsInGame();
765+
if (bIsInGame && NeoUI::Button(m_wszCachedTexts[MMBTN_RESUME]).bPressed)
766766
{
767-
const auto btnInfo = BTNS_INFO[i];
768-
if (btnInfo.flags & iFlagToMatch)
767+
m_state = STATE_ROOT;
768+
GetGameUI()->SendMainMenuCommand("ResumeGame");
769+
}
770+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_FINDSERVER]).bPressed)
771+
{
772+
m_state = STATE_SERVERBROWSER;
773+
}
774+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_CREATESERVER]).bPressed)
775+
{
776+
m_state = STATE_NEWGAME;
777+
}
778+
if (bIsInGame)
779+
{
780+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_DISCONNECT]).bPressed)
769781
{
770-
if (btnInfo.isFake)
771-
{
772-
NeoUI::Pad();
773-
continue;
774-
}
775-
const auto retBtn = NeoUI::Button(m_wszDispBtnTexts[i]);
776-
if (retBtn.bPressed || (i == MMBTN_QUIT && !IsInGame() && NeoUI::BindKeyBack()))
777-
{
778-
surface()->PlaySound("ui/buttonclickrelease.wav");
779-
if (btnInfo.command)
780-
{
781-
m_state = STATE_ROOT;
782-
if (btnInfo.isMainMenuCommand)
783-
{
784-
GetGameUI()->SendMainMenuCommand(btnInfo.command);
785-
}
786-
else
787-
{
788-
engine->ClientCmd(btnInfo.command);
789-
}
790-
}
791-
else if (btnInfo.nextState < STATE__TOTAL)
792-
{
793-
m_state = btnInfo.nextState;
794-
if (m_state == STATE_SETTINGS)
795-
{
796-
NeoSettingsRestore(&m_ns);
797-
}
798-
}
799-
}
800-
if (retBtn.bMouseHover)
801-
{
802-
mouseOverButton = true;
803-
if (i != m_iHoverBtn && param.eMode == NeoUI::MODE_MOUSEMOVED)
804-
{ // Sound rollover feedback
805-
surface()->PlaySound("ui/buttonrollover.wav");
806-
m_iHoverBtn = i;
807-
}
808-
}
782+
m_state = STATE_ROOT;
783+
GetGameUI()->SendMainMenuCommand("Disconnect");
784+
}
785+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_PLAYERLIST]).bPressed)
786+
{
787+
m_state = STATE_PLAYERLIST;
809788
}
810789
}
811-
if (!mouseOverButton && m_iHoverBtn < BTNS_TOTAL && param.eMode == NeoUI::MODE_MOUSEMOVED)
790+
else
812791
{
813-
m_iHoverBtn = -1;
792+
NeoUI::Pad();
793+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_TUTORIAL]).bPressed)
794+
{
795+
m_state = STATE_ROOT;
796+
engine->ClientCmd("sv_use_steam_networking 0; map " TUTORIAL_MAP_CLASSES);
797+
}
798+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_FIRINGRANGE]).bPressed)
799+
{
800+
m_state = STATE_ROOT;
801+
engine->ClientCmd("sv_use_steam_networking 0; map " TUTORIAL_MAP_SHOOTING);
802+
}
803+
}
804+
NeoUI::Pad();
805+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_OPTIONS]).bPressed)
806+
{
807+
m_state = STATE_SETTINGS;
808+
NeoSettingsRestore(&m_ns);
809+
}
810+
if (NeoUI::Button(m_wszCachedTexts[MMBTN_QUIT]).bPressed)
811+
{
812+
m_state = STATE_QUIT;
814813
}
815814
}
816815
NeoUI::EndSection();
@@ -994,47 +993,23 @@ void CNeoRoot::MainLoopRoot(const MainLoopParam param)
994993
NeoUI::EndSection();
995994
#endif
996995
g_uiCtx.dPanel.x = param.wide - 128;
997-
g_uiCtx.dPanel.y = param.tall - 96;
996+
g_uiCtx.dPanel.y = param.tall - 96 - 48;
998997
g_uiCtx.dPanel.wide = 128;
999-
g_uiCtx.dPanel.tall = 1;
1000-
NeoUI::BeginSection();
1001-
g_uiCtx.eButtonTextStyle = NeoUI::TEXTSTYLE_CENTER;
1002-
const auto musicPlayerBtn = NeoUI::Button(L"Music");
1003-
if (musicPlayerBtn.bPressed)
1004-
{
1005-
surface()->PlaySound("ui/buttonclickrelease.wav");
1006-
engine->ClientCmd("neo_mp3");
1007-
1008-
}
1009-
NeoUI::EndSection();
1010-
1011-
NeoUI::BeginSection();
1012-
g_uiCtx.dPanel.y = param.tall - 48;
1013-
const auto creditsBtn = NeoUI::Button(L"Credits");
1014-
if (creditsBtn.bPressed)
1015-
{
1016-
surface()->PlaySound("ui/buttonclickrelease.wav");
1017-
m_state = STATE_CREDITS;
1018-
}
1019-
NeoUI::EndSection();
998+
g_uiCtx.dPanel.tall = param.tall;
1020999

1021-
if (param.eMode == NeoUI::MODE_MOUSEMOVED)
1000+
NeoUI::BeginSection(NeoUI::SECTIONFLAG_PLAYBUTTONSOUNDS);
10221001
{
1023-
if (musicPlayerBtn.bMouseHover && SMBTN_MP3 != m_iHoverBtn)
1024-
{ // Sound rollover feedback
1025-
surface()->PlaySound("ui/buttonrollover.wav");
1026-
m_iHoverBtn = SMBTN_MP3;
1027-
}
1028-
else if (creditsBtn.bMouseHover && SMBTN_CREDITS != m_iHoverBtn)
1002+
g_uiCtx.eButtonTextStyle = NeoUI::TEXTSTYLE_CENTER;
1003+
if (NeoUI::Button(L"Music").bPressed)
10291004
{
1030-
surface()->PlaySound("ui/buttonrollover.wav");
1031-
m_iHoverBtn = SMBTN_CREDITS;
1005+
engine->ClientCmd("neo_mp3");
10321006
}
1033-
else if ((!musicPlayerBtn.bMouseHover && SMBTN_MP3 == m_iHoverBtn) || (!creditsBtn.bMouseHover && SMBTN_CREDITS == m_iHoverBtn))
1007+
if (NeoUI::Button(L"Credits").bPressed)
10341008
{
1035-
m_iHoverBtn = -1;
1009+
m_state = STATE_CREDITS;
10361010
}
10371011
}
1012+
NeoUI::EndSection();
10381013

10391014
NeoUI::EndContext();
10401015
}
@@ -1067,7 +1042,7 @@ void CNeoRoot::MainLoopSettings(const MainLoopParam param)
10671042
g_uiCtx.dPanel.y = (param.tall / 2) - (iTallTotal / 2);
10681043
g_uiCtx.dPanel.tall = g_uiCtx.layout.iRowTall;
10691044
g_uiCtx.bgColor = COLOR_NEOPANELFRAMEBG;
1070-
NeoUI::BeginContext(&g_uiCtx, param.eMode, g_pNeoRoot->m_wszDispBtnTexts[MMBTN_OPTIONS], "CtxOptions");
1045+
NeoUI::BeginContext(&g_uiCtx, param.eMode, g_pNeoRoot->m_wszCachedTexts[MMBTN_OPTIONS], "CtxOptions");
10711046
{
10721047
NeoUI::BeginSection(NeoUI::SECTIONFLAG_ROWWIDGETS | NeoUI::SECTIONFLAG_EXCLUDECONTROLLER);
10731048
{
@@ -1164,7 +1139,7 @@ void CNeoRoot::MainLoopNewGame(const MainLoopParam param)
11641139
g_uiCtx.dPanel.y = (param.tall / 2) - (iTallTotal / 2);
11651140
g_uiCtx.dPanel.tall = g_uiCtx.layout.iRowTall * (g_iRowsInScreen + 1);
11661141
g_uiCtx.bgColor = COLOR_NEOPANELFRAMEBG;
1167-
NeoUI::BeginContext(&g_uiCtx, param.eMode, m_wszDispBtnTexts[MMBTN_CREATESERVER], "CtxNewGame");
1142+
NeoUI::BeginContext(&g_uiCtx, param.eMode, m_wszCachedTexts[MMBTN_CREATESERVER], "CtxNewGame");
11681143
{
11691144
NeoUI::BeginSection(NeoUI::SECTIONFLAG_DEFAULTFOCUS);
11701145
{
@@ -1382,7 +1357,7 @@ void CNeoRoot::MainLoopServerBrowser(const MainLoopParam param)
13821357
g_uiCtx.dPanel.y = (param.tall / 2) - (iTallTotal / 2);
13831358
g_uiCtx.dPanel.tall = g_uiCtx.layout.iRowTall * 2;
13841359
g_uiCtx.bgColor = COLOR_NEOPANELFRAMEBG;
1385-
NeoUI::BeginContext(&g_uiCtx, param.eMode, m_wszDispBtnTexts[MMBTN_FINDSERVER], "CtxServerBrowser");
1360+
NeoUI::BeginContext(&g_uiCtx, param.eMode, m_wszCachedTexts[MMBTN_FINDSERVER], "CtxServerBrowser");
13861361
{
13871362
bool bForceRefresh = false;
13881363
NeoUI::BeginSection(NeoUI::SECTIONFLAG_ROWWIDGETS);

src/game/client/neo/ui/neo_root.h

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,6 @@ enum RootState
8686
struct WidgetInfo
8787
{
8888
const char *label;
89-
bool isFake;
90-
const char *command; // TODO: Replace
91-
bool isMainMenuCommand;
92-
RootState nextState;
93-
int flags;
9489
};
9590

9691
enum WidgetInfoFlags
@@ -107,17 +102,12 @@ enum MainMenuButtons
107102
MMBTN_CREATESERVER,
108103
MMBTN_DISCONNECT,
109104
MMBTN_PLAYERLIST,
110-
MMBTN_SEPARATOR1,
111105
MMBTN_TUTORIAL,
112106
MMBTN_FIRINGRANGE,
113-
MMBTN_SEPARATOR2,
114107
MMBTN_OPTIONS,
115108
MMBTN_QUIT,
116109

117-
BTNS_TOTAL,
118-
119-
SMBTN_MP3,
120-
SMBTN_CREDITS,
110+
MMBTN__TOTAL,
121111
};
122112

123113
struct SprayInfo
@@ -143,12 +133,10 @@ class CNeoRoot : public vgui::EditablePanel, public CGameEventListener
143133
void UpdateControls();
144134

145135
IGameUI *m_gameui = nullptr;
146-
int m_iHoverBtn = -1;
147136
RootState m_state = STATE_ROOT;
148137
CAvatarImage *m_avImage = nullptr;
149138

150-
wchar_t m_wszDispBtnTexts[BTNS_TOTAL][64] = {};
151-
int m_iWszDispBtnTextsSizes[BTNS_TOTAL] = {};
139+
wchar_t m_wszCachedTexts[MMBTN__TOTAL][64] = {};
152140

153141
CNeoRootInput *m_panelCaptureInput = nullptr;
154142
void OnRelayedKeyCodeTyped(vgui::KeyCode code);

src/game/client/neo/ui/neo_ui.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -307,14 +307,18 @@ void BeginContext(NeoUI::Context *pNextCtx, const NeoUI::Mode eMode, const wchar
307307
vgui::surface()->DrawPrintText(wszTitle, V_wcslen(wszTitle));
308308
}
309309
break;
310-
case MODE_MOUSEMOVED:
311-
c->iHot = FOCUSOFF_NUM;
312-
c->iHotSection = -1;
313-
break;
314310
default:
315311
break;
316312
}
317313

314+
c->iHotPersist = c->iHot;
315+
c->iHotPersistSection = c->iHotSection;
316+
if (c->eMode == MODE_MOUSEMOVED)
317+
{
318+
c->iHot = FOCUSOFF_NUM;
319+
c->iHotSection = -1;
320+
}
321+
318322
// Force SwapFont on main to prevent crash on startup
319323
SwapFont(FONT_NTLARGE, true);
320324
c->eButtonTextStyle = TEXTSTYLE_LEFT;
@@ -807,6 +811,7 @@ GetMouseinFocusedRet BeginWidget(const WidgetFlag eWidgetFlag)
807811
// Check mouse hot/active states if WIDGETFLAG_MOUSE flag set
808812
if (eWidgetFlag & WIDGETFLAG_MOUSE)
809813
{
814+
const bool bNotCurHot = (c->iHotPersist != c->iWidget || c->iHotPersistSection != c->iSection);
810815
const bool bMouseIn = IN_BETWEEN_EQ(c->rWidgetArea.x0, c->iMouseAbsX, c->rWidgetArea.x1)
811816
&& IN_BETWEEN_EQ(c->rWidgetArea.y0, c->iMouseAbsY, c->rWidgetArea.y1);
812817
if (bMouseIn)
@@ -834,6 +839,7 @@ GetMouseinFocusedRet BeginWidget(const WidgetFlag eWidgetFlag)
834839
return GetMouseinFocusedRet{
835840
.bActive = bActive,
836841
.bHot = bHot,
842+
.bNewHot = bNotCurHot && bHot,
837843
};
838844
}
839845

@@ -1064,6 +1070,20 @@ NeoUI::RetButton BaseButton(const wchar_t *wszText, const char *szTexturePath, c
10641070
}
10651071
}
10661072

1073+
if (c->iSectionFlags & SECTIONFLAG_PLAYBUTTONSOUNDS)
1074+
{
1075+
if (ret.bPressed)
1076+
{
1077+
vgui::surface()->PlaySound(c->pszSoundBtnPressed);
1078+
}
1079+
if (wdgState.bNewHot &&
1080+
((c->eMode == MODE_MOUSEMOVED && ret.bMouseHover) ||
1081+
(c->eMode == MODE_KEYPRESSED && !ret.bPressed)))
1082+
{
1083+
vgui::surface()->PlaySound(c->pszSoundBtnRollover);
1084+
}
1085+
}
1086+
10671087
EndWidget(wdgState);
10681088
return ret;
10691089
}

src/game/client/neo/ui/neo_ui.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ enum ESectionFlag
173173
// Make sure to have Bind so controllers don't get cut out from being
174174
// able to utilize actions from this section.
175175
SECTIONFLAG_EXCLUDECONTROLLER = 1 << 2,
176+
// Allow the hover and button click sound to play on buttons
177+
SECTIONFLAG_PLAYBUTTONSOUNDS = 1 << 3,
176178
};
177179
typedef int ISectionFlags;
178180

@@ -260,6 +262,11 @@ struct Context
260262
int iHot;
261263
int iHotSection;
262264

265+
// vs iHot this persists between Begin/EndContext
266+
// only used for bNewHot detection
267+
int iHotPersist;
268+
int iHotPersistSection;
269+
263270
int iActive;
264271
int iActiveSection;
265272
bool bValueEdited;
@@ -286,12 +293,17 @@ struct Context
286293
int iTextSelDrag = -1;
287294
int iTextSelDragSection = -1;
288295
int irTextWidths[MAX_TEXTINPUT_U8BYTES_LIMIT] = {};
296+
297+
// Sound paths
298+
const char *pszSoundBtnPressed = "ui/buttonclickrelease.wav";
299+
const char *pszSoundBtnRollover = "ui/buttonrollover.wav";
289300
};
290301

291302
struct GetMouseinFocusedRet
292303
{
293304
bool bActive;
294305
bool bHot;
306+
bool bNewHot;
295307
};
296308

297309
struct RetButton

0 commit comments

Comments
 (0)