GadgetTextEntry.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  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: TextEntry.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: TextEntry.cpp
  36. //
  37. // Created: Colin Day, June 2001
  38. //
  39. // Desc: Text entry GUI gadget
  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/Language.h"
  47. #include "GameClient/DisplayStringManager.h"
  48. #include "GameClient/GameWindow.h"
  49. #include "GameClient/Gadget.h"
  50. #include "GameClient/GameWindowManager.h"
  51. #include "GameClient/IMEManager.h"
  52. // DEFINES ////////////////////////////////////////////////////////////////////
  53. // PRIVATE TYPES //////////////////////////////////////////////////////////////
  54. #ifdef _INTERNAL
  55. // for occasional debugging...
  56. //#pragma optimize("", off)
  57. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  58. #endif
  59. ///////////////////////////////////////////////////////////////////////////////
  60. // PRIVATE DATA ///////////////////////////////////////////////////////////////
  61. ///////////////////////////////////////////////////////////////////////////////
  62. static Byte drawCnt = 0;
  63. // static TbIME *ourIME = NULL; ///< @todo need this for IME kanji support
  64. static GameWindow *curWindow = NULL; /**< so we can keep track of the input
  65. window when using IME */
  66. // PUBLIC DATA ////////////////////////////////////////////////////////////////
  67. // PRIVATE PROTOTYPES /////////////////////////////////////////////////////////
  68. // PRIVATE FUNCTIONS //////////////////////////////////////////////////////////
  69. ///////////////////////////////////////////////////////////////////////////////
  70. // PUBLIC FUNCTIONS ///////////////////////////////////////////////////////////
  71. ///////////////////////////////////////////////////////////////////////////////
  72. // GadgetTextEntryInput =======================================================
  73. /** Handle input for text entry field */
  74. //=============================================================================
  75. WindowMsgHandledType GadgetTextEntryInput( GameWindow *window, UnsignedInt msg,
  76. WindowMsgData mData1, WindowMsgData mData2 )
  77. {
  78. EntryData *e = (EntryData *)window->winGetUserData();
  79. WinInstanceData *instData = window->winGetInstanceData();
  80. if ( TheIMEManager && TheIMEManager->isAttachedTo( window) && TheIMEManager->isComposing())
  81. {
  82. // ignore input while IME has focus
  83. return MSG_HANDLED;
  84. }
  85. switch( msg )
  86. {
  87. // ------------------------------------------------------------------------
  88. case GWM_IME_CHAR:
  89. {
  90. WideChar ch = (WideChar) mData1;
  91. // --------------------------------------------------------------------
  92. if ( ch == VK_RETURN )
  93. {
  94. // Done with this edit
  95. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  96. GEM_EDIT_DONE,
  97. (WindowMsgData)window,
  98. 0 );
  99. return MSG_HANDLED;
  100. };
  101. if( ch )
  102. {
  103. // Constrain keys based on rules for entry box.
  104. if( e->numericalOnly )
  105. {
  106. if( TheWindowManager->winIsDigit( ch ) == 0 )
  107. return MSG_HANDLED;
  108. }
  109. if( e->alphaNumericalOnly )
  110. {
  111. if( TheWindowManager->winIsAlNum( ch ) == 0 )
  112. return MSG_HANDLED;
  113. }
  114. if ( e->aSCIIOnly )
  115. {
  116. if ( TheWindowManager->winIsAscii( ch ) == 0 )
  117. {
  118. return MSG_HANDLED;
  119. }
  120. }
  121. if( e->charPos < e->maxTextLen-1 )
  122. {
  123. e->text->appendChar( ch );
  124. e->sText->appendChar( L'*' );
  125. e->charPos++;
  126. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  127. GEM_UPDATE_TEXT,
  128. (WindowMsgData)window,
  129. 0 );
  130. }
  131. }
  132. break;
  133. }
  134. // ------------------------------------------------------------------------
  135. case GWM_CHAR:
  136. if ( BitTest( mData2, KEY_STATE_DOWN ) && BitTest( mData2, KEY_STATE_ALT | KEY_STATE_CONTROL ) )
  137. {
  138. return MSG_IGNORED; // text extries shouldn't care about CTRL+* or ALT+*
  139. }
  140. switch( mData1 )
  141. {
  142. /*
  143. // --------------------------------------------------------------------
  144. case KEY_KPENTER:
  145. case KEY_ENTER:
  146. // Done with this edit
  147. if( BitTest( mData2, KEY_STATE_DOWN ) )
  148. {
  149. if( e->receivedUnichar == FALSE )
  150. {
  151. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  152. GEM_EDIT_DONE,
  153. (WindowMsgData)window,
  154. 0 );
  155. }
  156. }
  157. break;
  158. */
  159. // --------------------------------------------------------------------
  160. // Don't process these keys
  161. case KEY_ESC:
  162. case KEY_PGUP:
  163. case KEY_PGDN:
  164. case KEY_HOME:
  165. case KEY_END:
  166. case KEY_F1:
  167. case KEY_F2:
  168. case KEY_F3:
  169. case KEY_F4:
  170. case KEY_F5:
  171. case KEY_F6:
  172. case KEY_F7:
  173. case KEY_F8:
  174. case KEY_F9:
  175. case KEY_F10:
  176. case KEY_F11:
  177. case KEY_F12:
  178. case KEY_CAPS:
  179. case KEY_DEL:
  180. return MSG_IGNORED;
  181. // --------------------------------------------------------------------
  182. case KEY_DOWN:
  183. case KEY_RIGHT:
  184. case KEY_TAB:
  185. if( BitTest( mData2, KEY_STATE_DOWN ) )
  186. {
  187. GameWindow *parent;
  188. parent = window->winGetParent();
  189. if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
  190. parent = NULL;
  191. if(parent)
  192. TheWindowManager->winNextTab(parent);
  193. else
  194. TheWindowManager->winNextTab(window);
  195. }
  196. break;
  197. // --------------------------------------------------------------------
  198. case KEY_UP:
  199. case KEY_LEFT:
  200. if( BitTest( mData2, KEY_STATE_DOWN ) )
  201. {
  202. GameWindow *parent;
  203. parent = window->winGetParent();
  204. if(parent && !BitTest(parent->winGetStyle(), GWS_COMBO_BOX))
  205. parent = NULL;
  206. if(parent)
  207. TheWindowManager->winPrevTab(parent);
  208. else
  209. TheWindowManager->winPrevTab(window);
  210. }
  211. break;
  212. // --------------------------------------------------------------------
  213. case KEY_BACKSPACE:
  214. if( BitTest( mData2, KEY_STATE_DOWN ) )
  215. {
  216. // if conCharPos != 0 this will fall through to next case.
  217. // it should be noted that conCharPos can only != 0 in Jap & Kor
  218. if( e->conCharPos == 0 )
  219. {
  220. if( e->charPos > 0 )
  221. {
  222. e->text->removeLastChar();
  223. e->sText->removeLastChar();
  224. e->charPos--;
  225. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  226. GEM_UPDATE_TEXT,
  227. (WindowMsgData)window,
  228. 0 );
  229. } // end if
  230. }
  231. }
  232. break;
  233. } // end switch( mData1 )
  234. break;
  235. // ------------------------------------------------------------------------
  236. case GWM_LEFT_DOWN:
  237. BitSet( instData->m_state, WIN_STATE_HILITED );
  238. TheWindowManager->winSetFocus( window );
  239. break;
  240. // ------------------------------------------------------------------------
  241. case GWM_MOUSE_ENTERING:
  242. if (BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  243. {
  244. BitSet( instData->m_state, WIN_STATE_HILITED );
  245. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  246. GBM_MOUSE_ENTERING,
  247. (WindowMsgData)window, 0 );
  248. //TheWindowManager->winSetFocus( window );
  249. }
  250. break;
  251. // ------------------------------------------------------------------------
  252. case GWM_MOUSE_LEAVING:
  253. if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  254. {
  255. BitClear( instData->m_state, WIN_STATE_HILITED );
  256. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  257. GBM_MOUSE_LEAVING,
  258. (WindowMsgData)window, 0 );
  259. }
  260. break;
  261. // ------------------------------------------------------------------------
  262. case GWM_LEFT_DRAG:
  263. if( BitTest( instData->getStyle(), GWS_MOUSE_TRACK ) )
  264. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  265. GGM_LEFT_DRAG,
  266. (WindowMsgData)window, 0 );
  267. break;
  268. // ------------------------------------------------------------------------
  269. default:
  270. return MSG_IGNORED;
  271. } // end switch( msg )
  272. return MSG_HANDLED;
  273. } // end GadgetTextEntryInput
  274. // GadgetTextEntrySystem ======================================================
  275. /** Handle system messages for entry field */
  276. //=============================================================================
  277. WindowMsgHandledType GadgetTextEntrySystem( GameWindow *window, UnsignedInt msg,
  278. WindowMsgData mData1, WindowMsgData mData2 )
  279. {
  280. EntryData *e = (EntryData *)window->winGetUserData();
  281. WinInstanceData *instData = window->winGetInstanceData();
  282. switch( msg )
  283. {
  284. // ------------------------------------------------------------------------
  285. case GEM_GET_TEXT:
  286. *(UnicodeString*)mData2 = e->text->getText();
  287. break;
  288. // ------------------------------------------------------------------------
  289. case GEM_SET_TEXT:
  290. {
  291. const UnicodeString* ustr = (const UnicodeString*)mData1;
  292. e->text->setText( *ustr );
  293. e->charPos = ustr->getLength();
  294. e->constructText->setText( UnicodeString::TheEmptyString );
  295. e->conCharPos = 0;
  296. // set our secret text string to be filled with '*' the same length
  297. e->sText->setText( UnicodeString::TheEmptyString );
  298. Int len = ustr->getLength();
  299. for( Int i = 0; i < len; i++ )
  300. e->sText->appendChar( L'*' );
  301. break;
  302. } // end set text
  303. // ------------------------------------------------------------------------
  304. case GWM_CREATE:
  305. break;
  306. // ------------------------------------------------------------------------
  307. case GWM_DESTROY:
  308. // delete the edit display string
  309. TheDisplayStringManager->freeDisplayString( e->text );
  310. TheDisplayStringManager->freeDisplayString( e->sText );
  311. TheDisplayStringManager->freeDisplayString( e->constructText );
  312. // delete construct list
  313. if( e->constructList )
  314. TheWindowManager->winDestroy( e->constructList );
  315. // free all edit data
  316. delete( (EntryData *)window->winGetUserData() );
  317. break;
  318. // ------------------------------------------------------------------------
  319. case GWM_INPUT_FOCUS:
  320. if( mData1 == FALSE )
  321. {
  322. // If we're losing focus
  323. /// @todo need to enable this for IME support
  324. // ourIME->UnActivate();
  325. curWindow = NULL;
  326. BitClear( instData->m_state, WIN_STATE_SELECTED );
  327. BitClear( instData->m_state, WIN_STATE_HILITED );
  328. if( e->constructList )
  329. e->constructList->winHide( TRUE );
  330. e->constructText->setText( UnicodeString::TheEmptyString );
  331. e->conCharPos = 0;
  332. if(TheIMEManager && TheIMEManager->isAttachedTo(window))
  333. TheIMEManager->attach(NULL);
  334. //TheIMEManager->detatch();
  335. }
  336. else
  337. {
  338. curWindow = window;
  339. /// @todo need to enable this for IME support
  340. if (TheIMEManager)
  341. TheIMEManager->attach( window );
  342. // ourIME->Activate( (void *)ApplicationHWnd );
  343. BitSet( instData->m_state, WIN_STATE_SELECTED );
  344. BitSet( instData->m_state, WIN_STATE_HILITED );
  345. }
  346. TheWindowManager->winSendSystemMsg( window->winGetOwner(),
  347. GGM_FOCUS_CHANGE,
  348. mData1,
  349. window->winGetWindowId() );
  350. *(Bool*)mData2 = TRUE;
  351. break;
  352. default:
  353. return MSG_IGNORED;
  354. } // end switch( msg )
  355. return MSG_HANDLED;
  356. } // end GadgetTextEntrySystem
  357. /** @todo we might want to do something like this if we use IME for language
  358. * support in this product */
  359. /*
  360. // used to create interface to IME
  361. BoolCode InitializeEntryGadget( void )
  362. {
  363. ourIME = NEW TbIME;
  364. ourIME->Composition_SetMaxLength( 11 );
  365. return TRUE;
  366. }
  367. // used to destroy interface to IME
  368. BoolCode ShutdownEntryGadget( void )
  369. {
  370. delete ourIME;
  371. ourIME = NULL;
  372. return TRUE;
  373. }
  374. void InformEntry( WideChar c )
  375. {
  376. Int i, listCount = 0;
  377. EntryData *e;
  378. if( ourIME == NULL || curWindow == NULL )
  379. return;
  380. e = (EntryData *)curWindow->winGetUserData();
  381. if( ( (OurLanguage == LANGUAGE_ID_JAPANESE) ||
  382. (OurLanguage == LANGUAGE_ID_KOREAN) ) &&
  383. ( (e->aSCIIOnly == FALSE ) &&
  384. (e->alphaNumericalOnly == FALSE ) &&
  385. (e->numericalOnly == FALSE ) ) )
  386. {
  387. e->receivedUnichar = TRUE;
  388. // we must eat the following keys
  389. switch( c )
  390. {
  391. case L'\a':
  392. case L'\b':
  393. case L'\f':
  394. case L'\t':
  395. case L'\v':
  396. return;
  397. // we must completely ignore the return key
  398. case L'\r':
  399. case L'\n':
  400. e->receivedUnichar = FALSE;
  401. return;
  402. }
  403. if( e->charPos < e->maxTextLen-1 )
  404. {
  405. e->text[ e->charPos++ ] = c;
  406. e->text[ e->charPos ] = 0;
  407. }
  408. // always update the construction buffer after a key has come through here.
  409. TheWindowManager->winStrcpy( e->constructText, (WideChar *)ourIME->Composition_Get() );
  410. e->conCharPos = NoxStrlen( e->constructText );
  411. // we might need to update our listbox
  412. listCount = ourIME->CandidateList_GetSize();
  413. if( TRUE ) //listCount == 0)
  414. {
  415. // if no entries just hide it and leave
  416. if( e->constructList )
  417. e->constructList->winHide( TRUE );
  418. }
  419. else
  420. {
  421. Int maxWidth = 0;
  422. ListboxData list = NULL;
  423. ICoord2D constructSize, sliderSize;
  424. WinHide( e->constructList, FALSE );
  425. list = (ListBoxData)e->constructList->winGetUserData();
  426. e->constructList->winGetSize( &constructSize.x, &constructSize.y );
  427. list->slider->winGetSize( &sliderSize.x, &sliderSize.y );
  428. TheWindowManager->winSendSystemMsg( e->constructList, GLM_DEL_ALL, 0, 0 );
  429. for( i=0; i<listCount; i++ )
  430. {
  431. Int tempWidth;
  432. WideChar *text = (WideChar *)ourIME->CandidateList_GetItem( i );
  433. TheWindowManager->winGetTextSize( e->constructList->instData.font,
  434. text, NULL, &tempWidth, 0 );
  435. if( tempWidth > maxWidth )
  436. maxWidth = tempWidth;
  437. UnicodeString tmp(text);
  438. TheWindowManager->winSendSystemMsg( e->constructList, GLM_ADD_ENTRY,
  439. (WindowMsgData)&tmp, -1 );
  440. }
  441. e->constructList->winSetSize( maxWidth + sliderSize.y,
  442. constructSize.y );
  443. }
  444. }
  445. }
  446. */
  447. // GadgetTextEntrySetFont =====================================================
  448. /** Set the font for a text entry control, we need to set the window
  449. * text font, the tooltip font, and the edit text display strings for
  450. * the text data itself and the secret text */
  451. //=============================================================================
  452. void GadgetTextEntrySetFont( GameWindow *g, GameFont *font )
  453. {
  454. EntryData *entryData = (EntryData *)g->winGetUserData();
  455. DisplayString *dString;
  456. // set the font for the display strings all windows have
  457. dString = g->winGetInstanceData()->getTextDisplayString();
  458. if( dString )
  459. dString->setFont( font );
  460. dString = g->winGetInstanceData()->getTooltipDisplayString();
  461. if( dString )
  462. dString->setFont( font );
  463. // text entry specific
  464. if( entryData )
  465. {
  466. dString = entryData->text;
  467. if( dString )
  468. dString->setFont( font );
  469. dString = entryData->sText;
  470. if( dString )
  471. dString->setFont( font );
  472. } // end if
  473. } // end GadgetTextEntrySetFont
  474. // GadgetTextEntryGetText =======================================================
  475. /** Get the text for a Text entry */
  476. //=============================================================================
  477. UnicodeString GadgetTextEntryGetText( GameWindow *textentry )
  478. {
  479. // sanity
  480. if( textentry == NULL )
  481. return UnicodeString::TheEmptyString;
  482. // verify that this is a list box
  483. if( BitTest( textentry->winGetStyle(), GWS_ENTRY_FIELD ) == FALSE )
  484. return UnicodeString::TheEmptyString;
  485. UnicodeString result;
  486. TheWindowManager->winSendSystemMsg( textentry, GEM_GET_TEXT, 0, (WindowMsgData)&result );
  487. return result;
  488. } // end GadgetListBoxGetText