GadgetPushButton.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711
  1. /*
  2. ** Command & Conquer Generals(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. // DEFINES ////////////////////////////////////////////////////////////////////
  53. // PRIVATE TYPES //////////////////////////////////////////////////////////////
  54. // PRIVATE DATA ///////////////////////////////////////////////////////////////
  55. // PUBLIC DATA ////////////////////////////////////////////////////////////////
  56. // PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
  57. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  58. // GadgetPushButtonInput ======================================================
  59. /** Handle input for push button */
  60. //=============================================================================
  61. WindowMsgHandledType GadgetPushButtonInput( GameWindow *window,
  62. UnsignedInt msg,
  63. WindowMsgData mData1,
  64. WindowMsgData mData2 )
  65. {
  66. WinInstanceData *instData = window->winGetInstanceData();
  67. switch( msg )
  68. {
  69. // ------------------------------------------------------------------------
  70. case GWM_MOUSE_ENTERING:
  71. {
  72. if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  73. {
  74. BitSet( instData->m_state, WIN_STATE_HILITED );
  75. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  76. GBM_MOUSE_ENTERING,
  77. (WindowMsgData)window,
  78. mData1 );
  79. //TheWindowManager->winSetFocus( window );
  80. }
  81. if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
  82. {
  83. WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
  84. BitSet(instDataParent->m_state, WIN_STATE_HILITED);
  85. }
  86. break;
  87. } // end mouse entering
  88. // ------------------------------------------------------------------------
  89. case GWM_MOUSE_LEAVING:
  90. {
  91. if(BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  92. {
  93. BitClear( instData->m_state, WIN_STATE_HILITED );
  94. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  95. GBM_MOUSE_LEAVING,
  96. (WindowMsgData)window,
  97. mData1 );
  98. }
  99. //
  100. // if this is not a check-like button, clear any selected state when the
  101. // move leaves the window area
  102. //
  103. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  104. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) )
  105. BitClear( instData->m_state, WIN_STATE_SELECTED );
  106. //TheWindowManager->winSetFocus( NULL );
  107. if(window->winGetParent() && BitTest(window->winGetParent()->winGetStyle(),GWS_HORZ_SLIDER) )
  108. {
  109. WinInstanceData *instDataParent = window->winGetParent()->winGetInstanceData();
  110. BitClear(instDataParent->m_state, WIN_STATE_HILITED);
  111. }
  112. break;
  113. } // end mouse leaving
  114. // ------------------------------------------------------------------------
  115. case GWM_LEFT_DRAG:
  116. {
  117. TheWindowManager->winSendSystemMsg( instData->getOwner(), GGM_LEFT_DRAG,
  118. (WindowMsgData)window, mData1 );
  119. break;
  120. } // end left drag
  121. // ------------------------------------------------------------------------
  122. case GWM_LEFT_DOWN:
  123. {
  124. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  125. AudioEventRTS buttonClick;
  126. if(pData && pData->altSound.isNotEmpty())
  127. buttonClick.setEventName(pData->altSound);
  128. else
  129. buttonClick.setEventName("GUIClick");
  130. if( TheAudio )
  131. {
  132. TheAudio->addAudioEvent( &buttonClick );
  133. } // end if
  134. //
  135. // for 'check-like' buttons we have "dual state", we flip the selected status
  136. // in that case instead of just turning it on like normal ... also note
  137. // that selected messages are sent immediately
  138. //
  139. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  140. {
  141. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  142. BitClear( instData->m_state, WIN_STATE_SELECTED );
  143. else
  144. BitSet( instData->m_state, WIN_STATE_SELECTED );
  145. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  146. (WindowMsgData)window, mData1 );
  147. } // end if
  148. else
  149. {
  150. // just select as normal
  151. BitSet( instData->m_state, WIN_STATE_SELECTED );
  152. } // end else
  153. break;
  154. } // end left down
  155. //-------------------------------------------------------------------------
  156. case GWM_LEFT_UP:
  157. {
  158. //
  159. // note check like selected messages aren't sent here ... they are sent
  160. // on the down press
  161. //
  162. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  163. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  164. {
  165. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  166. (WindowMsgData)window, mData1 );
  167. BitClear( instData->m_state, WIN_STATE_SELECTED );
  168. }
  169. else
  170. {
  171. // this up click was not meant for this button
  172. return MSG_IGNORED;
  173. }
  174. break;
  175. } // end left up or left click
  176. // ------------------------------------------------------------------------
  177. case GWM_RIGHT_DOWN:
  178. {
  179. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  180. AudioEventRTS buttonClick;
  181. if(pData && pData->altSound.isNotEmpty())
  182. buttonClick.setEventName(pData->altSound);
  183. else
  184. buttonClick.setEventName("GUIClick");
  185. if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
  186. {
  187. // Need to be specially marked to care about right mouse events
  188. if( TheAudio )
  189. {
  190. TheAudio->addAudioEvent( &buttonClick );
  191. } // end if
  192. //
  193. // for 'check-like' buttons we have "dual state", we flip the selected status
  194. // in that case instead of just turning it on like normal ... also note
  195. // that selected messages are sent immediately
  196. //
  197. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  198. {
  199. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  200. BitClear( instData->m_state, WIN_STATE_SELECTED );
  201. else
  202. BitSet( instData->m_state, WIN_STATE_SELECTED );
  203. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
  204. (WindowMsgData)window, mData1 );
  205. } // end if
  206. else
  207. {
  208. // just select as normal
  209. BitSet( instData->m_state, WIN_STATE_SELECTED );
  210. } // end else
  211. }
  212. else
  213. {
  214. // Else I don't care about right events
  215. return MSG_IGNORED;
  216. }
  217. break;
  218. } // end right down
  219. //-------------------------------------------------------------------------
  220. case GWM_RIGHT_UP:
  221. {
  222. if( BitTest( instData->getStatus(), WIN_STATUS_RIGHT_CLICK ) )
  223. {
  224. //
  225. // note check like selected messages aren't sent here ... they are sent
  226. // on the down press
  227. //
  228. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  229. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  230. {
  231. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED_RIGHT,
  232. (WindowMsgData)window, mData1 );
  233. BitClear( instData->m_state, WIN_STATE_SELECTED );
  234. }
  235. else
  236. {
  237. // this up click was not meant for this button
  238. return MSG_IGNORED;
  239. }
  240. }
  241. else
  242. {
  243. // Else I don't care about right events
  244. return MSG_IGNORED;
  245. }
  246. break;
  247. } // end right up or right click
  248. // ------------------------------------------------------------------------
  249. case GWM_CHAR:
  250. {
  251. switch( mData1 )
  252. {
  253. // --------------------------------------------------------------------
  254. case KEY_ENTER:
  255. case KEY_SPACE:
  256. {
  257. if( BitTest( mData2, KEY_STATE_UP ) )
  258. {
  259. //
  260. // note check like selected messages aren't sent here ... they are sent
  261. // on the down press
  262. //
  263. if( BitTest( instData->getState(), WIN_STATE_SELECTED ) &&
  264. BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  265. {
  266. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  267. (WindowMsgData)window, 0 );
  268. BitClear( instData->m_state, WIN_STATE_SELECTED );
  269. }
  270. }
  271. else
  272. {
  273. //
  274. // for 'check-like' buttons we have "dual state", we flip the selected status
  275. // in that case instead of just turning it on like normal ... also note
  276. // that selected messages are sent immediately
  277. //
  278. if( BitTest( window->winGetStatus(), WIN_STATUS_CHECK_LIKE ) )
  279. {
  280. if( BitTest( instData->m_state, WIN_STATE_SELECTED ) )
  281. BitClear( instData->m_state, WIN_STATE_SELECTED );
  282. else
  283. BitSet( instData->m_state, WIN_STATE_SELECTED );
  284. TheWindowManager->winSendSystemMsg( instData->getOwner(), GBM_SELECTED,
  285. (WindowMsgData)window, mData1 );
  286. } // end if
  287. else
  288. {
  289. // just select as normal
  290. BitSet( instData->m_state, WIN_STATE_SELECTED );
  291. } // end else
  292. } // end else
  293. break;
  294. } // end handle enter and space button
  295. // --------------------------------------------------------------------
  296. case KEY_DOWN:
  297. case KEY_RIGHT:
  298. case KEY_TAB:
  299. {
  300. if( BitTest( mData2, KEY_STATE_DOWN ) )
  301. TheWindowManager->winNextTab(window);
  302. break;
  303. } // end key down, right or tab
  304. // --------------------------------------------------------------------
  305. case KEY_UP:
  306. case KEY_LEFT:
  307. {
  308. if( BitTest( mData2, KEY_STATE_DOWN ) )
  309. TheWindowManager->winPrevTab(window);
  310. break;
  311. } // end key up or left
  312. // --------------------------------------------------------------------
  313. default:
  314. return MSG_IGNORED;
  315. } // end switch on char
  316. break;
  317. } // end character message
  318. // ------------------------------------------------------------------------
  319. default:
  320. return MSG_IGNORED;
  321. } // end switch( msg )
  322. return MSG_HANDLED;
  323. } // end GadgetPushButtonInput
  324. // GadgetPushButtonSystem =====================================================
  325. /** Handle system messages for push button */
  326. //=============================================================================
  327. WindowMsgHandledType GadgetPushButtonSystem( GameWindow *window, UnsignedInt msg,
  328. WindowMsgData mData1, WindowMsgData mData2 )
  329. {
  330. WinInstanceData *instData = window->winGetInstanceData();
  331. switch( msg )
  332. {
  333. // ------------------------------------------------------------------------
  334. case GGM_SET_LABEL:
  335. {
  336. // set text into the win instance text data field
  337. window->winSetText( *(UnicodeString*)mData1 );
  338. break;
  339. }
  340. // ------------------------------------------------------------------------
  341. case GWM_CREATE:
  342. break;
  343. // ------------------------------------------------------------------------
  344. case GWM_DESTROY:
  345. {
  346. PushButtonData *pData = (PushButtonData *)window->winGetUserData();
  347. if(pData)
  348. delete pData;
  349. window->winSetUserData(NULL);
  350. }
  351. break;
  352. // ------------------------------------------------------------------------
  353. case GWM_INPUT_FOCUS:
  354. if( mData1 == FALSE )
  355. BitClear( instData->m_state, WIN_STATE_HILITED );
  356. else
  357. BitSet( instData->m_state, WIN_STATE_HILITED );
  358. TheWindowManager->winSendSystemMsg( instData->getOwner(),
  359. GGM_FOCUS_CHANGE,
  360. (WindowMsgData)mData1,
  361. window->winGetWindowId() );
  362. if( mData1 == FALSE )
  363. *(Bool*)mData2 = FALSE;
  364. else
  365. *(Bool*)mData2 = TRUE;
  366. break;
  367. default:
  368. return MSG_IGNORED;
  369. } // end switch( msg )
  370. return MSG_HANDLED;
  371. } // end GadgetPushButtonSystem
  372. // ------------------------------------------------------------------------------------------------
  373. /** Set the visual status of a button to make it looked checked/unchecked ... DO NOT send
  374. * any actual button selected messages, this is ONLY VISUAL */
  375. // ------------------------------------------------------------------------------------------------
  376. void GadgetCheckLikeButtonSetVisualCheck( GameWindow *g, Bool checked )
  377. {
  378. // sanity
  379. if( g == NULL )
  380. return;
  381. // get instance data
  382. WinInstanceData *instData = g->winGetInstanceData();
  383. if( instData == NULL )
  384. return;
  385. // sanity, must be a check like button
  386. if( BitTest( g->winGetStatus(), WIN_STATUS_CHECK_LIKE ) == FALSE )
  387. {
  388. DEBUG_CRASH(( "GadgetCheckLikeButtonSetVisualCheck: Window is not 'CHECK-LIKE'\n" ));
  389. return;
  390. } // end if
  391. // set or clear the 'pushed' state
  392. if( instData )
  393. {
  394. if( checked == TRUE )
  395. BitSet( instData->m_state, WIN_STATE_SELECTED );
  396. else
  397. BitClear( instData->m_state, WIN_STATE_SELECTED );
  398. } // end if
  399. } // end GadgetCheckLikeButtonSetVisualCheck
  400. // ------------------------------------------------------------------------------------------------
  401. // ------------------------------------------------------------------------------------------------
  402. Bool GadgetCheckLikeButtonIsChecked( GameWindow *g )
  403. {
  404. // sanity
  405. if( g == NULL )
  406. return FALSE;
  407. // get instance data
  408. WinInstanceData *instData = g->winGetInstanceData();
  409. if( instData == NULL )
  410. return FALSE;
  411. // we just hold this "check like dual state thingie" using the selected state
  412. return BitTest( instData->m_state, WIN_STATE_SELECTED );
  413. } // end GadgetCheckLikeButtonIsChecked
  414. // ------------------------------------------------------------------------------------------------
  415. // ------------------------------------------------------------------------------------------------
  416. void GadgetButtonEnableCheckLike( GameWindow *g, Bool makeCheckLike, Bool initiallyChecked )
  417. {
  418. // sanity
  419. if( g == NULL )
  420. return;
  421. // get inst data
  422. WinInstanceData *instData = g->winGetInstanceData();
  423. if( instData == NULL )
  424. return;
  425. // make it check like
  426. if( makeCheckLike )
  427. g->winSetStatus( WIN_STATUS_CHECK_LIKE );
  428. else
  429. g->winClearStatus( WIN_STATUS_CHECK_LIKE );
  430. // set the initially checked "state"
  431. if( initiallyChecked )
  432. BitSet( instData->m_state, WIN_STATE_SELECTED );
  433. else
  434. BitClear( instData->m_state, WIN_STATE_SELECTED );
  435. } // end GadgetButtonEnableCheckLike
  436. // GadgetButtonSetText ========================================================
  437. /** Set the text for a push button */
  438. //=============================================================================
  439. void GadgetButtonSetText( GameWindow *g, UnicodeString text )
  440. {
  441. // sanity
  442. if( g == NULL )
  443. return;
  444. TheWindowManager->winSendSystemMsg( g, GGM_SET_LABEL, (WindowMsgData)&text, 0 );
  445. } // end GadgetButtonSetText
  446. PushButtonData * getNewPushButtonData( void )
  447. {
  448. PushButtonData *p = NEW PushButtonData;
  449. if(!p)
  450. return NULL;
  451. p->userData = NULL;
  452. p->drawBorder = FALSE;
  453. p->drawClock = NO_CLOCK;
  454. p->overlayImage = NULL;
  455. return p;
  456. }
  457. // GadgetButtonSetBorder ======================================================
  458. /** Set to draw the special borders in the game */
  459. //=============================================================================
  460. void GadgetButtonSetBorder( GameWindow *g, Color color, Bool drawBorder = TRUE )
  461. {
  462. if( g == NULL )
  463. return;
  464. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  465. if(!pData)
  466. {
  467. pData = getNewPushButtonData();
  468. }
  469. pData->drawBorder = drawBorder;
  470. pData->colorBorder = color;
  471. g->winSetUserData(pData);
  472. }
  473. // GadgetButtonDrawClock ======================================================
  474. /** Set to draw a rectClock on the button */
  475. //=============================================================================
  476. void GadgetButtonDrawClock( GameWindow *g, Int percent, Color color )
  477. {
  478. if( g == NULL )
  479. return;
  480. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  481. if(!pData)
  482. {
  483. pData = getNewPushButtonData();
  484. }
  485. pData->drawClock = NORMAL_CLOCK;
  486. pData->percentClock = percent;
  487. pData->colorClock = color;
  488. g->winSetUserData(pData);
  489. }
  490. // GadgetButtonDrawInverseClock ======================================================
  491. /** Set to draw an inversed rectClock on the button */
  492. //=============================================================================
  493. void GadgetButtonDrawInverseClock( GameWindow *g, Int percent, Color color )
  494. {
  495. if( g == NULL )
  496. return;
  497. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  498. if(!pData)
  499. {
  500. pData = getNewPushButtonData();
  501. }
  502. pData->drawClock = INVERSE_CLOCK;
  503. pData->percentClock = percent;
  504. pData->colorClock = color;
  505. g->winSetUserData(pData);
  506. }
  507. void GadgetButtonDrawOverlayImage( GameWindow *g, const Image *image )
  508. {
  509. if( g == NULL )
  510. return;
  511. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  512. if(!pData)
  513. {
  514. pData = getNewPushButtonData();
  515. }
  516. pData->overlayImage = image;
  517. g->winSetUserData(pData);
  518. }
  519. // GadgetButtonSetData ======================================================
  520. /** Sets random data that the user can contain on the button */
  521. //=============================================================================
  522. void GadgetButtonSetData(GameWindow *g, void *data)
  523. {
  524. if( g == NULL )
  525. return;
  526. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  527. if(!pData)
  528. {
  529. pData = getNewPushButtonData();
  530. }
  531. pData->userData = data;
  532. g->winSetUserData(pData);
  533. }
  534. // GadgetButtonGetData ======================================================
  535. /** Gets the random data the user had already set on the button */
  536. //=============================================================================
  537. void *GadgetButtonGetData(GameWindow *g)
  538. {
  539. if( g == NULL )
  540. return NULL;
  541. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  542. if(!pData)
  543. {
  544. return NULL;
  545. }
  546. return pData->userData;
  547. }
  548. void GadgetButtonSetAltSound(GameWindow *g, AsciiString altSound )
  549. {
  550. if(!g)
  551. return;
  552. PushButtonData *pData = (PushButtonData *)g->winGetUserData();
  553. if(!pData)
  554. {
  555. return;
  556. }
  557. pData->altSound = altSound;
  558. }