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.

1097 lines
32 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Basic button control
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include <stdio.h>
  8. #include <utlsymbol.h>
  9. #include <vgui/IBorder.h>
  10. #include <vgui/IInput.h>
  11. #include <vgui/IScheme.h>
  12. #include <vgui/ISurface.h>
  13. #include <vgui/ISystem.h>
  14. #include <vgui/IVGui.h>
  15. #include <vgui/MouseCode.h>
  16. #include <vgui/KeyCode.h>
  17. #include <KeyValues.h>
  18. #include <vgui_controls/Button.h>
  19. #include <vgui_controls/FocusNavGroup.h>
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include <tier0/memdbgon.h>
  22. using namespace vgui;
  23. // global list of all the names of all the sounds played by buttons
  24. CUtlSymbolTable g_ButtonSoundNames;
  25. DECLARE_BUILD_FACTORY_DEFAULT_TEXT( Button, Button );
  26. //-----------------------------------------------------------------------------
  27. // Purpose: Constructor
  28. //-----------------------------------------------------------------------------
  29. Button::Button(Panel *parent, const char *panelName, const char *text, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, text)
  30. {
  31. Init();
  32. if ( pActionSignalTarget && pCmd )
  33. {
  34. AddActionSignalTarget( pActionSignalTarget );
  35. SetCommand( pCmd );
  36. }
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Constructor
  40. //-----------------------------------------------------------------------------
  41. Button::Button(Panel *parent, const char *panelName, const wchar_t *wszText, Panel *pActionSignalTarget, const char *pCmd ) : Label(parent, panelName, wszText)
  42. {
  43. Init();
  44. if ( pActionSignalTarget && pCmd )
  45. {
  46. AddActionSignalTarget( pActionSignalTarget );
  47. SetCommand( pCmd );
  48. }
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. void Button::Init()
  54. {
  55. _buttonFlags.SetFlag( USE_CAPTURE_MOUSE | BUTTON_BORDER_ENABLED );
  56. _mouseClickMask = 0;
  57. _actionMessage = NULL;
  58. _defaultBorder = NULL;
  59. _depressedBorder = NULL;
  60. _keyFocusBorder = NULL;
  61. m_bSelectionStateSaved = false;
  62. m_bStaySelectedOnClick = false;
  63. m_bStaySelectedOnClick = false;
  64. m_sArmedSoundName = UTL_INVAL_SYMBOL;
  65. m_sDepressedSoundName = UTL_INVAL_SYMBOL;
  66. m_sReleasedSoundName = UTL_INVAL_SYMBOL;
  67. SetTextInset(6, 0);
  68. SetMouseClickEnabled( MOUSE_LEFT, true );
  69. SetButtonActivationType(ACTIVATE_ONPRESSEDANDRELEASED);
  70. // labels have this off by default, but we need it on
  71. SetPaintBackgroundEnabled( true );
  72. _paint = true;
  73. REGISTER_COLOR_AS_OVERRIDABLE( _defaultFgColor, "defaultFgColor_override" );
  74. REGISTER_COLOR_AS_OVERRIDABLE( _defaultBgColor, "defaultBgColor_override" );
  75. REGISTER_COLOR_AS_OVERRIDABLE( _armedFgColor, "armedFgColor_override" );
  76. REGISTER_COLOR_AS_OVERRIDABLE( _armedBgColor, "armedBgColor_override" );
  77. REGISTER_COLOR_AS_OVERRIDABLE( _depressedFgColor, "depressedFgColor_override" );
  78. REGISTER_COLOR_AS_OVERRIDABLE( _depressedBgColor, "depressedBgColor_override" );
  79. REGISTER_COLOR_AS_OVERRIDABLE( _selectedFgColor, "selectedFgColor_override" );
  80. REGISTER_COLOR_AS_OVERRIDABLE( _selectedBgColor, "selectedBgColor_override" );
  81. REGISTER_COLOR_AS_OVERRIDABLE( _keyboardFocusColor, "keyboardFocusColor_override" );
  82. REGISTER_COLOR_AS_OVERRIDABLE( _blinkFgColor, "blinkFgColor_override" );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose: Destructor
  86. //-----------------------------------------------------------------------------
  87. Button::~Button()
  88. {
  89. if (_actionMessage)
  90. {
  91. _actionMessage->deleteThis();
  92. }
  93. }
  94. //-----------------------------------------------------------------------------
  95. // Purpose:
  96. //-----------------------------------------------------------------------------
  97. void Button::SetButtonActivationType(ActivationType_t activationType)
  98. {
  99. _activationType = activationType;
  100. }
  101. //-----------------------------------------------------------------------------
  102. // Purpose: Set button border attribute enabled.
  103. //-----------------------------------------------------------------------------
  104. void Button::SetButtonBorderEnabled( bool state )
  105. {
  106. if ( state != _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) )
  107. {
  108. _buttonFlags.SetFlag( BUTTON_BORDER_ENABLED, state );
  109. InvalidateLayout(false);
  110. }
  111. }
  112. //-----------------------------------------------------------------------------
  113. // Purpose: Set button selected state.
  114. //-----------------------------------------------------------------------------
  115. void Button::SetSelected( bool state )
  116. {
  117. if ( _buttonFlags.IsFlagSet( SELECTED ) != state )
  118. {
  119. _buttonFlags.SetFlag( SELECTED, state );
  120. RecalculateDepressedState();
  121. InvalidateLayout(false);
  122. }
  123. if ( !m_bStayArmedOnClick && state && _buttonFlags.IsFlagSet( ARMED ) )
  124. {
  125. _buttonFlags.SetFlag( ARMED, false );
  126. InvalidateLayout(false);
  127. }
  128. }
  129. void Button::SetBlink( bool state )
  130. {
  131. if ( _buttonFlags.IsFlagSet( BLINK ) != state )
  132. {
  133. _buttonFlags.SetFlag( BLINK, state );
  134. RecalculateDepressedState();
  135. InvalidateLayout(false);
  136. }
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose: Set button force depressed state.
  140. //-----------------------------------------------------------------------------
  141. void Button::ForceDepressed(bool state)
  142. {
  143. if ( _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) != state )
  144. {
  145. _buttonFlags.SetFlag( FORCE_DEPRESSED, state );
  146. RecalculateDepressedState();
  147. InvalidateLayout(false);
  148. }
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose: Set button depressed state with respect to the force depressed state.
  152. //-----------------------------------------------------------------------------
  153. void Button::RecalculateDepressedState( void )
  154. {
  155. bool newState;
  156. if (!IsEnabled())
  157. {
  158. newState = false;
  159. }
  160. else
  161. {
  162. if ( m_bStaySelectedOnClick && _buttonFlags.IsFlagSet( SELECTED ) )
  163. {
  164. newState = false;
  165. }
  166. else
  167. {
  168. newState = _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) ? true : (_buttonFlags.IsFlagSet(ARMED) && _buttonFlags.IsFlagSet( SELECTED ) );
  169. }
  170. }
  171. _buttonFlags.SetFlag( DEPRESSED, newState );
  172. }
  173. //-----------------------------------------------------------------------------
  174. // Purpose: Sets whether or not the button captures all mouse input when depressed
  175. // Defaults to true
  176. // Should be set to false for things like menu items where there is a higher-level mouse capture
  177. //-----------------------------------------------------------------------------
  178. void Button::SetUseCaptureMouse( bool state )
  179. {
  180. _buttonFlags.SetFlag( USE_CAPTURE_MOUSE, state );
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose: Check if mouse capture is enabled.
  184. // Output : Returns true on success, false on failure.
  185. //-----------------------------------------------------------------------------
  186. bool Button::IsUseCaptureMouseEnabled( void )
  187. {
  188. return _buttonFlags.IsFlagSet( USE_CAPTURE_MOUSE );
  189. }
  190. //-----------------------------------------------------------------------------
  191. // Purpose: Set armed state.
  192. //-----------------------------------------------------------------------------
  193. void Button::SetArmed(bool state)
  194. {
  195. if ( _buttonFlags.IsFlagSet( ARMED ) != state )
  196. {
  197. _buttonFlags.SetFlag( ARMED, state );
  198. RecalculateDepressedState();
  199. InvalidateLayout(false);
  200. // play any sounds specified
  201. if (state && m_sArmedSoundName != UTL_INVAL_SYMBOL)
  202. {
  203. surface()->PlaySound(g_ButtonSoundNames.String(m_sArmedSoundName));
  204. }
  205. }
  206. }
  207. //-----------------------------------------------------------------------------
  208. // Purpose: Check armed state
  209. //-----------------------------------------------------------------------------
  210. bool Button::IsArmed()
  211. {
  212. return _buttonFlags.IsFlagSet( ARMED );
  213. }
  214. KeyValues *Button::GetActionMessage()
  215. {
  216. return _actionMessage->MakeCopy();
  217. }
  218. void Button::PlayButtonReleasedSound()
  219. {
  220. // check for playing a transition sound
  221. if ( m_sReleasedSoundName != UTL_INVAL_SYMBOL )
  222. {
  223. surface()->PlaySound( g_ButtonSoundNames.String( m_sReleasedSoundName ) );
  224. }
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose: Activate a button click.
  228. //-----------------------------------------------------------------------------
  229. void Button::DoClick()
  230. {
  231. SetSelected(true);
  232. FireActionSignal();
  233. PlayButtonReleasedSound();
  234. static ConVarRef vgui_nav_lock( "vgui_nav_lock" );
  235. if ( ( !vgui_nav_lock.IsValid() || vgui_nav_lock.GetInt() == 0 ) && NavigateActivate() )
  236. {
  237. vgui_nav_lock.SetValue( 1 );
  238. }
  239. if ( !m_bStaySelectedOnClick )
  240. {
  241. SetSelected(false);
  242. }
  243. }
  244. //-----------------------------------------------------------------------------
  245. // Purpose: Check selected state
  246. //-----------------------------------------------------------------------------
  247. bool Button::IsSelected()
  248. {
  249. return _buttonFlags.IsFlagSet( SELECTED );
  250. }
  251. //-----------------------------------------------------------------------------
  252. // Purpose: Check depressed state
  253. //-----------------------------------------------------------------------------
  254. bool Button::IsDepressed()
  255. {
  256. return _buttonFlags.IsFlagSet( DEPRESSED );
  257. }
  258. bool Button::IsBlinking( void )
  259. {
  260. return _buttonFlags.IsFlagSet( BLINK );
  261. }
  262. //-----------------------------------------------------------------------------
  263. // Drawing focus box?
  264. //-----------------------------------------------------------------------------
  265. bool Button::IsDrawingFocusBox()
  266. {
  267. return _buttonFlags.IsFlagSet( DRAW_FOCUS_BOX );
  268. }
  269. void Button::DrawFocusBox( bool bEnable )
  270. {
  271. _buttonFlags.SetFlag( DRAW_FOCUS_BOX, bEnable );
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose:
  275. //-----------------------------------------------------------------------------
  276. void Button::NavigateTo()
  277. {
  278. BaseClass::NavigateTo();
  279. SetArmed( true );
  280. if ( IsPC() )
  281. {
  282. RequestFocus( 0 );
  283. }
  284. }
  285. //-----------------------------------------------------------------------------
  286. // Purpose:
  287. //-----------------------------------------------------------------------------
  288. void Button::NavigateFrom()
  289. {
  290. BaseClass::NavigateFrom();
  291. SetArmed( false );
  292. OnKeyCodeReleased( KEY_XBUTTON_A );
  293. }
  294. //-----------------------------------------------------------------------------
  295. // Purpose: Paint button on screen
  296. //-----------------------------------------------------------------------------
  297. void Button::Paint(void)
  298. {
  299. if ( !ShouldPaint() )
  300. return;
  301. BaseClass::Paint();
  302. if ( HasFocus() && IsEnabled() && IsDrawingFocusBox() )
  303. {
  304. int x0, y0, x1, y1;
  305. int wide, tall;
  306. GetSize(wide, tall);
  307. x0 = 3, y0 = 3, x1 = wide - 4 , y1 = tall - 2;
  308. DrawFocusBorder(x0, y0, x1, y1);
  309. }
  310. }
  311. //-----------------------------------------------------------------------------
  312. // Purpose: Perform graphical layout of button.
  313. //-----------------------------------------------------------------------------
  314. void Button::PerformLayout()
  315. {
  316. // reset our border
  317. SetBorder( GetBorder(_buttonFlags.IsFlagSet( DEPRESSED ), _buttonFlags.IsFlagSet( ARMED ), _buttonFlags.IsFlagSet( SELECTED ), HasFocus() ) );
  318. // set our color
  319. SetFgColor(GetButtonFgColor());
  320. SetBgColor(GetButtonBgColor());
  321. BaseClass::PerformLayout();
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Get button foreground color
  325. // Output : Color
  326. //-----------------------------------------------------------------------------
  327. Color Button::GetButtonFgColor()
  328. {
  329. if ( !_buttonFlags.IsFlagSet( BLINK ) )
  330. {
  331. if (_buttonFlags.IsFlagSet( DEPRESSED ))
  332. return _depressedFgColor;
  333. if (_buttonFlags.IsFlagSet( ARMED ))
  334. return _armedFgColor;
  335. if (_buttonFlags.IsFlagSet( SELECTED))
  336. return _selectedFgColor;
  337. return _defaultFgColor;
  338. }
  339. Color cBlendedColor;
  340. if (_buttonFlags.IsFlagSet( DEPRESSED ))
  341. cBlendedColor = _depressedFgColor;
  342. else if (_buttonFlags.IsFlagSet( ARMED ))
  343. cBlendedColor = _armedFgColor;
  344. else if (_buttonFlags.IsFlagSet( SELECTED ))
  345. cBlendedColor = _selectedFgColor;
  346. else
  347. cBlendedColor = _defaultFgColor;
  348. float fBlink = ( sinf( system()->GetTimeMillis() * 0.01f ) + 1.0f ) * 0.5f;
  349. if ( _buttonFlags.IsFlagSet( BLINK ) )
  350. {
  351. cBlendedColor[ 0 ] = (float)cBlendedColor[ 0 ] * fBlink + (float)_blinkFgColor[ 0 ] * ( 1.0f - fBlink );
  352. cBlendedColor[ 1 ] = (float)cBlendedColor[ 1 ] * fBlink + (float)_blinkFgColor[ 1 ] * ( 1.0f - fBlink );
  353. cBlendedColor[ 2 ] = (float)cBlendedColor[ 2 ] * fBlink + (float)_blinkFgColor[ 2 ] * ( 1.0f - fBlink );
  354. cBlendedColor[ 3 ] = (float)cBlendedColor[ 3 ] * fBlink + (float)_blinkFgColor[ 3 ] * ( 1.0f - fBlink );
  355. }
  356. return cBlendedColor;
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Get button background color
  360. //-----------------------------------------------------------------------------
  361. Color Button::GetButtonBgColor()
  362. {
  363. if (_buttonFlags.IsFlagSet( DEPRESSED ))
  364. return _depressedBgColor;
  365. if (_buttonFlags.IsFlagSet( ARMED ))
  366. return _armedBgColor;
  367. if (_buttonFlags.IsFlagSet( SELECTED ))
  368. return _selectedBgColor;
  369. return _defaultBgColor;
  370. }
  371. //-----------------------------------------------------------------------------
  372. // Purpose: Called when key focus is received
  373. //-----------------------------------------------------------------------------
  374. void Button::OnSetFocus()
  375. {
  376. InvalidateLayout(false);
  377. BaseClass::OnSetFocus();
  378. }
  379. //-----------------------------------------------------------------------------
  380. // Purpose: Respond when focus is killed
  381. //-----------------------------------------------------------------------------
  382. void Button::OnKillFocus()
  383. {
  384. InvalidateLayout(false);
  385. BaseClass::OnKillFocus();
  386. }
  387. //-----------------------------------------------------------------------------
  388. // Purpose:
  389. //-----------------------------------------------------------------------------
  390. void Button::ApplySchemeSettings(IScheme *pScheme)
  391. {
  392. BaseClass::ApplySchemeSettings(pScheme);
  393. // get the borders we need
  394. _defaultBorder = pScheme->GetBorder("ButtonBorder");
  395. _depressedBorder = pScheme->GetBorder("ButtonDepressedBorder");
  396. _keyFocusBorder = pScheme->GetBorder("ButtonKeyFocusBorder");
  397. _defaultFgColor = GetSchemeColor("Button.TextColor", Color(255, 255, 255, 255), pScheme);
  398. _defaultBgColor = GetSchemeColor("Button.BgColor", Color(0, 0, 0, 255), pScheme);
  399. _armedFgColor = GetSchemeColor("Button.ArmedTextColor", _defaultFgColor, pScheme);
  400. _armedBgColor = GetSchemeColor("Button.ArmedBgColor", _defaultBgColor, pScheme);
  401. _selectedFgColor = GetSchemeColor("Button.SelectedTextColor", _selectedFgColor, pScheme);
  402. _selectedBgColor = GetSchemeColor("Button.SelectedBgColor", _selectedBgColor, pScheme);
  403. _depressedFgColor = GetSchemeColor("Button.DepressedTextColor", _defaultFgColor, pScheme);
  404. _depressedBgColor = GetSchemeColor("Button.DepressedBgColor", _defaultBgColor, pScheme);
  405. _keyboardFocusColor = GetSchemeColor("Button.FocusBorderColor", Color(0,0,0,255), pScheme);
  406. _blinkFgColor = GetSchemeColor("Button.BlinkColor", Color(255, 155, 0, 255), pScheme);
  407. InvalidateLayout();
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Purpose: Set default button colors.
  411. //-----------------------------------------------------------------------------
  412. void Button::SetDefaultColor(Color fgColor, Color bgColor)
  413. {
  414. if (!(_defaultFgColor == fgColor && _defaultBgColor == bgColor))
  415. {
  416. _defaultFgColor = fgColor;
  417. _defaultBgColor = bgColor;
  418. InvalidateLayout(false);
  419. }
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose: Set armed button colors
  423. //-----------------------------------------------------------------------------
  424. void Button::SetArmedColor(Color fgColor, Color bgColor)
  425. {
  426. if (!(_armedFgColor == fgColor && _armedBgColor == bgColor))
  427. {
  428. _armedFgColor = fgColor;
  429. _armedBgColor = bgColor;
  430. InvalidateLayout(false);
  431. }
  432. }
  433. //-----------------------------------------------------------------------------
  434. // Purpose: Set armed button colors
  435. //-----------------------------------------------------------------------------
  436. void Button::SetSelectedColor(Color fgColor, Color bgColor)
  437. {
  438. if (!(_selectedFgColor == fgColor && _selectedBgColor == bgColor))
  439. {
  440. _selectedFgColor = fgColor;
  441. _selectedBgColor = bgColor;
  442. InvalidateLayout(false);
  443. }
  444. }
  445. //-----------------------------------------------------------------------------
  446. // Purpose: Set depressed button colors
  447. //-----------------------------------------------------------------------------
  448. void Button::SetDepressedColor(Color fgColor, Color bgColor)
  449. {
  450. if (!(_depressedFgColor == fgColor && _depressedBgColor == bgColor))
  451. {
  452. _depressedFgColor = fgColor;
  453. _depressedBgColor = bgColor;
  454. InvalidateLayout(false);
  455. }
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose: Set blink button color
  459. //-----------------------------------------------------------------------------
  460. void Button::SetBlinkColor(Color fgColor)
  461. {
  462. if (!(_blinkFgColor == fgColor))
  463. {
  464. _blinkFgColor = fgColor;
  465. InvalidateLayout(false);
  466. }
  467. }
  468. //-----------------------------------------------------------------------------
  469. // Purpose: Set default button border attributes.
  470. //-----------------------------------------------------------------------------
  471. void Button::SetDefaultBorder(IBorder *border)
  472. {
  473. _defaultBorder = border;
  474. InvalidateLayout(false);
  475. }
  476. //-----------------------------------------------------------------------------
  477. // Purpose: Set depressed button border attributes.
  478. //-----------------------------------------------------------------------------
  479. void Button::SetDepressedBorder(IBorder *border)
  480. {
  481. _depressedBorder = border;
  482. InvalidateLayout(false);
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose: Set key focus button border attributes.
  486. //-----------------------------------------------------------------------------
  487. void Button::SetKeyFocusBorder(IBorder *border)
  488. {
  489. _keyFocusBorder = border;
  490. InvalidateLayout(false);
  491. }
  492. //-----------------------------------------------------------------------------
  493. // Purpose: Get button border attributes.
  494. //-----------------------------------------------------------------------------
  495. IBorder *Button::GetBorder(bool depressed, bool armed, bool selected, bool keyfocus)
  496. {
  497. if ( _buttonFlags.IsFlagSet( BUTTON_BORDER_ENABLED ) )
  498. {
  499. // raised buttons with no armed state
  500. if (depressed)
  501. return _depressedBorder;
  502. if (keyfocus)
  503. return _keyFocusBorder;
  504. if (IsEnabled() && _buttonFlags.IsFlagSet( DEFAULT_BUTTON ))
  505. return _keyFocusBorder;
  506. return _defaultBorder;
  507. }
  508. else
  509. {
  510. // flat buttons that raise
  511. if (depressed)
  512. return _depressedBorder;
  513. if (armed)
  514. return _defaultBorder;
  515. }
  516. return _defaultBorder;
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Purpose: sets this button to be the button that is accessed by default
  520. // when the user hits ENTER or SPACE
  521. //-----------------------------------------------------------------------------
  522. void Button::SetAsCurrentDefaultButton(int state)
  523. {
  524. if ( _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) != (bool)state )
  525. {
  526. _buttonFlags.SetFlag( DEFAULT_BUTTON, state );
  527. if (state)
  528. {
  529. // post a message up notifying our nav group that we're now the default button
  530. KeyValues *msg = new KeyValues( "CurrentDefaultButtonSet" );
  531. msg->SetInt( "button", ToHandle() );
  532. CallParentFunction( msg );
  533. }
  534. InvalidateLayout();
  535. Repaint();
  536. }
  537. }
  538. //-----------------------------------------------------------------------------
  539. // Purpose: sets this button to be the button that is accessed by default
  540. // when the user hits ENTER or SPACE
  541. //-----------------------------------------------------------------------------
  542. void Button::SetAsDefaultButton(int state)
  543. {
  544. if ( _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) != (bool)state )
  545. {
  546. _buttonFlags.SetFlag( DEFAULT_BUTTON, state );
  547. if (state)
  548. {
  549. // post a message up notifying our nav group that we're now the default button
  550. KeyValues *msg = new KeyValues( "DefaultButtonSet" );
  551. msg->SetInt( "button", ToHandle() );
  552. CallParentFunction( msg );
  553. }
  554. InvalidateLayout();
  555. Repaint();
  556. }
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose: sets rollover sound
  560. //-----------------------------------------------------------------------------
  561. void Button::SetArmedSound(const char *sound)
  562. {
  563. if (sound)
  564. {
  565. m_sArmedSoundName = g_ButtonSoundNames.AddString(sound);
  566. }
  567. else
  568. {
  569. m_sArmedSoundName = UTL_INVAL_SYMBOL;
  570. }
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. //-----------------------------------------------------------------------------
  575. void Button::SetDepressedSound(const char *sound)
  576. {
  577. if (sound)
  578. {
  579. m_sDepressedSoundName = g_ButtonSoundNames.AddString(sound);
  580. }
  581. else
  582. {
  583. m_sDepressedSoundName = UTL_INVAL_SYMBOL;
  584. }
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Purpose:
  588. //-----------------------------------------------------------------------------
  589. void Button::SetReleasedSound(const char *sound)
  590. {
  591. if (sound)
  592. {
  593. m_sReleasedSoundName = g_ButtonSoundNames.AddString(sound);
  594. }
  595. else
  596. {
  597. m_sReleasedSoundName = UTL_INVAL_SYMBOL;
  598. }
  599. }
  600. //-----------------------------------------------------------------------------
  601. // Purpose: Set button to be mouse clickable or not.
  602. //-----------------------------------------------------------------------------
  603. void Button::SetMouseClickEnabled(MouseCode code,bool state)
  604. {
  605. if(state)
  606. {
  607. //set bit to 1
  608. _mouseClickMask|=1<<((int)(code+1));
  609. }
  610. else
  611. {
  612. //set bit to 0
  613. _mouseClickMask&=~(1<<((int)(code+1)));
  614. }
  615. }
  616. //-----------------------------------------------------------------------------
  617. // Purpose: Check if button is mouse clickable
  618. //-----------------------------------------------------------------------------
  619. bool Button::IsMouseClickEnabled(MouseCode code)
  620. {
  621. if(_mouseClickMask&(1<<((int)(code+1))))
  622. {
  623. return true;
  624. }
  625. return false;
  626. }
  627. //-----------------------------------------------------------------------------
  628. // Purpose: sets the command to send when the button is pressed
  629. //-----------------------------------------------------------------------------
  630. void Button::SetCommand( const char *command )
  631. {
  632. SetCommand(new KeyValues("Command", "command", command));
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Purpose: sets the message to send when the button is pressed
  636. //-----------------------------------------------------------------------------
  637. void Button::SetCommand( KeyValues *message )
  638. {
  639. // delete the old message
  640. if (_actionMessage)
  641. {
  642. _actionMessage->deleteThis();
  643. }
  644. _actionMessage = message;
  645. }
  646. //-----------------------------------------------------------------------------
  647. // Purpose: Peeks at the message to send when button is pressed
  648. // Input : -
  649. // Output : KeyValues
  650. //-----------------------------------------------------------------------------
  651. KeyValues *Button::GetCommand()
  652. {
  653. return _actionMessage;
  654. }
  655. //-----------------------------------------------------------------------------
  656. // Purpose: Message targets that the button has been pressed
  657. //-----------------------------------------------------------------------------
  658. void Button::FireActionSignal()
  659. {
  660. // message-based action signal
  661. if (_actionMessage)
  662. {
  663. // see if it's a url
  664. if (!stricmp(_actionMessage->GetName(), "command")
  665. && !strnicmp(_actionMessage->GetString("command", ""), "url ", strlen("url "))
  666. && strstr(_actionMessage->GetString("command", ""), "://"))
  667. {
  668. // it's a command to launch a url, run it
  669. system()->ShellExecute("open", _actionMessage->GetString("command", " ") + 4);
  670. }
  671. PostActionSignal(_actionMessage->MakeCopy());
  672. }
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Purpose: gets info about the button
  676. //-----------------------------------------------------------------------------
  677. bool Button::RequestInfo(KeyValues *outputData)
  678. {
  679. if (!stricmp(outputData->GetName(), "CanBeDefaultButton"))
  680. {
  681. outputData->SetInt("result", CanBeDefaultButton() ? 1 : 0);
  682. return true;
  683. }
  684. else if (!stricmp(outputData->GetName(), "GetState"))
  685. {
  686. outputData->SetInt("state", IsSelected());
  687. return true;
  688. }
  689. else if ( !stricmp( outputData->GetName(), "GetCommand" ))
  690. {
  691. if ( _actionMessage )
  692. {
  693. outputData->SetString( "command", _actionMessage->GetString( "command", "" ) );
  694. }
  695. else
  696. {
  697. outputData->SetString( "command", "" );
  698. }
  699. return true;
  700. }
  701. return BaseClass::RequestInfo(outputData);
  702. }
  703. //-----------------------------------------------------------------------------
  704. // Purpose:
  705. //-----------------------------------------------------------------------------
  706. bool Button::CanBeDefaultButton(void)
  707. {
  708. return true;
  709. }
  710. //-----------------------------------------------------------------------------
  711. // Purpose: Get control settings for editing
  712. //-----------------------------------------------------------------------------
  713. void Button::GetSettings( KeyValues *outResourceData )
  714. {
  715. BaseClass::GetSettings(outResourceData);
  716. if (_actionMessage)
  717. {
  718. outResourceData->SetString("command", _actionMessage->GetString("command", ""));
  719. }
  720. outResourceData->SetInt("default", _buttonFlags.IsFlagSet( DEFAULT_BUTTON ) );
  721. if ( m_bSelectionStateSaved )
  722. {
  723. outResourceData->SetInt( "selected", IsSelected() );
  724. }
  725. }
  726. //-----------------------------------------------------------------------------
  727. // Purpose:
  728. //-----------------------------------------------------------------------------
  729. void Button::ApplySettings( KeyValues *inResourceData )
  730. {
  731. BaseClass::ApplySettings(inResourceData);
  732. const char *cmd = inResourceData->GetString("command", "");
  733. if (*cmd)
  734. {
  735. // add in the command
  736. SetCommand(cmd);
  737. }
  738. // set default button state
  739. int defaultButton = inResourceData->GetInt("default");
  740. if (defaultButton && CanBeDefaultButton())
  741. {
  742. SetAsDefaultButton(true);
  743. }
  744. // saved selection state
  745. int iSelected = inResourceData->GetInt( "selected", -1 );
  746. if ( iSelected != -1 )
  747. {
  748. SetSelected( iSelected != 0 );
  749. m_bSelectionStateSaved = true;
  750. }
  751. m_bStaySelectedOnClick = inResourceData->GetBool( "stayselectedonclick", false );
  752. m_bStayArmedOnClick = inResourceData->GetBool( "stay_armed_on_click", false );
  753. const char *sound = inResourceData->GetString("sound_armed", "");
  754. if (*sound)
  755. {
  756. SetArmedSound(sound);
  757. }
  758. sound = inResourceData->GetString("sound_depressed", "");
  759. if (*sound)
  760. {
  761. SetDepressedSound(sound);
  762. }
  763. sound = inResourceData->GetString("sound_released", "");
  764. if (*sound)
  765. {
  766. SetReleasedSound(sound);
  767. }
  768. _activationType = (ActivationType_t)inResourceData->GetInt( "button_activation_type", ACTIVATE_ONRELEASED );
  769. }
  770. //-----------------------------------------------------------------------------
  771. // Purpose: Describes editing details
  772. //-----------------------------------------------------------------------------
  773. const char *Button::GetDescription( void )
  774. {
  775. static char buf[1024];
  776. Q_snprintf(buf, sizeof(buf), "%s, string command, int default", BaseClass::GetDescription());
  777. return buf;
  778. }
  779. //-----------------------------------------------------------------------------
  780. // Purpose:
  781. //-----------------------------------------------------------------------------
  782. void Button::OnSetState(int state)
  783. {
  784. SetSelected((bool)state);
  785. Repaint();
  786. }
  787. //-----------------------------------------------------------------------------
  788. // Purpose:
  789. //-----------------------------------------------------------------------------
  790. void Button::OnCursorEntered()
  791. {
  792. if (IsEnabled() && !IsSelected() )
  793. {
  794. SetArmed( true );
  795. }
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Purpose:
  799. //-----------------------------------------------------------------------------
  800. void Button::OnCursorExited()
  801. {
  802. if ( !_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && !IsSelected() )
  803. {
  804. SetArmed( false );
  805. }
  806. }
  807. //-----------------------------------------------------------------------------
  808. // Purpose:
  809. //-----------------------------------------------------------------------------
  810. void Button::OnMousePressed(MouseCode code)
  811. {
  812. if (!IsEnabled())
  813. return;
  814. if (!IsMouseClickEnabled(code))
  815. return;
  816. if (_activationType == ACTIVATE_ONPRESSED)
  817. {
  818. if ( IsKeyBoardInputEnabled() )
  819. {
  820. RequestFocus();
  821. }
  822. DoClick();
  823. return;
  824. }
  825. // play activation sound
  826. if (m_sDepressedSoundName != UTL_INVAL_SYMBOL)
  827. {
  828. surface()->PlaySound(g_ButtonSoundNames.String(m_sDepressedSoundName));
  829. }
  830. if (IsUseCaptureMouseEnabled() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
  831. {
  832. {
  833. if ( IsKeyBoardInputEnabled() )
  834. {
  835. RequestFocus();
  836. }
  837. SetSelected(true);
  838. Repaint();
  839. }
  840. // lock mouse input to going to this button
  841. input()->SetMouseCapture(GetVPanel());
  842. }
  843. }
  844. //-----------------------------------------------------------------------------
  845. // Purpose:
  846. //-----------------------------------------------------------------------------
  847. void Button::OnMouseDoublePressed(MouseCode code)
  848. {
  849. OnMousePressed(code);
  850. }
  851. //-----------------------------------------------------------------------------
  852. // Purpose:
  853. //-----------------------------------------------------------------------------
  854. void Button::OnMouseReleased(MouseCode code)
  855. {
  856. // ensure mouse capture gets released
  857. if (IsUseCaptureMouseEnabled())
  858. {
  859. input()->SetMouseCapture(NULL);
  860. }
  861. if (_activationType == ACTIVATE_ONPRESSED)
  862. return;
  863. if (!IsMouseClickEnabled(code))
  864. return;
  865. if (!IsSelected() && _activationType == ACTIVATE_ONPRESSEDANDRELEASED)
  866. return;
  867. // it has to be both enabled and (mouse over the button or using a key) to fire
  868. if ( IsEnabled() && ( GetVPanel() == input()->GetMouseOver() || _buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) ) )
  869. {
  870. DoClick();
  871. }
  872. else if ( !m_bStaySelectedOnClick )
  873. {
  874. SetSelected(false);
  875. }
  876. // make sure the button gets unselected
  877. Repaint();
  878. }
  879. //-----------------------------------------------------------------------------
  880. // Purpose:
  881. //-----------------------------------------------------------------------------
  882. void Button::OnKeyCodePressed(KeyCode code)
  883. {
  884. KeyCode localCode = GetBaseButtonCode( code );
  885. if( ( localCode == KEY_XBUTTON_A || localCode == STEAMCONTROLLER_A ) && IsEnabled() )
  886. {
  887. SetArmed( true );
  888. _buttonFlags.SetFlag( BUTTON_KEY_DOWN );
  889. if( _activationType != ACTIVATE_ONRELEASED )
  890. {
  891. DoClick();
  892. }
  893. }
  894. else if (code == KEY_SPACE || code == KEY_ENTER)
  895. {
  896. SetArmed(true);
  897. _buttonFlags.SetFlag( BUTTON_KEY_DOWN );
  898. OnMousePressed(MOUSE_LEFT);
  899. if (IsUseCaptureMouseEnabled()) // undo the mouse capture since its a fake mouse click!
  900. {
  901. input()->SetMouseCapture(NULL);
  902. }
  903. }
  904. else
  905. {
  906. _buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
  907. BaseClass::OnKeyCodePressed( code );
  908. }
  909. }
  910. //-----------------------------------------------------------------------------
  911. // Purpose:
  912. //-----------------------------------------------------------------------------
  913. void Button::OnKeyCodeReleased( KeyCode keycode )
  914. {
  915. vgui::KeyCode code = GetBaseButtonCode( keycode );
  916. if ( _buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && ( code == KEY_XBUTTON_A || code == KEY_XBUTTON_START || code == STEAMCONTROLLER_A ) )
  917. {
  918. SetArmed( true );
  919. if( _activationType != ACTIVATE_ONPRESSED )
  920. {
  921. DoClick();
  922. }
  923. }
  924. else if (_buttonFlags.IsFlagSet( BUTTON_KEY_DOWN ) && (code == KEY_SPACE || code == KEY_ENTER))
  925. {
  926. SetArmed(true);
  927. OnMouseReleased(MOUSE_LEFT);
  928. }
  929. else
  930. {
  931. BaseClass::OnKeyCodeReleased( keycode );
  932. }
  933. _buttonFlags.ClearFlag( BUTTON_KEY_DOWN );
  934. if ( !( code == KEY_XSTICK1_UP || code == KEY_XSTICK1_DOWN || code == KEY_XSTICK1_LEFT || code == KEY_XSTICK1_RIGHT ||
  935. code == KEY_XSTICK2_UP || code == KEY_XSTICK2_DOWN || code == KEY_XSTICK2_LEFT || code == KEY_XSTICK2_RIGHT ||
  936. code == KEY_XBUTTON_UP || code == KEY_XBUTTON_DOWN || code == KEY_XBUTTON_LEFT || code == KEY_XBUTTON_RIGHT ||
  937. keycode == KEY_UP|| keycode == KEY_DOWN || keycode == KEY_LEFT || keycode == KEY_RIGHT ) )
  938. {
  939. SetArmed( false );
  940. }
  941. }
  942. //-----------------------------------------------------------------------------
  943. // Purpose: Override this to draw different focus border
  944. //-----------------------------------------------------------------------------
  945. void Button::DrawFocusBorder(int tx0, int ty0, int tx1, int ty1)
  946. {
  947. surface()->DrawSetColor(_keyboardFocusColor);
  948. DrawDashedLine(tx0, ty0, tx1, ty0+1, 1, 1); // top
  949. DrawDashedLine(tx0, ty0, tx0+1, ty1, 1, 1); // left
  950. DrawDashedLine(tx0, ty1-1, tx1, ty1, 1, 1); // bottom
  951. DrawDashedLine(tx1-1, ty0, tx1, ty1, 1, 1); // right
  952. }
  953. //-----------------------------------------------------------------------------
  954. // Purpose: Size the object to its button and text. - only works from in ApplySchemeSettings or PerformLayout()
  955. //-----------------------------------------------------------------------------
  956. void Button::SizeToContents()
  957. {
  958. int wide, tall;
  959. GetContentSize(wide, tall);
  960. SetSize(wide + Label::Content, tall + Label::Content);
  961. }