Counter Strike : Global Offensive Source Code
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.

515 lines
14 KiB

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