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.

1349 lines
39 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dme_controls/attributeslider.h"
  7. #include "materialsystem/imesh.h"
  8. #include "movieobjects/dmeanimationset.h"
  9. #include "vgui/IInput.h"
  10. #include "vgui/ISurface.h"
  11. #include "vgui_controls/TextEntry.h"
  12. #include "vgui_controls/TextImage.h"
  13. #include "vgui_controls/subrectimage.h"
  14. #include "vgui_controls/CheckButton.h"
  15. #include "dme_controls/BaseAnimSetAttributeSliderPanel.h"
  16. #include "dme_controls/BaseAnimationSetEditor.h"
  17. // memdbgon must be the last include file in a .cpp file!!!
  18. #include "tier0/memdbgon.h"
  19. using namespace vgui;
  20. //-----------------------------------------------------------------------------
  21. // Enums
  22. //-----------------------------------------------------------------------------
  23. #define SLIDER_PIXEL_SPACING 3
  24. #define CIRCULAR_CONTROL_RADIUS 6.0f
  25. #define UNDO_CHAIN_MOUSEWHEEL_ATTRIBUTE_SLIDER 9876
  26. #define FRAC_PER_PIXEL 0.0025f
  27. #define ANIM_SET_ATTRIBUTE_SLIDER_BALANCE_INSET 30
  28. #define ANIM_SET_ATTRIBUTE_SLIDER_LEFT_BORDER 5
  29. #define ANIM_SET_ATTRIBUTE_SLIDER_GRAPH_BUTTON_WIDTH 16
  30. #define ANIM_SET_ATTRIBUTE_SLIDER_MULTILEVEL_INSET 30
  31. static ConVar ifm_attributeslider_sensitivity( "ifm_attributeslider_sensitivity", "3.0", 0 );
  32. //-----------------------------------------------------------------------------
  33. // Globals
  34. //-----------------------------------------------------------------------------
  35. static Color s_TextColor( 200, 200, 200, 192 );
  36. static Color s_TextColorFocus( 208, 143, 40, 192 );
  37. // NOTE: Index with [preview][selected]
  38. static Color s_BarColor[2][2] =
  39. {
  40. { Color( 45, 45, 45, 255 ), Color( 150, 80, 0, 255 ) },
  41. { Color( 30, 255, 255, 80 ), Color( 30, 180, 255, 255 ) }
  42. };
  43. static Color s_ZeroColor[2][2] =
  44. {
  45. { Color( 33, 33, 33, 255 ), Color( 0, 255, 255, 60 ) },
  46. { Color( 100, 80, 0, 255 ), Color( 0, 180, 255, 255 ) }
  47. };
  48. static Color s_DraggingBarColor( 142, 142, 142, 255 );
  49. static Color s_PreviewTickColor( 255, 164, 8, 255 );
  50. static Color s_OldValueTickColor( 100, 100, 100, 63 );
  51. static Color s_MidpointColor( 115, 115, 115, 255 );
  52. //-----------------------------------------------------------------------------
  53. // Blends flex values in left-right space instead of balance/value space
  54. //-----------------------------------------------------------------------------
  55. static void BlendFlexValues( AttributeValue_t *pResult, const AttributeValue_t &src, const AttributeValue_t &dest, float flBlend, float flBalanceFilter = 0.5f )
  56. {
  57. // Apply the left-right balance to the target
  58. float flLeftFilter, flRightFilter;
  59. ValueBalanceToLeftRight( &flLeftFilter, &flRightFilter, flBlend, flBalanceFilter );
  60. // Do the math in 'left-right' space because we filter in that space
  61. float flSrcLeft, flSrcRight;
  62. ValueBalanceToLeftRight( &flSrcLeft, &flSrcRight, src.m_pValue[ANIM_CONTROL_VALUE], src.m_pValue[ANIM_CONTROL_BALANCE] );
  63. float flDestLeft, flDestRight;
  64. ValueBalanceToLeftRight( &flDestLeft, &flDestRight, dest.m_pValue[ANIM_CONTROL_VALUE], dest.m_pValue[ANIM_CONTROL_BALANCE] );
  65. float flTargetLeft = flSrcLeft + flLeftFilter * ( flDestLeft - flSrcLeft );
  66. float flTargetRight = flSrcRight + flRightFilter * ( flDestRight - flSrcRight );
  67. LeftRightToValueBalance( &pResult->m_pValue[ANIM_CONTROL_VALUE], &pResult->m_pValue[ANIM_CONTROL_BALANCE], flTargetLeft, flTargetRight,
  68. ( flBlend <= 0.5f ) ? src.m_pValue[ANIM_CONTROL_BALANCE] : dest.m_pValue[ANIM_CONTROL_BALANCE] );
  69. pResult->m_pValue[ANIM_CONTROL_MULTILEVEL] = src.m_pValue[ANIM_CONTROL_MULTILEVEL] + ( dest.m_pValue[ANIM_CONTROL_MULTILEVEL] - src.m_pValue[ANIM_CONTROL_MULTILEVEL] ) * flBlend;
  70. }
  71. //-----------------------------------------------------------------------------
  72. // The panel used to do text entry when double-clicking in the slider
  73. //-----------------------------------------------------------------------------
  74. class CAttributeSliderTextEntry : public TextEntry
  75. {
  76. DECLARE_CLASS_SIMPLE( CAttributeSliderTextEntry, TextEntry );
  77. public:
  78. CAttributeSliderTextEntry( CAttributeSlider *slider, const char *panelName ) :
  79. BaseClass( (Panel *)slider, panelName ), m_pSlider( slider )
  80. {
  81. Assert( m_pSlider );
  82. }
  83. MESSAGE_FUNC_PARAMS( OnKillFocus, "KillFocus", kv );
  84. virtual void OnMouseWheeled( int delta );
  85. private:
  86. CAttributeSlider *m_pSlider;
  87. };
  88. //-----------------------------------------------------------------------------
  89. //
  90. // CAttributeSlider begins here
  91. //
  92. //-----------------------------------------------------------------------------
  93. //-----------------------------------------------------------------------------
  94. // Constructor, destructor
  95. //-----------------------------------------------------------------------------
  96. CAttributeSlider::CAttributeSlider( CBaseAnimSetAttributeSliderPanel *parent, const char *panelName, CDmElement *pControl ) :
  97. BaseClass( (Panel *)parent, panelName ),
  98. m_pParent( parent ),
  99. m_pWhite( NULL ),
  100. m_bPreviewEnabled( false ),
  101. m_bSimplePreviewOnly( true ),
  102. m_bCursorInsidePanel( false ),
  103. m_flPreviewGoalTime( -1.0f ),
  104. m_bRampUp( false ),
  105. m_bFaderBeingDragged( false ),
  106. m_flFaderAmount( 1.0f ),
  107. m_bIsLogPreviewControl( false ),
  108. m_bSelected( false ),
  109. m_pRightTextField( 0 )
  110. {
  111. m_SliderMode = SLIDER_MODE_NONE;
  112. m_hControl = pControl;
  113. // Cache off control information since this state should never change
  114. // NOTE: If it ever does, just change the implementations of
  115. // IsTransform + GetMidpoint to always read these values from the attributes
  116. m_bTransform = pControl->GetValue< bool >( "transform" );
  117. m_nDragStartPosition[ 0 ] = m_nDragStartPosition[ 1 ] = 0;
  118. m_nAccum[ 0 ] = m_nAccum[ 1 ] = 0;
  119. m_flDragStartValue = 1.0f;
  120. m_flDragStartBalance = 0.5f;
  121. SetPaintBackgroundEnabled( true );
  122. m_pName = new TextImage( panelName );
  123. m_pValues[ 0 ] = new TextImage( "" );
  124. m_pValues[ 1 ] = new TextImage( "" );
  125. m_pValues[ 2 ] = new TextImage( "" );
  126. m_pCircleImage = new CSubRectImage( "tools/ifm/icon_balance", false, 7, 8, 19, 15 );
  127. // Allocate a white material
  128. KeyValues *pVMTKeyValues = new KeyValues( "UnlitGeneric" );
  129. pVMTKeyValues->SetInt( "$vertexcolor", 1 );
  130. pVMTKeyValues->SetInt( "$vertexalpha", 1 );
  131. pVMTKeyValues->SetInt( "$ignorez", 1 );
  132. pVMTKeyValues->SetInt( "$no_fullbright", 1 );
  133. pVMTKeyValues->SetInt( "$nocull", 1 );
  134. m_pWhite.Init( "AttributeSlider_White", NULL, pVMTKeyValues );
  135. SetBgColor( Color( 42, 42, 42, 255 ) );
  136. m_bIsControlActive[ANIM_CONTROL_VALUE] = true;
  137. m_bIsControlActive[ANIM_CONTROL_BALANCE] = false;
  138. m_bIsControlActive[ANIM_CONTROL_MULTILEVEL] = false;
  139. m_pTextField = new CAttributeSliderTextEntry( this, panelName );
  140. m_pTextField->SetVisible( false );
  141. m_pTextField->SetEnabled( false );
  142. m_pTextField->SelectAllOnFocusAlways( true );
  143. SetPaintBorderEnabled( false );
  144. }
  145. CAttributeSlider::~CAttributeSlider()
  146. {
  147. m_pWhite.Shutdown();
  148. delete m_pCircleImage;
  149. delete m_pName;
  150. delete m_pValues[ 0 ];
  151. delete m_pValues[ 1 ];
  152. delete m_pValues[ 2 ];
  153. }
  154. //-----------------------------------------------------------------------------
  155. // Scheme
  156. //-----------------------------------------------------------------------------
  157. void CAttributeSlider::ApplySchemeSettings( IScheme *scheme )
  158. {
  159. BaseClass::ApplySchemeSettings( scheme );
  160. m_pName->SetFont( scheme->GetFont( "Default" ) );
  161. m_pName->SetColor( s_TextColor );
  162. m_pName->ResizeImageToContent();
  163. m_pValues[ 0 ]->SetColor( s_TextColor );
  164. m_pValues[ 0 ]->SetFont( scheme->GetFont( "Default" ) );
  165. m_pValues[ 1 ]->SetColor( s_TextColorFocus );
  166. m_pValues[ 1 ]->SetFont( scheme->GetFont( "Default" ) );
  167. m_pValues[ 2 ]->SetColor( s_TextColor );
  168. m_pValues[ 2 ]->SetFont( scheme->GetFont( "Default" ) );
  169. m_pCircleImage->SetColor( Color( 255, 255, 255, 255 ) );
  170. SetBgColor( Color( 42, 42, 42, 255 ) );
  171. SetFgColor( Color( 194, 120, 0, 255 ) );
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Gets/sets the slider value.
  175. // NOTE: This may not match the value pushed into the control because of fading
  176. //-----------------------------------------------------------------------------
  177. static const char *s_pChangeMessage[ANIM_CONTROL_COUNT] =
  178. {
  179. "SliderMoved",
  180. "BalanceChanged",
  181. "MultiLevelChanged",
  182. };
  183. static const char *s_pChangeKeyValue[ANIM_CONTROL_COUNT] =
  184. {
  185. "position",
  186. "balance",
  187. "level",
  188. };
  189. void CAttributeSlider::ActivateControl( AnimationControlType_t type, bool bActive )
  190. {
  191. if ( m_bIsControlActive[type] != bActive )
  192. {
  193. m_bIsControlActive[type] = bActive;
  194. if ( bActive )
  195. {
  196. PostActionSignal( new KeyValues( s_pChangeMessage[type], s_pChangeKeyValue[type], m_Control.m_pValue[type] ) );
  197. }
  198. }
  199. }
  200. bool CAttributeSlider::IsControlActive( AnimationControlType_t type )
  201. {
  202. return m_bIsControlActive[type];
  203. }
  204. void CAttributeSlider::SetValue( AnimationControlType_t type, float flValue )
  205. {
  206. if ( m_Control.m_pValue[type] != flValue )
  207. {
  208. m_Control.m_pValue[type] = flValue;
  209. if ( m_bIsControlActive[type] )
  210. {
  211. PostActionSignal( new KeyValues( s_pChangeMessage[type], s_pChangeKeyValue[type], flValue ) );
  212. }
  213. }
  214. }
  215. void CAttributeSlider::SetValue( const AttributeValue_t& value )
  216. {
  217. for ( int i = 0; i < ANIM_CONTROL_COUNT; ++i )
  218. {
  219. SetValue( (AnimationControlType_t)i, value.m_pValue[i] );
  220. }
  221. }
  222. float CAttributeSlider::GetValue( AnimationControlType_t type ) const
  223. {
  224. return m_Control.m_pValue[type];
  225. }
  226. const AttributeValue_t& CAttributeSlider::GetValue() const
  227. {
  228. return m_Control;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Returns the default value for the control
  232. //-----------------------------------------------------------------------------
  233. float CAttributeSlider::GetControlDefaultValue( AnimationControlType_t type ) const
  234. {
  235. if ( IsTransform() )
  236. return 0.0f;
  237. Assert( m_hControl.Get() );
  238. if ( !m_hControl.Get() )
  239. return 0.0f;
  240. switch ( type )
  241. {
  242. case ANIM_CONTROL_VALUE:
  243. return m_hControl->GetValue<float>( "defaultValue" );
  244. case ANIM_CONTROL_BALANCE:
  245. return m_hControl->GetValue<float>( "defaultBalance" );
  246. case ANIM_CONTROL_MULTILEVEL:
  247. return m_hControl->GetValue<float>( "defaultMultilevel" );
  248. }
  249. return 0.0f;
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Given a mouse position in (x,y) in local coordinates, which animation control is it over?
  253. //-----------------------------------------------------------------------------
  254. AnimationControlType_t CAttributeSlider::DetermineControl( int x, int y )
  255. {
  256. if ( IsControlActive( ANIM_CONTROL_MULTILEVEL ) )
  257. {
  258. Rect_t rect;
  259. GetControlRect( &rect, ANIM_CONTROL_MULTILEVEL );
  260. if ( x >= rect.x && x < rect.x + rect.width && y >= rect.y && y < rect.y + rect.height )
  261. return ANIM_CONTROL_MULTILEVEL;
  262. }
  263. return ANIM_CONTROL_VALUE;
  264. }
  265. void CAttributeSlider::SetSelected( bool state )
  266. {
  267. m_bSelected = state;
  268. }
  269. bool CAttributeSlider::IsSelected() const
  270. {
  271. return m_bSelected;
  272. }
  273. void CAttributeSlider::SetIsLogPreviewControl( bool state )
  274. {
  275. m_bIsLogPreviewControl = state;
  276. }
  277. void CAttributeSlider::OnCursorEntered()
  278. {
  279. BaseClass::OnCursorEntered();
  280. m_bCursorInsidePanel = true;
  281. }
  282. void CAttributeSlider::OnCursorExited()
  283. {
  284. BaseClass::OnCursorExited();
  285. m_bCursorInsidePanel = false;
  286. }
  287. //-----------------------------------------------------------------------------
  288. // Mouse event handlers
  289. //-----------------------------------------------------------------------------
  290. void CAttributeSlider::OnMousePressed( MouseCode code )
  291. {
  292. if ( !IsEnabled() || IsInTextEntry() || IsDragging() )
  293. return;
  294. // Deal with transform sliders
  295. if ( m_bTransform )
  296. {
  297. bool bCtrlDown = ( input()->IsKeyDown( KEY_LCONTROL ) || input()->IsKeyDown( KEY_RCONTROL ) );
  298. m_pParent->SetLogPreviewControl( m_hControl );
  299. if ( !bCtrlDown )
  300. {
  301. m_pParent->ClearSelectedControls();
  302. }
  303. m_pParent->SetControlSelected( this, !IsSelected() );
  304. return;
  305. }
  306. // Determine which control we clicked on
  307. int x,y;
  308. input()->GetCursorPosition( x, y );
  309. ScreenToLocal( x, y );
  310. AnimationControlType_t type = DetermineControl( x, y );
  311. // Right click sets the value to match the default value
  312. if ( code == MOUSE_RIGHT )
  313. {
  314. SetValue( type, GetControlDefaultValue( type ) );
  315. CUndoScopeGuard guard( "Set Slider Value To Default" );
  316. StampValueIntoLogs( type, GetControlDefaultValue( type ) );
  317. return;
  318. }
  319. if ( code != MOUSE_LEFT )
  320. return;
  321. // Cache off the value at the click point
  322. // in case we end up receiving a double-click
  323. m_InitialTextEntryValue = m_Control;
  324. // Enter drag mode
  325. m_SliderMode = (SliderMode_t)( SLIDER_MODE_FIRST_DRAG_MODE + type );
  326. m_nDragStartPosition[ 0 ] = x;
  327. m_nDragStartPosition[ 1 ] = y;
  328. m_nAccum[ 0 ] = m_nAccum[ 1 ] = 0;
  329. m_flDragStartValue = GetValue( type );
  330. m_flDragStartBalance = GetValue( ANIM_CONTROL_BALANCE );
  331. input()->SetMouseCapture( GetVPanel() );
  332. SetCursor( dc_blank );
  333. m_pParent->RecomputePreview();
  334. }
  335. void CAttributeSlider::OnCursorMoved( int x, int y )
  336. {
  337. if ( !IsEnabled() || !IsDragging() || m_bTransform )
  338. return;
  339. // NOTE: This works because we always slam the mouse to be back at the start position
  340. // at the end of this function
  341. // Accumulate the total mouse movement
  342. int dx = x - m_nDragStartPosition[ 0 ];
  343. m_nAccum[ 0 ] += dx;
  344. float flFactor = FRAC_PER_PIXEL * ifm_attributeslider_sensitivity.GetFloat();
  345. bool bInRecordMode = m_pParent->GetEditor()->GetRecordingState() == AS_RECORD;
  346. float flMinVal = bInRecordMode ? -1.0f : 0.0f;
  347. float flMaxVal = bInRecordMode ? 2.0f : 1.0f;
  348. // Clamp accum so we never generate values < -1 or > 2
  349. int nMinVal = floor( ( -m_flDragStartValue + flMinVal ) / flFactor );
  350. int nMaxVal = ceil( ( -m_flDragStartValue + flMaxVal ) / flFactor );
  351. m_nAccum[ 0 ] = clamp( m_nAccum[ 0 ], nMinVal, nMaxVal );
  352. float flDelta = flFactor * m_nAccum[ 0 ];
  353. if ( GetDragControl() == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  354. {
  355. // do the hacky conversion from the ui's left/right to the underlying value/balance
  356. float flLeftValue, flRightValue;
  357. ValueBalanceToLeftRight( &flLeftValue, &flRightValue, m_flDragStartValue, m_flDragStartBalance );
  358. float flLeftDelta, flRightDelta;
  359. ValueBalanceToLeftRight( &flLeftDelta, &flRightDelta, flDelta, m_pParent->GetBalanceSliderValue() );
  360. flLeftValue = clamp( flLeftValue + flLeftDelta, flMinVal, flMaxVal );
  361. flRightValue = clamp( flRightValue + flRightDelta, flMinVal, flMaxVal );
  362. float flValue, flBalance;
  363. LeftRightToValueBalance( &flValue, &flBalance, flLeftValue, flRightValue );
  364. SetValue( GetDragControl(), flValue );
  365. SetValue( ANIM_CONTROL_BALANCE, flBalance ); // TODO - add balance for multi control as well
  366. }
  367. else
  368. {
  369. float flValue = clamp( m_flDragStartValue + flDelta, flMinVal, flMaxVal );
  370. SetValue( GetDragControl(), flValue );
  371. }
  372. // Slam the cursor back to the drag start point
  373. if ( x != m_nDragStartPosition[ 0 ] || y != m_nDragStartPosition[ 1 ] )
  374. {
  375. x = m_nDragStartPosition[ 0 ];
  376. y = m_nDragStartPosition[ 1 ];
  377. LocalToScreen( x, y );
  378. input()->SetCursorPos( x, y );
  379. }
  380. }
  381. void CAttributeSlider::OnMouseReleased( MouseCode code )
  382. {
  383. if ( !IsEnabled() || !IsDragging() || m_bTransform )
  384. return;
  385. m_SliderMode = SLIDER_MODE_NONE;
  386. input()->SetMouseCapture( NULL );
  387. SetCursor( dc_arrow );
  388. m_pParent->RecomputePreview();
  389. }
  390. //-----------------------------------------------------------------------------
  391. //
  392. // Methods related to text entry mode
  393. //
  394. //-----------------------------------------------------------------------------
  395. //-----------------------------------------------------------------------------
  396. // Called by the text entry code to enter the value into the logs
  397. //-----------------------------------------------------------------------------
  398. void CAttributeSlider::StampValueIntoLogs( AnimationControlType_t type, float flValue )
  399. {
  400. Assert( !m_bTransform );
  401. m_pParent->StampValueIntoLogs( m_hControl, type, flValue );
  402. }
  403. //-----------------------------------------------------------------------------
  404. // Key typed key handler
  405. //-----------------------------------------------------------------------------
  406. void CAttributeSlider::OnKeyCodeTyped( KeyCode code )
  407. {
  408. if ( !IsInTextEntry() )
  409. {
  410. BaseClass::OnKeyCodeTyped( code );
  411. return;
  412. }
  413. switch ( code )
  414. {
  415. default:
  416. BaseClass::OnKeyCodeTyped( code );
  417. break;
  418. case KEY_ESCAPE:
  419. DiscardTextEntryValue();
  420. break;
  421. case KEY_ENTER:
  422. AcceptTextEntryValue();
  423. break;
  424. }
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Methods to entry text entry mode
  428. //-----------------------------------------------------------------------------
  429. void CAttributeSlider::EnterTextEntryMode( AnimationControlType_t type, bool bRelatchValues )
  430. {
  431. if ( m_bTransform )
  432. return;
  433. m_SliderMode = (SliderMode_t)( SLIDER_MODE_FIRST_TEXT_MODE + type );
  434. // For double-clicking, ignore the value set by the first single mouse click
  435. if ( !bRelatchValues )
  436. {
  437. SetValue( m_InitialTextEntryValue );
  438. }
  439. m_pTextField->SetVisible( true );
  440. m_pTextField->SetEnabled( true );
  441. if ( type == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  442. {
  443. if ( !m_pRightTextField )
  444. {
  445. m_pRightTextField = new CAttributeSliderTextEntry( this, GetName() );
  446. m_pRightTextField->SetVisible( false );
  447. m_pRightTextField->SetEnabled( false );
  448. m_pRightTextField->SelectAllOnFocusAlways( true );
  449. InvalidateLayout();
  450. }
  451. m_pRightTextField->SetVisible( true );
  452. m_pRightTextField->SetEnabled( true );
  453. float flValue = m_InitialTextEntryValue.m_pValue[ ANIM_CONTROL_VALUE ];
  454. float flBalance = m_InitialTextEntryValue.m_pValue[ ANIM_CONTROL_BALANCE ];
  455. float flLeftValue, flRightValue;
  456. ValueBalanceToLeftRight( &flLeftValue, &flRightValue, flValue, flBalance );
  457. char val[ 64 ];
  458. V_snprintf( val, sizeof( val ), "%f", flLeftValue );
  459. m_pTextField->SetText( val );
  460. V_snprintf( val, sizeof( val ), "%f", flRightValue );
  461. m_pRightTextField->SetText( val );
  462. m_pRightTextField->GotoTextEnd();
  463. m_pRightTextField->RequestFocus();
  464. }
  465. else
  466. {
  467. char val[ 64 ];
  468. Q_snprintf( val, sizeof( val ), "%f", m_InitialTextEntryValue.m_pValue[ type ] );
  469. m_pTextField->SetText( val );
  470. }
  471. m_pTextField->GotoTextEnd();
  472. m_pTextField->RequestFocus();
  473. }
  474. //-----------------------------------------------------------------------------
  475. // Methods to accept or discard the value in the text entry field
  476. //-----------------------------------------------------------------------------
  477. void CAttributeSlider::AcceptTextEntryValue()
  478. {
  479. if ( !IsInTextEntry() )
  480. return;
  481. Assert( !m_bTransform );
  482. // Get the value in the text entry field
  483. char buf[ 64 ];
  484. m_pTextField->GetText( buf, sizeof( buf ) );
  485. float flValue = Q_atof( buf );
  486. // Hide the text entry
  487. m_pTextField->SetVisible( false );
  488. m_pTextField->SetEnabled( false );
  489. if ( m_pRightTextField && GetTextEntryControl() == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  490. {
  491. float flLeftValue = flValue;
  492. // Get the value in the text entry field
  493. buf[0] = 0;
  494. m_pRightTextField->GetText( buf, sizeof( buf ) );
  495. float flRightValue = Q_atof( buf );
  496. // Hide the text entry
  497. m_pRightTextField->SetVisible( false );
  498. m_pRightTextField->SetEnabled( false );
  499. float flBalance;
  500. LeftRightToValueBalance( &flValue, &flBalance, flLeftValue, flRightValue );
  501. SetValue( ANIM_CONTROL_BALANCE, flBalance );
  502. StampValueIntoLogs( ANIM_CONTROL_BALANCE, flBalance );
  503. }
  504. // Apply the change
  505. AnimationControlType_t type = GetTextEntryControl();
  506. SetValue( type, flValue );
  507. StampValueIntoLogs( type, flValue );
  508. m_SliderMode = SLIDER_MODE_NONE;
  509. RequestFocus();
  510. }
  511. void CAttributeSlider::DiscardTextEntryValue()
  512. {
  513. if ( !IsInTextEntry() )
  514. return;
  515. Assert( !m_bTransform );
  516. // Hide the text entry
  517. m_pTextField->SetVisible( false );
  518. m_pTextField->SetEnabled( false );
  519. if ( m_pRightTextField && GetTextEntryControl() == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  520. {
  521. m_pRightTextField->SetVisible( false );
  522. m_pRightTextField->SetEnabled( false );
  523. }
  524. m_SliderMode = SLIDER_MODE_NONE;
  525. RequestFocus();
  526. }
  527. //-----------------------------------------------------------------------------
  528. // Methods of the text entry widget
  529. //-----------------------------------------------------------------------------
  530. void CAttributeSliderTextEntry::OnKillFocus( KeyValues *pParams )
  531. {
  532. Assert( m_pSlider );
  533. SelectNone();
  534. VPANEL hPanel = (VPANEL)pParams->GetPtr( "newPanel" );
  535. if ( hPanel != INVALID_PANEL && vgui::ipanel()->GetParent( hPanel ) == m_pSlider->GetVPanel() )
  536. return;
  537. m_pSlider->AcceptTextEntryValue();
  538. }
  539. void CAttributeSliderTextEntry::OnMouseWheeled( int delta )
  540. {
  541. if ( m_pSlider->m_bTransform )
  542. return;
  543. float deltaFactor;
  544. if ( input()->IsKeyDown(KEY_LSHIFT) )
  545. {
  546. deltaFactor = ((float)delta) * 10.0f;
  547. }
  548. else if ( input()->IsKeyDown(KEY_LCONTROL) )
  549. {
  550. deltaFactor = ((float)delta) / 100.0;
  551. }
  552. else
  553. {
  554. deltaFactor = ((float)delta) / 10.0;
  555. }
  556. char sz[ 64 ];
  557. GetText( sz, sizeof( sz ) );
  558. float val = Q_atof( sz ) + deltaFactor;
  559. if ( input()->IsKeyDown(KEY_LALT) )
  560. {
  561. val = clamp( val, 0.0f, 1.0f );
  562. }
  563. Q_snprintf( sz, sizeof( sz ), "%f", val );
  564. SetText( sz );
  565. m_pSlider->SetValue( ANIM_CONTROL_VALUE, val );
  566. CUndoScopeGuard guard( UNDO_CHAIN_MOUSEWHEEL_ATTRIBUTE_SLIDER, "Set Slider Value" );
  567. m_pSlider->StampValueIntoLogs( m_pSlider->GetTextEntryControl(), val );
  568. }
  569. void CAttributeSlider::OnMouseDoublePressed( MouseCode code )
  570. {
  571. if ( !IsEnabled() || IsDragging() )
  572. return;
  573. if ( code != MOUSE_LEFT )
  574. return;
  575. int x,y;
  576. input()->GetCursorPosition( x, y );
  577. ScreenToLocal( x, y );
  578. AnimationControlType_t type = DetermineControl( x, y );
  579. EnterTextEntryMode( type, false );
  580. }
  581. //-----------------------------------------------------------------------------
  582. //
  583. // Methods related to preview
  584. //
  585. //-----------------------------------------------------------------------------
  586. void CAttributeSlider::EnablePreview( bool state, bool simple, bool faderdrag )
  587. {
  588. m_bPreviewEnabled = state;
  589. m_bSimplePreviewOnly = simple;
  590. m_bFaderBeingDragged = faderdrag;
  591. }
  592. bool CAttributeSlider::IsPreviewEnabled() const
  593. {
  594. return m_bPreviewEnabled;
  595. }
  596. bool CAttributeSlider::IsSimplePreview() const
  597. {
  598. return m_bSimplePreviewOnly;
  599. }
  600. #define ATTRIBUTE_SLIDER_RAMP_TIME 0.5f
  601. bool CAttributeSlider::IsRampingTowardPreview() const
  602. {
  603. if ( m_flPreviewGoalTime == -1.0f )
  604. return false;
  605. return true;
  606. }
  607. void CAttributeSlider::RampDown()
  608. {
  609. if ( m_flPreviewGoalTime == -1.0f )
  610. return;
  611. m_Previous.m_Current = GetValue();
  612. m_Previous.m_Full = GetValue( );
  613. m_bRampUp = false;
  614. }
  615. void CAttributeSlider::UpdateFaderAmount( float flAmount )
  616. {
  617. m_flFaderAmount = flAmount;
  618. AttributeValue_t current = GetValue();
  619. if ( m_flPreviewGoalTime == -1.0f )
  620. {
  621. BlendFlexValues( &m_Preview.m_Current, current, m_Preview.m_Full, flAmount );
  622. return;
  623. }
  624. BlendFlexValues( &m_Next.m_Current, current, m_Next.m_Full, flAmount );
  625. }
  626. void CAttributeSlider::UpdateTime( float dt )
  627. {
  628. if ( m_flPreviewGoalTime == -1.0f )
  629. return;
  630. // Move toward goal
  631. if ( m_bRampUp )
  632. {
  633. if ( m_flPreviewGoalTime < ATTRIBUTE_SLIDER_RAMP_TIME )
  634. {
  635. m_flPreviewGoalTime += dt;
  636. }
  637. }
  638. else
  639. {
  640. m_flPreviewGoalTime -= dt;
  641. }
  642. if ( m_flPreviewGoalTime >= ATTRIBUTE_SLIDER_RAMP_TIME )
  643. {
  644. m_Preview = m_Next;
  645. m_flPreviewGoalTime = ATTRIBUTE_SLIDER_RAMP_TIME;
  646. }
  647. else if ( m_flPreviewGoalTime <= 0.0f )
  648. {
  649. m_flPreviewGoalTime = -1.0f;
  650. m_Preview = m_Previous;
  651. }
  652. else
  653. {
  654. float frac = m_flPreviewGoalTime / ATTRIBUTE_SLIDER_RAMP_TIME;
  655. BlendFlexValues( &m_Preview.m_Current, m_Previous.m_Current, m_Next.m_Current, frac );
  656. BlendFlexValues( &m_Preview.m_Full, m_Previous.m_Full, m_Next.m_Full, frac );
  657. }
  658. }
  659. void CAttributeSlider::SetPreview( const AttributeValue_t &value, const AttributeValue_t &full, bool instantaneous, bool startfromcurrent )
  660. {
  661. m_bRampUp = true;
  662. if ( instantaneous )
  663. {
  664. m_Next.m_Current = value;
  665. m_Next.m_Full = full;
  666. m_Preview = m_Previous = m_Next;
  667. m_flPreviewGoalTime = -1.0f;
  668. }
  669. else
  670. {
  671. // Current becomes previous, next becomes goal and preview starts moving toward that goal
  672. if ( startfromcurrent )
  673. {
  674. m_Previous.m_Current = GetValue( );
  675. m_Previous.m_Full = GetValue( );
  676. }
  677. else
  678. {
  679. m_Previous = m_Preview;
  680. }
  681. m_Next.m_Current = value;
  682. m_Next.m_Full = full;
  683. m_flPreviewGoalTime = 0.0f;
  684. }
  685. }
  686. const AttributeValue_t &CAttributeSlider::GetPreview() const
  687. {
  688. return m_Preview.m_Current;
  689. }
  690. float CAttributeSlider::GetPreview( AnimationControlType_t type ) const
  691. {
  692. return m_Preview.m_Current.m_pValue[type];
  693. }
  694. // Estimates the value of the control given a local coordinate
  695. float CAttributeSlider::EstimateValueAtPos( int nLocalX, int nLocalY ) const
  696. {
  697. Rect_t rect;
  698. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  699. float flFactor = rect.width > 1 ? (float)( nLocalX - rect.x ) / (float)( rect.width - 1 ) : 0.5f;
  700. flFactor = clamp( flFactor, 0.0f, 1.0f );
  701. return flFactor;
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Layout
  705. //-----------------------------------------------------------------------------
  706. void CAttributeSlider::PerformLayout()
  707. {
  708. BaseClass::PerformLayout();
  709. Rect_t rect;
  710. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  711. // Place the text entry along the main attribute track rectangle
  712. if ( m_pRightTextField && GetTextEntryControl() == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  713. {
  714. m_pTextField ->SetBounds( rect.x, rect.y, rect.width / 2, rect.height );
  715. m_pRightTextField->SetBounds( rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height );
  716. }
  717. else
  718. {
  719. m_pTextField->SetBounds( rect.x, rect.y, rect.width, rect.height );
  720. }
  721. }
  722. void CAttributeSlider::GetControlRect( Rect_t *pRect, AnimationControlType_t type ) const
  723. {
  724. int sw, sh;
  725. const_cast<CAttributeSlider*>( this )->GetSize( sw, sh );
  726. int cw, ch;
  727. m_pCircleImage->GetSize( cw, ch );
  728. switch ( type )
  729. {
  730. case ANIM_CONTROL_VALUE:
  731. pRect->x = 2 * SLIDER_PIXEL_SPACING + cw;
  732. pRect->y = SLIDER_PIXEL_SPACING;
  733. pRect->width = sw - pRect->x * 2;
  734. pRect->height = max( 0, sh - SLIDER_PIXEL_SPACING * 2 );
  735. break;
  736. /*
  737. case ANIM_CONTROL_BALANCE:
  738. pRect->x = SLIDER_PIXEL_SPACING;
  739. pRect->y = max( 0, sh - ch ) / 2;
  740. pRect->width = cw;
  741. pRect->height = min( ch, sh );
  742. break;
  743. */
  744. case ANIM_CONTROL_MULTILEVEL:
  745. pRect->x = sw - SLIDER_PIXEL_SPACING - cw;
  746. pRect->y = max( 0, sh - ch ) / 2;
  747. pRect->width = cw;
  748. pRect->height = min( ch, sh );
  749. break;
  750. }
  751. }
  752. bool CAttributeSlider::IsFaderBeingDragged()
  753. {
  754. return IsPreviewEnabled() && m_bFaderBeingDragged;
  755. }
  756. //-----------------------------------------------------------------------------
  757. //
  758. // Methods related to painting start here
  759. //
  760. //-----------------------------------------------------------------------------
  761. //-----------------------------------------------------------------------------
  762. // Used to control how fader-driven ticks look
  763. //-----------------------------------------------------------------------------
  764. float CAttributeSlider::GetPreviewAlphaScale() const
  765. {
  766. return max( m_flFaderAmount, 0.1f );
  767. }
  768. //-----------------------------------------------------------------------------
  769. // Draws a tick on the main control
  770. //-----------------------------------------------------------------------------
  771. void CAttributeSlider::DrawTick( const Color& clr, float frac, int width, int inset )
  772. {
  773. // Get the control position
  774. Rect_t rect;
  775. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  776. // Inset by 1 pixel
  777. rect.x++; rect.y++; rect.width -= 2; rect.height -= 2;
  778. surface()->DrawSetColor( clr );
  779. int previewx = (int)( frac * (float)rect.width + 0.5f ) + rect.x;
  780. int previewtall = rect.height - 2 * inset;
  781. int ypos = rect.y + ( rect.height - previewtall ) / 2;
  782. int xpos = previewx - width / 2;
  783. xpos = clamp( xpos, rect.x, rect.x + rect.width - width );
  784. surface()->DrawFilledRect( xpos, ypos, xpos + width, ypos + previewtall );
  785. }
  786. //-----------------------------------------------------------------------------
  787. // Draws a preview tick on the main control
  788. //-----------------------------------------------------------------------------
  789. void CAttributeSlider::DrawPreviewTick( bool bMainTick )
  790. {
  791. Color col = s_PreviewTickColor;
  792. col[ 3 ] *= bMainTick ? GetPreviewAlphaScale() : 0.5f;
  793. DrawTick( col, m_Next.m_Full.m_pValue[ ANIM_CONTROL_VALUE ], 2, 2 );
  794. }
  795. //-----------------------------------------------------------------------------
  796. // Draws a tick on a circular control
  797. //-----------------------------------------------------------------------------
  798. void CAttributeSlider::DrawCircularTick( const Color& clr, float flValue, int nCenterX, int nCenterY, float flRadius )
  799. {
  800. float flFraction = 1.0f;
  801. float flAngle = 0.0f;
  802. if ( flValue < 0.5f )
  803. {
  804. flFraction = ( flValue / 0.5f );
  805. flAngle = 180.0f + flFraction * 180.0f;
  806. }
  807. else
  808. {
  809. flFraction = ( flValue - 0.5f ) * 2.0f;
  810. flAngle = flFraction * 180.0f;
  811. }
  812. float flRadians = DEG2RAD( flAngle );
  813. float ca = cos( flRadians );
  814. float sa = sin( flRadians );
  815. int nEndX = nCenterX + flRadius * sa;
  816. int nEndY = nCenterY - flRadius * ca;
  817. surface()->DrawSetColor( clr );
  818. surface()->DrawLine( nCenterX, nCenterY, nEndX, nEndY );
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Draws a preview of a circular control
  822. //-----------------------------------------------------------------------------
  823. void CAttributeSlider::DrawCircularPreview( AnimationControlType_t type, bool bMainTick, float flRadius )
  824. {
  825. Rect_t rect;
  826. GetControlRect( &rect, type );
  827. // Fill left from top
  828. float flPreview = m_Next.m_Full.m_pValue[type];
  829. float flCurrent = GetValue( type );
  830. Color clr = s_PreviewTickColor;
  831. clr[ 3 ] *= bMainTick ? GetPreviewAlphaScale() : 0.5f;
  832. int nCenterX = rect.x + rect.width / 2;
  833. int nCenterY = rect.y + rect.height / 2;
  834. DrawCircularTick( clr, flPreview, nCenterX, nCenterY, flRadius );
  835. if ( m_bSimplePreviewOnly && !m_bFaderBeingDragged )
  836. return;
  837. clr = s_OldValueTickColor;
  838. if ( !bMainTick )
  839. {
  840. clr[ 3 ] *= 0.5f;
  841. }
  842. DrawCircularTick( clr, flCurrent, nCenterX, nCenterY, flRadius );
  843. }
  844. //-----------------------------------------------------------------------------
  845. // Paints ticks
  846. //-----------------------------------------------------------------------------
  847. void CAttributeSlider::Paint()
  848. {
  849. DrawTick( s_OldValueTickColor, GetValue( ANIM_CONTROL_VALUE ), 1, 0 );
  850. if ( m_bPreviewEnabled )
  851. {
  852. DrawPreviewTick( true );
  853. if ( IsControlActive( ANIM_CONTROL_BALANCE ) )
  854. {
  855. DrawCircularPreview( ANIM_CONTROL_BALANCE, true, CIRCULAR_CONTROL_RADIUS );
  856. }
  857. if ( IsControlActive( ANIM_CONTROL_MULTILEVEL ) )
  858. {
  859. DrawCircularPreview( ANIM_CONTROL_MULTILEVEL, true, CIRCULAR_CONTROL_RADIUS );
  860. }
  861. }
  862. }
  863. //-----------------------------------------------------------------------------
  864. // Draws the min, current, and max values for the slider
  865. //-----------------------------------------------------------------------------
  866. void CAttributeSlider::DrawValueLabel( float flValue )
  867. {
  868. float flMinVal = 0.0f;
  869. float flMaxVal = 1.0f;
  870. flValue = clamp( flValue, flMinVal, flMaxVal );
  871. Rect_t rect;
  872. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  873. int cw, ch;
  874. char sz[ 32 ];
  875. Q_snprintf( sz, sizeof( sz ), "%.1f", flMinVal );
  876. m_pValues[ 0 ]->SetText( sz );
  877. m_pValues[ 0 ]->ResizeImageToContent();
  878. m_pValues[ 0 ]->GetContentSize( cw, ch );
  879. m_pValues[ 0 ]->SetPos( rect.x + 5, rect.y + ( rect.height - ch ) * 0.5f );
  880. m_pValues[ 0 ]->Paint();
  881. Q_snprintf( sz, sizeof( sz ), "%.1f", flMaxVal );
  882. m_pValues[ 2 ]->SetText( sz );
  883. m_pValues[ 2 ]->ResizeImageToContent();
  884. m_pValues[ 2 ]->GetContentSize( cw, ch );
  885. m_pValues[ 2 ]->SetPos( rect.x + rect.width - cw - 5, rect.y + ( rect.height - ch ) * 0.5f );
  886. m_pValues[ 2 ]->Paint();
  887. Q_snprintf( sz, sizeof( sz ), "%.3f", flValue );
  888. m_pValues[ 1 ]->SetText( sz );
  889. m_pValues[ 1 ]->ResizeImageToContent();
  890. m_pValues[ 1 ]->GetContentSize( cw, ch );
  891. m_pValues[ 1 ]->SetPos( rect.x + ( rect.width - cw ) * 0.5f, rect.y + ( rect.height - ch ) * 0.5f );
  892. m_pValues[ 1 ]->Paint();
  893. }
  894. //-----------------------------------------------------------------------------
  895. // Draws the text for the slider. It's either the slider name, or its value if dragging is happening
  896. //-----------------------------------------------------------------------------
  897. void CAttributeSlider::DrawNameLabel()
  898. {
  899. if ( IsDragging() )
  900. {
  901. float flValue = GetValue( GetDragControl() );
  902. DrawValueLabel( flValue );
  903. return;
  904. }
  905. if ( IsInTextEntry() )
  906. return;
  907. int w, h;
  908. GetSize( w, h );
  909. int cw, ch;
  910. Color clr = m_bCursorInsidePanel ? s_TextColorFocus : s_TextColor;
  911. m_pName->SetColor( clr );
  912. m_pName->GetContentSize( cw, ch );
  913. Rect_t rect;
  914. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  915. m_pName->SetPos( rect.x + ( rect.width - cw ) * 0.5f, rect.y + ( rect.height - ch ) * 0.5f );
  916. m_pName->Paint();
  917. }
  918. //-----------------------------------------------------------------------------
  919. // Draws the midpoint value for the slider
  920. //-----------------------------------------------------------------------------
  921. void CAttributeSlider::DrawMidpoint( int x, int ty, int ttall )
  922. {
  923. surface()->DrawSetColor( s_MidpointColor );
  924. surface()->DrawFilledRect( x, ty, x + 1, ty + ttall );
  925. }
  926. //-----------------------------------------------------------------------------
  927. // Paints circular controls used for balance + multilevel controls
  928. //-----------------------------------------------------------------------------
  929. void CAttributeSlider::PaintCircularControl( float flValue, const Rect_t& rect )
  930. {
  931. flValue = clamp( flValue, 0.0f, 1.0f );
  932. m_pCircleImage->SetPos( rect.x, rect.y );
  933. m_pCircleImage->Paint();
  934. int ofs[ 2 ] = { 0 };
  935. LocalToScreen( ofs[ 0 ], ofs[ 1 ] );
  936. int nCenterX = ofs[ 0 ] + rect.x + rect.width / 2;
  937. int nCenterY = ofs[ 1 ] + rect.y + rect.height / 2;
  938. float maxTrianges = 36.0f;
  939. float frac = 0.0f;
  940. float step = 180.0f / (float)( maxTrianges );
  941. float ang = 0.0f;
  942. float clamp = 360.0f;
  943. int numTriangles = 0;
  944. float radius = CIRCULAR_CONTROL_RADIUS;
  945. float zpos = vgui::surface()->GetZPos();
  946. Vector centerVert( nCenterX, nCenterY, zpos );
  947. Vector top;
  948. top = centerVert;
  949. top.y -= radius;
  950. // Fill left from top
  951. if ( flValue < 0.5f )
  952. {
  953. frac = 1.0f - ( flValue / 0.5f );
  954. numTriangles = (int)( frac * ( maxTrianges ) + 0.5f );
  955. clamp = 180.0f;
  956. step = -step;
  957. ang = 360.0f;
  958. }
  959. else
  960. {
  961. frac = ( flValue - 0.5f ) / 0.5f;
  962. numTriangles = (int)( frac * ( maxTrianges ) + 0.5f );
  963. clamp = 180.0f;
  964. }
  965. if ( numTriangles == 0 )
  966. return;
  967. CMatRenderContextPtr pRenderContext( materials );
  968. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_pWhite );
  969. Color clr( 102, 102, 102, 255 );
  970. CMeshBuilder meshBuilder;
  971. meshBuilder.Begin( pMesh, MATERIAL_TRIANGLES, numTriangles );
  972. Vector next;
  973. next.Init();
  974. for ( int j = 0; j < numTriangles; j++ )
  975. {
  976. ang += step;
  977. //ang = min( ang, clamp );
  978. float flRadians = DEG2RAD( ang );
  979. float ca = cos( flRadians );
  980. float sa = sin( flRadians );
  981. meshBuilder.Position3fv( centerVert.Base() );
  982. meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a() );
  983. meshBuilder.TexCoord2f( 0, 0, 0 );
  984. meshBuilder.AdvanceVertex();
  985. next.Init();
  986. next.x = radius * sa;
  987. next.y = -radius * ca;
  988. next += centerVert;
  989. if ( step > 0 )
  990. {
  991. meshBuilder.Position3fv( top.Base() );
  992. meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a() );
  993. meshBuilder.TexCoord2f( 0, 0, 1 );
  994. meshBuilder.AdvanceVertex();
  995. meshBuilder.Position3fv( next.Base() );
  996. meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a() );
  997. meshBuilder.TexCoord2f( 0, 1, 0 );
  998. meshBuilder.AdvanceVertex();
  999. }
  1000. else
  1001. {
  1002. meshBuilder.Position3fv( next.Base() );
  1003. meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a() );
  1004. meshBuilder.TexCoord2f( 0, 0, 1 );
  1005. meshBuilder.AdvanceVertex();
  1006. meshBuilder.Position3fv( top.Base() );
  1007. meshBuilder.Color4ub( clr.r(), clr.g(), clr.b(), clr.a() );
  1008. meshBuilder.TexCoord2f( 0, 1, 0 );
  1009. meshBuilder.AdvanceVertex();
  1010. }
  1011. top = next;
  1012. }
  1013. meshBuilder.End();
  1014. pMesh->Draw();
  1015. }
  1016. //-----------------------------------------------------------------------------
  1017. // Paints the slider
  1018. //-----------------------------------------------------------------------------
  1019. void CAttributeSlider::PaintBackground()
  1020. {
  1021. Rect_t rect;
  1022. GetControlRect( &rect, ANIM_CONTROL_VALUE );
  1023. // Paint the border
  1024. surface()->DrawSetColor( Color( 24, 24, 24, 255 ) );
  1025. // top and left
  1026. surface()->DrawOutlinedRect( rect.x, rect.y, rect.x + rect.width, rect.y + 1 );
  1027. surface()->DrawOutlinedRect( rect.x, rect.y, rect.x + 1, rect.y + rect.height );
  1028. // right
  1029. surface()->DrawSetColor( Color( 33, 33, 33, 255 ) );
  1030. surface()->DrawOutlinedRect( rect.x + rect.width - 1, rect.y, rect.x + rect.width, rect.y + rect.height );
  1031. // bottom
  1032. surface()->DrawSetColor( Color( 56, 56, 56, 255 ) );
  1033. surface()->DrawOutlinedRect( rect.x, rect.y + rect.height - 1, rect.x + rect.width, rect.y + rect.height );
  1034. // Inset the rect by 1 pixel
  1035. ++rect.x; ++rect.y; rect.width -= 2; rect.height -= 2;
  1036. int y0 = rect.y;
  1037. int y1 = rect.y + rect.height / 2;
  1038. int y2 = rect.y + rect.height;
  1039. // Draw the main bar background
  1040. surface()->DrawSetColor( s_ZeroColor[ m_bIsLogPreviewControl ][ IsSelected() ] );
  1041. surface()->DrawFilledRect( rect.x, y0, rect.x + rect.width, y2 );
  1042. AnimationControlType_t viewType = ANIM_CONTROL_VALUE;
  1043. if ( IsDragging() )
  1044. {
  1045. viewType = GetDragControl();
  1046. }
  1047. else if ( IsInTextEntry() )
  1048. {
  1049. viewType = GetTextEntryControl();
  1050. }
  1051. bool bUsePreview = m_bPreviewEnabled && ( !m_bSimplePreviewOnly || m_bFaderBeingDragged );
  1052. float flMidPoint = GetControlDefaultValue( viewType );
  1053. int nMidPoint = (int)( (float)rect.width * clamp( flMidPoint, 0.0f, 1.0f ) + 0.5f );
  1054. float flValue = bUsePreview ? m_Preview.m_Current.m_pValue[viewType] : GetValue( viewType );
  1055. if ( viewType == ANIM_CONTROL_VALUE && IsControlActive( ANIM_CONTROL_BALANCE ) )
  1056. {
  1057. float flBalance = bUsePreview ? m_Preview.m_Current.m_pValue[ ANIM_CONTROL_BALANCE ] : GetValue( ANIM_CONTROL_BALANCE );
  1058. float flLeftValue, flRightValue;
  1059. ValueBalanceToLeftRight( &flLeftValue, &flRightValue, flValue, flBalance );
  1060. int nLeftValue = (int)( (float)rect.width * clamp( flLeftValue, 0.0f, 1.0f ) + 0.5f );
  1061. int nRightValue = (int)( (float)rect.width * clamp( flRightValue, 0.0f, 1.0f ) + 0.5f );
  1062. // Draw the current value as a bar from the midpoint
  1063. surface()->DrawSetColor( IsDragging() ? s_DraggingBarColor : s_BarColor[ m_bIsLogPreviewControl ][ IsSelected() ] );
  1064. surface()->DrawFilledRect( rect.x + min( nLeftValue, nMidPoint ), y0, rect.x + max( nLeftValue, nMidPoint ), y1 );
  1065. surface()->DrawFilledRect( rect.x + min( nRightValue, nMidPoint ), y1, rect.x + max( nRightValue, nMidPoint ), y2 );
  1066. }
  1067. else
  1068. {
  1069. Assert( viewType != ANIM_CONTROL_BALANCE );
  1070. int nValue = (int)( (float)rect.width * clamp( flValue, 0.0f, 1.0f ) + 0.5f );
  1071. // Draw the current value as a bar from the midpoint
  1072. surface()->DrawSetColor( IsDragging() ? s_DraggingBarColor : s_BarColor[ m_bIsLogPreviewControl ][ IsSelected() ] );
  1073. surface()->DrawFilledRect( rect.x + min( nValue, nMidPoint ), y0, rect.x + max( nValue, nMidPoint ), y2 );
  1074. }
  1075. // Draw the midpoint over the top of the current value
  1076. DrawMidpoint( rect.x + nMidPoint, rect.y, rect.height );
  1077. // Draw the name or value over the top of that
  1078. DrawNameLabel();
  1079. // Paints the circular controls
  1080. if ( IsControlActive( ANIM_CONTROL_MULTILEVEL ) )
  1081. {
  1082. float flMultiValue = bUsePreview ? m_Preview.m_Current.m_pValue[ANIM_CONTROL_MULTILEVEL] : GetValue( ANIM_CONTROL_MULTILEVEL );
  1083. GetControlRect( &rect, ANIM_CONTROL_MULTILEVEL );
  1084. PaintCircularControl( flMultiValue, rect );
  1085. // Draws the midpoint for the circular controls
  1086. int nCenterX = rect.x + rect.width / 2;
  1087. int nCenterY = rect.y + rect.height / 2;
  1088. DrawCircularTick( s_MidpointColor, GetControlDefaultValue( ANIM_CONTROL_MULTILEVEL ), nCenterX, nCenterY, CIRCULAR_CONTROL_RADIUS );
  1089. }
  1090. }