MSGBOX.CPP 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. /*
  2. ** Command & Conquer Red Alert(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. /* $Header: /CounterStrike/MSGBOX.CPP 1 3/03/97 10:25a Joe_bostic $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : OPTIONS.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : June 8, 1994 *
  30. * *
  31. * Last Update : August 24, 1995 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * WWMessageBox::Process -- Handles all the options graphic interface. *
  36. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  37. #include "function.h"
  38. #include "msgbox.h"
  39. #include "gadget.h"
  40. #ifdef FIXIT_VERSION_3
  41. bool cancel_current_msgbox = false;
  42. #endif
  43. /***********************************************************************************************
  44. * WWMessageBox::Process -- pops up a message with yes/no, etc *
  45. * *
  46. * This function displays a dialog box with a one-line message, and *
  47. * up to two buttons. The 2nd button is optional. The buttons default *
  48. * to "OK" and nothing, respectively. The hotkeys for the buttons are *
  49. * RETURN and ESCAPE. *
  50. * *
  51. * INPUT: *
  52. * msg message to display *
  53. * b1txt text for 1st button *
  54. * b2txt text for 2nd button; NULL = no 2nd button *
  55. * *
  56. * OUTPUT: *
  57. * # of button selected (0 = 1st) *
  58. * *
  59. * WARNINGS: *
  60. * 'msg' text must be <= 38 chars *
  61. * 'b1txt' and 'b2txt' must each be <= 18 chars *
  62. * *
  63. * HISTORY: *
  64. * 11/08/1994 BR : Created. *
  65. * 05/18/1995 JLB : Uses new font and dialog style. *
  66. * 08/24/1995 JLB : Handles three buttons. *
  67. *=============================================================================================*/
  68. #define BUTTON_1 1
  69. #define BUTTON_2 2
  70. #define BUTTON_3 3
  71. #define BUTTON_FLAG 0x8000
  72. int WWMessageBox::Process(const char * msg, const char * b1txt, const char * b2txt, const char * b3txt, bool preserve)
  73. {
  74. #define BUFFSIZE (511)
  75. char buffer[BUFFSIZE];
  76. bool retval;
  77. bool process; // loop while true
  78. int selection;
  79. bool pressed;
  80. int curbutton;
  81. TextButtonClass * buttons[3];
  82. void * back;
  83. BOOL display; // display level
  84. int realval[5];
  85. #ifndef WIN32
  86. int preservex,preservey,preservew,preserveh;
  87. #endif
  88. #ifdef WIN32
  89. GraphicBufferClass seen_buff_save(VisiblePage.Get_Width(), VisiblePage.Get_Height(), (void*)NULL);
  90. #endif
  91. if (b1txt != NULL && *b1txt == '\0') b1txt = NULL;
  92. if (b2txt != NULL && *b2txt == '\0') b2txt = NULL;
  93. if (b3txt != NULL && *b3txt == '\0') b3txt = NULL;
  94. Fancy_Text_Print(TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT);
  95. /*
  96. ** Examine the optional button parameters. Fetch the width and starting
  97. ** characters for each.
  98. */
  99. int bwidth, bheight; // button width and height
  100. int numbuttons = 0;
  101. if (b1txt != NULL) {
  102. /*
  103. ** Build the button list.
  104. */
  105. bheight = FontHeight + FontYSpacing + (2 * RESFACTOR);
  106. bwidth = max((String_Pixel_Width(b1txt) + (8 * RESFACTOR)), (30 * RESFACTOR));
  107. if (b2txt != NULL) {
  108. numbuttons = 2;
  109. bwidth = max((String_Pixel_Width( b2txt ) + (8 * RESFACTOR)), bwidth);
  110. if (b3txt != NULL) {
  111. numbuttons = 3;
  112. }
  113. } else {
  114. numbuttons = 1;
  115. }
  116. }
  117. /*
  118. ** Determine the dimensions of the text to be used for the dialog box.
  119. ** These dimensions will control how the dialog box looks.
  120. */
  121. buffer[BUFFSIZE-1] = 0;
  122. strncpy(buffer, msg, BUFFSIZE-1);
  123. Fancy_Text_Print(TXT_NONE, 0, 0, TBLACK, TBLACK, TPF_TEXT);
  124. int width;
  125. int height;
  126. int lines = Format_Window_String(buffer, 255 * RESFACTOR, width, height);
  127. TextPrintType tpf = TPF_TEXT;
  128. width = max(width, (90 * RESFACTOR));
  129. width += 40 * RESFACTOR;
  130. height += (numbuttons == 0) ? (40 * RESFACTOR) : (60 * RESFACTOR);
  131. int x = (SeenBuff.Get_Width() - width) / 2;
  132. int y = (SeenBuff.Get_Height() - height) / 2;
  133. int printx = x + (20 * RESFACTOR);
  134. /*
  135. ** Special hack to center a one line dialog box text.
  136. */
  137. if (lines == 1) {
  138. printx = x + width/2;
  139. tpf = tpf | TPF_CENTER;
  140. }
  141. /*
  142. ** Other inits.
  143. */
  144. Set_Logic_Page(SeenBuff);
  145. #ifdef WIN32
  146. VisiblePage.Blit(seen_buff_save);
  147. #endif
  148. /*
  149. ** Initialize the button structures. All are initialized, even though one (or none) may
  150. ** actually be added to the button list.
  151. */
  152. //DOS BUILD GERMAN BUTTONS NEED TO ONE ON TOP OF THE OTHER VG 11/6/96
  153. TextButtonClass button1(BUTTON_1, b1txt, TPF_BUTTON,
  154. x + ((numbuttons == 1) ? ((width - bwidth) >> 1) : (20 * RESFACTOR)), y + height - (bheight + (15 * RESFACTOR)), bwidth);
  155. /*
  156. ** Center button.
  157. */
  158. TextButtonClass button2(BUTTON_2, b2txt, TPF_BUTTON,
  159. x + width - (bwidth + (20 * RESFACTOR)), y + height - (bheight + (15 * RESFACTOR)), bwidth);
  160. /*
  161. ** Right button.
  162. */
  163. TextButtonClass button3(BUTTON_3, b3txt, TPF_BUTTON, 0, y + height - (bheight + (15 * RESFACTOR)));
  164. button3.X = x + ((width - button3.Width) >> 1);
  165. TextButtonClass * buttonlist = 0;
  166. curbutton = 0;
  167. /*
  168. ** Add and initialize the buttons to the button list.
  169. */
  170. memset(buttons, '\0', sizeof(buttons));
  171. if (numbuttons > 0) {
  172. buttonlist = &button1;
  173. buttons[0] = &button1;
  174. realval[0] = BUTTON_1;
  175. if (numbuttons > 2) {
  176. button3.Add(*buttonlist);
  177. buttons[1] = &button3;
  178. realval[1] = BUTTON_3;
  179. button2.Add(*buttonlist);
  180. buttons[2] = &button2;
  181. realval[2] = BUTTON_2;
  182. buttons[curbutton]->Turn_On();
  183. } else {
  184. if (numbuttons == 2) {
  185. button2.Add(*buttonlist);
  186. buttons[1] = &button2;
  187. realval[1] = BUTTON_2;
  188. buttons[curbutton]->Turn_On();
  189. }
  190. }
  191. }
  192. /*
  193. ** Draw the dialog.
  194. */
  195. Hide_Mouse();
  196. if (preserve) {
  197. #ifndef WIN32
  198. preservex = max(0, x-4);
  199. preservey = max(0, y-4);
  200. preservew = min(width+8, 320-preservex);
  201. preserveh = min(height+8, 200-preservey);
  202. back = new char[preservew * preserveh];
  203. SeenBuff.To_Buffer(preservex, preservey, preservew, preserveh, back, preservew * preserveh);
  204. #else
  205. back = new char[width * height];
  206. SeenBuff.To_Buffer(x, y, width, height, back, width * height);
  207. #endif
  208. }
  209. Dialog_Box(x, y, width, height);
  210. Draw_Caption(Caption, x, y, width);
  211. /*
  212. ** Draw the body of the message.
  213. */
  214. Fancy_Text_Print(buffer, printx, y + 20*RESFACTOR, GadgetClass::Get_Color_Scheme(), TBLACK, tpf);
  215. /*
  216. ** Redraw the buttons.
  217. */
  218. if (buttonlist) {
  219. buttonlist->Draw_All();
  220. }
  221. Show_Mouse();
  222. /*
  223. ** Main Processing Loop.
  224. */
  225. if (buttonlist) {
  226. process = true;
  227. pressed = false;
  228. while (process) {
  229. #ifdef WIN32
  230. /*
  231. ** If we have just received input focus again after running in the background then
  232. ** we need to redraw.
  233. */
  234. if (AllSurfaces.SurfacesRestored) {
  235. AllSurfaces.SurfacesRestored = false;
  236. seen_buff_save.Blit(VisiblePage);
  237. display = true;
  238. }
  239. #endif
  240. if (display) {
  241. display = false;
  242. Hide_Mouse();
  243. Dialog_Box(x, y, width, height);
  244. Draw_Caption(Caption, x, y, width);
  245. /*
  246. ** Draw the body of the message.
  247. */
  248. Fancy_Text_Print(buffer, printx, y + 20*RESFACTOR, GadgetClass::Get_Color_Scheme(), TBLACK, tpf);
  249. /*
  250. ** Redraw the buttons.
  251. */
  252. if (buttonlist) {
  253. buttonlist->Draw_All();
  254. }
  255. Show_Mouse();
  256. }
  257. /*
  258. ** Invoke game callback.
  259. */
  260. Call_Back();
  261. /*
  262. ** Fetch and process input.
  263. */
  264. KeyNumType input = buttonlist->Input();
  265. #ifdef FIXIT_VERSION_3
  266. // I really hate to do this, but... ajw
  267. if( cancel_current_msgbox )
  268. {
  269. cancel_current_msgbox = false;
  270. input = KN_ESC;
  271. }
  272. #endif
  273. switch (input) {
  274. case (KN_ESC):
  275. selection = realval[numbuttons-1];
  276. pressed = true;
  277. #ifdef NEVER
  278. if (numbuttons > 2) {
  279. selection = realval[1];
  280. pressed = true;
  281. } else {
  282. selection = realval[2];
  283. pressed = true;
  284. }
  285. #endif
  286. break;
  287. case (BUTTON_1|BUTTON_FLAG):
  288. selection = realval[0];
  289. pressed = true;
  290. break;
  291. case (BUTTON_2|BUTTON_FLAG):
  292. if (numbuttons > 2) {
  293. selection = realval[2];
  294. } else {
  295. selection = realval[1];
  296. }
  297. pressed = true;
  298. break;
  299. case (BUTTON_3|BUTTON_FLAG):
  300. selection = realval[1];
  301. pressed = true;
  302. break;
  303. case (KN_LEFT):
  304. if (numbuttons > 1) {
  305. buttons[curbutton]->Turn_Off();
  306. buttons[curbutton]->Flag_To_Redraw();
  307. curbutton--;
  308. if (curbutton < 0) {
  309. curbutton = numbuttons - 1;
  310. }
  311. buttons[curbutton]->Turn_On();
  312. buttons[curbutton]->Flag_To_Redraw();
  313. }
  314. break;
  315. case (KN_RIGHT):
  316. if (numbuttons > 1) {
  317. buttons[curbutton]->Turn_Off();
  318. buttons[curbutton]->Flag_To_Redraw();
  319. curbutton++;
  320. if (curbutton > (numbuttons - 1) ) {
  321. curbutton = 0;
  322. }
  323. buttons[curbutton]->Turn_On();
  324. buttons[curbutton]->Flag_To_Redraw();
  325. }
  326. break;
  327. case (KN_RETURN):
  328. selection = realval[curbutton];
  329. pressed = true;
  330. break;
  331. /*
  332. ** Check 'input' to see if it's the 1st char of button text
  333. */
  334. default:
  335. break;
  336. }
  337. if (pressed) {
  338. TextButtonClass * toggle;
  339. /*
  340. ** Turn all the buttons off.
  341. */
  342. toggle = (TextButtonClass *)buttonlist->Extract_Gadget(BUTTON_1);
  343. if (toggle != NULL) {
  344. toggle->Turn_Off();
  345. toggle->IsPressed = false;
  346. }
  347. toggle = (TextButtonClass *)buttonlist->Extract_Gadget(BUTTON_2);
  348. if (toggle != NULL) {
  349. toggle->Turn_Off();
  350. toggle->IsPressed = false;
  351. }
  352. toggle = (TextButtonClass *)buttonlist->Extract_Gadget(BUTTON_3);
  353. if (toggle != NULL) {
  354. toggle->Turn_Off();
  355. toggle->IsPressed = false;
  356. }
  357. /*
  358. ** Turn on and depress the button that was selected.
  359. */
  360. if (selection == BUTTON_1 || selection == BUTTON_2 || selection == BUTTON_3) {
  361. TextButtonClass * toggle = (TextButtonClass *)buttonlist->Extract_Gadget(selection);
  362. if (toggle != NULL) {
  363. toggle->Turn_On();
  364. // toggle->IsOn = true;
  365. toggle->IsPressed = true;
  366. }
  367. }
  368. Hide_Mouse();
  369. buttonlist->Draw_All(true);
  370. Show_Mouse();
  371. switch (selection) {
  372. case (BUTTON_1):
  373. retval = 0;
  374. process = false;
  375. break;
  376. case (BUTTON_2):
  377. retval = 1;
  378. process = false;
  379. break;
  380. case BUTTON_3:
  381. retval = 2;
  382. process = false;
  383. break;
  384. }
  385. pressed = false;
  386. }
  387. }
  388. } else {
  389. Keyboard->Clear();
  390. }
  391. /*
  392. ** Restore the screen if necessary.
  393. */
  394. if (preserve) {
  395. Hide_Mouse();
  396. if (SeenBuff.Lock()) {
  397. #ifdef WIN32
  398. Buffer_To_Page(x, y, width, height, back, &SeenBuff);
  399. #else
  400. MCGA_Buffer_To_Page(preservex, preservey, preservew, preserveh, back, &SeenBuff);
  401. #endif
  402. }
  403. SeenBuff.Unlock();
  404. delete[] back;
  405. back = NULL;
  406. Show_Mouse();
  407. }
  408. return(retval);
  409. }
  410. /***********************************************************************************************
  411. * WWMessageBox::Process -- this one takes integer text arguments *
  412. * *
  413. * INPUT: *
  414. * msg message to display *
  415. * b1txt text for 1st button *
  416. * b2txt text for 2nd button; NULL = no 2nd button *
  417. * *
  418. * OUTPUT: *
  419. * # of button selected (0 = 1st) *
  420. * *
  421. * WARNINGS: *
  422. * 'msg' text must be <= 38 chars *
  423. * 'b1txt' and 'b2txt' must each be <= 18 chars *
  424. * *
  425. * HISTORY: *
  426. * 12/12/1994 BR : Created. *
  427. * 06/18/1995 JLB : Simplified. *
  428. *=============================================================================================*/
  429. int WWMessageBox::Process(int msg, int b1txt, int b2txt, int b3txt, bool preserve)
  430. {
  431. return(Process(Text_String(msg), b1txt, b2txt, b3txt, preserve));
  432. }
  433. /***********************************************************************************************
  434. * WWMessageBox::Process -- Displays message box. *
  435. * *
  436. * This routine will display a message box and wait for player input. It varies from the *
  437. * other message box functions only in the type of parameters it takes. *
  438. * *
  439. * INPUT: msg -- Pointer to text string for the message itself. *
  440. * *
  441. * b1txt -- Text number for the "ok" button. *
  442. * *
  443. * b2txt -- Text number for the "cancel" button. *
  444. * *
  445. * OUTPUT: Returns with the button selected. "true" if "OK" was pressed, and "false" if *
  446. * "CANCEL" was pressed. *
  447. * *
  448. * WARNINGS: none *
  449. * *
  450. * HISTORY: *
  451. * 06/18/1995 JLB : Created. *
  452. *=============================================================================================*/
  453. int WWMessageBox::Process(char const * msg, int b1txt, int b2txt, int b3txt, bool preserve)
  454. {
  455. return(Process(msg, Text_String(b1txt), Text_String(b2txt), Text_String(b3txt), preserve));
  456. }