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.

360 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <vgui/IInput.h>
  8. #include <vgui/ILocalize.h>
  9. #include <vgui/ISurface.h>
  10. #include <vgui/ISystem.h>
  11. #include <vgui/IVGui.h>
  12. #include <KeyValues.h>
  13. #include <vgui_controls/Button.h>
  14. #include <vgui_controls/Controls.h>
  15. #include <vgui_controls/Label.h>
  16. #include <vgui_controls/ProgressBar.h>
  17. #include <vgui_controls/ProgressBox.h>
  18. #include <stdio.h>
  19. // memdbgon must be the last include file in a .cpp file!!!
  20. #include <tier0/memdbgon.h>
  21. using namespace vgui;
  22. #ifndef max
  23. #define max(a,b) (((a) > (b)) ? (a) : (b))
  24. #endif
  25. //-----------------------------------------------------------------------------
  26. // Purpose: Constructor
  27. //-----------------------------------------------------------------------------
  28. ProgressBox::ProgressBox(const char *title, const char *text, const char *pszUnknownTimeString, Panel *parent) : Frame(parent, NULL, parent ? false : true)
  29. {
  30. // save off the non-localized title, since we may need to dynamically localize it (on progress updates)
  31. const wchar_t *ws = g_pVGuiLocalize->Find(title);
  32. if (ws)
  33. {
  34. wcsncpy(m_wszTitleString, ws, sizeof(m_wszTitleString) / sizeof(wchar_t));
  35. }
  36. else
  37. {
  38. g_pVGuiLocalize->ConvertANSIToUnicode(title, m_wszTitleString, sizeof(m_wszTitleString));
  39. }
  40. m_pMessageLabel = new Label(this, NULL, pszUnknownTimeString);
  41. ws = g_pVGuiLocalize->Find(text);
  42. if (ws)
  43. {
  44. wcsncpy(m_wcsInfoString, ws, sizeof(m_wcsInfoString) / sizeof(wchar_t));
  45. }
  46. else
  47. {
  48. m_wcsInfoString[0] = 0;
  49. }
  50. ws = g_pVGuiLocalize->Find(pszUnknownTimeString);
  51. if (ws)
  52. {
  53. wcsncpy(m_wszUnknownTimeString, ws, sizeof(m_wszUnknownTimeString) / sizeof(wchar_t));
  54. }
  55. else
  56. {
  57. m_wszUnknownTimeString[0] = 0;
  58. }
  59. Init();
  60. }
  61. //-----------------------------------------------------------------------------
  62. // Purpose: Constructor
  63. //-----------------------------------------------------------------------------
  64. ProgressBox::ProgressBox(const wchar_t *wszTitle, const wchar_t *wszText, const wchar_t *wszUnknownTimeString, Panel *parent) : Frame(parent, NULL, parent ? false : true)
  65. {
  66. wcsncpy(m_wszTitleString, wszTitle, sizeof(m_wszTitleString) / sizeof(wchar_t));
  67. m_pMessageLabel = new Label(this, NULL, wszUnknownTimeString);
  68. wcsncpy(m_wcsInfoString, wszText, sizeof(m_wcsInfoString) / sizeof(wchar_t));
  69. wcsncpy(m_wszUnknownTimeString, wszUnknownTimeString, sizeof(m_wszUnknownTimeString) / sizeof(wchar_t));
  70. Init();
  71. }
  72. //-----------------------------------------------------------------------------
  73. // Purpose: Constructor Helper
  74. //-----------------------------------------------------------------------------
  75. void ProgressBox::Init()
  76. {
  77. m_pProgressBar = new ProgressBar(this, NULL);
  78. m_pProgressBar->SetVisible(false);
  79. m_pCancelButton = new Button(this, NULL, "#VGui_Cancel");
  80. m_pCancelButton->SetSize(72, 24);
  81. m_pCancelButton->SetCommand("Cancel");
  82. SetMenuButtonResponsive(false);
  83. SetMinimizeButtonVisible(false);
  84. SetCancelButtonVisible(false);
  85. SetSizeable(false);
  86. SetSize(384, 128);
  87. m_flCurrentProgress = 0.0f;
  88. m_flFirstProgressUpdate = -0.1f;
  89. m_flLastProgressUpdate = 0.0f;
  90. // mark ourselves as needed ticked once a second, to force us to repaint
  91. ivgui()->AddTickSignal(GetVPanel(), 1000);
  92. UpdateTitle();
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose: Destructor
  96. //-----------------------------------------------------------------------------
  97. ProgressBox::~ProgressBox()
  98. {
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose: resize the message label
  102. //-----------------------------------------------------------------------------
  103. void ProgressBox::ApplySchemeSettings(IScheme *pScheme)
  104. {
  105. BaseClass::ApplySchemeSettings(pScheme);
  106. int wide, tall;
  107. m_pMessageLabel->GetContentSize(wide, tall);
  108. SetSize(384, tall + 92);
  109. m_pMessageLabel->SetSize(344, tall);
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose: Put the message box into a modal state
  113. // Does not suspend execution - use addActionSignal to get return value
  114. //-----------------------------------------------------------------------------
  115. void ProgressBox::DoModal(Frame *pFrameOver)
  116. {
  117. ShowWindow(pFrameOver);
  118. input()->SetAppModalSurface(GetVPanel());
  119. }
  120. //-----------------------------------------------------------------------------
  121. // Purpose: Activates the window
  122. //-----------------------------------------------------------------------------
  123. void ProgressBox::ShowWindow(Frame *pFrameOver)
  124. {
  125. // move to the middle of the screen
  126. // get the screen size
  127. int wide, tall;
  128. // get our dialog size
  129. GetSize(wide, tall);
  130. if (pFrameOver)
  131. {
  132. int frameX, frameY;
  133. int frameWide, frameTall;
  134. pFrameOver->GetPos(frameX, frameY);
  135. pFrameOver->GetSize(frameWide, frameTall);
  136. SetPos((frameWide - wide) / 2 + frameX, (frameTall - tall) / 2 + frameY);
  137. }
  138. else
  139. {
  140. int swide, stall;
  141. surface()->GetScreenSize(swide, stall);
  142. // put the dialog in the middle of the screen
  143. SetPos((swide - wide) / 2, (stall - tall) / 2);
  144. }
  145. BaseClass::Activate();
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose: Put the text and OK buttons in correct place
  149. //-----------------------------------------------------------------------------
  150. void ProgressBox::PerformLayout()
  151. {
  152. int x, y, wide, tall;
  153. GetClientArea(x, y, wide, tall);
  154. wide += x;
  155. tall += y;
  156. int leftEdge = x + 16;
  157. m_pMessageLabel->SetPos(leftEdge, y + 12);
  158. m_pProgressBar->SetPos(leftEdge, y + 14 + m_pMessageLabel->GetTall() + 2);
  159. m_pProgressBar->SetSize(wide - 44, 24);
  160. if (m_pCancelButton->IsVisible())
  161. {
  162. // make room for cancel
  163. int px, py, pw, pt;
  164. int offs = m_pCancelButton->GetWide();
  165. m_pProgressBar->GetBounds(px, py, pw, pt);
  166. m_pCancelButton->SetPos(px + pw - offs, py);
  167. m_pProgressBar->SetSize(pw - offs - 10, pt);
  168. }
  169. BaseClass::PerformLayout();
  170. }
  171. //-----------------------------------------------------------------------------
  172. // Purpose: updates progress bar, range [0, 1]
  173. //-----------------------------------------------------------------------------
  174. void ProgressBox::SetProgress(float progress)
  175. {
  176. Assert(progress >= 0.0f && progress <= 1.0f);
  177. m_pProgressBar->SetProgress(progress);
  178. m_pProgressBar->SetVisible(true);
  179. // only update progress timings if the progress has actually changed
  180. if (progress != m_flCurrentProgress)
  181. {
  182. // store off timings for calculating time remaining
  183. if (m_flFirstProgressUpdate < 0.0f)
  184. {
  185. m_flFirstProgressUpdate = (float)system()->GetFrameTime();
  186. }
  187. m_flCurrentProgress = progress;
  188. m_flLastProgressUpdate = (float)system()->GetFrameTime();
  189. UpdateTitle();
  190. }
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose: sets the info text
  194. //-----------------------------------------------------------------------------
  195. void ProgressBox::SetText(const char *text)
  196. {
  197. m_pMessageLabel->SetText(text);
  198. }
  199. //-----------------------------------------------------------------------------
  200. // Purpose: Updates the dialog title text
  201. //-----------------------------------------------------------------------------
  202. void ProgressBox::UpdateTitle()
  203. {
  204. // update progress text
  205. wchar_t unicode[256];
  206. wchar_t completion[64];
  207. if ((int)(m_flCurrentProgress * 100.0f) > 0)
  208. {
  209. _snwprintf(completion, sizeof(completion) / sizeof(wchar_t), L"- %d%% complete", (int)(m_flCurrentProgress * 100.0f));
  210. }
  211. else
  212. {
  213. completion[0] = 0;
  214. }
  215. g_pVGuiLocalize->ConstructString(unicode, sizeof(unicode), m_wszTitleString, 1, completion);
  216. SetTitle(unicode, true);
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose: called every render
  220. //-----------------------------------------------------------------------------
  221. void ProgressBox::OnThink()
  222. {
  223. // calculate the progress made
  224. if (m_flFirstProgressUpdate >= 0.0f && m_wcsInfoString[0])
  225. {
  226. wchar_t timeRemaining[128];
  227. if (ProgressBar::ConstructTimeRemainingString(timeRemaining, sizeof(timeRemaining), m_flFirstProgressUpdate, (float)system()->GetFrameTime(), m_flCurrentProgress, m_flLastProgressUpdate, true))
  228. {
  229. wchar_t unicode[256];
  230. g_pVGuiLocalize->ConstructString(unicode, sizeof(unicode), m_wcsInfoString, 1, timeRemaining);
  231. m_pMessageLabel->SetText(unicode);
  232. }
  233. else
  234. {
  235. m_pMessageLabel->SetText(m_wszUnknownTimeString);
  236. }
  237. }
  238. }
  239. //-----------------------------------------------------------------------------
  240. // Purpose: Forces us to repaint once per second
  241. //-----------------------------------------------------------------------------
  242. void ProgressBox::OnTick()
  243. {
  244. if (m_flFirstProgressUpdate >= 0.0f)
  245. {
  246. Repaint();
  247. }
  248. BaseClass::OnTick();
  249. }
  250. //-----------------------------------------------------------------------------
  251. // Purpose: Handles ESC closing dialog
  252. //-----------------------------------------------------------------------------
  253. void ProgressBox::OnCommand(const char *command)
  254. {
  255. if (!stricmp(command, "Cancel"))
  256. {
  257. OnCancel();
  258. }
  259. else
  260. {
  261. BaseClass::OnCommand(command);
  262. }
  263. }
  264. //-----------------------------------------------------------------------------
  265. // Purpose: close button pressed
  266. //-----------------------------------------------------------------------------
  267. void ProgressBox::OnCloseFrameButtonPressed()
  268. {
  269. OnCancel();
  270. }
  271. //-----------------------------------------------------------------------------
  272. // Purpose: Deletes self when closed
  273. //-----------------------------------------------------------------------------
  274. void ProgressBox::OnClose()
  275. {
  276. BaseClass::OnClose();
  277. // modal surface is released on deletion
  278. MarkForDeletion();
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose:
  282. //-----------------------------------------------------------------------------
  283. void ProgressBox::OnShutdownRequest()
  284. {
  285. // Shutdown the dialog
  286. PostMessage(this, new KeyValues("Command", "command", "Cancel"));
  287. }
  288. //-----------------------------------------------------------------------------
  289. // Purpose: On update cancelled
  290. //-----------------------------------------------------------------------------
  291. void ProgressBox::OnCancel()
  292. {
  293. // post a message that we've been cancelled
  294. PostActionSignal(new KeyValues("ProgressBoxCancelled"));
  295. // close this dialog
  296. Close();
  297. }
  298. //-----------------------------------------------------------------------------
  299. // Purpose: Toggles visibility of the close box.
  300. //-----------------------------------------------------------------------------
  301. void ProgressBox::SetCancelButtonVisible(bool state)
  302. {
  303. BaseClass::SetCloseButtonVisible(state);
  304. m_pCancelButton->SetVisible(state);
  305. InvalidateLayout();
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Purpose:
  309. //-----------------------------------------------------------------------------
  310. void ProgressBox::SetCancelButtonEnabled(bool state)
  311. {
  312. m_pCancelButton->SetEnabled(state);
  313. BaseClass::SetCloseButtonVisible(state);
  314. InvalidateLayout();
  315. Repaint();
  316. }