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.

520 lines
15 KiB

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