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.

368 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include <math.h>
  7. #include <dme_controls/ChannelGraphPanel.h>
  8. #include <vgui/IScheme.h>
  9. #include <vgui/ISurface.h>
  10. #include <vgui/IVGui.h>
  11. #include "vgui/IInput.h"
  12. // memdbgon must be the last include file in a .cpp file!!!
  13. #include <tier0/memdbgon.h>
  14. using namespace vgui;
  15. DECLARE_BUILD_FACTORY( CChannelGraphPanel );
  16. //-----------------------------------------------------------------------------
  17. // Purpose: Constructor
  18. //-----------------------------------------------------------------------------
  19. CChannelGraphPanel::CChannelGraphPanel( Panel *parent, const char *name )
  20. : BaseClass( parent, name ), m_font( 0 ),
  21. m_graphMinTime( 0 ), m_graphMaxTime( 0 ),
  22. m_graphMinValue( 0.0f ), m_graphMaxValue( 0.0f ),
  23. m_nMouseStartX( -1 ), m_nMouseStartY( -1 ),
  24. m_nMouseLastX( -1 ), m_nMouseLastY( -1 ),
  25. m_nTextBorder( 2 ), m_nGraphOriginX( 40 ), m_nGraphOriginY( 10 )
  26. {
  27. }
  28. void CChannelGraphPanel::SetChannel( CDmeChannel *pChannel )
  29. {
  30. m_hChannel = pChannel;
  31. CDmeLog *pLog = m_hChannel->GetLog();
  32. m_graphMinTime = pLog->GetBeginTime();
  33. m_graphMaxTime = pLog->GetEndTime();
  34. m_graphMinValue = FLT_MAX;
  35. m_graphMaxValue = -FLT_MAX;
  36. int nComponents = NumComponents( pLog->GetDataType() );
  37. int nKeys = pLog->GetKeyCount();
  38. for ( int k = 0; k < nKeys; ++k )
  39. {
  40. DmeTime_t t = pLog->GetKeyTime( k );
  41. for ( int i = 0; i < nComponents; ++i )
  42. {
  43. float f = pLog->GetComponent( t, i );
  44. m_graphMinValue = min( m_graphMinValue, f );
  45. m_graphMaxValue = max( m_graphMaxValue, f );
  46. }
  47. }
  48. }
  49. //-----------------------------------------------------------------------------
  50. // input methods
  51. //-----------------------------------------------------------------------------
  52. void CChannelGraphPanel::OnSizeChanged( int newWide, int newTall ) // called after the size of a panel has been changed
  53. {
  54. int wide = newWide - m_nGraphOriginX;
  55. int tall = newTall - m_nGraphOriginY;
  56. m_flTimeToPixel = wide / ( m_graphMaxTime - m_graphMinTime ).GetSeconds();
  57. m_flValueToPixel = tall / ( m_graphMaxValue - m_graphMinValue );
  58. }
  59. void CChannelGraphPanel::OnMousePressed( MouseCode code )
  60. {
  61. BaseClass::OnMousePressed( code );
  62. if ( code != MOUSE_LEFT )
  63. return;
  64. vgui::input()->GetCursorPos( m_nMouseStartX, m_nMouseStartY );
  65. ScreenToLocal( m_nMouseStartX, m_nMouseStartY );
  66. m_nMouseLastX = m_nMouseStartX;
  67. m_nMouseLastY = m_nMouseStartY;
  68. input()->SetMouseCapture( GetVPanel() );
  69. }
  70. void CChannelGraphPanel::OnMouseReleased( MouseCode code )
  71. {
  72. BaseClass::OnMouseReleased( code );
  73. if ( code != MOUSE_LEFT )
  74. return;
  75. m_nMouseStartX = m_nMouseStartY = -1;
  76. m_nMouseLastX = m_nMouseLastY = -1;
  77. input()->SetMouseCapture( NULL );
  78. }
  79. void CChannelGraphPanel::OnCursorMoved( int mx, int my )
  80. {
  81. BaseClass::OnCursorMoved( mx, my );
  82. if ( !vgui::input()->IsMouseDown( MOUSE_LEFT ) )
  83. return;
  84. bool bInValueLegend = m_nMouseStartX < m_nGraphOriginX;
  85. bool bInTimeLegend = m_nMouseStartY > GetTall() - m_nGraphOriginY - 1;
  86. if ( bInTimeLegend && bInValueLegend )
  87. {
  88. bInTimeLegend = bInValueLegend = false;
  89. }
  90. int dx = mx - m_nMouseLastX;
  91. int dy = my - m_nMouseLastY;
  92. if ( bInTimeLegend )
  93. {
  94. if ( abs( dy ) > abs( dx ) )
  95. {
  96. m_graphMinTime -= DmeTime_t( dy / m_flTimeToPixel );
  97. m_graphMaxTime += DmeTime_t( dy / m_flTimeToPixel );
  98. m_flTimeToPixel = ( GetWide() - m_nGraphOriginX ) / ( m_graphMaxTime - m_graphMinTime ).GetSeconds();
  99. int x = mx = m_nMouseLastX;
  100. int y = my = m_nMouseLastY;
  101. LocalToScreen( x, y );
  102. vgui::input()->SetCursorPos( x, y );
  103. }
  104. else
  105. {
  106. m_graphMinTime -= DmeTime_t( dx / m_flTimeToPixel );
  107. m_graphMaxTime -= DmeTime_t( dx / m_flTimeToPixel );
  108. }
  109. }
  110. else if ( bInValueLegend )
  111. {
  112. if ( abs( dx ) > abs( dy ) )
  113. {
  114. m_graphMinValue += dx / m_flValueToPixel;
  115. m_graphMaxValue -= dx / m_flValueToPixel;
  116. m_flValueToPixel = ( GetTall() - m_nGraphOriginY ) / ( m_graphMaxValue - m_graphMinValue );
  117. int x = mx = m_nMouseLastX;
  118. int y = my = m_nMouseLastY;
  119. LocalToScreen( x, y );
  120. vgui::input()->SetCursorPos( x, y );
  121. }
  122. else
  123. {
  124. m_graphMinValue += dy / m_flValueToPixel;
  125. m_graphMaxValue += dy / m_flValueToPixel;
  126. }
  127. }
  128. m_nMouseLastX = mx;
  129. m_nMouseLastY = my;
  130. }
  131. void CChannelGraphPanel::OnMouseWheeled( int delta )
  132. {
  133. // TODO - zoom in around current time?
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose: lays out the graph
  137. //-----------------------------------------------------------------------------
  138. void CChannelGraphPanel::PerformLayout()
  139. {
  140. BaseClass::PerformLayout();
  141. }
  142. float GetDisplayIncrement( int windowpixels, int fontpixels, float valuerange, int *pDecimalPlaces = NULL )
  143. {
  144. float ratio = valuerange * fontpixels / ( windowpixels );
  145. int nPower = ( int )ceil( log10( ratio ) );
  146. if ( pDecimalPlaces )
  147. {
  148. *pDecimalPlaces = max( 0, -nPower );
  149. }
  150. return pow( 10.0f, nPower );
  151. }
  152. int CChannelGraphPanel::TimeToPixel( DmeTime_t time )
  153. {
  154. return m_nGraphOriginX + ( int )floor( m_flTimeToPixel * ( time - m_graphMinTime ).GetSeconds() + 0.5f );
  155. }
  156. int CChannelGraphPanel::ValueToPixel( float flValue )
  157. {
  158. return m_nGraphOriginY + ( int )floor( m_flValueToPixel * ( flValue - m_graphMinValue ) + 0.5f );
  159. }
  160. //-----------------------------------------------------------------------------
  161. // Purpose: draws the graph
  162. //-----------------------------------------------------------------------------
  163. void CChannelGraphPanel::Paint()
  164. {
  165. // estimate the size of the graph marker text
  166. int wide = GetWide() - m_nGraphOriginX;
  167. int tall = GetTall() - m_nGraphOriginY;
  168. int textwidth = 40, textheight = 10;
  169. surface()->GetTextSize( m_font, L"999.9", textwidth, textheight );
  170. // draw current time marker
  171. DmeTime_t curtime = m_hChannel->GetCurrentTime();
  172. if ( curtime >= m_graphMinTime && curtime <= m_graphMaxTime )
  173. {
  174. Color cyan( 0, 255, 255, 255 );
  175. surface()->DrawSetColor( cyan );
  176. int x = TimeToPixel( curtime );
  177. surface()->DrawLine( x, 0, x, GetTall() - m_nGraphOriginY - 1 );
  178. }
  179. // draw left/bottom graph border
  180. Color black( 0, 0, 0, 255 );
  181. surface()->DrawSetColor( black );
  182. surface()->DrawLine( m_nGraphOriginX, GetTall() - m_nGraphOriginY - 1, GetWide(), GetTall() - m_nGraphOriginY - 1 );
  183. surface()->DrawLine( m_nGraphOriginX, GetTall() - m_nGraphOriginY - 1, m_nGraphOriginX, 0 );
  184. surface()->DrawSetTextColor( black );
  185. surface()->DrawSetTextFont( m_font );
  186. // draw graph tickmarks and values along the left border
  187. int nDecimalPlaces = 0;
  188. float flValueIncrement = GetDisplayIncrement( tall, ( int )( 1.5f * textheight ), m_graphMaxValue - m_graphMinValue, &nDecimalPlaces );
  189. int nMinValueIndex = ( int )ceil ( m_graphMinValue / flValueIncrement );
  190. int nMaxValueIndex = ( int )floor( m_graphMaxValue / flValueIncrement );
  191. float flValue = nMinValueIndex * flValueIncrement;
  192. for ( int i = nMinValueIndex; i <= nMaxValueIndex; ++i, flValue += flValueIncrement )
  193. {
  194. wchar_t pFormat[ 32 ];
  195. V_swprintf_safe( pFormat, L"%%.%df", nDecimalPlaces );
  196. wchar_t wstring[ 32 ];
  197. V_swprintf_safe( wstring, pFormat, flValue );
  198. int tw = 0, th = 0;
  199. surface()->GetTextSize( m_font, wstring, tw, th );
  200. int y = GetTall() - ValueToPixel( flValue ) - 1;
  201. surface()->DrawSetTextPos( m_nGraphOriginX - m_nTextBorder - tw, y - textheight / 2 );
  202. surface()->DrawPrintText( wstring, wcslen( wstring ) );
  203. surface()->DrawLine( m_nGraphOriginX - m_nTextBorder, y, m_nGraphOriginX, y );
  204. }
  205. // draw graph tickmarks and times along the bottom border
  206. float flTimeIncrement = GetDisplayIncrement( wide, textwidth, ( m_graphMaxTime - m_graphMinTime ).GetSeconds(), &nDecimalPlaces );
  207. int nMinTimeIndex = ( int )ceil ( m_graphMinTime.GetSeconds() / flTimeIncrement );
  208. int nMaxTimeIndex = ( int )floor( m_graphMaxTime.GetSeconds() / flTimeIncrement );
  209. float flTime = nMinTimeIndex * flTimeIncrement;
  210. for ( int i = nMinTimeIndex; i <= nMaxTimeIndex; ++i, flTime += flTimeIncrement )
  211. {
  212. wchar_t pFormat[ 32 ];
  213. V_swprintf_safe( pFormat, L"%%.%df", nDecimalPlaces );
  214. wchar_t wstring[ 32 ];
  215. V_swprintf_safe( wstring, pFormat, flTime );
  216. int tw = 0, th = 0;
  217. surface()->GetTextSize( m_font, wstring, tw, th );
  218. int x = TimeToPixel( DmeTime_t( flTime ) );
  219. surface()->DrawSetTextPos( x - tw / 2, GetTall() - m_nGraphOriginY + m_nTextBorder - 1 );
  220. surface()->DrawPrintText( wstring, wcslen( wstring ) );
  221. surface()->DrawLine( x, GetTall() - m_nGraphOriginY + m_nTextBorder - 1, x, GetTall() - m_nGraphOriginY - 1 );
  222. }
  223. static Color s_componentColors[] =
  224. {
  225. Color( 255, 0, 0, 255 ),
  226. Color( 0, 255, 0, 255 ),
  227. Color( 0, 0, 255, 255 ),
  228. Color( 0, 0, 0, 255 ),
  229. };
  230. CDmeLog *pLog = m_hChannel->GetLog();
  231. int nComponents = NumComponents( pLog->GetDataType() );
  232. int nKeys = pLog->GetKeyCount();
  233. // draw plotted graph
  234. for ( int i = 0; i < nComponents; ++i )
  235. {
  236. Color &color = s_componentColors[ i % ARRAYSIZE( s_componentColors ) ];
  237. surface()->DrawSetColor( color );
  238. int lastx = -1;
  239. int lasty = -1;
  240. for ( int k = 0; k < nKeys; ++k )
  241. {
  242. DmeTime_t t = pLog->GetKeyTime( k );
  243. float f = pLog->GetComponent( t, i );
  244. int x = TimeToPixel( t );
  245. int y = GetTall() - ValueToPixel( f ) - 1;
  246. if ( k )
  247. {
  248. surface()->DrawLine( lastx, lasty, x, y );
  249. }
  250. lastx = x;
  251. lasty = y;
  252. }
  253. }
  254. }
  255. //-----------------------------------------------------------------------------
  256. // Purpose: sets up colors
  257. //-----------------------------------------------------------------------------
  258. void CChannelGraphPanel::ApplySchemeSettings(IScheme *pScheme)
  259. {
  260. BaseClass::ApplySchemeSettings(pScheme);
  261. m_font = pScheme->GetFont( "DefaultVerySmall" );
  262. surface()->GetTextSize( m_font, L"999.9", m_nGraphOriginX, m_nGraphOriginY );
  263. m_nGraphOriginX += 2 * m_nTextBorder;
  264. m_nGraphOriginY += 2 * m_nTextBorder;
  265. SetFgColor(GetSchemeColor("CChannelGraphPanel.FgColor", pScheme));
  266. SetBgColor(GetSchemeColor("CChannelGraphPanel.BgColor", pScheme));
  267. SetBorder(pScheme->GetBorder("ButtonDepressedBorder"));
  268. }
  269. //-----------------------------------------------------------------------------
  270. //
  271. // CChannelGraphFrame methods
  272. //
  273. //-----------------------------------------------------------------------------
  274. CChannelGraphFrame::CChannelGraphFrame( Panel *parent, const char *pTitle )
  275. : BaseClass( parent, "CChannelGraphFrame" )
  276. {
  277. SetTitle( pTitle, true );
  278. SetSizeable( true );
  279. SetCloseButtonVisible( true );
  280. SetMinimumSize( 200, 100 );
  281. SetVisible( true );
  282. SetSize( 400, 200 );
  283. SetPos( 100, 100 );
  284. m_pChannelGraph = new CChannelGraphPanel( this, "ChannelGraph" );
  285. SetScheme( vgui::scheme()->LoadSchemeFromFile( "Resource/BoxRocket.res", "BoxRocket" ) );
  286. }
  287. void CChannelGraphFrame::SetChannel( CDmeChannel *pChannel )
  288. {
  289. m_pChannelGraph->SetChannel( pChannel );
  290. }
  291. void CChannelGraphFrame::OnCommand( const char *cmd )
  292. {
  293. BaseClass::OnCommand( cmd );
  294. m_pChannelGraph->OnCommand( cmd );
  295. }
  296. void CChannelGraphFrame::PerformLayout()
  297. {
  298. BaseClass::PerformLayout();
  299. int border = 5;
  300. int iWidth, iHeight;
  301. GetSize( iWidth, iHeight );
  302. m_pChannelGraph->SetPos( border, GetCaptionHeight() + border );
  303. m_pChannelGraph->SetSize( iWidth - 2 * border, iHeight - GetCaptionHeight() - 2 * border );
  304. }