GadgetPushButton.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: GadgetPushButton.cpp /////////////////////////////////////////////////
  24. //-----------------------------------------------------------------------------
  25. //
  26. // Westwood Studios Pacific.
  27. //
  28. // Confidential Information
  29. // Copyright (C) 2001 - All Rights Reserved
  30. //
  31. //-----------------------------------------------------------------------------
  32. //
  33. // Project: RTS3
  34. //
  35. // File name: PushButton.cpp
  36. //
  37. // Created: Colin Day, June 2001
  38. //
  39. // Desc: Pushbutton GUI gadget control callbacks
  40. //
  41. //-----------------------------------------------------------------------------
  42. ///////////////////////////////////////////////////////////////////////////////
  43. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  44. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  45. // USER INCLUDES //////////////////////////////////////////////////////////////
  46. #include "Common/AudioEventRTS.h"
  47. #include "Common/Language.h"
  48. #include "Common/GameAudio.h"
  49. #include "GameClient/Gadget.h"
  50. #include "GameClient/GameWindowManager.h"
  51. #include "GameClient/InGameUI.h"
  52. #ifdef _INTERNAL
  53. // for occasional debugging...
  54. //#pragma optimize("", off)
  55. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  56. #endif
  57. // DEFINES ////////////////////////////////////////////////////////////////////
  58. // PRIVATE TYPES //////////////////////////////////////////////////////////////
  59. // PRIVATE DATA ///////////////////////////////////////////////////////////////
  60. // PUBLIC DATA ////////////////////////////////////////////////////////////////
  61. // PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
  62. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  63. static Bool buttonTriggersOnMouseDown(GameWindow *window)
  64. {
  65. // Buttons with the on down status set trigger on mouse down. jba. [8/6/2003]
  66. Bool onDown = BitTest( window->winGetStatus(), WIN_STATUS_ON_MOUSE_DOWN);
  67. // Checkboxes always trigger on mouse down. jba [8/6/2003]
  68. if (BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE )) {
  69. onDown = true;
  70. }
  71. return onDown;
  72. }
  73. // GadgetPushButtonInput ======================================================
  74. /** Handle input for push button */
  75. //=============================================================================
  76. WindowMsgHandledType GadgetPushButtonInput( GameWindow *window,
  77. UnsignedInt msg,
  78. WindowMsgData mData1,
  79. WindowMsgData mData2 )
  80. {
  81. WinInstanceData *instData = window->winGetInstanceData();
  82. switch( msg )
  83. {
  84. // ------------------------------------------------------------------------
  85. case GWM_MOUSE_ENTERING:
  86. {
  87. if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  88. {
  89. BitSet( instData->m_state, WIN_STATE_HILITED );
  90. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  91. GBM_MOUSE_ENTERING,
  92. (WindowMsgData)window,
  93. mData1 );
  94. //TheWindowManager->winSetFocus( window );
  95. }
  96. if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
  97. {
  98. WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
  99. BitSet(instDataParent->m_state, WIN_STATE_HILITED);
  100. }
  101. break;
  102. } // end mouse entering
  103. // ------------------------------------------------------------------------
  104. case GWM_MOUSE_LEAVING:
  105. {
  106. if(BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  107. {
  108. BitClear( instData->m_state, WIN_STATE_HILITED );
  109. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  110. GBM_MOUSE_LEAVING,
  111. (WindowMsgData)window,
  112. mData1 );
  113. }
  114. //
  115. // if this is not a check-like button, clear any selected state when the
  116. // move leaves the window area
  117. //
  118. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  119. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
  120. BitClear( instData->m_state, WIN_STATE_SELECTED );
  121. //TheWindowManager->winSetFocus( NULL );
  122. if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
  123. {
  124. WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
  125. BitClear(instDataParent->m_state, WIN_STATE_HILITED);
  126. }
  127. break;
  128. } // end mouse leaving
  129. // ------------------------------------------------------------------------
  130. case GWM_LEFT_DRAG:
  131. {
  132. TheWindowManager->winSendSystemMsg( instData->getOwner(), GGM_LEFT_DRAG,
  133. (WindowMsgData)window, mData1 );
  134. break;
  135. } // end left drag
  136. // ------------------------------------------------------------------------
  137. case GWM_LEFT_DOWN:
  138. {
  139. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  140. AudioEventRTS buttonClick;
  141. if(pData && pData->altSound.isNotEmpty())
  142. buttonClick.setEventName(pData->altSound);
  143. else
  144. buttonClick.setEventName("GUIClick");
  145. if( TheAudio )
  146. {
  147. TheAudio->addAudioEvent( &buttonClick );
  148. } // end if
  149. //
  150. // for 'check-like' buttons we have "dual state", we flip the selected status
  151. // in that case instead of just turning it on like normal ... also note
  152. // that selected messages are sent immediately
  153. //
  154. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  155. {
  156. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  157. BitClear( instData->m_state, WIN_STATE_SELECTED );
  158. else
  159. BitSet( instData->m_state, WIN_STATE_SELECTED );
  160. } // end if
  161. else
  162. {
  163. // just select as normal
  164. BitSet( instData->m_state, WIN_STATE_SELECTED );
  165. } // end else
  166. if (buttonTriggersOnMouseDown(window)) {
  167. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  168. (WindowMsgData)window, mData1 );
  169. }
  170. break;
  171. } // end left down
  172. //-------------------------------------------------------------------------
  173. case GWM_LEFT_UP:
  174. {
  175. //
  176. // note check like selected messages aren't sent here ... they are sent
  177. // on the down press
  178. //
  179. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  180. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  181. {
  182. if (!buttonTriggersOnMouseDown(window)) {
  183. // If it didn't trigger on mouse down, trigger on the mouse up. jba [8/6/2003]
  184. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  185. (WindowMsgData)window, mData1 );
  186. }
  187. BitClear( instData->m_state, WIN_STATE_SELECTED );
  188. }
  189. else
  190. {
  191. // this up click was not meant for this button
  192. return MSG_IGNORED;
  193. }
  194. break;
  195. } // end left up or left click
  196. // ------------------------------------------------------------------------
  197. case GWM_RIGHT_DOWN:
  198. {
  199. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  200. AudioEventRTS buttonClick;
  201. if(pData && pData->altSound.isNotEmpty())
  202. buttonClick.setEventName(pData->altSound);
  203. else
  204. buttonClick.setEventName("GUIClick");
  205. if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
  206. {
  207. // Need to be specially marked to care about right mouse events
  208. if( TheAudio )
  209. {
  210. TheAudio->addAudioEvent( &buttonClick );
  211. } // end if
  212. //
  213. // for 'check-like' buttons we have "dual state", we flip the selected status
  214. // in that case instead of just turning it on like normal ... also note
  215. // that selected messages are sent immediately
  216. //
  217. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  218. {
  219. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  220. BitClear( instData->m_state, WIN_STATE_SELECTED );
  221. else
  222. BitSet( instData->m_state, WIN_STATE_SELECTED );
  223. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
  224. (WindowMsgData)window, mData1 );
  225. } // end if
  226. else
  227. {
  228. // just select as normal
  229. BitSet( instData->m_state, WIN_STATE_SELECTED );
  230. } // end else
  231. }
  232. else
  233. {
  234. // Else I don't care about right events
  235. return MSG_IGNORED;
  236. }
  237. break;
  238. } // end right down
  239. //-------------------------------------------------------------------------
  240. case GWM_RIGHT_UP:
  241. {
  242. if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
  243. {
  244. //
  245. // note check like selected messages aren't sent here ... they are sent
  246. // on the down press
  247. //
  248. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  249. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  250. {
  251. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
  252. (WindowMsgData)window, mData1 );
  253. BitClear( instData->m_state, WIN_STATE_SELECTED );
  254. }
  255. else
  256. {
  257. // this up click was not meant for this button
  258. return MSG_IGNORED;
  259. }
  260. }
  261. else
  262. {
  263. // Else I don't care about right events
  264. return MSG_IGNORED;
  265. }
  266. break;
  267. } // end right up or right click
  268. // ------------------------------------------------------------------------
  269. case GWM_CHAR:
  270. {
  271. switch( mData1 )
  272. {
  273. // --------------------------------------------------------------------
  274. case KEY_ENTER:
  275. case KEY_SPACE:
  276. {
  277. if( BitTest( mData2, KEY_STATE_UP ) )
  278. {
  279. //
  280. // note check like selected messages aren't sent here ... they are sent
  281. // on the down press
  282. //
  283. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  284. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  285. {
  286. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  287. (WindowMsgData)window, 0 );
  288. BitClear( instData->m_state, WIN_STATE_SELECTED );
  289. }
  290. }
  291. else
  292. {
  293. //
  294. // for 'check-like' buttons we have "dual state", we flip the selected status
  295. // in that case instead of just turning it on like normal ... also note
  296. // that selected messages are sent immediately
  297. //
  298. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  299. {
  300. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  301. BitClear( instData->m_state, WIN_STATE_SELECTED );
  302. else
  303. BitSet( instData->m_state, WIN_STATE_SELECTED );
  304. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  305. (WindowMsgData)window, mData1 );
  306. } // end if
  307. else
  308. {
  309. // just select as normal
  310. BitSet( instData->m_state, WIN_STATE_SELECTED );
  311. } // end else
  312. } // end else
  313. break;
  314. } // end handle enter and space button
  315. // --------------------------------------------------------------------
  316. case KEY_DOWN:
  317. case KEY_RIGHT:
  318. case KEY_TAB:
  319. {
  320. if( BitTest( mData2, KEY_STATE_DOWN ) )
  321. TheWindowManager->winNextTab(window);
  322. break;
  323. } // end key down, right or tab
  324. // --------------------------------------------------------------------
  325. case KEY_UP:
  326. case KEY_LEFT:
  327. {
  328. if( BitTest( mData2, KEY_STATE_DOWN ) )
  329. TheWindowManager->winPrevTab(window);
  330. break;
  331. } // end key up or left
  332. // --------------------------------------------------------------------
  333. default:
  334. return MSG_IGNORED;
  335. } // end switch on char
  336. break;
  337. } // end character message
  338. // ------------------------------------------------------------------------
  339. default:
  340. return MSG_IGNORED;
  341. } // end switch( msg )
  342. return MSG_HANDLED;
  343. } // end GadgetPushButtonInput
  344. // GadgetPushButtonSystem =====================================================
  345. /** Handle system messages for push button */
  346. //=============================================================================
  347. WindowMsgHandledType GadgetPushButtonSystem( GameWindow *window, UnsignedInt msg,
  348. WindowMsgData mData1, WindowMsgData mData2 )
  349. {
  350. WinInstanceData *instData = window->winGetInstanceData();
  351. switch( msg )
  352. {
  353. // ------------------------------------------------------------------------
  354. case GGM_SET_LABEL:
  355. {
  356. // set text into the win instance text data field
  357. window->winSetText( *(UnicodeString*)mData1 );
  358. break;
  359. }
  360. // ------------------------------------------------------------------------
  361. case GWM_CREATE:
  362. break;
  363. // ------------------------------------------------------------------------
  364. case GWM_DESTROY:
  365. {
  366. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  367. if(pData)
  368. delete pData;
  369. window->winSetUserData(NULL);
  370. }
  371. break;
  372. // ------------------------------------------------------------------------
  373. case GWM_INPUT_FOCUS:
  374. if( mData1 == FALSE )
  375. BitClear( instData->m_state, WIN_STATE_HILITED );
  376. else
  377. BitSet( instData->m_state, WIN_STATE_HILITED );
  378. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  379. GGM_FOCUS_CHANGE,
  380. (WindowMsgData)mData1,
  381. window->winGetWindowId() );
  382. if( mData1 == FALSE )
  383. *(Bool*)mData2 = FALSE;
  384. else
  385. *(Bool*)mData2 = TRUE;
  386. break;
  387. default:
  388. return MSG_IGNORED;
  389. } // end switch( msg )
  390. return MSG_HANDLED;
  391. } // end GadgetPushButtonSystem
  392. // ------------------------------------------------------------------------------------------------
  393. /** Set the visual status of a button to make it looked checked/unchecked ... DO NOT send
  394. * any actual button selected messages, this is ONLY VISUAL */
  395. // ------------------------------------------------------------------------------------------------
  396. void GadgetCheckLikeButtonSetVisualCheck( GameWindow *g, Bool checked )
  397. {
  398. // sanity
  399. if( g == NULL )
  400. return;
  401. // get instance data
  402. WinInstanceData *instData = g->winGetInstanceData();
  403. if( instData == NULL )
  404. return;
  405. // sanity, must be a check like button
  406. if( BitTest( g->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  407. {
  408. DEBUG_CRASH(( "GadgetCheckLikeButtonSetVisualCheck: Window is not 'CHECK-LIKE'\n" ));
  409. return;
  410. } // end if
  411. // set or clear the 'pushed' state
  412. if( instData )
  413. {
  414. if( checked == TRUE )
  415. BitSet( instData->m_state, WIN_STATE_SELECTED );
  416. else
  417. BitClear( instData->m_state, WIN_STATE_SELECTED );
  418. } // end if
  419. } // end GadgetCheckLikeButtonSetVisualCheck
  420. // ------------------------------------------------------------------------------------------------
  421. // ------------------------------------------------------------------------------------------------
  422. Bool GadgetCheckLikeButtonIsChecked( GameWindow *g )
  423. {
  424. // sanity
  425. if( g == NULL )
  426. return FALSE;
  427. // get instance data
  428. WinInstanceData *instData = g->winGetInstanceData();
  429. if( instData == NULL )
  430. return FALSE;
  431. // we just hold this "check like dual state thingie" using the selected state
  432. return BitTest( instData->m_state, WIN_STATE_SELECTED );
  433. } // end GadgetCheckLikeButtonIsChecked
  434. // ------------------------------------------------------------------------------------------------
  435. // ------------------------------------------------------------------------------------------------
  436. void GadgetButtonEnableCheckLike( GameWindow *g, Bool makeCheckLike, Bool initiallyChecked )
  437. {
  438. // sanity
  439. if( g == NULL )
  440. return;
  441. // get inst data
  442. WinInstanceData *instData = g->winGetInstanceData();
  443. if( instData == NULL )
  444. return;
  445. // make it check like
  446. if( makeCheckLike )
  447. g->winSetStatus( WIN_STATUS_CHECK_LIKE );
  448. else
  449. g->winClearStatus( WIN_STATUS_CHECK_LIKE );
  450. // set the initially checked "state"
  451. if( initiallyChecked )
  452. BitSet( instData->m_state, WIN_STATE_SELECTED );
  453. else
  454. BitClear( instData->m_state, WIN_STATE_SELECTED );
  455. } // end GadgetButtonEnableCheckLike
  456. // GadgetButtonSetText ========================================================
  457. /** Set the text for a push button */
  458. //=============================================================================
  459. void GadgetButtonSetText( GameWindow *g, UnicodeString text )
  460. {
  461. // sanity
  462. if( g == NULL )
  463. return;
  464. TheWindowManager->winSendSystemMsg( g, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
  465. } // end GadgetButtonSetText
  466. PushButtonData * getNewPushButtonData( void )
  467. {
  468. PushButtonData *p = NEW PushButtonData;
  469. if(!p)
  470. return NULL;
  471. p->userData = NULL;
  472. p->drawBorder = FALSE;
  473. p->drawClock = NO_CLOCK;
  474. p->overlayImage = NULL;
  475. return p;
  476. }
  477. // GadgetButtonSetBorder ======================================================
  478. /** Set to draw the special borders in the game */
  479. //=============================================================================
  480. void GadgetButtonSetBorder( GameWindow *g, Color color, Bool drawBorder = TRUE )
  481. {
  482. if( g == NULL )
  483. return;
  484. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  485. if(!pData)
  486. {
  487. pData = getNewPushButtonData();
  488. }
  489. pData->drawBorder = drawBorder;
  490. pData->colorBorder = color;
  491. g->winSetUserData(pData);
  492. }
  493. // GadgetButtonDrawClock ======================================================
  494. /** Set to draw a rectClock on the button */
  495. //=============================================================================
  496. void GadgetButtonDrawClock( GameWindow *g, Int percent, Color color )
  497. {
  498. if( g == NULL )
  499. return;
  500. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  501. if(!pData)
  502. {
  503. pData = getNewPushButtonData();
  504. }
  505. pData->drawClock = NORMAL_CLOCK;
  506. pData->percentClock = percent;
  507. pData->colorClock = color;
  508. g->winSetUserData(pData);
  509. }
  510. // GadgetButtonDrawInverseClock ======================================================
  511. /** Set to draw an inversed rectClock on the button */
  512. //=============================================================================
  513. void GadgetButtonDrawInverseClock( GameWindow *g, Int percent, Color color )
  514. {
  515. if( g == NULL )
  516. return;
  517. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  518. if(!pData)
  519. {
  520. pData = getNewPushButtonData();
  521. }
  522. pData->drawClock = INVERSE_CLOCK;
  523. pData->percentClock = percent;
  524. pData->colorClock = color;
  525. g->winSetUserData(pData);
  526. }
  527. void GadgetButtonDrawOverlayImage( GameWindow *g, const Image *image )
  528. {
  529. if( g == NULL )
  530. return;
  531. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  532. if(!pData)
  533. {
  534. pData = getNewPushButtonData();
  535. }
  536. pData->overlayImage = image;
  537. g->winSetUserData(pData);
  538. }
  539. // GadgetButtonSetData ======================================================
  540. /** Sets random data that the user can contain on the button */
  541. //=============================================================================
  542. void GadgetButtonSetData(GameWindow *g, void *data)
  543. {
  544. if( g == NULL )
  545. return;
  546. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  547. if(!pData)
  548. {
  549. pData = getNewPushButtonData();
  550. }
  551. pData->userData = data;
  552. g->winSetUserData(pData);
  553. }
  554. // GadgetButtonGetData ======================================================
  555. /** Gets the random data the user had already set on the button */
  556. //=============================================================================
  557. void *GadgetButtonGetData(GameWindow *g)
  558. {
  559. if( g == NULL )
  560. return NULL;
  561. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  562. if(!pData)
  563. {
  564. return NULL;
  565. }
  566. return pData->userData;
  567. }
  568. void GadgetButtonSetAltSound(GameWindow *g, AsciiString altSound )
  569. {
  570. if(!g)
  571. return;
  572. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  573. if(!pData)
  574. {
  575. return;
  576. }
  577. pData->altSound = altSound;
  578. }