Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1082 lines
31 KiB

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