]> icculus.org git repositories - taylor/freespace2.git/blob - src/popup/popup.cpp
disable popups for now
[taylor/freespace2.git] / src / popup / popup.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell 
5  * or otherwise commercially exploit the source or things you created based on
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Popup/Popup.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Code for displaying pop-up dialog boxes
16  *
17  * $Log$
18  * Revision 1.4  2003/05/25 02:30:43  taylor
19  * Freespace 1 support
20  *
21  * Revision 1.3  2002/06/09 04:41:25  relnev
22  * added copyright header
23  *
24  * Revision 1.2  2002/05/07 03:16:51  theoddone33
25  * The Great Newline Fix
26  *
27  * Revision 1.1.1.1  2002/05/03 03:28:10  root
28  * Initial import.
29  *
30  * 
31  * 12    10/14/99 2:00p Jefff
32  * added include for os_poll to fix build error
33  * 
34  * 11    10/14/99 10:18a Daveb
35  * Fixed incorrect CD checking problem on standalone server.
36  * 
37  * 10    8/16/99 9:50a Jefff
38  * added mouseover webcursor options to user-defined popup buttons.
39  * 
40  * 9     8/11/99 5:47p Jefff
41  * fixed button bitmap loading
42  * 
43  * 8     8/04/99 10:53a Dave
44  * Added title to the user tips popup.
45  * 
46  * 7     8/02/99 9:13p Dave
47  * Added popup tips.
48  * 
49  * 6     6/18/99 5:16p Dave
50  * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
51  * dialog to PXO screen.
52  * 
53  * 5     6/01/99 3:52p Dave
54  * View footage screen. Fixed xstrings to not display the & symbol. Popup,
55  * dead popup, pxo find player popup, pxo private room popup.
56  * 
57  * 4     2/11/99 3:08p Dave
58  * PXO refresh button. Very preliminary squad war support.
59  * 
60  * 3     10/13/98 9:29a Dave
61  * Started neatening up freespace.h. Many variables renamed and
62  * reorganized. Added AlphaColors.[h,cpp]
63  * 
64  * 2     10/07/98 10:53a Dave
65  * Initial checkin.
66  * 
67  * 1     10/07/98 10:51a Dave
68  * 
69  * 36    5/11/98 11:39p Dave
70  * Stuff.
71  * 
72  * 35    3/22/98 10:59p Allender
73  * don't stop time in multiplayer when "in mission"
74  * 
75  * 34    3/17/98 12:41a Lawrance
76  * Support \n's between title and body
77  * 
78  * 33    3/12/98 4:11p Dave
79  * AL: Check that max popup lines isn't exceeded
80  * 
81  * 32    2/22/98 12:19p John
82  * Externalized some strings
83  * 
84  * 31    2/10/98 3:26p Hoffoss
85  * Don't check for 'dead key set' unless in the mission.
86  * 
87  * 30    2/05/98 11:21p Lawrance
88  * move death popup to below letterbox view
89  * 
90  * 29    2/05/98 11:09a Dave
91  * Fixed an ingame join bug. Fixed a read-only file problem with
92  * multiplauer file xfer.
93  * 
94  * 28    2/03/98 11:52p Lawrance
95  * Don't highlight default choice if there is only one.
96  * 
97  * 27    2/03/98 8:18p Dave
98  * More MT stats transfer stuff
99  * 
100  * 26    1/30/98 3:05p Lawrance
101  * reposition text on death popup
102  * 
103  * 25    1/29/98 6:55p Lawrance
104  * Integrate new art for the death popup
105  * 
106  * 24    1/28/98 6:24p Dave
107  * Made standalone use ~8 megs less memory. Fixed multiplayer submenu
108  * sequencing problem.
109  * 
110  * 23    1/27/98 5:52p Lawrance
111  * support new "tiny" popups
112  * 
113  * 22    1/27/98 5:01p Dave
114  * Put in support for leaving multiplayer games in the pause state. Fixed
115  * a popup bug which freed saved screens incorrectly. Reworked scoring
116  * kill and assist evaluation.
117  * 
118  * 21    1/27/98 3:25p Hoffoss
119  * Made popups use the correct button icons for default positive and
120  * negative buttons.
121  * 
122  * 20    1/26/98 6:28p Lawrance
123  * Use '&' meta char for underlining, change how keyboard usage works so
124  * fits better with mouse usage.
125  * 
126  * 19    1/23/98 12:01a Lawrance
127  * Fix bug when in single-choice popups.
128  * 
129  * 18    1/22/98 10:45p Lawrance
130  * Implment default selections and arrow key navigation.
131  * 
132  * 17    1/20/98 5:52p Lawrance
133  * center popup text in X and Y directions.  Support single affirmative
134  * icon special placement.
135  * 
136  * 16    1/19/98 11:37p Lawrance
137  * Fixing Optimization build warnings
138  * 
139  * 15    1/17/98 10:04p Lawrance
140  * fix errors in popup comments
141  * 
142  * 14    1/15/98 2:52p Lawrance
143  * Fix problem with reading bogus buttons.
144  * 
145  * 13    1/14/98 6:55p Dave
146  * Fixed a slew of multiplayer bugs. Made certain important popups ignore
147  * the escape character.
148  * 
149  * 12    1/14/98 6:42p Hoffoss
150  * Massive changes to UI code.  A lot cleaner and better now.  Did all
151  * this to get the new UI_DOT_SLIDER to work properly, which the old code
152  * wasn't flexible enough to handle.
153  * 
154  * 11    1/14/98 12:23p Lawrance
155  * Support for three choice popups.
156  * 
157  * 10    1/13/98 5:37p Dave
158  * Reworked a lot of standalone interface code. Put in single and
159  * multiplayer popups for death sequence. Solidified multiplayer kick
160  * code.
161  * 
162  * 9     1/13/98 4:06p Lawrance
163  * Add underline char for shortcuts.
164  * 
165  * 8     1/11/98 11:14p Lawrance
166  * Don't grey out background when popup is active.
167  * 
168  * 7     1/08/98 10:32a Lawrance
169  * Grey out screen when a popup appears.
170  * 
171  * 6     1/02/98 9:08p Lawrance
172  * Integrated art for popups, expanded options.
173  * 
174  * 5     12/30/97 4:30p Sandeep
175  * Added conditional popups
176  * 
177  * 4     12/26/97 10:01p Lawrance
178  * Allow keyboard shortcuts for popup buttons
179  * 
180  * 3     12/24/97 9:49p Lawrance
181  * ensure mouse gets drawn when popup menu is up
182  * 
183  * 2     12/24/97 8:54p Lawrance
184  * Integrating new popup code
185  * 
186  * 1     12/24/97 3:51p Lawrance
187  *
188  * $NoKeywords: $
189  */
190
191 #include <stdarg.h>
192 #include <string.h>
193 #include "freespace.h"
194 #include "gamesequence.h"
195 #include "key.h"
196 #include "mouse.h"
197 #include "ui.h"
198 #include "parselo.h"
199 #include "popup.h"
200 #include "gamesnd.h"
201 #include "animplay.h"
202 #include "contexthelp.h"
203 #include "keycontrol.h"
204 #include "player.h"
205 #include "font.h"
206 #include "alphacolors.h"
207 #include "osapi.h"
208
209 #define POPUP_MAX_CHOICES                       3                                       // max number of buttons allowed on popup
210
211 #define POPUP_MAX_LINE_CHARS            256                             // max chars of msg text allowed per line
212 #define POPUP_MAX_LINES                         30                                      // max lines of text allowed
213 #define POPUP_MAX_CHARS                         2048                            // total max chars 
214 #define POPUP_INPUT_MAX_CHARS           255                             // max length of input string
215
216 #define POPUP_NOCHANGE                          100
217 #define POPUP_ABORT                                     101
218
219 int Popup_max_display[GR_NUM_RESOLUTIONS] = {
220         11,
221         19
222 };
223
224 #ifndef MAKE_FS1  // to avoid trying to find the interface tool
225 const char *Popup_slider_name[GR_NUM_RESOLUTIONS] = {
226         "slider",
227         "2_slider"
228 };
229 #endif
230
231 int Popup_slider_coords[GR_NUM_RESOLUTIONS][4] = {
232         { // GR_640
233                 121, 109, 15, 105
234         },
235         { // GR_1024
236                 195, 177, 30, 173
237         }
238 };
239
240 ////////////////////////////////////////////////////////////////
241 // Internal popup flags
242 ////////////////////////////////////////////////////////////////
243 #define PF_INPUT                                                (1<<0)                  // contents of the box is an inputbox and a caption
244
245 ////////////////////////////////////////////////////////////////
246 // Popup data struct
247 ////////////////////////////////////////////////////////////////
248 typedef struct popup_info
249 {
250         int     nchoices;                                                                                                               // number of choices user can pick
251         char    *button_text[POPUP_MAX_CHOICES];                                                        // button text
252         int     keypress[POPUP_MAX_CHOICES];                                                            // button keypress shortcut
253         int     shortcut_index[POPUP_MAX_CHOICES];                                              // what char should be underlines for shortcut
254         char    raw_text[POPUP_MAX_CHARS];                                                                      // the unbroken text for the popup
255         char    title[POPUP_MAX_LINE_CHARS];                                                            // title text for popup (optional)
256         int     nlines;
257         char    msg_lines[POPUP_MAX_LINES][POPUP_MAX_LINE_CHARS];       // lines of text in popup
258         char    input_text[POPUP_INPUT_MAX_CHARS];                                              // input box text (if this is an inputbox popup)
259         int     max_input_text_len;
260         int     web_cursor_flag[POPUP_MAX_CHOICES];                                             // flag for using web cursor over button
261 } popup_info;
262
263 ////////////////////////////////////////////////////////////////
264 // UI Data and constants
265 ////////////////////////////////////////////////////////////////
266 UI_WINDOW       Popup_window;
267 UI_BUTTON       Popup_buttons[POPUP_MAX_CHOICES];                       // actual lit buttons
268 UI_BUTTON       Popup_button_regions[POPUP_MAX_CHOICES];        // fake buttons used for mouse detection over text
269 UI_INPUTBOX     Popup_input;                                                                            // input box for the popup
270 #ifndef MAKE_FS1
271 UI_SLIDER2      Popup_slider;                                                                           // if we have more text in the popup than can be displayed at once
272 #endif
273
274 // extents for message portion of popup
275 int Popup_text_coords[GR_NUM_RESOLUTIONS][4] = {
276         { // GR_640
277 #ifdef MAKE_FS1
278                 154, 144, 331, 105
279 #else
280                 137, 106, 343, 113
281 #endif
282         },
283         { // GR_1024
284                 219, 169, 558, 182
285         }
286 };
287
288 // input popup info
289 // offset from the first y text line value to place the centered input box
290 int Popup_input_y_offset[GR_NUM_RESOLUTIONS] = {
291         40, 
292         40
293 };
294
295 // offset from the first y text line value to start drawing text
296 int Popup_input_text_y_offset[GR_NUM_RESOLUTIONS] = {
297         30,
298         30
299 };
300
301 typedef struct popup_background
302 {
303         const char      *filename;                                                      // filename for background
304         int     coords[2];                                                      // coords to draw background at
305 } popup_background;
306
307 ////////////////////////////////////////////////////////////////
308 // Module globals
309 ////////////////////////////////////////////////////////////////
310 static int Popup_is_active=0;
311 static int Popup_should_die=0;                  // popup should quit during the next iteration of its loop
312
313 static popup_info Popup_info;
314 static int Popup_flags;
315
316 static int Title_coords[GR_NUM_RESOLUTIONS][5] =
317 {
318         { // GR_640
319 #ifdef MAKE_FS1
320                 154,    // x-left
321                 144,    // y-top
322                 331,    // width
323                 26,             // height
324                 320             // center
325 #else
326                 137,            // x-left
327                 106,            // y-top
328                 343,            // width
329                 26,             //      height
330                 308             // center
331 #endif
332         },
333         { // GR_1024
334                 220,            // x-left
335                 169,            // y-top
336                 553,            // width
337                 26,             //      height
338                 496             // center
339         }
340 };
341
342 static int Button_regions[GR_NUM_RESOLUTIONS][3][4] = {
343         { // GR_640             
344 #ifdef MAKE_FS1
345                 {464, 269, 505, 290},           // upper right pixel of text, lower right pixel of button
346                 {464, 297, 505, 320},
347                 {464, 323, 505, 342}
348 #else
349                 {464, 232, 510, 250},           // upper right pixel of text, lower right pixel of button
350                 {464, 262, 510, 279},           
351                 {464, 292, 510, 308}            
352 #endif
353         },
354         { // GR_1024
355                 {752, 373, 806, 406},           // upper right pixel of text, lower right pixel of button
356                 {752, 421, 806, 461},           
357                 {752, 468, 806, 506}            
358         }
359 };
360
361 static int Button_coords[GR_NUM_RESOLUTIONS][3][2] =
362 {
363         { // GR_640
364 #ifdef MAKE_FS1
365                 {474, 257},             // upper left pixel
366                 {474, 291},
367                 {474, 318}              
368 #else
369                 {474, 224},             // upper left pixel
370                 {474, 258},
371                 {474, 286}              
372 #endif
373         },
374         { // GR_1024
375                 {758, 358},             // upper left pixel
376                 {758, 413},
377                 {758, 458},             
378         }
379 };
380
381 static popup_background Popup_background[GR_NUM_RESOLUTIONS][4] = 
382 {
383         { // GR_640
384 #ifdef MAKE_FS1
385         { "Pop2a",              { 131, 122} },
386         { "Pop2a",              { 131, 122 } },
387         { "Pop3",               { 131, 122 } },
388 #else
389                 { "Pop2",               { 129, 99 } },
390                 { "Pop2",               { 129, 99 } },
391                 { "Pop3",               { 129, 99 } },          
392 #endif
393         },
394         { // GR_1024
395                 { "2_Pop2",             { 206, 158 } },
396                 { "2_Pop2",             { 206, 158 } },
397                 { "2_Pop3",             { 206, 158 } },         
398         }
399 };
400
401 #define BUTTON_NEGATIVE                         0
402 #define BUTTON_POSITIVE                         1
403 #define BUTTON_GENERIC_FIRST            2
404 #define BUTTON_GENERIC_SECOND           3
405 #define BUTTON_GENERIC_THIRD            4
406 static const char *Popup_button_filenames[GR_NUM_RESOLUTIONS][2][5] = 
407 {
408         { // GR_640
409 #ifdef MAKE_FS1
410                 {"Pop2a_00",                    // negative
411                 "Pop2a_01",                             // positive
412                 "Pop2a_02",                             // first generic
413                 "Pop2a_03",                             // second generic
414                 "Pop2a_04"},                    // third generic
415
416                 {"Pop2a_00",                    // negative
417                 "Pop2a_01",                             // positive
418                 "PopD_00",                              // first generic
419                 "PopD_01",                              // second generic
420                 "PopD_02"},                             // third generic
421 #else
422                 {"Pop_00",                              // negative
423                 "Pop_01",                               // positive
424                 "Pop_02",                               // first generic
425                 "Pop_03",                               // second generic
426                 "Pop_04"},                              // third generic
427
428                 {"Pop_00",                              // negative
429                 "Pop_01",                               // positive
430                 "PopD_00",                              // first generic
431                 "PopD_01",                              // second generic
432                 "PopD_02"},                             // third generic
433 #endif
434         },
435         { // GR_1024
436                 {"2_Pop_00",                    // negative
437                 "2_Pop_01",                             // positive
438                 "2_Pop_02",                             // first generic
439                 "2_Pop_03",                             // second generic
440                 "2_Pop_04"},                    // third generic
441
442                 {"2_Pop_00",                    // negative
443                 "2_Pop_01",                             // positive
444                 "2_PopD_00",                    // first generic
445                 "2_PopD_01",                    // second generic
446                 "2_PopD_02"},                   // third generic
447         }
448 };
449
450 int Popup_running_state;
451 int Popup_default_choice;       // which choice is highlighted (ie what gets choosen when enter is pressed)
452
453 // see if any popup buttons have been pressed
454 // exit: POPUP_NOCHANGE         => no buttons pressed
455 //                      >=0                                     =>      button index that was pressed
456 int popup_check_buttons(popup_info *pi)
457 {
458         int                     i;
459         UI_BUTTON       *b;
460
461         for ( i = 0; i < pi->nchoices; i++ ) {
462                 b = &Popup_button_regions[i];
463                 if ( b->pressed() ) {
464                         return i;
465                 }
466
467                 b = &Popup_buttons[i];
468                 if ( b->pressed() ) {
469                         return i;
470                 }
471         }
472
473         return POPUP_NOCHANGE;
474 }
475
476 // maybe play a sound when key up/down is pressed to switch default choice
477 void popup_play_default_change_sound(popup_info *pi)
478 {
479         if ( pi->nchoices > 1 ) {
480                 int i, mouse_over=0;
481                 UI_BUTTON *br, *b;
482
483                 // only play if mouse not currently highlighting a choice
484
485                 for ( i = 0; i < pi->nchoices; i++ ) {
486                         br = &Popup_button_regions[i];
487                         b = &Popup_buttons[i];
488                         if ( br->button_down() ) {
489                                 mouse_over=1;
490                                 break;
491                         }
492
493                         if ( br->button_hilighted() && !b->button_down() ) {
494                                 mouse_over=1;
495                                 break;
496                         }
497
498                         if ( b->button_hilighted() ) {
499                                 mouse_over=1;
500                         }
501                 }
502
503                 if (!mouse_over) {
504                         gamesnd_play_iface(SND_USER_SELECT);
505                 }
506         }
507 }
508
509 // do any key processing here
510 // input:       pi                                      =>      data about the popup
511 //                              k                                       => key that was pressed
512 //
513 // exit: 0 .. nchoices-1        => choice selected through keypress
514 //                      POPUP_ABORT                     =>      abort the popup
515 //                      POPUP_NOCHANGE          => nothing happenned
516 int popup_process_keys(popup_info *pi, int k, int flags)
517 {
518         int i, masked_k;
519
520         if ( k <= 0 ) {
521                 return POPUP_NOCHANGE;
522         }
523
524         for ( i = 0; i < pi->nchoices; i++ ) {
525                 if ( pi->keypress[i] == key_get_text_input() ) {
526                         Popup_default_choice=i;
527                         Popup_buttons[i].press_button();
528                         return i;
529                 }
530         }
531         
532         switch(k) {
533
534         case SDLK_RETURN:
535                 // select the current default choice
536                 return Popup_default_choice;
537                 break;
538
539         case SDLK_ESCAPE:
540                 // only process the escape key if this flag is not set
541                 if(!(flags & PF_IGNORE_ESC)){
542                         return POPUP_ABORT;
543                 }
544                 break;
545
546         case SDLK_DOWN:
547         case SDLK_KP_2:
548         case SDLK_TAB:
549                 popup_play_default_change_sound(pi);
550                 Popup_default_choice++;
551                 if ( Popup_default_choice >= pi->nchoices ) {
552                         Popup_default_choice=0;
553                 }
554                 break;
555
556         case SDLK_UP:
557         case SDLK_KP_8:
558         case KEY_SHIFTED+SDLK_TAB:
559                 popup_play_default_change_sound(pi);
560                 Popup_default_choice--;
561                 if ( Popup_default_choice < 0 ) {
562                         Popup_default_choice=pi->nchoices-1;
563                 }
564                 break;
565
566         default:
567                 break;
568         } // end switch
569
570
571         masked_k = k & ~KEY_CTRLED;     // take out CTRL modifier only
572         if ( (PF_ALLOW_DEAD_KEYS) && (Game_mode & GM_IN_MISSION) ) {
573                 process_set_of_keys(masked_k, Dead_key_set_size, Dead_key_set);
574                 button_info_do(&Player->bi);    // call functions based on status of button_info bit vectors
575         }
576
577         return POPUP_NOCHANGE;
578 }
579
580 // Split off the title and break up the body lines
581 void popup_split_lines(popup_info *pi, int flags)
582 {
583         int     nlines, i, body_offset = 0;
584         int     n_chars[POPUP_MAX_LINES];
585         char    *p_str[POPUP_MAX_LINES];
586         int len;
587
588         gr_set_font(FONT1);
589         n_chars[0]=0;
590
591         nlines = split_str(pi->raw_text, 1000, n_chars, p_str, POPUP_MAX_LINES);
592         SDL_assert(nlines >= 0 && nlines <= POPUP_MAX_LINES );
593
594         if ( flags & (PF_TITLE | PF_TITLE_BIG) ) {
595                 // get first line out
596                 len = SDL_min(n_chars[0] + 1, POPUP_MAX_LINE_CHARS);
597                 SDL_strlcpy(pi->title, p_str[0], len);
598                 body_offset = 1;
599         }
600
601         if ( flags & PF_BODY_BIG ) {
602                 gr_set_font(FONT2);
603         }
604
605         nlines = split_str(pi->raw_text, Popup_text_coords[gr_screen.res][2], n_chars, p_str, POPUP_MAX_LINES);
606         SDL_assert(nlines >= 0 && nlines <= POPUP_MAX_LINES );
607
608         pi->nlines = nlines - body_offset;
609
610         for ( i = 0; i < pi->nlines; i++ ) {
611                 SDL_assert(n_chars[i+body_offset] < POPUP_MAX_LINE_CHARS);
612                 len = SDL_min(n_chars[i+body_offset] + 1, POPUP_MAX_LINE_CHARS);
613                 SDL_strlcpy(pi->msg_lines[i], p_str[i+body_offset], len);
614         }
615
616         gr_set_font(FONT1);
617 }
618
619 // figure out what filename to use for the button icon
620 const char *popup_get_button_filename(popup_info *pi, int i, int flags)
621 {
622         const char *fname = NULL;
623         int is_tiny=0;  
624
625         // check for special button texts and if found, use specialized buttons for them.
626         if ((!SDL_strcasecmp(pi->button_text[i], POPUP_OK + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_YES + 1)) && !(flags & PF_NO_SPECIAL_BUTTONS)){
627                 return Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE];
628         }
629
630         if ((!SDL_strcasecmp(pi->button_text[i], POPUP_CANCEL + 1) || !SDL_strcasecmp(pi->button_text[i], POPUP_NO + 1)) && !(flags & PF_NO_SPECIAL_BUTTONS)){
631                 return Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE];
632         }
633
634         switch (pi->nchoices) {
635         case 0:
636                 fname = "";
637                 break;
638         case 1:
639                 if ( (flags & PF_USE_AFFIRMATIVE_ICON) && !(flags & PF_NO_SPECIAL_BUTTONS) ) {
640                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE];
641                 } else if ( flags & PF_USE_NEGATIVE_ICON && !(flags & PF_NO_SPECIAL_BUTTONS) ) {
642                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE];
643                 } else {
644                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_FIRST];
645                 }
646                 break;
647
648         case 2:
649                 if ( flags & PF_USE_NEGATIVE_ICON && i==0 ) {
650                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_NEGATIVE];
651                         break;
652                 } 
653
654                 if ( flags & PF_USE_AFFIRMATIVE_ICON && i==1 ) {
655                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_POSITIVE];
656                         break;
657                 } 
658
659                 if ( i == 0 ) {
660                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_FIRST];
661                 } else {
662                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_SECOND];
663                 }
664
665                 break;
666
667         case 3:
668                 switch(i) {
669                 case 0:
670                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_FIRST];
671                         break;
672                 case 1:
673                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_SECOND];
674                         break;
675                 case 2:
676                         fname = Popup_button_filenames[gr_screen.res][is_tiny][BUTTON_GENERIC_THIRD];
677                         break;
678                 }
679                 break;
680         }
681
682         return fname;
683 }
684
685 // bogus handling function for slider (we don't need it to do anything)
686 void popup_slider_bogus()
687 {
688 }
689
690 // init the Popup window
691 int popup_init(popup_info *pi, int flags)
692 {
693         int                                     i;
694         UI_BUTTON                       *b;
695         popup_background        *pbg;
696         const char                      *fname;
697
698         if(pi->nchoices == 0){
699                 pbg = &Popup_background[gr_screen.res][0];
700         } else {
701                 pbg = &Popup_background[gr_screen.res][pi->nchoices-1];
702         }
703
704         // anytime in single player, and multiplayer, not in mission, go ahead and stop time
705         if ( (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) ){
706                 game_stop_time();
707         }
708
709         // create base window
710         Popup_window.create(pbg->coords[0], pbg->coords[1], Popup_text_coords[gr_screen.res][2]+100, Popup_text_coords[gr_screen.res][3]+50, 0);
711         Popup_window.set_foreground_bmap(pbg->filename);
712
713         // create buttons
714         for (i=0; i<pi->nchoices; i++) {
715                 b = &Popup_buttons[i];
716                 // accommodate single-choice positive icon being positioned differently
717                 if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) {
718                         b->create(&Popup_window, "", Button_coords[gr_screen.res][i+1][0], Button_coords[gr_screen.res][i+1][1], 30, 25, 0, 1);
719                 } else {
720                         b->create(&Popup_window, "", Button_coords[gr_screen.res][i][0], Button_coords[gr_screen.res][i][1], 30, 25, 0, 1);
721                 }
722
723                 fname = popup_get_button_filename(pi, i, flags);
724                 b->set_bmaps(fname, 3, 0);
725                 b->set_highlight_action(common_play_highlight_sound);
726                 if ( pi->keypress[i] >= 0 ) {
727                         b->set_hotkey(pi->keypress[i]);
728                 }
729
730                 // create invisible buttons to detect mouse presses... can't use mask since button region is dynamically sized
731                 int lx, w, h;
732
733                 gr_get_string_size(&w, &h, pi->button_text[i]);
734                 lx = Button_regions[gr_screen.res][i][0] - w;
735                 b = &Popup_button_regions[i];   
736
737                 // accommodate single-choice positive icon being positioned differently
738                 if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) {
739                         b->create(&Popup_window, "", lx, Button_regions[gr_screen.res][i+1][1], Button_regions[gr_screen.res][i+1][2]-lx, Button_regions[gr_screen.res][i+1][3]-Button_regions[gr_screen.res][i+1][1], 0, 1);
740                 } else {
741                         b->create(&Popup_window, "", lx, Button_regions[gr_screen.res][i][1], Button_regions[gr_screen.res][i][2]-lx, Button_regions[gr_screen.res][i][3]-Button_regions[gr_screen.res][i][1], 0, 1);
742                 }
743
744                 b->hide();
745         }
746
747         // webcursor setup
748         if (Web_cursor_bitmap >= 0) {
749                 if (flags & PF_WEB_CURSOR_1) {
750                         Popup_buttons[1].set_custom_cursor_bmap(Web_cursor_bitmap);
751                 }
752                 if (flags & PF_WEB_CURSOR_2) {
753                         Popup_buttons[2].set_custom_cursor_bmap(Web_cursor_bitmap);
754                 }
755         }
756
757         // if this is an input popup, create and center the popup
758         if(flags & PF_INPUT){
759                 Popup_input.create(&Popup_window, Popup_text_coords[gr_screen.res][0], pbg->coords[1] + Popup_input_y_offset[gr_screen.res], Popup_text_coords[gr_screen.res][2], pi->max_input_text_len, "", UI_INPUTBOX_FLAG_INVIS | UI_INPUTBOX_FLAG_ESC_CLR | UI_INPUTBOX_FLAG_ESC_FOC | UI_INPUTBOX_FLAG_KEYTHRU | UI_INPUTBOX_FLAG_TEXT_CEN);
760                 Popup_input.set_focus();
761         }       
762         
763         Popup_default_choice=0;
764         Popup_should_die = 0;
765
766         if (flags & PF_RUN_STATE) {
767                 Popup_running_state = 1;
768         } else {
769                 Popup_running_state = 0;
770         }
771
772         popup_split_lines(pi, flags);
773
774 #ifndef MAKE_FS1
775         // create the popup slider (which we may not need to use
776         Popup_slider.create(&Popup_window, Popup_slider_coords[gr_screen.res][0], Popup_slider_coords[gr_screen.res][1], Popup_slider_coords[gr_screen.res][2], Popup_slider_coords[gr_screen.res][3], pi->nlines > Popup_max_display[gr_screen.res] ? pi->nlines - Popup_max_display[gr_screen.res] : 0,
777                                                                 Popup_slider_name[gr_screen.res], popup_slider_bogus, popup_slider_bogus, NULL);
778 #endif
779
780         return 0;
781 }
782
783 // called when a popup goes away
784 void popup_close(popup_info *pi,int screen)
785 {
786         int i;
787         
788         gamesnd_play_iface(SND_POPUP_DISAPPEAR);        // play sound when popup disappears
789
790         for (i=0; i<pi->nchoices; i++ ) {
791                 if ( pi->button_text[i] != NULL ) {
792                         free(pi->button_text[i]);
793                         pi->button_text[i] = NULL;
794                 }
795         }
796
797         if(screen >= 0){
798                 gr_free_screen(screen); 
799         }
800         Popup_window.destroy();
801         anim_ignore_next_frametime();                                   // to avoid skips in animation since next frametime is saturated
802         game_flush();
803
804         Popup_is_active = 0;
805         Popup_running_state = 0;
806
807         // anytime in single player, and multiplayer, not in mission, go ahead and stop time
808         if ( (Game_mode & GM_NORMAL) || ((Game_mode & GM_MULTIPLAYER) && !(Game_mode & GM_IN_MISSION)) )
809                 game_start_time();
810 }
811
812 // set the popup text color
813 void popup_set_text_color(int flags)
814 {
815         if ( flags & PF_BODY_RED ) {
816                 gr_set_color_fast(&Color_red);
817                 return;
818         }
819
820         if ( flags & PF_BODY_GREEN ) {
821                 gr_set_color_fast(&Color_green);
822                 return;
823         }
824
825         if ( flags & PF_BODY_BLUE ) {
826                 gr_set_color_fast(&Color_blue);
827                 return;
828         }
829
830         gr_set_color_fast(&Color_bright_blue);
831 }
832
833 // set the popup text color
834 void popup_set_title_color(int flags)
835 {
836         if ( flags & PF_TITLE_RED ) {
837                 gr_set_color_fast(&Color_red);
838                 return;
839         }
840
841         if ( flags & PF_TITLE_GREEN ) {
842                 gr_set_color_fast(&Color_green);
843                 return;
844         }
845
846         if ( flags & PF_TITLE_BLUE ) {
847                 gr_set_color_fast(&Color_blue);
848                 return;
849         }
850
851         if ( flags & PF_TITLE_WHITE ) {
852                 gr_set_color_fast(&Color_bright_white);
853                 return;
854         }
855
856         gr_set_color_fast(&Color_bright_blue);
857 }
858
859 // Draw the title centered within the popup
860 void popup_draw_title(int sy, const char *line, int flags)
861 {
862         int w, h, sx;
863
864         if ( flags & PF_TITLE_BIG ) {
865                 gr_set_font(FONT2);
866         } else {
867                 gr_set_font(FONT1);
868         }
869
870         gr_get_string_size(&w, &h, line);
871         sx = fl2i(Title_coords[gr_screen.res][4] - w/2.0f + 0.5f);
872
873         popup_set_title_color(flags);
874         gr_string(sx,sy,line);
875 }
876
877 // calculate the starting display index
878 int popup_calc_starting_index(popup_info *pi)
879 {
880         // we're basically ignoring any titles here. 
881         if(pi->nlines <= Popup_max_display[gr_screen.res]){
882                 return 0;
883         }
884
885 #ifndef MAKE_FS1
886         // otherwise, we want to see what item index the slider is on
887         return Popup_slider.get_currentItem();
888 #else
889         return 0;
890 #endif
891 }
892
893 // Figure out the y-coord to start drawing the popup text.  The text
894 // is centered vertically within the popup.
895 int popup_calc_starting_y(popup_info *pi, int flags)
896 {
897         int sy, total_h=0;
898         int num_lines = pi->nlines > Popup_max_display[gr_screen.res] ? Popup_max_display[gr_screen.res] : pi->nlines;
899
900         if ( flags & (PF_TITLE | PF_TITLE_BIG) ) {
901                 if ( flags & PF_TITLE_BIG ) {
902                         gr_set_font(FONT2);
903                 } else {
904                         gr_set_font(FONT1);
905                 }
906                 total_h += gr_get_font_height();
907         }
908
909         if ( flags & PF_BODY_BIG ) {
910                 gr_set_font(FONT2);
911         } else {
912                 gr_set_font(FONT1);
913         }
914
915         total_h += num_lines * gr_get_font_height();
916         sy = fl2i((Popup_text_coords[gr_screen.res][1] + Popup_text_coords[gr_screen.res][3]/2.0f) - total_h/2.0f + 0.5f);
917
918         // if this is an input style box, add in some y
919         if(flags & PF_INPUT){
920                 sy += Popup_input_text_y_offset[gr_screen.res];
921         }
922
923         return sy;
924 }
925
926 // Draw the message text nicely formatted in the popup
927 void popup_draw_msg_text(popup_info *pi, int flags)
928 {
929         int sx, sy, i, w, h;
930         int line_index;
931         int line_count;
932
933         // figure out the starting display 
934         line_index = popup_calc_starting_index(pi);
935
936         // figure out the starting y:
937         sy = popup_calc_starting_y(pi, flags);
938
939         // draw title if required
940         if ( flags & (PF_TITLE | PF_TITLE_BIG) ) {
941                 popup_draw_title(sy, pi->title, flags);
942                 sy += gr_get_font_height();
943         }
944
945         // draw body 
946         if ( flags & PF_BODY_BIG ) {
947                 gr_set_font(FONT2);
948         } else {
949                 gr_set_font(FONT1);
950         }
951
952         popup_set_text_color(flags);
953         line_count = 0;
954         for ( i = line_index; i < pi->nlines; i++, line_count++ ) {
955                 // if we've already displayed the max # of lines
956                 if(line_count >= Popup_max_display[gr_screen.res]){
957                         break;
958                 }
959
960                 gr_get_string_size(&w, &h, pi->msg_lines[i]);
961                 sx = fl2i(Title_coords[gr_screen.res][4] - w/2.0f + 0.5f);
962                 gr_string(sx, sy + line_count * h, pi->msg_lines[i]);
963         }
964
965         // maybe draw "more"
966         h = 10;
967         if(i < pi->nlines){
968                 gr_set_color_fast(&Color_bright_red);
969                 gr_string(Title_coords[gr_screen.res][4], sy + (Popup_max_display[gr_screen.res]) * h, XSTR("More", 459));
970         }
971
972         gr_set_font(FONT1);     // reset back to regular font size
973 }
974
975 // Draw the button text nicely formatted in the popup
976 void popup_draw_button_text(popup_info *pi, int flags)
977 {
978         int w, h, i, sx, sy;
979
980         gr_set_color_fast(&Color_bright_blue);
981
982         for ( i=0; i < pi->nchoices; i++ ) {
983                 gr_get_string_size(&w, &h, pi->button_text[i]);
984
985                 if ( (pi->nchoices == 1) && (flags&PF_USE_AFFIRMATIVE_ICON) ) {
986                         sx = Button_regions[gr_screen.res][i+1][0]-w;
987                         sy = Button_regions[gr_screen.res][i+1][1]+4;
988                 } else {
989                         sx = Button_regions[gr_screen.res][i][0]-w;
990                         sy = Button_regions[gr_screen.res][i][1]+4;
991                 }
992
993                 gr_string(sx, sy, pi->button_text[i]);
994
995                 // figure out where to draw underline char
996                 if ( pi->shortcut_index[i] > 0 ) {
997                         int     cut=pi->shortcut_index[i];
998                         char    save_char=pi->button_text[i][cut];
999                         pi->button_text[i][cut] = 0;
1000                         gr_get_string_size(&w, &h, pi->button_text[i]);
1001                         pi->button_text[i][cut] = save_char;
1002                         sx += w;
1003                 }
1004                 
1005                 if ( pi->shortcut_index[i] >= 0 ) {
1006                         gr_printf(sx, sy, NOX("%c"), 95);
1007                 }
1008         }
1009 }
1010
1011 // See if any of the button should change appearance based on mouse position
1012 void popup_force_draw_buttons(popup_info *pi)
1013 {
1014         int i,mouse_is_highlighting=0;
1015         UI_BUTTON *br, *b;
1016
1017         for ( i = 0; i < pi->nchoices; i++ ) {
1018                 br = &Popup_button_regions[i];
1019                 b = &Popup_buttons[i];
1020                 if ( br->button_down() ) {
1021                         b->draw_forced(2);
1022                         mouse_is_highlighting=1;
1023                         continue;
1024                 }
1025
1026                 if ( (b->button_hilighted()) || (br->button_hilighted() && !b->button_down()) ) {
1027                         Popup_default_choice=i;
1028                         mouse_is_highlighting=1;
1029                         b->draw_forced(1);
1030                 }
1031         }
1032
1033         // Only if mouse is not highlighting an option, let the default choice be drawn highlighted
1034         if ( (!mouse_is_highlighting) && (pi->nchoices>1) ) {
1035                 for ( i = 0; i < pi->nchoices; i++ ) {
1036                         b = &Popup_buttons[i];
1037                         // highlight the default choice
1038                         if ( i == Popup_default_choice ) {
1039                                 b->draw_forced(1);
1040                         }
1041                 }
1042         }
1043 }
1044
1045 // exit: -1                                             =>      error
1046 //                      0..nchoices-1           => choice
1047 int popup_do(popup_info *pi, int flags)
1048 {
1049         int screen_id, choice = -1, done = 0;
1050
1051         screen_id = gr_save_screen();
1052
1053         if ( popup_init(pi, flags) == -1 ){
1054                 return -1;
1055         }
1056
1057 #ifdef __EMSCRIPTEN__
1058         STUB_FUNCTION;
1059         return POPUP_ABORT;
1060 #endif
1061
1062         while(!done) {
1063                 int k;
1064
1065                 os_poll();
1066
1067                 // if we were killed by a call to popup_kill_any_active(), kill the popup
1068                 if(Popup_should_die){
1069                         choice = -1;
1070                         break;
1071                 }
1072
1073                 // if we're flagged as should be running the state underneath, then do so
1074                 if(flags & PF_RUN_STATE){
1075                         game_do_state(gameseq_get_state());
1076                 }
1077                 // otherwise just run the common functions (for networking,etc)
1078                 else {
1079                         game_set_frametime(-1);
1080                         game_do_state_common(gameseq_get_state(),flags & PF_NO_NETWORKING);     // do stuff common to all states 
1081                 }
1082
1083                 k = Popup_window.process();                                             // poll for input, handle mouse
1084                 choice = popup_process_keys(pi, k, flags);
1085                 if ( choice != POPUP_NOCHANGE ) {
1086                         done=1;
1087                 }
1088
1089                 if ( !done ) {
1090                         choice = popup_check_buttons(pi);
1091                         if ( choice != POPUP_NOCHANGE ) {
1092                                 done=1;
1093                         }
1094                 }
1095
1096                 // don't draw anything 
1097                 if(!(flags & PF_RUN_STATE)){
1098                         gr_restore_screen(screen_id);
1099                 }
1100
1101                 // if this is an input popup, store the input text
1102                 if(flags & PF_INPUT){
1103                         Popup_input.get_text(pi->input_text);
1104                 }
1105
1106                 Popup_window.draw();
1107                 popup_force_draw_buttons(pi);
1108                 popup_draw_msg_text(pi, flags);
1109                 popup_draw_button_text(pi, flags);
1110                 gr_flip();
1111         }
1112
1113         popup_close(pi,screen_id);
1114         return choice;
1115 }
1116
1117 int popup_do_with_condition(popup_info *pi, int flags, int(*condition)())
1118 {
1119         int screen_id, choice = -1, done = 0;
1120         int test;
1121         screen_id = gr_save_screen();
1122         if ( popup_init(pi, flags) == -1 )
1123                 return -1;
1124
1125 #ifdef __EMSCRIPTEN__
1126         STUB_FUNCTION;
1127         return POPUP_ABORT;
1128 #endif
1129
1130         while(!done) {
1131                 int k;
1132
1133                 os_poll();
1134                 
1135                 game_set_frametime(-1);
1136                 game_do_state_common(gameseq_get_state());      // do stuff common to all states 
1137                 gr_restore_screen(screen_id);
1138
1139                 // draw one frame first
1140                 Popup_window.draw();
1141                 popup_force_draw_buttons(pi);
1142                 popup_draw_msg_text(pi, flags);
1143                 popup_draw_button_text(pi, flags);
1144                 gr_flip();
1145
1146                 // test the condition function or process for the window
1147                 if ((test = condition()) > 0) {
1148                         done = 1;
1149                         choice = test;
1150                 } else {
1151                         k = Popup_window.process();                                             // poll for input, handle mouse
1152                         choice = popup_process_keys(pi, k, flags);
1153                         if ( choice != POPUP_NOCHANGE ) {
1154                                 done=1;
1155                         }
1156
1157                         if ( !done ) {
1158                                 choice = popup_check_buttons(pi);
1159                                 if ( choice != POPUP_NOCHANGE ) {
1160                                         done=1;
1161                                 }
1162                         }
1163                 }               
1164         }
1165
1166         popup_close(pi,screen_id);
1167         return choice;
1168 }
1169
1170
1171 // maybe assign a keyboard shortcut to this button
1172 // input:       pi              =>      popup information so far
1173 //                              i               =>      number of choice
1174 //                              str     => string for button press      
1175 void popup_maybe_assign_keypress(popup_info *pi, int n, char *str)
1176 {
1177         int i,j,len=0,next_char_is_shortcut=0;
1178
1179         pi->keypress[n]=-1;
1180         pi->shortcut_index[n]=-1;
1181
1182         len=strlen(str)+1;
1183
1184         pi->button_text[n] = (char*)malloc(len);
1185         memset(pi->button_text[n], 0, len);
1186
1187         j=0;
1188         // copy chars over, watching for underline meta-char '&'
1189         for (i=0; i<len-1; i++) {
1190                 if ( str[i] == '&' ) {
1191                         pi->shortcut_index[n]=i;
1192                         next_char_is_shortcut=1;
1193                 } else {
1194                         if ( next_char_is_shortcut ) {
1195                                 next_char_is_shortcut=0;
1196                                 char first_char_string[2];
1197                                 first_char_string[0]=str[i];
1198                                 first_char_string[1]=0;
1199                                 SDL_strlwr(first_char_string);
1200                                 pi->keypress[n] = first_char_string[0];
1201                         }
1202                         pi->button_text[n][j++]=str[i]; 
1203                 }
1204         }
1205 }
1206
1207 // input:       flags                   =>              flags                   =>              formatting specificatons (PF_...)
1208 //                              nchoices                =>              number of choices popup has
1209 //                              text_1          =>              text for first button
1210 //                              ...                     =>              
1211 //                              text_n          =>              text for last button
1212 //                              msg text                =>              text msg for popup (can be of form "%s",pl->text)
1213 //
1214 // exit: choice selected (0..nchoices-1)
1215 //                      will return -1 if there was an error or popup was aborted
1216 //
1217 // typical usage:
1218 //
1219 //      rval = popup(0, 2, POPUP_OK, POPUP_CANCEL, "Sorry %s, try again", pl->callsign);
1220 int popup(int flags, int nchoices, ... )
1221 {
1222         int                     i, choice;
1223         char                    *format, *s;
1224         va_list         args;   
1225
1226         if ( Popup_is_active ) {
1227                 Int3();         // should never happen
1228                 return -1;
1229         }
1230
1231         Popup_flags = flags;
1232
1233         SDL_assert( nchoices > 0 && nchoices <= POPUP_MAX_CHOICES );
1234         Popup_info.nchoices = nchoices;
1235
1236         va_start(args, nchoices );
1237
1238         // get button text
1239         for (i=0; i<nchoices; i++ )     {
1240                 s = va_arg( args, char * );
1241                 Popup_info.button_text[i] = NULL;
1242                 popup_maybe_assign_keypress(&Popup_info, i, s);
1243         }
1244
1245         // get msg text
1246         format = va_arg( args, char * );
1247         Popup_info.raw_text[0] = 0;
1248         SDL_vsnprintf(Popup_info.raw_text, SDL_arraysize(Popup_info.raw_text), format, args);
1249         va_end(args);
1250         
1251         gamesnd_play_iface(SND_POPUP_APPEAR);   // play sound when popup appears
1252
1253         Mouse_hidden = 0;
1254         Popup_is_active = 1;
1255
1256         choice = popup_do( &Popup_info, flags );
1257         switch(choice) {
1258         case POPUP_ABORT:
1259                 return -1;
1260         default:
1261                 return choice;
1262         } // end switch
1263 }
1264
1265 // determine if a popup is being drawn
1266 int popup_active()
1267 {
1268         return Popup_is_active;
1269 }
1270
1271 // This function displays a popup message box and every frame it checks the condition() function
1272 // which is passed in as an argument.
1273 // If the condition() returns TRUE, the message box ends itself.  This function returns whatever
1274 // the condition() did if the condition() occurred, and FALSE if the cancel button was pressed.
1275 int popup_till_condition(int (*condition)(), ...) 
1276 {
1277         int                     choice;
1278         char                    *format, *s;
1279         va_list         args;
1280         int flags = 0;          
1281
1282         if ( Popup_is_active ) {
1283                 Int3();         // should never happen
1284                 return -1;
1285         }
1286         //int nchoices = 1;
1287         Popup_info.nchoices = 1;
1288
1289         Popup_flags = 0;
1290
1291         va_start(args, condition );
1292
1293         // get button text
1294         s = va_arg( args, char * );
1295         Popup_info.button_text[0] = NULL;
1296         popup_maybe_assign_keypress(&Popup_info, 0, s);
1297
1298         // get msg text
1299         format = va_arg( args, char * );
1300         Popup_info.raw_text[0] = 0;
1301         SDL_vsnprintf(Popup_info.raw_text, SDL_arraysize(Popup_info.raw_text), format, args);
1302         va_end(args);
1303                 
1304         gamesnd_play_iface(SND_POPUP_APPEAR);   // play sound when popup appears
1305
1306         Mouse_hidden = 0;
1307         Popup_is_active = 1;
1308
1309         choice = popup_do_with_condition( &Popup_info, flags, condition );
1310         switch(choice) {
1311         case POPUP_ABORT:
1312                 return 0;
1313         default:
1314                 return choice;
1315         } // end switch
1316 }
1317
1318 // popup to return the value from an input box
1319 char *popup_input(int flags, const char *caption, int max_output_len)
1320 {
1321         if ( Popup_is_active ) {
1322                 Int3();         // should never happen
1323                 return NULL;
1324         }
1325
1326         // make it an inputbox type popup
1327         Popup_flags = flags;
1328         Popup_flags |= PF_INPUT;
1329
1330         // add a cancel button
1331         Popup_info.nchoices = 0;
1332         // popup_maybe_assign_keypress(&Popup_info, 0, "&Cancel");      
1333
1334         // get msg text
1335         SDL_assert(caption != NULL);
1336         SDL_strlcpy(Popup_info.raw_text, caption, SDL_arraysize(Popup_info.raw_text));
1337         SDL_assert(strlen(Popup_info.raw_text) < POPUP_MAX_CHARS );
1338
1339         // set input text length
1340         if((max_output_len > POPUP_INPUT_MAX_CHARS) || (max_output_len == -1)){
1341                 Popup_info.max_input_text_len = POPUP_INPUT_MAX_CHARS - 1;
1342         } else {
1343                 Popup_info.max_input_text_len = max_output_len;
1344         }
1345
1346         // zero the popup input text
1347         memset(Popup_info.input_text, 0, POPUP_INPUT_MAX_CHARS);
1348         
1349         gamesnd_play_iface(SND_POPUP_APPEAR);   // play sound when popup appears
1350
1351         Mouse_hidden = 0;
1352         Popup_is_active = 1;
1353
1354         // if the user cancelled
1355         if(popup_do(&Popup_info, Popup_flags) == POPUP_ABORT){
1356                 return NULL;
1357         }
1358         
1359         // otherwise return the
1360         return Popup_info.input_text;   
1361 }
1362
1363 int popup_running_state()
1364 {
1365         return Popup_running_state;
1366 }
1367
1368 // kill any active popup, forcing it to return -1 (similar to ESC)
1369 void popup_kill_any_active()
1370 {
1371         if(Popup_is_active){
1372                 Popup_should_die = 1;
1373         }
1374 }
1375
1376 // change the text inside of the popup 
1377 void popup_change_text(const char *new_text)
1378 {
1379         // copy the raw text
1380         SDL_strlcpy(Popup_info.raw_text, new_text, SDL_arraysize(Popup_info.raw_text));
1381
1382         // recalculate all display information
1383         popup_split_lines(&Popup_info,Popup_flags);
1384 }
1385