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