Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

532 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //
  7. //=============================================================================//
  8. //
  9. // menu.cpp
  10. //
  11. // generic menu handler
  12. //
  13. #include "cbase.h"
  14. #include "text_message.h"
  15. #include "hud_macros.h"
  16. #include "iclientmode.h"
  17. #include "weapon_selection.h"
  18. #include <vgui/VGUI.h>
  19. #include <vgui/ISurface.h>
  20. #include <vgui/ILocalize.h>
  21. #include <KeyValues.h>
  22. #include <vgui_controls/AnimationController.h>
  23. #define MAX_MENU_STRING 512
  24. wchar_t g_szMenuString[MAX_MENU_STRING];
  25. char g_szPrelocalisedMenuString[MAX_MENU_STRING];
  26. #include "menu.h"
  27. // memdbgon must be the last include file in a .cpp file!!!
  28. #include "tier0/memdbgon.h"
  29. //
  30. //-----------------------------------------------------
  31. //
  32. DECLARE_HUDELEMENT( CHudMenu );
  33. DECLARE_HUD_MESSAGE( CHudMenu, ShowMenu );
  34. //
  35. //-----------------------------------------------------
  36. //
  37. static char* ConvertCRtoNL( char *str )
  38. {
  39. for ( char *ch = str; *ch != 0; ch++ )
  40. if ( *ch == '\r' )
  41. *ch = '\n';
  42. return str;
  43. }
  44. //-----------------------------------------------------------------------------
  45. // Purpose:
  46. //-----------------------------------------------------------------------------
  47. CHudMenu::CHudMenu( const char *pElementName ) :
  48. CHudElement( pElementName ), BaseClass(NULL, "HudMenu")
  49. {
  50. m_nSelectedItem = -1;
  51. vgui::Panel *pParent = g_pClientMode->GetViewport();
  52. SetParent( pParent );
  53. SetHiddenBits( HIDEHUD_MISCSTATUS );
  54. }
  55. //-----------------------------------------------------------------------------
  56. // Purpose:
  57. //-----------------------------------------------------------------------------
  58. void CHudMenu::Init( void )
  59. {
  60. HOOK_HUD_MESSAGE( CHudMenu, ShowMenu );
  61. m_bMenuTakesInput = false;
  62. m_bMenuDisplayed = false;
  63. m_bitsValidSlots = 0;
  64. m_Processed.RemoveAll();
  65. m_nMaxPixels = 0;
  66. m_nHeight = 0;
  67. Reset();
  68. }
  69. //-----------------------------------------------------------------------------
  70. // Purpose:
  71. //-----------------------------------------------------------------------------
  72. void CHudMenu::Reset( void )
  73. {
  74. g_szPrelocalisedMenuString[0] = 0;
  75. m_fWaitingForMore = false;
  76. }
  77. //-----------------------------------------------------------------------------
  78. // Purpose:
  79. // Output : Returns true on success, false on failure.
  80. //-----------------------------------------------------------------------------
  81. bool CHudMenu::IsMenuOpen( void )
  82. {
  83. return m_bMenuDisplayed && m_bMenuTakesInput;
  84. }
  85. //-----------------------------------------------------------------------------
  86. // Purpose:
  87. //-----------------------------------------------------------------------------
  88. void CHudMenu::VidInit( void )
  89. {
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose:
  93. //-----------------------------------------------------------------------------
  94. void CHudMenu::OnThink()
  95. {
  96. float flSelectionTimeout = MENU_SELECTION_TIMEOUT;
  97. // If we've been open for a while without input, hide
  98. if ( m_bMenuDisplayed && ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout ) )
  99. {
  100. m_bMenuDisplayed = false;
  101. }
  102. }
  103. //-----------------------------------------------------------------------------
  104. // Purpose:
  105. //-----------------------------------------------------------------------------
  106. bool CHudMenu::ShouldDraw( void )
  107. {
  108. bool draw = CHudElement::ShouldDraw() && m_bMenuDisplayed;
  109. if ( !draw )
  110. return false;
  111. // check for if menu is set to disappear
  112. if ( m_flShutoffTime > 0 && m_flShutoffTime <= gpGlobals->realtime )
  113. {
  114. // times up, shutoff
  115. m_bMenuDisplayed = false;
  116. return false;
  117. }
  118. return draw;
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose:
  122. // Input : *text -
  123. // textlen -
  124. // font -
  125. // x -
  126. // y -
  127. //-----------------------------------------------------------------------------
  128. void CHudMenu::PaintString( const wchar_t *text, int textlen, vgui::HFont& font, int x, int y )
  129. {
  130. vgui::surface()->DrawSetTextFont( font );
  131. vgui::surface()->DrawSetTextPos( x, y );
  132. for ( int ch = 0; ch < textlen; ch++ )
  133. {
  134. vgui::surface()->DrawUnicodeChar( text[ch] );
  135. }
  136. }
  137. //-----------------------------------------------------------------------------
  138. // Purpose:
  139. //-----------------------------------------------------------------------------
  140. void CHudMenu::Paint()
  141. {
  142. if ( !m_bMenuDisplayed )
  143. return;
  144. // center it
  145. int x = 20;
  146. Color menuColor = m_MenuColor;
  147. Color itemColor = m_ItemColor;
  148. int c = m_Processed.Count();
  149. int border = 20;
  150. int wide = m_nMaxPixels + border;
  151. int tall = m_nHeight + border;
  152. int y = ( ScreenHeight() - tall ) * 0.5f;
  153. DrawBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
  154. //DrawTexturedBox( x - border/2, y - border/2, wide, tall, m_BoxColor, m_flSelectionAlphaOverride / 255.0f );
  155. menuColor[3] = menuColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
  156. itemColor[3] = itemColor[3] * ( m_flSelectionAlphaOverride / 255.0f );
  157. for ( int i = 0; i < c; i++ )
  158. {
  159. ProcessedLine *line = &m_Processed[ i ];
  160. Assert( line );
  161. Color clr = line->menuitem != 0 ? itemColor : menuColor;
  162. bool canblur = false;
  163. if ( line->menuitem != 0 &&
  164. m_nSelectedItem >= 0 &&
  165. ( line->menuitem == m_nSelectedItem ) )
  166. {
  167. canblur = true;
  168. }
  169. vgui::surface()->DrawSetTextColor( clr );
  170. int drawLen = line->length;
  171. if ( line->menuitem != 0 )
  172. {
  173. drawLen *= m_flTextScan;
  174. }
  175. vgui::surface()->DrawSetTextFont( line->menuitem != 0 ? m_hItemFont : m_hTextFont );
  176. PaintString( &g_szMenuString[ line->startchar ], drawLen,
  177. line->menuitem != 0 ? m_hItemFont : m_hTextFont, x, y );
  178. if ( canblur )
  179. {
  180. // draw the overbright blur
  181. for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f)
  182. {
  183. if (fl >= 1.0f)
  184. {
  185. PaintString( &g_szMenuString[ line->startchar ], drawLen, m_hItemFontPulsing, x, y );
  186. }
  187. else
  188. {
  189. // draw a percentage of the last one
  190. Color col = clr;
  191. col[3] *= fl;
  192. vgui::surface()->DrawSetTextColor(col);
  193. PaintString( &g_szMenuString[ line->startchar ], drawLen, m_hItemFontPulsing, x, y );
  194. }
  195. }
  196. }
  197. y += line->height;
  198. }
  199. }
  200. //-----------------------------------------------------------------------------
  201. // Purpose: selects an item from the menu
  202. //-----------------------------------------------------------------------------
  203. void CHudMenu::SelectMenuItem( int menu_item )
  204. {
  205. // if menu_item is in a valid slot, send a menuselect command to the server
  206. if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) )
  207. {
  208. char szbuf[32];
  209. Q_snprintf( szbuf, sizeof( szbuf ), "menuselect %d\n", menu_item );
  210. engine->ClientCmd( szbuf );
  211. m_nSelectedItem = menu_item;
  212. // Pulse the selection
  213. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuPulse");
  214. // remove the menu quickly
  215. m_bMenuTakesInput = false;
  216. m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
  217. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
  218. }
  219. }
  220. void CHudMenu::ProcessText( void )
  221. {
  222. m_Processed.RemoveAll();
  223. m_nMaxPixels = 0;
  224. m_nHeight = 0;
  225. int i = 0;
  226. int startpos = i;
  227. int menuitem = 0;
  228. while ( i < MAX_MENU_STRING )
  229. {
  230. wchar_t ch = g_szMenuString[ i ];
  231. if ( ch == 0 )
  232. break;
  233. if ( i == startpos &&
  234. ( ch == L'-' && g_szMenuString[ i + 1 ] == L'>' ) )
  235. {
  236. // Special handling for menu item specifiers
  237. swscanf( &g_szMenuString[ i + 2 ], L"%d", &menuitem );
  238. i += 2;
  239. startpos += 2;
  240. continue;
  241. }
  242. // Skip to end of line
  243. while ( i < MAX_MENU_STRING && g_szMenuString[i] != 0 && g_szMenuString[i] != L'\n' )
  244. {
  245. i++;
  246. }
  247. // Store off line
  248. if ( ( i - startpos ) >= 1 )
  249. {
  250. ProcessedLine line;
  251. line.menuitem = menuitem;
  252. line.startchar = startpos;
  253. line.length = i - startpos;
  254. line.pixels = 0;
  255. line.height = 0;
  256. m_Processed.AddToTail( line );
  257. }
  258. menuitem = 0;
  259. // Skip delimiter
  260. if ( g_szMenuString[i] == '\n' )
  261. {
  262. i++;
  263. }
  264. startpos = i;
  265. }
  266. // Add final block
  267. if ( i - startpos >= 1 )
  268. {
  269. ProcessedLine line;
  270. line.menuitem = menuitem;
  271. line.startchar = startpos;
  272. line.length = i - startpos;
  273. line.pixels = 0;
  274. line.height = 0;
  275. m_Processed.AddToTail( line );
  276. }
  277. // Now compute pixels needed
  278. int c = m_Processed.Count();
  279. for ( i = 0; i < c; i++ )
  280. {
  281. ProcessedLine *l = &m_Processed[ i ];
  282. Assert( l );
  283. int pixels = 0;
  284. vgui::HFont font = l->menuitem != 0 ? m_hItemFont : m_hTextFont;
  285. for ( int ch = 0; ch < l->length; ch++ )
  286. {
  287. pixels += vgui::surface()->GetCharacterWidth( font, g_szMenuString[ ch + l->startchar ] );
  288. }
  289. l->pixels = pixels;
  290. l->height = vgui::surface()->GetFontTall( font );
  291. if ( pixels > m_nMaxPixels )
  292. {
  293. m_nMaxPixels = pixels;
  294. }
  295. m_nHeight += l->height;
  296. }
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: Local method to hide a menu, mirroring code found in
  300. // MsgFunc_ShowMenu.
  301. //-----------------------------------------------------------------------------
  302. void CHudMenu::HideMenu( void )
  303. {
  304. m_bMenuTakesInput = false;
  305. m_flShutoffTime = gpGlobals->realtime + m_flOpenCloseTime;
  306. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuClose");
  307. }
  308. //-----------------------------------------------------------------------------
  309. // Purpose: Local method to bring up a menu, mirroring code found in
  310. // MsgFunc_ShowMenu.
  311. //
  312. // takes two values:
  313. // menuName : menu name string
  314. // validSlots: a bitfield describing the valid keys
  315. //-----------------------------------------------------------------------------
  316. void CHudMenu::ShowMenu( const char * menuName, int validSlots )
  317. {
  318. m_flShutoffTime = -1;
  319. m_bitsValidSlots = validSlots;
  320. m_fWaitingForMore = 0;
  321. Q_strncpy( g_szPrelocalisedMenuString, menuName, sizeof( g_szPrelocalisedMenuString ) );
  322. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpen");
  323. m_nSelectedItem = -1;
  324. // we have the whole string, so we can localise it now
  325. char szMenuString[MAX_MENU_STRING];
  326. Q_strncpy( szMenuString, ConvertCRtoNL( hudtextmessage->BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ), sizeof( szMenuString ) );
  327. g_pVGuiLocalize->ConvertANSIToUnicode( szMenuString, g_szMenuString, sizeof( g_szMenuString ) );
  328. ProcessText();
  329. m_bMenuDisplayed = true;
  330. m_bMenuTakesInput = true;
  331. m_flSelectionTime = gpGlobals->curtime;
  332. }
  333. //-----------------------------------------------------------------------------
  334. // Purpose:
  335. //-----------------------------------------------------------------------------
  336. void CHudMenu::ShowMenu_KeyValueItems( KeyValues *pKV )
  337. {
  338. m_flShutoffTime = -1;
  339. m_fWaitingForMore = 0;
  340. m_bitsValidSlots = 0;
  341. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpen");
  342. m_nSelectedItem = -1;
  343. g_szMenuString[0] = '\0';
  344. wchar_t *pWritePosition = g_szMenuString;
  345. int nRemaining = sizeof( g_szMenuString ) / sizeof( wchar_t );
  346. int nCount;
  347. int i = 0;
  348. for ( KeyValues *item = pKV->GetFirstSubKey(); item != NULL; item = item->GetNextKey() )
  349. {
  350. // Set this slot valid
  351. m_bitsValidSlots |= (1<<i);
  352. const char *pszItem = item->GetName();
  353. const wchar_t *wLocalizedItem = g_pVGuiLocalize->Find( pszItem );
  354. nCount = _snwprintf( pWritePosition, nRemaining, L"%d. %ls\n", i+1, wLocalizedItem );
  355. nRemaining -= nCount;
  356. pWritePosition += nCount;
  357. i++;
  358. }
  359. // put a cancel on the end
  360. m_bitsValidSlots |= (1<<9);
  361. nCount = _snwprintf( pWritePosition, nRemaining, L"0. %ls\n", g_pVGuiLocalize->Find( "#Cancel" ) );
  362. nRemaining -= nCount;
  363. pWritePosition += nCount;
  364. ProcessText();
  365. m_bMenuDisplayed = true;
  366. m_bMenuTakesInput = true;
  367. m_flSelectionTime = gpGlobals->curtime;
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose: Message handler for ShowMenu message
  371. // takes four values:
  372. // short: a bitfield of keys that are valid input
  373. // char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen.
  374. // byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, false if it's the last string
  375. // string: menu string to display
  376. // if this message is never received, then scores will simply be the combined totals of the players.
  377. //-----------------------------------------------------------------------------
  378. void CHudMenu::MsgFunc_ShowMenu( bf_read &msg)
  379. {
  380. m_bitsValidSlots = (short)msg.ReadWord();
  381. int DisplayTime = msg.ReadChar();
  382. int NeedMore = msg.ReadByte();
  383. if ( DisplayTime > 0 )
  384. {
  385. m_flShutoffTime = m_flOpenCloseTime + DisplayTime + gpGlobals->realtime;
  386. }
  387. else
  388. {
  389. m_flShutoffTime = -1;
  390. }
  391. if ( m_bitsValidSlots )
  392. {
  393. char szString[2048];
  394. msg.ReadString( szString, sizeof(szString) );
  395. if ( !m_fWaitingForMore ) // this is the start of a new menu
  396. {
  397. Q_strncpy( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ) );
  398. }
  399. else
  400. { // append to the current menu string
  401. Q_strncat( g_szPrelocalisedMenuString, szString, sizeof( g_szPrelocalisedMenuString ), COPY_ALL_CHARACTERS );
  402. }
  403. if ( !NeedMore )
  404. {
  405. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("MenuOpen");
  406. m_nSelectedItem = -1;
  407. // we have the whole string, so we can localise it now
  408. char szMenuString[MAX_MENU_STRING];
  409. Q_strncpy( szMenuString, ConvertCRtoNL( hudtextmessage->BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ), sizeof( szMenuString ) );
  410. g_pVGuiLocalize->ConvertANSIToUnicode( szMenuString, g_szMenuString, sizeof( g_szMenuString ) );
  411. ProcessText();
  412. }
  413. m_bMenuDisplayed = true;
  414. m_bMenuTakesInput = true;
  415. m_flSelectionTime = gpGlobals->curtime;
  416. }
  417. else
  418. {
  419. HideMenu();
  420. }
  421. m_fWaitingForMore = NeedMore;
  422. }
  423. //-----------------------------------------------------------------------------
  424. // Purpose: hud scheme settings
  425. //-----------------------------------------------------------------------------
  426. void CHudMenu::ApplySchemeSettings(vgui::IScheme *pScheme)
  427. {
  428. BaseClass::ApplySchemeSettings(pScheme);
  429. SetPaintBackgroundEnabled( false );
  430. // set our size
  431. int screenWide, screenTall;
  432. int x, y;
  433. GetPos(x, y);
  434. GetHudSize(screenWide, screenTall);
  435. SetBounds(0, y, screenWide, screenTall - y);
  436. ProcessText();
  437. }