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.

344 lines
9.8 KiB

  1. //========= Copyright 1996-2005, 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/CircularProgressBar.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. #include "mathlib/mathlib.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include <tier0/memdbgon.h>
  19. using namespace vgui;
  20. DECLARE_BUILD_FACTORY( CircularProgressBar );
  21. //-----------------------------------------------------------------------------
  22. // Purpose: Constructor
  23. //-----------------------------------------------------------------------------
  24. CircularProgressBar::CircularProgressBar(Panel *parent, const char *panelName) : ProgressBar(parent, panelName)
  25. {
  26. m_iProgressDirection = CircularProgressBar::PROGRESS_CCW;
  27. for ( int i = 0; i < NUM_PROGRESS_TEXTURES; i++ )
  28. {
  29. m_nTextureId[i] = -1;
  30. m_pszImageName[i] = NULL;
  31. m_lenImageName[i] = 0;
  32. }
  33. }
  34. //-----------------------------------------------------------------------------
  35. // Purpose: Destructor
  36. //-----------------------------------------------------------------------------
  37. CircularProgressBar::~CircularProgressBar()
  38. {
  39. for ( int i = 0; i < NUM_PROGRESS_TEXTURES; i++ )
  40. {
  41. delete [] m_pszImageName[i];
  42. m_lenImageName[i] = 0;
  43. }
  44. }
  45. //-----------------------------------------------------------------------------
  46. // Purpose:
  47. //-----------------------------------------------------------------------------
  48. void CircularProgressBar::ApplySettings(KeyValues *inResourceData)
  49. {
  50. for ( int i = 0; i < NUM_PROGRESS_TEXTURES; i++ )
  51. {
  52. delete [] m_pszImageName[i];
  53. m_pszImageName[i] = NULL;
  54. m_lenImageName[i] = 0;
  55. }
  56. const char *imageName = inResourceData->GetString("fg_image", "");
  57. if (*imageName)
  58. {
  59. SetFgImage( imageName );
  60. }
  61. imageName = inResourceData->GetString("bg_image", "");
  62. if (*imageName)
  63. {
  64. SetBgImage( imageName );
  65. }
  66. BaseClass::ApplySettings( inResourceData );
  67. }
  68. //-----------------------------------------------------------------------------
  69. // Purpose:
  70. //-----------------------------------------------------------------------------
  71. void CircularProgressBar::ApplySchemeSettings(IScheme *pScheme)
  72. {
  73. BaseClass::ApplySchemeSettings(pScheme);
  74. SetFgColor(GetSchemeColor("CircularProgressBar.FgColor", pScheme));
  75. SetBgColor(GetSchemeColor("CircularProgressBar.BgColor", pScheme));
  76. SetBorder(NULL);
  77. for ( int i = 0; i < NUM_PROGRESS_TEXTURES; i++ )
  78. {
  79. if ( m_pszImageName[i] && strlen( m_pszImageName[i] ) > 0 )
  80. {
  81. if ( m_nTextureId[i] == -1 )
  82. {
  83. m_nTextureId[i] = surface()->CreateNewTextureID();
  84. }
  85. surface()->DrawSetTextureFile( m_nTextureId[i], m_pszImageName[i], true, false);
  86. }
  87. }
  88. }
  89. //-----------------------------------------------------------------------------
  90. // Purpose: sets an image by file name
  91. //-----------------------------------------------------------------------------
  92. void CircularProgressBar::SetImage(const char *imageName, progress_textures_t iPos)
  93. {
  94. const char *pszDir = "vgui/";
  95. int len = Q_strlen(imageName) + 1;
  96. len += strlen(pszDir);
  97. if ( m_pszImageName[iPos] && ( m_lenImageName[iPos] < len ) )
  98. {
  99. // If we already have a buffer, but it is too short, then free the buffer
  100. delete [] m_pszImageName[iPos];
  101. m_pszImageName[iPos] = NULL;
  102. m_lenImageName[iPos] = 0;
  103. }
  104. if ( !m_pszImageName[iPos] )
  105. {
  106. m_pszImageName[iPos] = new char[ len ];
  107. m_lenImageName[iPos] = len;
  108. }
  109. Q_snprintf( m_pszImageName[iPos], len, "%s%s", pszDir, imageName );
  110. InvalidateLayout(false, true); // force applyschemesettings to run
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Purpose:
  114. //-----------------------------------------------------------------------------
  115. void CircularProgressBar::PaintBackground()
  116. {
  117. // If we don't have a Bg image, use the foreground
  118. int iTextureID = m_nTextureId[PROGRESS_TEXTURE_BG] != -1 ? m_nTextureId[PROGRESS_TEXTURE_BG] : m_nTextureId[PROGRESS_TEXTURE_FG];
  119. vgui::surface()->DrawSetTexture( iTextureID );
  120. vgui::surface()->DrawSetColor( GetBgColor() );
  121. int wide, tall;
  122. GetSize(wide, tall);
  123. vgui::surface()->DrawTexturedRect( 0, 0, wide, tall );
  124. }
  125. //-----------------------------------------------------------------------------
  126. // Purpose:
  127. //-----------------------------------------------------------------------------
  128. void CircularProgressBar::Paint()
  129. {
  130. float flProgress = GetProgress();
  131. float flEndAngle;
  132. if ( m_iProgressDirection == PROGRESS_CW )
  133. {
  134. flEndAngle = flProgress;
  135. }
  136. else
  137. {
  138. flEndAngle = ( 1.0 - flProgress );
  139. }
  140. DrawCircleSegment( GetFgColor(), flEndAngle, ( m_iProgressDirection == PROGRESS_CW ) );
  141. }
  142. typedef struct
  143. {
  144. float minProgressRadians;
  145. float vert1x;
  146. float vert1y;
  147. float vert2x;
  148. float vert2y;
  149. int swipe_dir_x;
  150. int swipe_dir_y;
  151. } circular_progress_segment_t;
  152. namespace vgui
  153. {
  154. // This defines the properties of the 8 circle segments
  155. // in the circular progress bar.
  156. circular_progress_segment_t Segments[8] =
  157. {
  158. { 0.0, 0.5, 0.0, 1.0, 0.0, 1, 0 },
  159. { M_PI * 0.25, 1.0, 0.0, 1.0, 0.5, 0, 1 },
  160. { M_PI * 0.5, 1.0, 0.5, 1.0, 1.0, 0, 1 },
  161. { M_PI * 0.75, 1.0, 1.0, 0.5, 1.0, -1, 0 },
  162. { M_PI, 0.5, 1.0, 0.0, 1.0, -1, 0 },
  163. { M_PI * 1.25, 0.0, 1.0, 0.0, 0.5, 0, -1 },
  164. { M_PI * 1.5, 0.0, 0.5, 0.0, 0.0, 0, -1 },
  165. { M_PI * 1.75, 0.0, 0.0, 0.5, 0.0, 1, 0 },
  166. };
  167. };
  168. #define SEGMENT_ANGLE ( M_PI / 4 )
  169. // function to draw from A to B degrees, with a direction
  170. // we draw starting from the top ( 0 progress )
  171. void CircularProgressBar::DrawCircleSegment( Color c, float flEndProgress, bool bClockwise )
  172. {
  173. if ( m_nTextureId[PROGRESS_TEXTURE_FG] == -1 )
  174. return;
  175. int wide, tall;
  176. GetSize(wide, tall);
  177. float flWide = (float)wide;
  178. float flTall = (float)tall;
  179. float flHalfWide = (float)wide / 2;
  180. float flHalfTall = (float)tall / 2;
  181. vgui::surface()->DrawSetTexture( m_nTextureId[PROGRESS_TEXTURE_FG] );
  182. vgui::surface()->DrawSetColor( c );
  183. // if we want to progress CCW, reverse a few things
  184. if ( !bClockwise )
  185. {
  186. float flEndProgressRadians = flEndProgress * M_PI * 2;
  187. int i;
  188. for ( i=0;i<8;i++ )
  189. {
  190. float segmentRadiansMin = Segments[i].minProgressRadians;
  191. float segmentRadiansMax = segmentRadiansMin + SEGMENT_ANGLE;
  192. if ( flEndProgressRadians < segmentRadiansMax )
  193. {
  194. vgui::Vertex_t v[3];
  195. // vert 0 is ( 0.5, 0.5 )
  196. v[0].m_Position.Init( flHalfWide, flHalfTall );
  197. v[0].m_TexCoord.Init( 0.5f, 0.5f );
  198. float flInternalProgress = segmentRadiansMax - flEndProgressRadians;
  199. if ( flInternalProgress < SEGMENT_ANGLE )
  200. {
  201. // Calc how much of this slice we should be drawing
  202. flInternalProgress = SEGMENT_ANGLE - flInternalProgress;
  203. if ( i % 2 == 1 )
  204. {
  205. flInternalProgress = SEGMENT_ANGLE - flInternalProgress;
  206. }
  207. float flTan = tan(flInternalProgress);
  208. float flDeltaX, flDeltaY;
  209. if ( i % 2 == 1 )
  210. {
  211. flDeltaX = ( flHalfWide - flHalfTall * flTan ) * Segments[i].swipe_dir_x;
  212. flDeltaY = ( flHalfTall - flHalfWide * flTan ) * Segments[i].swipe_dir_y;
  213. }
  214. else
  215. {
  216. flDeltaX = flHalfTall * flTan * Segments[i].swipe_dir_x;
  217. flDeltaY = flHalfWide * flTan * Segments[i].swipe_dir_y;
  218. }
  219. v[1].m_Position.Init( Segments[i].vert1x * flWide + flDeltaX, Segments[i].vert1y * flTall + flDeltaY );
  220. v[1].m_TexCoord.Init( Segments[i].vert1x + ( flDeltaX / flHalfWide ) * 0.5, Segments[i].vert1y + ( flDeltaY / flHalfTall ) * 0.5 );
  221. }
  222. else
  223. {
  224. // full segment, easy calculation
  225. v[1].m_Position.Init( flHalfWide + flWide * ( Segments[i].vert1x - 0.5 ), flHalfTall + flTall * ( Segments[i].vert1y - 0.5 ) );
  226. v[1].m_TexCoord.Init( Segments[i].vert1x, Segments[i].vert1y );
  227. }
  228. // vert 2 is ( Segments[i].vert1x, Segments[i].vert1y )
  229. v[2].m_Position.Init( flHalfWide + flWide * ( Segments[i].vert2x - 0.5 ), flHalfTall + flTall * ( Segments[i].vert2y - 0.5 ) );
  230. v[2].m_TexCoord.Init( Segments[i].vert2x, Segments[i].vert2y );
  231. vgui::surface()->DrawTexturedPolygon( 3, v );
  232. }
  233. }
  234. return;
  235. }
  236. float flEndProgressRadians = flEndProgress * M_PI * 2;
  237. int i;
  238. for ( i=0;i<8;i++ )
  239. {
  240. if ( flEndProgressRadians > Segments[i].minProgressRadians )
  241. {
  242. vgui::Vertex_t v[3];
  243. // vert 0 is ( 0.5, 0.5 )
  244. v[0].m_Position.Init( flHalfWide, flHalfTall );
  245. v[0].m_TexCoord.Init( 0.5f, 0.5f );
  246. float flInternalProgress = flEndProgressRadians - Segments[i].minProgressRadians;
  247. if ( flInternalProgress < SEGMENT_ANGLE )
  248. {
  249. // Calc how much of this slice we should be drawing
  250. if ( i % 2 == 1 )
  251. {
  252. flInternalProgress = SEGMENT_ANGLE - flInternalProgress;
  253. }
  254. float flTan = tan(flInternalProgress);
  255. float flDeltaX, flDeltaY;
  256. if ( i % 2 == 1 )
  257. {
  258. flDeltaX = ( flHalfWide - flHalfTall * flTan ) * Segments[i].swipe_dir_x;
  259. flDeltaY = ( flHalfTall - flHalfWide * flTan ) * Segments[i].swipe_dir_y;
  260. }
  261. else
  262. {
  263. flDeltaX = flHalfTall * flTan * Segments[i].swipe_dir_x;
  264. flDeltaY = flHalfWide * flTan * Segments[i].swipe_dir_y;
  265. }
  266. v[2].m_Position.Init( Segments[i].vert1x * flWide + flDeltaX, Segments[i].vert1y * flTall + flDeltaY );
  267. v[2].m_TexCoord.Init( Segments[i].vert1x + ( flDeltaX / flHalfWide ) * 0.5, Segments[i].vert1y + ( flDeltaY / flHalfTall ) * 0.5 );
  268. }
  269. else
  270. {
  271. // full segment, easy calculation
  272. v[2].m_Position.Init( flHalfWide + flWide * ( Segments[i].vert2x - 0.5 ), flHalfTall + flTall * ( Segments[i].vert2y - 0.5 ) );
  273. v[2].m_TexCoord.Init( Segments[i].vert2x, Segments[i].vert2y );
  274. }
  275. // vert 2 is ( Segments[i].vert1x, Segments[i].vert1y )
  276. v[1].m_Position.Init( flHalfWide + flWide * ( Segments[i].vert1x - 0.5 ), flHalfTall + flTall * ( Segments[i].vert1y - 0.5 ) );
  277. v[1].m_TexCoord.Init( Segments[i].vert1x, Segments[i].vert1y );
  278. vgui::surface()->DrawTexturedPolygon( 3, v );
  279. }
  280. }
  281. }