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.

459 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <assert.h>
  7. #include <math.h>
  8. #include <stdio.h>
  9. #include <vgui_controls/AnalogBar.h>
  10. #include <vgui_controls/Controls.h>
  11. #include <vgui/ILocalize.h>
  12. #include <vgui/IScheme.h>
  13. #include <vgui/ISurface.h>
  14. #include <KeyValues.h>
  15. // memdbgon must be the last include file in a .cpp file!!!
  16. #include <tier0/memdbgon.h>
  17. using namespace vgui;
  18. DECLARE_BUILD_FACTORY( AnalogBar );
  19. #define ANALOG_BAR_HOME_SIZE 4
  20. #define ANALOG_BAR_HOME_GAP 2
  21. #define ANALOG_BAR_LESS_TALL ( ANALOG_BAR_HOME_SIZE + ANALOG_BAR_HOME_GAP )
  22. //-----------------------------------------------------------------------------
  23. // Purpose: Constructor
  24. //-----------------------------------------------------------------------------
  25. AnalogBar::AnalogBar(Panel *parent, const char *panelName) : Panel(parent, panelName)
  26. {
  27. _analogValue = 0.0f;
  28. m_pszDialogVar = NULL;
  29. SetSegmentInfo( 2, 6 );
  30. SetBarInset( 0 );
  31. m_iAnalogValueDirection = PROGRESS_EAST;
  32. m_fHomeValue = 2.0f;
  33. m_HomeColor = GetFgColor();
  34. }
  35. //-----------------------------------------------------------------------------
  36. // Purpose: Destructor
  37. //-----------------------------------------------------------------------------
  38. AnalogBar::~AnalogBar()
  39. {
  40. delete [] m_pszDialogVar;
  41. }
  42. //-----------------------------------------------------------------------------
  43. // Purpose: data accessor
  44. //-----------------------------------------------------------------------------
  45. void AnalogBar::SetSegmentInfo( int gap, int width )
  46. {
  47. _segmentGap = gap;
  48. _segmentWide = width;
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose: returns the number of segment blocks drawn
  52. //-----------------------------------------------------------------------------
  53. int AnalogBar::GetDrawnSegmentCount()
  54. {
  55. int wide, tall;
  56. GetSize(wide, tall);
  57. int segmentTotal = wide / (_segmentGap + _segmentWide);
  58. return (int)(segmentTotal * _analogValue);
  59. }
  60. //-----------------------------------------------------------------------------
  61. // Purpose: returns the total number of segment blocks drawn (active and inactive)
  62. //-----------------------------------------------------------------------------
  63. int AnalogBar::GetTotalSegmentCount()
  64. {
  65. int wide, tall;
  66. GetSize(wide, tall);
  67. int segmentTotal = wide / (_segmentGap + _segmentWide);
  68. return segmentTotal;
  69. }
  70. //-----------------------------------------------------------------------------
  71. // Purpose:
  72. //-----------------------------------------------------------------------------
  73. void AnalogBar::PaintBackground()
  74. {
  75. // Don't draw a background
  76. }
  77. void AnalogBar::PaintSegment( int &x, int &y, int tall, int wide, Color color, bool bHome )
  78. {
  79. switch( m_iAnalogValueDirection )
  80. {
  81. case PROGRESS_EAST:
  82. x += _segmentGap;
  83. if ( bHome )
  84. {
  85. surface()->DrawSetColor( GetHomeColor() );
  86. surface()->DrawFilledRect(x, y, x + _segmentWide, y + ANALOG_BAR_HOME_SIZE );
  87. surface()->DrawFilledRect(x, y + tall - (y * 2) - ANALOG_BAR_HOME_SIZE, x + _segmentWide, y + tall - (y * 2) );
  88. }
  89. surface()->DrawSetColor( color );
  90. surface()->DrawFilledRect(x, y + ANALOG_BAR_LESS_TALL, x + _segmentWide, y + tall - (y * 2) - ANALOG_BAR_LESS_TALL );
  91. x += _segmentWide;
  92. break;
  93. case PROGRESS_WEST:
  94. x -= _segmentGap + _segmentWide;
  95. if ( bHome )
  96. {
  97. surface()->DrawSetColor( GetHomeColor() );
  98. surface()->DrawFilledRect(x, y, x + _segmentWide, y + ANALOG_BAR_HOME_SIZE );
  99. surface()->DrawFilledRect(x, y + tall - (y * 2) - ANALOG_BAR_HOME_SIZE, x + _segmentWide, y + tall - (y * 2) );
  100. }
  101. surface()->DrawSetColor( color );
  102. surface()->DrawFilledRect(x, y + ANALOG_BAR_LESS_TALL, x + _segmentWide, y + tall - (y * 2) - ANALOG_BAR_LESS_TALL );
  103. break;
  104. case PROGRESS_NORTH:
  105. y -= _segmentGap + _segmentWide;
  106. if ( bHome )
  107. {
  108. surface()->DrawSetColor( GetHomeColor() );
  109. surface()->DrawFilledRect(x, y, x + ANALOG_BAR_HOME_SIZE, y + _segmentWide );
  110. surface()->DrawFilledRect(x + wide - (x * 2) - ANALOG_BAR_HOME_SIZE, y, x + wide - (x * 2), y + _segmentWide );
  111. }
  112. surface()->DrawSetColor( color );
  113. surface()->DrawFilledRect(x + ANALOG_BAR_LESS_TALL, y, x + wide - (x * 2) - ANALOG_BAR_LESS_TALL, y + _segmentWide);
  114. break;
  115. case PROGRESS_SOUTH:
  116. y += _segmentGap;
  117. if ( bHome )
  118. {
  119. surface()->DrawSetColor( GetHomeColor() );
  120. surface()->DrawFilledRect(x, y, x + ANALOG_BAR_HOME_SIZE, y + _segmentWide );
  121. surface()->DrawFilledRect(x + wide - (x * 2) - ANALOG_BAR_HOME_SIZE, y, x + wide - (x * 2), y + _segmentWide );
  122. }
  123. surface()->DrawSetColor( color );
  124. surface()->DrawFilledRect(x + ANALOG_BAR_LESS_TALL, y, x + wide - (x * 2) - ANALOG_BAR_LESS_TALL, y + _segmentWide);
  125. y += _segmentWide;
  126. break;
  127. }
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose:
  131. //-----------------------------------------------------------------------------
  132. void AnalogBar::Paint()
  133. {
  134. int wide, tall;
  135. GetSize(wide, tall);
  136. // gaps
  137. int segmentTotal = 0, segmentsDrawn = 0;
  138. int x = 0, y = 0;
  139. switch( m_iAnalogValueDirection )
  140. {
  141. case PROGRESS_WEST:
  142. x = wide;
  143. y = m_iBarInset;
  144. segmentTotal = wide / (_segmentGap + _segmentWide);
  145. segmentsDrawn = (int)(segmentTotal * _analogValue + 0.5f);
  146. break;
  147. case PROGRESS_EAST:
  148. x = 0;
  149. y = m_iBarInset;
  150. segmentTotal = wide / (_segmentGap + _segmentWide);
  151. segmentsDrawn = (int)(segmentTotal * _analogValue + 0.5f);
  152. break;
  153. case PROGRESS_NORTH:
  154. x = m_iBarInset;
  155. y = tall;
  156. segmentTotal = tall / (_segmentGap + _segmentWide);
  157. segmentsDrawn = (int)(segmentTotal * _analogValue + 0.5f);
  158. break;
  159. case PROGRESS_SOUTH:
  160. x = m_iBarInset;
  161. y = 0;
  162. segmentTotal = tall / (_segmentGap + _segmentWide);
  163. segmentsDrawn = (int)(segmentTotal * _analogValue + 0.5f);
  164. break;
  165. }
  166. int iHomeIndex = (int)( segmentTotal * m_fHomeValue + 0.5f ) - 1;
  167. if ( iHomeIndex < 0 )
  168. iHomeIndex = 0;
  169. for (int i = 0; i < segmentsDrawn; i++)
  170. PaintSegment( x, y, tall, wide, GetFgColor(), i == iHomeIndex );
  171. for (int i = segmentsDrawn; i < segmentTotal; i++)
  172. PaintSegment( x, y, tall, wide, GetBgColor(), i == iHomeIndex );
  173. }
  174. //-----------------------------------------------------------------------------
  175. // Purpose:
  176. //-----------------------------------------------------------------------------
  177. void AnalogBar::SetAnalogValue(float analogValue)
  178. {
  179. if (analogValue != _analogValue)
  180. {
  181. // clamp the analogValue value within the range
  182. if (analogValue < 0.0f)
  183. {
  184. analogValue = 0.0f;
  185. }
  186. else if (analogValue > 1.0f)
  187. {
  188. analogValue = 1.0f;
  189. }
  190. _analogValue = analogValue;
  191. Repaint();
  192. }
  193. }
  194. //-----------------------------------------------------------------------------
  195. // Purpose: data accessor
  196. //-----------------------------------------------------------------------------
  197. float AnalogBar::GetAnalogValue()
  198. {
  199. return _analogValue;
  200. }
  201. //-----------------------------------------------------------------------------
  202. // Purpose:
  203. //-----------------------------------------------------------------------------
  204. void AnalogBar::ApplySchemeSettings(IScheme *pScheme)
  205. {
  206. Panel::ApplySchemeSettings(pScheme);
  207. SetBgColor( Color( 255 - GetFgColor().r(), 255 - GetFgColor().g(), 255 - GetFgColor().b(), GetFgColor().a() ) );
  208. }
  209. //-----------------------------------------------------------------------------
  210. // Purpose: utility function for calculating a time remaining string
  211. //-----------------------------------------------------------------------------
  212. bool AnalogBar::ConstructTimeRemainingString(wchar_t *output, int outputBufferSizeInBytes, float startTime, float currentTime, float currentAnalogValue, float lastAnalogValueUpdateTime, bool addRemainingSuffix)
  213. {
  214. Assert( outputBufferSizeInBytes >= sizeof(output[0]) );
  215. Assert(lastAnalogValueUpdateTime <= currentTime);
  216. output[0] = 0;
  217. // calculate pre-extrapolation values
  218. float timeElapsed = lastAnalogValueUpdateTime - startTime;
  219. float totalTime = timeElapsed / currentAnalogValue;
  220. // calculate seconds
  221. int secondsRemaining = (int)(totalTime - timeElapsed);
  222. if (lastAnalogValueUpdateTime < currentTime)
  223. {
  224. // old update, extrapolate
  225. float analogValueRate = currentAnalogValue / timeElapsed;
  226. float extrapolatedAnalogValue = analogValueRate * (currentTime - startTime);
  227. float extrapolatedTotalTime = (currentTime - startTime) / extrapolatedAnalogValue;
  228. secondsRemaining = (int)(extrapolatedTotalTime - timeElapsed);
  229. }
  230. // if there's some time, make sure it's at least one second left
  231. if ( secondsRemaining == 0 && ( ( totalTime - timeElapsed ) > 0 ) )
  232. {
  233. secondsRemaining = 1;
  234. }
  235. // calculate minutes
  236. int minutesRemaining = 0;
  237. while (secondsRemaining >= 60)
  238. {
  239. minutesRemaining++;
  240. secondsRemaining -= 60;
  241. }
  242. char minutesBuf[16];
  243. Q_snprintf(minutesBuf, sizeof( minutesBuf ), "%d", minutesRemaining);
  244. char secondsBuf[16];
  245. Q_snprintf(secondsBuf, sizeof( secondsBuf ), "%d", secondsRemaining);
  246. if (minutesRemaining > 0)
  247. {
  248. wchar_t unicodeMinutes[16];
  249. g_pVGuiLocalize->ConvertANSIToUnicode(minutesBuf, unicodeMinutes, sizeof( unicodeMinutes ));
  250. wchar_t unicodeSeconds[16];
  251. g_pVGuiLocalize->ConvertANSIToUnicode(secondsBuf, unicodeSeconds, sizeof( unicodeSeconds ));
  252. const char *unlocalizedString = "#vgui_TimeLeftMinutesSeconds";
  253. if (minutesRemaining == 1 && secondsRemaining == 1)
  254. {
  255. unlocalizedString = "#vgui_TimeLeftMinuteSecond";
  256. }
  257. else if (minutesRemaining == 1)
  258. {
  259. unlocalizedString = "#vgui_TimeLeftMinuteSeconds";
  260. }
  261. else if (secondsRemaining == 1)
  262. {
  263. unlocalizedString = "#vgui_TimeLeftMinutesSecond";
  264. }
  265. char unlocString[64];
  266. Q_strncpy(unlocString, unlocalizedString,sizeof( unlocString ));
  267. if (addRemainingSuffix)
  268. {
  269. Q_strncat(unlocString, "Remaining", sizeof(unlocString ), COPY_ALL_CHARACTERS);
  270. }
  271. g_pVGuiLocalize->ConstructString(output, outputBufferSizeInBytes, g_pVGuiLocalize->Find(unlocString), 2, unicodeMinutes, unicodeSeconds);
  272. }
  273. else if (secondsRemaining > 0)
  274. {
  275. wchar_t unicodeSeconds[16];
  276. g_pVGuiLocalize->ConvertANSIToUnicode(secondsBuf, unicodeSeconds, sizeof( unicodeSeconds ));
  277. const char *unlocalizedString = "#vgui_TimeLeftSeconds";
  278. if (secondsRemaining == 1)
  279. {
  280. unlocalizedString = "#vgui_TimeLeftSecond";
  281. }
  282. char unlocString[64];
  283. Q_strncpy(unlocString, unlocalizedString,sizeof(unlocString));
  284. if (addRemainingSuffix)
  285. {
  286. Q_strncat(unlocString, "Remaining",sizeof(unlocString), COPY_ALL_CHARACTERS);
  287. }
  288. g_pVGuiLocalize->ConstructString(output, outputBufferSizeInBytes, g_pVGuiLocalize->Find(unlocString), 1, unicodeSeconds);
  289. }
  290. else
  291. {
  292. return false;
  293. }
  294. return true;
  295. }
  296. //-----------------------------------------------------------------------------
  297. // Purpose: data accessor
  298. //-----------------------------------------------------------------------------
  299. void AnalogBar::SetBarInset( int pixels )
  300. {
  301. m_iBarInset = pixels;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose: data accessor
  305. //-----------------------------------------------------------------------------
  306. int AnalogBar::GetBarInset( void )
  307. {
  308. return m_iBarInset;
  309. }
  310. //-----------------------------------------------------------------------------
  311. // Purpose:
  312. //-----------------------------------------------------------------------------
  313. void AnalogBar::ApplySettings(KeyValues *inResourceData)
  314. {
  315. _analogValue = inResourceData->GetFloat("analogValue", 0.0f);
  316. const char *dialogVar = inResourceData->GetString("variable", "");
  317. if (dialogVar && *dialogVar)
  318. {
  319. m_pszDialogVar = new char[strlen(dialogVar) + 1];
  320. strcpy(m_pszDialogVar, dialogVar);
  321. }
  322. BaseClass::ApplySettings(inResourceData);
  323. }
  324. //-----------------------------------------------------------------------------
  325. // Purpose:
  326. //-----------------------------------------------------------------------------
  327. void AnalogBar::GetSettings(KeyValues *outResourceData)
  328. {
  329. BaseClass::GetSettings(outResourceData);
  330. outResourceData->SetFloat("analogValue", _analogValue );
  331. if (m_pszDialogVar)
  332. {
  333. outResourceData->SetString("variable", m_pszDialogVar);
  334. }
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose: Returns a string description of the panel fields for use in the UI
  338. //-----------------------------------------------------------------------------
  339. const char *AnalogBar::GetDescription( void )
  340. {
  341. static char buf[1024];
  342. _snprintf(buf, sizeof(buf), "%s, string analogValue, string variable", BaseClass::GetDescription());
  343. return buf;
  344. }
  345. //-----------------------------------------------------------------------------
  346. // Purpose: updates analogValue bar bases on values
  347. //-----------------------------------------------------------------------------
  348. void AnalogBar::OnDialogVariablesChanged(KeyValues *dialogVariables)
  349. {
  350. if (m_pszDialogVar)
  351. {
  352. int val = dialogVariables->GetInt(m_pszDialogVar, -1);
  353. if (val >= 0.0f)
  354. {
  355. SetAnalogValue(val / 100.0f);
  356. }
  357. }
  358. }
  359. DECLARE_BUILD_FACTORY( ContinuousAnalogBar );
  360. //-----------------------------------------------------------------------------
  361. // Purpose: Constructor
  362. //-----------------------------------------------------------------------------
  363. ContinuousAnalogBar::ContinuousAnalogBar(Panel *parent, const char *panelName) : AnalogBar(parent, panelName)
  364. {
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose:
  368. //-----------------------------------------------------------------------------
  369. void ContinuousAnalogBar::Paint()
  370. {
  371. int x = 0, y = 0;
  372. int wide, tall;
  373. GetSize(wide, tall);
  374. surface()->DrawSetColor(GetFgColor());
  375. switch( m_iAnalogValueDirection )
  376. {
  377. case PROGRESS_EAST:
  378. surface()->DrawFilledRect( x, y, x + (int)( wide * _analogValue ), y + tall );
  379. break;
  380. case PROGRESS_WEST:
  381. surface()->DrawFilledRect( x + (int)( wide * ( 1.0f - _analogValue ) ), y, x + wide, y + tall );
  382. break;
  383. case PROGRESS_NORTH:
  384. surface()->DrawFilledRect( x, y + (int)( tall * ( 1.0f - _analogValue ) ), x + wide, y + tall );
  385. break;
  386. case PROGRESS_SOUTH:
  387. surface()->DrawFilledRect( x, y, x + wide, y + (int)( tall * _analogValue ) );
  388. break;
  389. }
  390. }