ExtendedMessageBox.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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: ExtendedMessageBox.cpp ///////////////////////////////////////////////////////////////////
  24. // Author: Matt Campbell, January 2003
  25. // Description: We go quiet in 1 day, gold in 15. Poor time to rewrite message boxes, so
  26. // we get this file instead. Phooey.
  27. ///////////////////////////////////////////////////////////////////////////////////////////////////
  28. // SYSTEM INCLUDES ////////////////////////////////////////////////////////////
  29. // USER INCLUDES //////////////////////////////////////////////////////////////
  30. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  31. #include "Common/GameEngine.h"
  32. #include "Common/NameKeyGenerator.h"
  33. #include "GameClient/WindowLayout.h"
  34. #include "GameClient/Gadget.h"
  35. #include "GameClient/Shell.h"
  36. #include "GameClient/KeyDefs.h"
  37. #include "GameClient/GadgetStaticText.h"
  38. #include "GameClient/GameWindowManager.h"
  39. #include "GameClient/ExtendedMessageBox.h"
  40. WindowMsgHandledType ExtendedMessageBoxSystem( GameWindow *window, UnsignedInt msg,
  41. WindowMsgData mData1, WindowMsgData mData2 );
  42. //-------------------------------------------------------------------------------------------------
  43. /** Create an extended Modal Message Box */
  44. //-------------------------------------------------------------------------------------------------
  45. static GameWindow *gogoExMessageBox(Int x, Int y, Int width, Int height, UnsignedShort buttonFlags,
  46. UnicodeString titleString, UnicodeString bodyString, void *userData,
  47. MessageBoxFunc yesCallback,
  48. MessageBoxFunc noCallback,
  49. MessageBoxFunc okCallback,
  50. MessageBoxFunc cancelCallback )
  51. {
  52. // first check to make sure we have some buttons to display
  53. if(buttonFlags == 0 )
  54. {
  55. return NULL;
  56. }
  57. GameWindow *parent = TheWindowManager->winCreateFromScript( AsciiString("Menus/MessageBox.wnd") );
  58. TheWindowManager->winSetModal( parent );
  59. TheWindowManager->winSetFocus( NULL ); // make sure we lose focus from other windows even if we refuse focus ourselves
  60. TheWindowManager->winSetFocus( parent );
  61. // If the user wants the size to be different then the default
  62. float ratioX, ratioY = 1;
  63. if( width > 0 && height > 0 )
  64. {
  65. ICoord2D temp;
  66. //First grab the percent increase/decrease compaired to the default size
  67. parent->winGetSize( &temp.x, &temp.y);
  68. ratioX = (float)width / (float)temp.x;
  69. ratioY = (float)height / (float)temp.y;
  70. //Set the window's new size
  71. parent->winSetSize( width, height);
  72. //Resize/reposition all the children windows based off the ratio
  73. GameWindow *child;
  74. for( child = parent->winGetChild(); child; child = child->winGetNext() )
  75. {
  76. child->winGetSize(&temp.x, &temp.y);
  77. temp.x =Int(temp.x * ratioX);
  78. temp.y =Int(temp.y * ratioY);
  79. child->winSetSize(temp.x, temp.y);
  80. child->winGetPosition(&temp.x, &temp.y);
  81. temp.x =Int(temp.x * ratioX);
  82. temp.y =Int(temp.y * ratioY);
  83. child->winSetPosition(temp.x, temp.y);
  84. }
  85. }
  86. // If the user wants to position the message box somewhere other then default
  87. if( x >= 0 && y >= 0)
  88. parent->winSetPosition(x, y);
  89. // Reposition the buttons
  90. Int buttonX[3], buttonY[3];
  91. //In the layout, buttonOk will be in the first button position
  92. NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonOk" ) );
  93. GameWindow *buttonOk = TheWindowManager->winGetWindowFromId(parent, buttonOkID);
  94. buttonOk->winGetPosition(&buttonX[0], &buttonY[0]);
  95. NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonYes" ) );
  96. GameWindow *buttonYes = TheWindowManager->winGetWindowFromId(parent, buttonYesID);
  97. //buttonNo in the second position
  98. NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonNo" ) );
  99. GameWindow *buttonNo = TheWindowManager->winGetWindowFromId(parent, buttonNoID);
  100. buttonNo->winGetPosition(&buttonX[1], &buttonY[1]);
  101. //and buttonCancel in the third
  102. NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonCancel" ) );
  103. GameWindow *buttonCancel = TheWindowManager->winGetWindowFromId(parent, buttonCancelID);
  104. buttonCancel->winGetPosition(&buttonX[2], &buttonY[2]);
  105. //we shouldn't have button OK and Yes on the same dialog
  106. if((buttonFlags & (MSG_BOX_OK | MSG_BOX_YES)) == (MSG_BOX_OK | MSG_BOX_YES) )
  107. {
  108. DEBUG_ASSERTCRASH(false, ("Passed in MSG_BOX_OK and MSG_BOX_YES. Big No No."));
  109. }
  110. //Position the OK button if we have one
  111. if( (buttonFlags & MSG_BOX_OK) == MSG_BOX_OK)
  112. {
  113. buttonOk->winSetPosition(buttonX[0], buttonY[0]);
  114. buttonOk->winHide(FALSE);
  115. }
  116. else if( (buttonFlags & MSG_BOX_YES) == MSG_BOX_YES)
  117. {
  118. //Position the Yes if we have one
  119. buttonYes->winSetPosition(buttonX[0], buttonY[0]);
  120. buttonYes->winHide(FALSE);
  121. }
  122. if((buttonFlags & (MSG_BOX_NO | MSG_BOX_CANCEL)) == (MSG_BOX_NO | MSG_BOX_CANCEL) )
  123. {
  124. //If we have both the No and Cancel button, then the no should go in the middle position
  125. buttonNo->winSetPosition(buttonX[1], buttonY[1]);
  126. buttonCancel->winSetPosition(buttonX[2], buttonY[2]);
  127. buttonNo->winHide(FALSE);
  128. buttonCancel->winHide(FALSE);
  129. }
  130. else if( (buttonFlags & MSG_BOX_NO) == MSG_BOX_NO)
  131. {
  132. //if we just have the no button, then position it in the right most spot
  133. buttonNo->winSetPosition(buttonX[2], buttonY[2]);
  134. buttonNo->winHide(FALSE);
  135. }
  136. else if( (buttonFlags & MSG_BOX_CANCEL) == MSG_BOX_CANCEL)
  137. {
  138. //else if we just have the Cancel button, well, it should always go in the right spot
  139. buttonCancel->winSetPosition(buttonX[2], buttonY[2]);
  140. buttonCancel->winHide(FALSE);
  141. }
  142. // Fill the text into the text boxes
  143. NameKeyType staticTextTitleID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:StaticTextTitle" ) );
  144. GameWindow *staticTextTitle = TheWindowManager->winGetWindowFromId(parent, staticTextTitleID);
  145. GadgetStaticTextSetText(staticTextTitle,titleString);
  146. NameKeyType staticTextMessageID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:StaticTextMessage" ) );
  147. GameWindow *staticTextMessage = TheWindowManager->winGetWindowFromId(parent, staticTextMessageID);
  148. GadgetStaticTextSetText(staticTextMessage,bodyString);
  149. // create a structure that will pass the functions to
  150. WindowExMessageBoxData *MsgBoxCallbacks = NEW WindowExMessageBoxData;
  151. MsgBoxCallbacks->cancelCallback = cancelCallback;
  152. MsgBoxCallbacks->noCallback = noCallback;
  153. MsgBoxCallbacks->okCallback = okCallback;
  154. MsgBoxCallbacks->yesCallback = yesCallback;
  155. MsgBoxCallbacks->userData = userData;
  156. //pass the structure to the dialog
  157. parent->winSetUserData( MsgBoxCallbacks );
  158. parent->winSetSystemFunc(ExtendedMessageBoxSystem);
  159. //make sure the dialog is showing and bring it to the top
  160. parent->winHide(FALSE);
  161. parent->winBringToTop();
  162. return parent;
  163. }// gogoExMessageBox
  164. GameWindow *ExMessageBoxYesNo (UnicodeString titleString,UnicodeString bodyString, void *userData,
  165. MessageBoxFunc yesCallback, MessageBoxFunc noCallback)
  166. {
  167. return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES , titleString, bodyString, userData, yesCallback, noCallback, NULL, NULL);
  168. }
  169. GameWindow *ExMessageBoxYesNoCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
  170. MessageBoxFunc yesCallback, MessageBoxFunc noCallback, MessageBoxFunc cancelCallback)
  171. {
  172. return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_NO | MSG_BOX_YES | MSG_BOX_CANCEL , titleString, bodyString, userData, yesCallback, noCallback, NULL, cancelCallback);
  173. }
  174. GameWindow *ExMessageBoxOkCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
  175. MessageBoxFunc okCallback, MessageBoxFunc cancelCallback)
  176. {
  177. return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_OK | MSG_BOX_CANCEL , titleString, bodyString, userData, NULL, NULL, okCallback, cancelCallback);
  178. }
  179. GameWindow *ExMessageBoxOk (UnicodeString titleString,UnicodeString bodyString, void *userData,
  180. MessageBoxFunc okCallback)
  181. {
  182. return gogoExMessageBox(-1,-1,-1,-1,MSG_BOX_OK, titleString, bodyString, userData, NULL, NULL, okCallback, NULL);
  183. }
  184. GameWindow *ExMessageBoxCancel (UnicodeString titleString,UnicodeString bodyString, void *userData,
  185. MessageBoxFunc cancelCallback)
  186. {
  187. return gogoExMessageBox(-1,-1,-1,-1, MSG_BOX_CANCEL, titleString, bodyString, userData, NULL, NULL, NULL, cancelCallback);
  188. }
  189. // PRIVATE DATA ///////////////////////////////////////////////////////////////////////////////////
  190. //-------------------------------------------------------------------------------------------------
  191. /** Message Box window system callback */
  192. //-------------------------------------------------------------------------------------------------
  193. WindowMsgHandledType ExtendedMessageBoxSystem( GameWindow *window, UnsignedInt msg,
  194. WindowMsgData mData1, WindowMsgData mData2 )
  195. {
  196. switch( msg )
  197. {
  198. //---------------------------------------------------------------------------------------------
  199. case GWM_DESTROY:
  200. {
  201. delete (WindowExMessageBoxData *)window->winGetUserData();
  202. window->winSetUserData( NULL );
  203. break;
  204. } // end case
  205. // --------------------------------------------------------------------------------------------
  206. case GWM_INPUT_FOCUS:
  207. {
  208. // if we're givin the opportunity to take the keyboard focus we must say we want it
  209. if( mData1 == TRUE )
  210. *(Bool *)mData2 = TRUE;
  211. break;
  212. } // end input
  213. //---------------------------------------------------------------------------------------------
  214. case GBM_SELECTED:
  215. {
  216. GameWindow *control = (GameWindow *)mData1;
  217. Int controlID = control->winGetWindowId();
  218. static NameKeyType buttonOkID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonOk" ) );
  219. static NameKeyType buttonYesID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonYes" ) );
  220. static NameKeyType buttonNoID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonNo" ) );
  221. static NameKeyType buttonCancelID = TheNameKeyGenerator->nameToKey( AsciiString( "MessageBox.wnd:ButtonCancel" ) );
  222. WindowExMessageBoxData *MsgBoxCallbacks = (WindowExMessageBoxData *)window->winGetUserData();
  223. MessageBoxReturnType ret = MB_RETURN_CLOSE;
  224. if( controlID == buttonOkID )
  225. {
  226. if (MsgBoxCallbacks->okCallback)
  227. ret = MsgBoxCallbacks->okCallback(MsgBoxCallbacks->userData);
  228. } // end if
  229. else if( controlID == buttonYesID )
  230. {
  231. if (MsgBoxCallbacks->yesCallback)
  232. ret = MsgBoxCallbacks->yesCallback(MsgBoxCallbacks->userData);
  233. } // end else if
  234. else if( controlID == buttonNoID )
  235. {
  236. if (MsgBoxCallbacks->noCallback)
  237. ret = MsgBoxCallbacks->noCallback(MsgBoxCallbacks->userData);
  238. } // end else if
  239. else if( controlID == buttonCancelID )
  240. {
  241. if (MsgBoxCallbacks->cancelCallback)
  242. ret = MsgBoxCallbacks->cancelCallback(MsgBoxCallbacks->userData);
  243. } // end else if
  244. if (ret == MB_RETURN_CLOSE)
  245. TheWindowManager->winDestroy(window);
  246. break;
  247. } // end selected
  248. //---------------------------------------------------------------------------------------------
  249. default:
  250. return MSG_IGNORED;
  251. } // end switch
  252. return MSG_HANDLED;
  253. } // end ExtendedMessageBoxSystem