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.

467 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $Workfile: $
  6. // $Date: $
  7. // $NoKeywords: $
  8. //=============================================================================//
  9. #include "cbase.h"
  10. #include <stdarg.h>
  11. #include "imessagechars.h"
  12. #include <vgui/IVGui.h>
  13. #include "VGuiMatSurface/IMatSystemSurface.h"
  14. #include <vgui_controls/Panel.h>
  15. #include <vgui_controls/Controls.h>
  16. #include <vgui/IScheme.h>
  17. #include <vgui/ISurface.h>
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. // Simultaneous message limit
  21. #define MAX_MESSAGECHARS_MESSAGES 1024
  22. #define MAX_MESSAGECHARSPANEL_LEN 1024
  23. //-----------------------------------------------------------------------------
  24. // Purpose: Panel for displaying console characters at specified locations
  25. //-----------------------------------------------------------------------------
  26. class CMessageCharsPanel : public vgui::Panel
  27. {
  28. typedef vgui::Panel BaseClass;
  29. public:
  30. // Internal pool of such messages
  31. typedef struct message_s
  32. {
  33. struct message_s *next;
  34. int x, y;
  35. byte r, g, b, a;
  36. char *text;
  37. vgui::HFont hCustomFont;
  38. float fTTL;
  39. int messageID;
  40. } message_t;
  41. // Construct/destruct
  42. CMessageCharsPanel( vgui::VPANEL parent );
  43. virtual ~CMessageCharsPanel( void );
  44. // Add block of text to list
  45. virtual int AddText(
  46. float flTime,
  47. vgui::HFont hCustomFont,
  48. int x,
  49. int y,
  50. int r,
  51. int g,
  52. int b,
  53. int a,
  54. char *fmt,
  55. int messageID,
  56. ... );
  57. // Determine text side and height
  58. virtual void GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string );
  59. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  60. virtual void Paint();
  61. virtual void OnTick( void );
  62. virtual bool ShouldDraw( void );
  63. void RemoveStringsByID( int messageID );
  64. void Clear( void );
  65. private:
  66. // Allocate a new message
  67. message_t *AllocMessage( void );
  68. // Clear out all messages
  69. void Reset( void );
  70. vgui::HFont m_hFont;
  71. // Pool of messages
  72. message_t m_Messages[ MAX_MESSAGECHARS_MESSAGES ];
  73. message_t *m_pActive;
  74. message_t *m_pFree;
  75. };
  76. //-----------------------------------------------------------------------------
  77. // Purpose:
  78. // Input : *parent -
  79. // Output :
  80. //-----------------------------------------------------------------------------
  81. CMessageCharsPanel::CMessageCharsPanel( vgui::VPANEL parent ) :
  82. BaseClass( NULL, "CMessageCharsPanel" )
  83. {
  84. SetParent( parent );
  85. SetSize( ScreenWidth(), ScreenHeight() );
  86. SetPos( 0, 0 );
  87. SetVisible( true );
  88. SetCursor( null );
  89. SetKeyBoardInputEnabled( false );
  90. SetMouseInputEnabled( false );
  91. m_hFont = vgui::INVALID_FONT;
  92. SetFgColor( Color( 0, 0, 0, 255 ) );
  93. SetPaintBackgroundEnabled( false );
  94. Q_memset( m_Messages, 0, sizeof( m_Messages ) );
  95. Reset();
  96. vgui::ivgui()->AddTickSignal( GetVPanel(), 100 );
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose:
  100. // Output :
  101. //-----------------------------------------------------------------------------
  102. CMessageCharsPanel::~CMessageCharsPanel( void )
  103. {
  104. }
  105. void CMessageCharsPanel::ApplySchemeSettings(vgui::IScheme *pScheme)
  106. {
  107. BaseClass::ApplySchemeSettings(pScheme);
  108. m_hFont = pScheme->GetFont( "Default" );
  109. Assert( m_hFont != vgui::INVALID_FONT );
  110. SetSize( ScreenWidth(), ScreenHeight() );
  111. SetPos( 0, 0 );
  112. }
  113. //-----------------------------------------------------------------------------
  114. // Purpose:
  115. //-----------------------------------------------------------------------------
  116. void CMessageCharsPanel::Clear( void )
  117. {
  118. Reset();
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose: Reset all messages
  122. //-----------------------------------------------------------------------------
  123. void CMessageCharsPanel::Reset( void )
  124. {
  125. m_pActive = NULL;
  126. int i;
  127. for( i = 0; i < MAX_MESSAGECHARS_MESSAGES-1; i++ )
  128. {
  129. if ( m_Messages[ i ].text )
  130. {
  131. delete[] m_Messages[ i ].text;
  132. m_Messages[ i ].text = NULL;
  133. }
  134. m_Messages[ i ].next = &m_Messages[ i + 1 ];
  135. }
  136. m_Messages[ i ].next = NULL;
  137. m_pFree = &m_Messages[ 0 ];
  138. SetVisible( false );
  139. }
  140. //-----------------------------------------------------------------------------
  141. // Purpose: Allocate a message if possible
  142. // Output : CMessageCharsPanel::message_t
  143. //-----------------------------------------------------------------------------
  144. CMessageCharsPanel::message_t *CMessageCharsPanel::AllocMessage( void )
  145. {
  146. CMessageCharsPanel::message_t *msg;
  147. if ( !m_pFree )
  148. return NULL;
  149. msg = m_pFree;
  150. m_pFree = m_pFree->next;
  151. msg->next = m_pActive;
  152. m_pActive = msg;
  153. msg->x = 0;
  154. msg->y = 0;
  155. msg->text = NULL;
  156. msg->hCustomFont = NULL;
  157. return msg;
  158. }
  159. //-----------------------------------------------------------------------------
  160. // Purpose: Allocate message and fill in data
  161. // Input : x -
  162. // y -
  163. // *fmt -
  164. // ... -
  165. // Output : int
  166. //-----------------------------------------------------------------------------
  167. int CMessageCharsPanel::AddText(
  168. float flTime,
  169. vgui::HFont hCustomFont,
  170. int x,
  171. int y,
  172. int r,
  173. int g,
  174. int b,
  175. int a,
  176. char *fmt,
  177. int messageID,
  178. ... )
  179. {
  180. va_list argptr;
  181. char data[ MAX_MESSAGECHARSPANEL_LEN ];
  182. int len;
  183. va_start(argptr, messageID);
  184. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  185. va_end(argptr);
  186. data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
  187. CMessageCharsPanel::message_t *msg = AllocMessage();
  188. if ( !msg )
  189. return x;
  190. msg->x = x;
  191. msg->y = y;
  192. msg->r = r;
  193. msg->g = g;
  194. msg->b = b;
  195. msg->a = a;
  196. msg->messageID = messageID;
  197. Assert( !msg->text );
  198. int textLength = Q_strlen( data ) + 1;
  199. msg->text = new char[ textLength ];
  200. Assert( msg->text );
  201. Q_strncpy( msg->text, data, textLength );
  202. if ( flTime )
  203. msg->fTTL = gpGlobals->curtime + flTime;
  204. else
  205. msg->fTTL = 0;
  206. SetVisible( true );
  207. if ( hCustomFont )
  208. msg->hCustomFont = hCustomFont;
  209. else
  210. msg->hCustomFont = m_hFont;
  211. // Return new cursor position
  212. return x + g_pMatSystemSurface->DrawTextLen( msg->hCustomFont, "%s", data );
  213. }
  214. //-----------------------------------------------------------------------------
  215. // Purpose: Determine text size ahead of time
  216. // Input : *wide -
  217. // *tall -
  218. // *string -
  219. //-----------------------------------------------------------------------------
  220. void CMessageCharsPanel::GetTextExtents( vgui::HFont hCustomFont, int *wide, int *tall, const char *string )
  221. {
  222. if ( !hCustomFont )
  223. {
  224. // Make sure we actually have the font...
  225. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  226. hCustomFont = pScheme->GetFont( "Default" );
  227. }
  228. Assert( hCustomFont );
  229. *wide = g_pMatSystemSurface->DrawTextLen( hCustomFont, "%s", (char *)string );
  230. *tall = vgui::surface()->GetFontTall( hCustomFont );
  231. }
  232. //-----------------------------------------------------------------------------
  233. // Purpose:
  234. //-----------------------------------------------------------------------------
  235. void CMessageCharsPanel::OnTick( void )
  236. {
  237. bool bVisible = ShouldDraw();
  238. if ( IsVisible() != bVisible )
  239. {
  240. SetVisible( bVisible );
  241. }
  242. }
  243. //-----------------------------------------------------------------------------
  244. // Purpose:
  245. // Output : Returns true on success, false on failure.
  246. //-----------------------------------------------------------------------------
  247. bool CMessageCharsPanel::ShouldDraw( void )
  248. {
  249. if ( !m_pActive )
  250. return false;
  251. return true;
  252. }
  253. //-----------------------------------------------------------------------------
  254. // Purpose:
  255. // Input :
  256. //-----------------------------------------------------------------------------
  257. void CMessageCharsPanel::Paint()
  258. {
  259. CMessageCharsPanel::message_t *msg = m_pActive;
  260. while ( msg )
  261. {
  262. g_pMatSystemSurface->DrawColoredText( msg->hCustomFont, msg->x, msg->y, msg->r, msg->g, msg->b, msg->a, "%s", msg->text );
  263. msg = msg->next;
  264. }
  265. // Clear our dead messages
  266. message_t *pPrev = NULL;
  267. message_t *pCurrent = m_pActive;
  268. while ( pCurrent )
  269. {
  270. if ( pCurrent->fTTL <= gpGlobals->curtime )
  271. {
  272. // Move it to the free list
  273. if ( !pPrev )
  274. {
  275. m_pActive = pCurrent->next;
  276. }
  277. else
  278. {
  279. pPrev->next = pCurrent->next;
  280. }
  281. // Store off next one, because we're about to move the current
  282. message_t *pNext = pCurrent->next;
  283. delete[] pCurrent->text;
  284. pCurrent->text = NULL;
  285. pCurrent->next = m_pFree;
  286. m_pFree = pCurrent;
  287. // Don't advance pPrev
  288. pCurrent = pNext;
  289. continue;
  290. }
  291. pPrev = pCurrent;
  292. pCurrent = pCurrent->next;
  293. }
  294. }
  295. void CMessageCharsPanel::RemoveStringsByID( int messageID )
  296. {
  297. for ( message_t *pCurrent = m_pActive; pCurrent; pCurrent = pCurrent->next )
  298. {
  299. if ( pCurrent->messageID == messageID )
  300. pCurrent->fTTL = gpGlobals->curtime - 1000;
  301. }
  302. }
  303. class CMessageChars : public IMessageChars
  304. {
  305. private:
  306. CMessageCharsPanel *messageCharsPanel;
  307. public:
  308. CMessageChars( void )
  309. {
  310. messageCharsPanel = NULL;
  311. }
  312. void Create( vgui::VPANEL parent )
  313. {
  314. messageCharsPanel = new CMessageCharsPanel( parent );
  315. }
  316. void Destroy( void )
  317. {
  318. if ( messageCharsPanel )
  319. {
  320. messageCharsPanel->SetParent( (vgui::Panel *)NULL );
  321. messageCharsPanel->MarkForDeletion();
  322. messageCharsPanel = NULL;
  323. }
  324. }
  325. int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
  326. {
  327. va_list argptr;
  328. char data[ MAX_MESSAGECHARSPANEL_LEN ];
  329. int len;
  330. va_start(argptr, messageID);
  331. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  332. va_end(argptr);
  333. data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
  334. if ( !messageCharsPanel )
  335. return x;
  336. return messageCharsPanel->AddText( flTime, hCustomFont, x, y, r, g, b, a, data, messageID );
  337. }
  338. int DrawStringForTime( float flTime, vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
  339. {
  340. int r = 192, g = 192, b = 192;
  341. va_list argptr;
  342. va_start(argptr, messageID);
  343. int result = DrawString( hCustomFont, x, y, r, g, b, 255, fmt, messageID, argptr );
  344. va_end( argptr );
  345. return result;
  346. }
  347. virtual void RemoveStringsByID( int messageID )
  348. {
  349. messageCharsPanel->RemoveStringsByID( messageID );
  350. }
  351. int DrawString( vgui::HFont hCustomFont, int x, int y, int r, int g, int b, int a, const char *fmt, int messageID, ... )
  352. {
  353. va_list argptr;
  354. va_start(argptr, messageID);
  355. int result = DrawStringForTime( 0, hCustomFont, x, y, r, g, b, a, fmt, messageID, argptr );
  356. va_end( argptr );
  357. return result;
  358. }
  359. int DrawString( vgui::HFont hCustomFont, int x, int y, const char *fmt, int messageID, ... )
  360. {
  361. va_list argptr;
  362. va_start(argptr, messageID);
  363. int result = DrawStringForTime( 0, hCustomFont, x, y, fmt, messageID, argptr );
  364. va_end( argptr );
  365. return result;
  366. }
  367. void GetStringLength( vgui::HFont hCustomFont, int *width, int *height, const char *fmt, ... )
  368. {
  369. if ( !messageCharsPanel )
  370. {
  371. return;
  372. }
  373. va_list argptr;
  374. char data[ MAX_MESSAGECHARSPANEL_LEN ];
  375. int len;
  376. va_start(argptr, fmt);
  377. len = Q_vsnprintf(data, sizeof( data ), fmt, argptr);
  378. va_end(argptr);
  379. data[ MAX_MESSAGECHARSPANEL_LEN - 1 ] = 0;
  380. messageCharsPanel->GetTextExtents( hCustomFont, width, height, data );
  381. }
  382. void Clear( void )
  383. {
  384. if ( !messageCharsPanel )
  385. return;
  386. messageCharsPanel->Clear();
  387. }
  388. };
  389. static CMessageChars g_MessageChars;
  390. IMessageChars *messagechars = ( IMessageChars * )&g_MessageChars;