]> icculus.org git repositories - taylor/freespace2.git/blob - src/ui/window.cpp
SDL2 port - stage 2
[taylor/freespace2.git] / src / ui / window.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/Ui/WINDOW.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * Routines to handle UI windows.
16  *
17  * $Log$
18  * Revision 1.3  2004/09/20 01:31:45  theoddone33
19  * GCC 3.4 fixes.
20  *
21  * Revision 1.2  2002/06/09 04:41:29  relnev
22  * added copyright header
23  *
24  * Revision 1.1.1.1  2002/05/03 03:28:11  root
25  * Initial import.
26  *
27  * 
28  * 30    10/14/99 2:52p Jefff
29  * localization fixes.  added support for hi-res specific xstr offsets
30  * 
31  * 29    8/16/99 4:06p Dave
32  * Big honking checkin.
33  * 
34  * 28    7/16/99 1:50p Dave
35  * 8 bit aabitmaps. yay.
36  * 
37  * 27    7/15/99 3:07p Dave
38  * 32 bit detection support. Mouse coord commandline.
39  * 
40  * 26    7/13/99 5:38p Jefff
41  * Added support for x offsets when drawing strings
42  * 
43  * 25    6/25/99 11:59a Dave
44  * Multi options screen.
45  * 
46  * 24    6/22/99 7:03p Dave
47  * New detail options screen.
48  * 
49  * 23    6/19/99 2:46p Dave
50  * New control config screen.
51  * 
52  * 22    6/18/99 5:16p Dave
53  * Added real beam weapon lighting. Fixed beam weapon sounds. Added MOTD
54  * dialog to PXO screen.
55  * 
56  * 21    6/04/99 11:32a Dave
57  * Added reset text to ship select screen. Fixed minor xstr bug in ui
58  * window
59  * 
60  * 20    6/02/99 6:18p Dave
61  * Fixed TNT lockup problems! Wheeeee!
62  * 
63  * 19    6/01/99 3:52p Dave
64  * View footage screen. Fixed xstrings to not display the & symbol. Popup,
65  * dead popup, pxo find player popup, pxo private room popup.
66  * 
67  * 18    5/22/99 5:35p Dave
68  * Debrief and chatbox screens. Fixed small hi-res HUD bug.
69  * 
70  * 17    5/21/99 6:45p Dave
71  * Sped up ui loading a bit. Sped up localization disk access stuff. Multi
72  * start game screen, multi password, and multi pxo-help screen.
73  * 
74  * 16    5/17/99 11:28a Dave
75  * 
76  * 15    5/17/99 9:25a Dave
77  * Updated PXO screen. Still needs popups.
78  * 
79  * 14    5/03/99 8:33p Dave
80  * New version of multi host options screen.
81  * 
82  * 13    4/16/99 5:22p Neilk
83  * Fixed UI_SLIDER2 bug
84  * 
85  * 12    2/21/99 6:02p Dave
86  * Fixed standalone WSS packets. 
87  * 
88  * 11    2/01/99 5:55p Dave
89  * Removed the idea of explicit bitmaps for buttons. Fixed text
90  * highlighting for disabled gadgets.
91  * 
92  * 10    1/29/99 2:08a Dave
93  * Fixed beam weapon collisions with players. Reduced size of scoring
94  * struct for multiplayer. Disabled PXO.
95  * 
96  * 9     1/29/99 12:47a Dave
97  * Put in sounds for beam weapon. A bunch of interface screens (tech
98  * database stuff).
99  * 
100  * 8     12/18/98 1:13a Dave
101  * Rough 1024x768 support for Direct3D. Proper detection and usage through
102  * the launcher.
103  * 
104  * 7     12/02/98 5:47p Dave
105  * Put in interface xstr code. Converted barracks screen to new format.
106  * 
107  * 6     11/30/98 1:07p Dave
108  * 16 bit conversion, first run.
109  * 
110  * 5     10/23/98 3:51p Dave
111  * Full support for tstrings.tbl and foreign languages. All that remains
112  * is to make it active in Fred.
113  * 
114  * 4     10/13/98 9:29a Dave
115  * Started neatening up freespace.h. Many variables renamed and
116  * reorganized. Added AlphaColors.[h,cpp]
117  * 
118  * 3     10/07/98 6:27p Dave
119  * Globalized mission and campaign file extensions. Removed Silent Threat
120  * special code. Moved \cache \players and \multidata into the \data
121  * directory.
122  * 
123  * 2     10/07/98 10:54a Dave
124  * Initial checkin.
125  * 
126  * 1     10/07/98 10:51a Dave
127  * 
128  *
129  * $NoKeywords: $
130  */
131
132 #include "osapi.h"
133 #include "uidefs.h"
134 #include "ui.h"
135 #include "freespace.h"
136 #include "bmpman.h"
137 #include "palman.h"
138 #include "parselo.h"
139 #include "timer.h"
140 #include "alphacolors.h"
141 #include "font.h"
142 #include "localize.h"
143 #include "cmdline.h"
144
145 // global xstr colors
146 color *Xstr_colors[UI_NUM_XSTR_COLORS][3] = {
147         {       // UI_XSTR_COLOR_GREEN
148                 &Color_normal,
149                 &Color_ui_light_green,
150                 &Color_ui_green,
151         },
152         {       // UI_XSTR_COLOR_PINK
153                 &Color_normal,
154                 &Color_ui_light_pink,
155                 &Color_ui_pink,
156         },
157 };
158
159 // --------------------------------------------------------------------
160 // UI_WINDOW constructor
161 //
162 //
163 UI_WINDOW::UI_WINDOW()
164 {
165         int idx;
166
167         mask_bmap_id = -1;                              // bitmap id of the mask bitmap to define hotspots
168         foreground_bmap_id = -1;                // bitmap id of the foreground bitmap to display
169         mask_bmap_ptr = NULL;                   // pointer to bitmap of the mask
170         mask_data = NULL;                                       // points to raw mask bitmap data
171         mask_w = -1;                                            // bitmap width
172         mask_h = -1;                                            // bitmap height
173         tooltip_handler = NULL;                 // pointer to function to handle custom tooltips
174
175         // NULL all the xstring structs
176         for(idx=0; idx<MAX_UI_XSTRS; idx++){
177                 xstrs[idx] = NULL;
178         }
179 }
180
181 // --------------------------------------------------------------------
182 // UI_WINDOW destructor
183 //
184 //
185 UI_WINDOW::~UI_WINDOW()
186 {
187 }
188
189 // --------------------------------------------------------------------
190 // UI_WINDOW::set_mask_bmap()
191 //
192 // Specify the filename for the mask bitmap to use.  This has the hotspots
193 // for all the different controls.
194 //
195 void UI_WINDOW::set_mask_bmap(const char *fname)
196 {
197         int bmap;
198
199         bmap = bm_load(fname);
200
201         if (bmap < 0) {
202                 Error(LOCATION, "Could not load in %s!", fname);
203
204         } else {
205                 set_mask_bmap(bmap, fname);
206         }
207 }
208
209 void UI_WINDOW::set_mask_bmap(int bmap, const char *name)
210 {
211         // int i;
212
213         // init_tooltips();
214         Assert(bmap >= 0);      
215
216         if (bmap != mask_bmap_id) {
217                 if (mask_bmap_id >= 0){
218                         bm_unlock(mask_bmap_id);
219                 }
220
221                 mask_w = -1;
222                 mask_h = -1;
223
224                 mask_bmap_id = bmap;
225                 mask_bmap_ptr = bm_lock(mask_bmap_id, 8, BMP_AABITMAP);
226                 mask_data = (ushort *) mask_bmap_ptr->data;             
227                 bm_get_info( bmap, &mask_w, &mask_h );
228                 tt_group = -1;
229                 /*
230                 for (i=0; i<Num_tooltip_groups; i++){
231                         if (!stricmp(Tooltip_groups[i].mask, name)){
232                                 tt_group = i;
233                         }
234                 }
235                 */
236         } else {
237                 nprintf(("UI", "Warning: tried to switch bitmap mask to the same bitmap\n"));
238         }
239 }
240
241 // --------------------------------------------------------------------
242 // UI_WINDOW::set_foreground_bmap()
243 //
244 // Specify the filename for the mask bitmap to display on the ui window as
245 // a background.
246 //
247 void UI_WINDOW::set_foreground_bmap(const char *fname)
248 {
249         // load in the background bitmap 
250         foreground_bmap_id = bm_load(fname);
251         if (foreground_bmap_id < 0) {
252                 Error(LOCATION,"Could not load in %s!",fname);
253         }
254 #ifndef HARDWARE_ONLY
255         palette_use_bm_palette(foreground_bmap_id);
256 #endif
257 }
258
259
260 void UI_WINDOW::create( int _x, int _y, int _w, int _h, int _flags )
261 {
262         x = _x;
263         y = _y;
264         w = _w;
265         h = _h;
266         flags = _flags;
267         first_gadget = NULL;
268         selected_gadget = NULL;
269         tooltip_handler = NULL;  // pointer to function to handle custom tooltips
270         ignore_gadgets = 0;
271         use_hack_to_get_around_stupid_problem_flag = 0;
272
273         f_id = gr_init_font("font01.vf");
274
275         if (_x < 0)
276                 _x = 0;
277         if (_x + _w - 1 >= gr_screen.max_w)
278                 _x = gr_screen.max_w - _w;
279         if (_y < 0)
280                 _y = 0;
281         if (_y + _h - 1 >= gr_screen.max_h)
282                 _y = gr_screen.max_h - _h;
283
284         game_flush();
285 }
286
287 void UI_WINDOW::release_bitmaps()
288 {
289         if (mask_bmap_ptr) {
290                 // done with the mask bitmap, so unlock it
291                 bm_unlock(mask_bmap_id);
292
293                 // unload the bitmaps
294                 if (mask_bmap_id >= 0) {
295                         bm_release(mask_bmap_id);
296                         mask_bmap_id = -1;
297                 }
298
299                 mask_bmap_ptr = NULL;
300         }
301
302         if (foreground_bmap_id >= 0) {
303                 bm_release(foreground_bmap_id);
304                 foreground_bmap_id = -1;
305         }
306 }
307
308 void UI_WINDOW::destroy()
309 {
310         UI_GADGET *cur;
311         int idx;
312
313         // free up any bitmaps
314         release_bitmaps();
315
316         // destroy all gadgets
317         if (first_gadget) {
318                 cur = first_gadget;
319                 do {
320                         cur->destroy();
321                         cur = cur->next;
322
323                 } while (cur != first_gadget);
324         }
325
326         // free up all xstrs
327         for(idx=0; idx<MAX_UI_XSTRS; idx++){
328                 // free up this struct
329                 if(xstrs[idx] != NULL){
330                         if(xstrs[idx]->xstr != NULL){
331                                 free((char *)xstrs[idx]->xstr);
332                         }
333                         free(xstrs[idx]);
334                         xstrs[idx] = NULL;
335                 }
336         }
337 }
338
339 void UI_WINDOW::draw()
340 {
341         UI_GADGET *tmp;
342
343         gr_reset_clip();
344         gr_set_font(f_id);
345
346         if (foreground_bmap_id >= 0) {
347                 gr_set_bitmap(foreground_bmap_id, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
348                 gr_bitmap(x, y);
349         }
350
351         if (flags & WIN_FILLED) {
352                 ui_draw_box_out(x, y, x+w-1, y+h-1);
353         }
354
355         if (flags & WIN_BORDER) {
356                 ui_draw_frame(x-BORDER_WIDTH, y-BORDER_WIDTH, x+w+BORDER_WIDTH-1, y+h+BORDER_WIDTH-1);
357         }
358
359         if (first_gadget) {
360                 tmp = first_gadget;
361                 do      {
362                         if (!tmp->hidden)
363                                 tmp->draw();
364
365                         tmp = tmp->next;
366
367                 } while (tmp != first_gadget);
368         }
369
370         if (first_gadget) {
371                 tmp = first_gadget;
372                 do      {
373                         if (!tmp->hidden && (tmp->kind == UI_KIND_BUTTON) && ((UI_BUTTON *) tmp)->button_down()){
374                                 tmp->draw();
375                         }
376
377                         tmp = tmp->next;
378                 } while (tmp != first_gadget);
379         }
380
381         // draw all xstrs
382         draw_xstrs();
383
384         // draw tooltips
385         draw_tooltip();
386
387         // convenient debug code for showing mouse coords
388         if(Cmdline_mouse_coords){
389                 int mx, my;
390                 mouse_get_pos(&mx, &my);
391                 // mprintf(("MOUSE (%d, %d)\n", mx, my));                                       
392                 gr_set_color_fast(&Color_normal);
393                 gr_printf(mx, my - 12, "%d %d", mx, my);
394         }       
395 }
396
397 void UI_WINDOW::draw_XSTR_forced(UI_GADGET *owner, int frame)
398 {
399         int idx;
400
401         // lookup the xstr and draw it if necessary
402         for(idx=0; idx<MAX_UI_XSTRS; idx++){
403                 if((xstrs[idx] != NULL) && (xstrs[idx]->assoc == owner)){
404                         draw_one_xstr(xstrs[idx], frame);                       
405                 }
406         }       
407 }
408
409 int UI_WINDOW::get_current_hotspot()
410 {
411         int offset, pixel_val;
412
413         if (!mask_data){
414                 return -1;
415         }
416
417         // check the pixel value under the mouse
418         offset = ui_mouse.y * gr_screen.max_w + ui_mouse.x;
419         pixel_val = *( ((ubyte*)mask_data) + offset);
420         return pixel_val;
421 }
422
423 void UI_WINDOW::draw_tooltip()
424 {
425         // int i;
426         // tooltip_group *ptr;
427         int hotspot;    
428         UI_GADGET *gadget;
429
430         if (tt_group < 0)
431                 return;
432
433         // ptr = &Tooltip_groups[tt_group];
434         hotspot = get_current_hotspot();
435
436 //      mprintf(("HOTSPOT: %d [%d]\n",hotspot, Framecount));
437
438         /*
439         if (hotspot != last_tooltip_hotspot) {
440                 last_tooltip_hotspot = hotspot;
441                 last_tooltip_time = timer_get_milliseconds();
442                 ttx = tty = -1;
443                 return;
444
445         } else if (timer_get_milliseconds() - last_tooltip_time < TOOLTIP_DELAY)
446                 return;
447         */
448
449         if (first_gadget) {
450                 gadget = first_gadget;
451                 do      {
452                         if (gadget->get_hotspot() == hotspot) {
453                                 if (gadget->hidden) {  // if control is hidden, don't draw tooltip for it.
454                                         return;
455                                 } else {
456                                         break;
457                                 }
458                         }
459
460                         gadget = gadget->next;
461
462                 } while (gadget != first_gadget);
463         }
464
465         /*
466         for (i=ptr->start; i<ptr->end; i++) {
467                 if (Tooltips[i].hotspot == hotspot) {
468                         char *str;
469                         int w, h;
470
471                         str = Tooltips[i].text;
472                         if (str[0] == '@') {
473                                 if (!tooltip_handler)
474                                         Error(LOCATION, "No tooltip handler for screen with mask \"%s\"", ptr->mask);
475
476                                 str = (*tooltip_handler)(str);  // Let the screen handle the custom tooltips
477                                 if (!str)
478                                         return;
479                         }
480
481                         if (ttx < 0 || tty < 0) {
482                                 gr_get_string_size(&w, &h, str);
483                                 Assert(w < 320 && h < 100);
484                                 ttx = ui_mouse.x - w / 2;
485                                 tty = ui_mouse.y - h;
486                         }
487
488                         render_tooltip(str);
489                 }
490         }
491         */
492 }
493
494 void UI_WINDOW::render_tooltip(const char *str)
495 {
496         int w, h;
497
498         gr_get_string_size(&w, &h, str);
499         Assert(w < gr_screen.max_w - 4 && h < gr_screen.max_h - 4);
500
501         if (ttx < 2)
502                 ttx = 2;
503
504         if (tty < 2)
505                 tty = 2;
506
507         if (ttx + w + 2 > gr_screen.max_w)
508                 ttx = gr_screen.max_w - w;
509
510         if (tty + h + 2 > gr_screen.max_h)
511                 tty = gr_screen.max_h - h;
512
513         gr_set_color_fast(&Color_black);
514         gr_rect(ttx - 1, tty - 1, w + 2, h + 1);
515
516         gr_set_color_fast(&Color_bright_white);
517         gr_string(ttx, tty, str);
518 }
519
520 // key_in: If not -1, this means to use this key as input, and not call game_poll()
521 int UI_WINDOW::process(int key_in,int process_mouse)
522 {
523         UI_GADGET *tmp;
524
525         // only does stuff in non THREADED mode
526         os_poll();
527
528         if (process_mouse){
529                 ui_mouse_process();
530         }
531
532         if (key_in == -1){
533                 keypress = game_check_key();
534         } else {
535                 keypress = key_in;
536         }
537
538         last_keypress = keypress;
539         do_dump_check();
540         if (mouse_captured_gadget && B1_RELEASED){
541                 mouse_captured_gadget = NULL;
542         }
543
544         // The following code was commented out by NeilK on 4/15/99 to fix a problem we were having with
545         //      the UI_SLIDER2 class not receiving the process event when the mouse was dragging the scroller
546         // but outside the mask region. I checked a handful of other screens and so no adverse affects
547         // of this change at the time.
548
549 /*
550         if (mouse_captured_gadget) {
551                 mouse_captured_gadget->process();  // if a control has captured the mouse, only it gets processed
552                 use_hack_to_get_around_stupid_problem_flag = 0;
553                 return last_keypress;
554         }
555 */
556         if (!first_gadget) {
557                 use_hack_to_get_around_stupid_problem_flag = 0;
558                 return last_keypress;
559         }
560
561         check_focus_switch_keys();
562
563         // run through all top level gadgets and process them (they are responsible for processing
564         // their children, which UI_GADGET will handle if you don't override process() or if you
565         // do, you call UI_GADGET::process()).
566         if ( !ignore_gadgets ) {
567                 tmp = first_gadget;
568                 do      {
569                         if ( !tmp->check_move() )
570                                 tmp->process();
571
572                         tmp = tmp->next;
573
574                 } while (tmp != first_gadget);
575         }
576
577         use_hack_to_get_around_stupid_problem_flag = 0;
578         return last_keypress;
579 }
580
581 void UI_WINDOW::check_focus_switch_keys()
582 {
583         return;
584 }
585
586 void UI_WINDOW::capture_mouse(UI_GADGET *gadget)
587 {
588         mouse_captured_gadget = gadget;
589 }
590
591 void UI_WINDOW::set_ignore_gadgets(int state)
592 {
593         ignore_gadgets = state;
594 }
595
596 void UI_WINDOW::add_XSTR(const char *string, int _xstr_id, int _x, int _y, UI_GADGET *_assoc, int _color_type, int _font_id)
597 {
598         int idx;
599         int found = -1;
600         UI_XSTR *x;
601
602         // try and find a free xstr
603         for(idx=0; idx<MAX_UI_XSTRS; idx++){
604                 if(xstrs[idx] == NULL){
605                         found = idx;
606                         break;
607                 }
608         }
609
610         // if we don't have a free spot
611         if(found < 0){
612                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
613                 return;
614         }
615
616         // allocate a new struct
617         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
618         if(xstrs[idx] == NULL){
619                 return;
620         }
621         x = xstrs[idx]; 
622
623         // fill in the data
624         x->xstr = strdup(string);               
625         if(x->xstr == NULL){
626                 free(x);
627                 xstrs[idx] = NULL;
628                 return;
629         }
630         x->xstr_id = _xstr_id;
631         x->x = _x;
632         x->y = _y;
633         x->assoc = _assoc;
634         x->font_id = _font_id;  
635         x->clr = _color_type;
636         Assert((x->clr >= 0) && (x->clr < UI_NUM_XSTR_COLORS));
637         if((x->clr < 0) || (x->clr >= UI_NUM_XSTR_COLORS)){
638                 x->clr = 0;
639         }       
640 }
641
642 void UI_WINDOW::add_XSTR(UI_XSTR *xstr)
643 {
644         int idx;
645         int found = -1;
646         UI_XSTR *x;
647
648         // try and find a free xstr
649         for(idx=0; idx<MAX_UI_XSTRS; idx++){
650                 if(xstrs[idx] == NULL){
651                         found = idx;
652                         break;
653                 }
654         }
655
656         // if we don't have a free spot
657         if(found < 0){
658                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
659                 return;
660         }
661
662         // allocate a new struct
663         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
664         if(xstrs[idx] == NULL){
665                 return;
666         }
667         x = xstrs[idx]; 
668
669         // fill in the data
670         x->xstr = strdup(xstr->xstr);
671         if(x->xstr == NULL){
672                 free(x);
673                 xstrs[idx] = NULL;
674                 return;
675         }
676         x->xstr_id = xstr->xstr_id;
677         x->x = xstr->x;
678         x->y = xstr->y;
679         x->assoc = xstr->assoc;
680         x->font_id = xstr->font_id;     
681         x->clr = xstr->clr;
682         Assert((x->clr >= 0) && (x->clr < UI_NUM_XSTR_COLORS));
683         if((x->clr < 0) || (x->clr >= UI_NUM_XSTR_COLORS)){
684                 x->clr = 0;
685         }       
686 }
687
688 void UI_WINDOW::draw_one_xstr(UI_XSTR *x, int frame)
689 {
690         font *f_backup = NULL;          
691         char str[255] = "";
692
693         // sanity
694         if((x == NULL) || (x->xstr == NULL)){
695                 return;
696         }
697
698         // if it has an associated gadet that is hidden, do nothing
699         if((x->assoc != NULL) && (x->assoc->hidden)){
700                 return;
701         }
702         
703         // maybe set the font
704         if(x->font_id >= 0){
705                 // backup the current font
706                 Assert(Current_font != NULL);
707                 f_backup = Current_font;
708
709                 // set the new font
710                 gr_set_font(x->font_id);
711         }
712
713         // set the color
714         if(x->assoc == NULL){                   
715                 gr_set_color_fast(&Color_normal);
716         } else {
717                 // just buttons for now
718                 switch(x->assoc->kind){
719                 case UI_KIND_BUTTON:                                    
720                         // override case
721                         if((frame != -1) && (frame < 3)){
722                                 gr_set_color_fast(Xstr_colors[x->clr][frame]);
723                         }
724                         // normal checking
725                         else {
726                                 // if the button is pressed
727                                 if(((UI_BUTTON*)x->assoc)->button_down()){
728                                         gr_set_color_fast(Xstr_colors[x->clr][2]);
729                                 } 
730                                 // if the mouse is just over it
731                                 else if(x->assoc->is_mouse_on()){
732                                         gr_set_color_fast(Xstr_colors[x->clr][1]);
733                                 } else {
734                                         gr_set_color_fast(Xstr_colors[x->clr][0]);
735                                 }
736                                 break;
737                         }
738                         break;
739
740                 // all other controls just draw the normal frame
741                 default :
742                         if((frame != -1) && (frame < 3)){
743                                 gr_set_color_fast(Xstr_colors[x->clr][frame]);
744                         } else {
745                                 gr_set_color_fast(Xstr_colors[x->clr][0]);
746                         }
747                         break;
748                 }               
749
750                 // if the gadget disabled, just draw the normal nonhighlighted frame
751                 if(x->assoc->disabled()){
752                         gr_set_color_fast(Xstr_colors[x->clr][0]);
753                 }
754         }
755
756         // print this puppy out 
757         int xoffset = lcl_get_xstr_offset(x->xstr_id, gr_screen.res);
758         strncpy(str, XSTR(x->xstr, x->xstr_id), 254);
759         if(str[0] == '&'){
760                 if(strlen(str) > 1){                    
761                         gr_string((x->x) + xoffset, x->y, str + 1);
762                 }
763         } else {
764                 gr_string((x->x) + xoffset, x->y, str);
765         }
766
767         // maybe restore the old font
768         if(f_backup != NULL){
769                 Current_font = f_backup;
770         }                       
771 }
772
773 void UI_WINDOW::draw_xstrs()
774 {
775         int idx = 0;
776         
777         // draw the xstrs
778         do {
779                 draw_one_xstr(xstrs[idx], -1);          
780
781                 // next xstr
782                 idx++;
783         } while(idx < MAX_UI_XSTRS);
784 }
785
786 // TEST CODE 
787
788 void UI_WINDOW::do_dump_check()
789 {
790 #if 0
791         if ( keypress == KEY_SHIFTED+KEY_CTRLED+KEY_ALTED+SDLK_F12 ) {
792                 FILE *fp;
793
794                 last_keypress = keypress = 0;
795
796                 mprintf(( "\n========== WINDOW GADGETS =========\n" ));
797                 mprintf(( "(Also dumped to ui.out)\n" ));
798
799                 fp = fopen( "ui.out", "wt" );
800                 tmp = first_gadget;
801                 do      {
802                         if ( tmp->parent == NULL ) {    
803                                 switch ( tmp->kind ) {
804                                 case UI_KIND_BUTTON:
805                                         mprintf(( "UI: Button at %d,%d\n", tmp->x, tmp->y ));
806                                         fprintf( fp, "UI: Button at %d,%d\n", tmp->x, tmp->y );
807                                         break;
808                                 case UI_KIND_KEYTRAP:
809                                         mprintf(( "UI: Keytrap at %d,%d\n", tmp->x, tmp->y ));
810                                         fprintf( fp, "UI: Keytrap at %d,%d\n", tmp->x, tmp->y );
811                                         break;
812                                 case UI_KIND_CHECKBOX:
813                                         mprintf(( "UI: Checkbox at %d,%d\n", tmp->x, tmp->y ));
814                                         fprintf( fp, "UI: Checkbox at %d,%d\n", tmp->x, tmp->y );
815                                         break;
816                                 case UI_KIND_RADIO:
817                                         mprintf(( "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y ));
818                                         fprintf( fp, "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y );
819                                         break;
820                                 case UI_KIND_SCROLLBAR:
821                                         mprintf(( "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y ));
822                                         fprintf( fp, "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y );
823                                         break;
824                                 case UI_KIND_LISTBOX:
825                                         mprintf(( "UI: Listbox at %d,%d\n", tmp->x, tmp->y ));
826                                         fprintf( fp, "UI: Listbox at %d,%d\n", tmp->x, tmp->y );
827                                         break;
828                                 case UI_KIND_INPUTBOX:
829                                         mprintf(( "UI: Inputbox at %d,%d\n", tmp->x, tmp->y ));
830                                         fprintf( fp, "UI: Inputbox at %d,%d\n", tmp->x, tmp->y );
831                                         break;
832                                 default:
833                                         mprintf(( "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y ));
834                                         fprintf( fp, "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y );
835                                 }
836                         }
837                         tmp = tmp->next;
838                 } while( tmp != first_gadget );
839                 fclose(fp);
840                 mprintf(( "===================================\n" ));
841         }
842 #endif
843 }
844
845 /*
846 void parse_tooltip(int n)
847 {
848         char buf[MESSAGE_LENGTH];
849
850         stuff_int(&Tooltips[n].hotspot);
851         stuff_string(buf, F_MESSAGE, NULL);
852         Tooltips[n].text = strdup(buf);
853 }
854
855 int parse_tooltips_group(int group, int n)
856 {
857         char buf[NAME_LENGTH];
858
859         Assert(group < MAX_TOOLTIP_GROUPS);
860         required_string("$Mask Filename:");
861         stuff_string(buf, F_NAME, NULL);
862         Tooltip_groups[group].mask = strdup(buf);
863         Tooltip_groups[group].start = n;
864
865         while (1) {
866                 if (check_for_string("#") || check_for_string("$")) {
867                         Tooltip_groups[group].end = n;
868                         return n;
869                 }
870
871                 Assert(n < MAX_TOOLTIPS);
872                 parse_tooltip(n++);
873         }
874 }
875
876 void parse_ship_tooltip(int n)
877 {
878 }
879
880 void parse_weapon_tooltip(int n)
881 {
882 }
883
884 void parse_tooltips()
885 {
886         int n;
887
888         // open localization
889         lcl_ext_open();
890
891         read_file_text("tooltips.tbl");
892
893         n = Num_tooltip_groups = 0;
894         reset_parse();
895
896         if (optional_string("#UI"))
897                 while (required_string_either("#", "$")) {
898                         n = parse_tooltips_group(Num_tooltip_groups, n);
899                         Num_tooltip_groups++;
900                 }
901
902         if (optional_string("#Ships"))
903                 while (required_string_either("#", "$")) {
904                         parse_ship_tooltip(Num_ship_tooltips);
905                         Num_ship_tooltips++;
906                 }
907
908         if (optional_string("#Weapons"))
909                 while (required_string_either("#", "$")) {
910                         parse_ship_tooltip(Num_weapon_tooltips);
911                         Num_weapon_tooltips++;
912                 }
913
914         required_string("#End");
915
916         // close localization
917         lcl_ext_close();
918 }
919
920 void init_tooltips()
921 {
922         static int inited = 0;
923
924         if (!inited) {
925                 int rval;
926
927                 if ((rval = setjmp(parse_abort)) != 0) {
928
929                 } else {                        
930 #ifndef DEMO
931                         parse_tooltips();
932 #endif
933                 }
934
935                 inited = 1;
936         }
937 }
938 */
939
940 void ok_clicked()
941 {
942         mprintf(( "OK Clicked!\n" ));
943 }
944
945 void do_help()
946 {
947         mprintf(( "Help!\n" ));
948 }
949