]> icculus.org git repositories - taylor/freespace2.git/blob - src/ui/window.cpp
get rid of some platform specific stuff
[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         SDL_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 (!SDL_strcasecmp(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                                 SDL_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         SDL_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         keypress_text = key_get_text_input();
545
546         // The following code was commented out by NeilK on 4/15/99 to fix a problem we were having with
547         //      the UI_SLIDER2 class not receiving the process event when the mouse was dragging the scroller
548         // but outside the mask region. I checked a handful of other screens and so no adverse affects
549         // of this change at the time.
550
551 /*
552         if (mouse_captured_gadget) {
553                 mouse_captured_gadget->process();  // if a control has captured the mouse, only it gets processed
554                 use_hack_to_get_around_stupid_problem_flag = 0;
555                 return last_keypress;
556         }
557 */
558         if (!first_gadget) {
559                 use_hack_to_get_around_stupid_problem_flag = 0;
560                 return last_keypress;
561         }
562
563         check_focus_switch_keys();
564
565         // run through all top level gadgets and process them (they are responsible for processing
566         // their children, which UI_GADGET will handle if you don't override process() or if you
567         // do, you call UI_GADGET::process()).
568         if ( !ignore_gadgets ) {
569                 tmp = first_gadget;
570                 do      {
571                         if ( !tmp->check_move() )
572                                 tmp->process();
573
574                         tmp = tmp->next;
575
576                 } while (tmp != first_gadget);
577         }
578
579         use_hack_to_get_around_stupid_problem_flag = 0;
580         return last_keypress;
581 }
582
583 void UI_WINDOW::check_focus_switch_keys()
584 {
585         return;
586 }
587
588 void UI_WINDOW::capture_mouse(UI_GADGET *gadget)
589 {
590         mouse_captured_gadget = gadget;
591 }
592
593 void UI_WINDOW::set_ignore_gadgets(int state)
594 {
595         ignore_gadgets = state;
596 }
597
598 void UI_WINDOW::add_XSTR(const char *string, int _xstr_id, int _x, int _y, UI_GADGET *_assoc, int _color_type, int _font_id)
599 {
600         int idx;
601         int found = -1;
602         UI_XSTR *x;
603
604         // try and find a free xstr
605         for(idx=0; idx<MAX_UI_XSTRS; idx++){
606                 if(xstrs[idx] == NULL){
607                         found = idx;
608                         break;
609                 }
610         }
611
612         // if we don't have a free spot
613         if(found < 0){
614                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
615                 return;
616         }
617
618         // allocate a new struct
619         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
620         if(xstrs[idx] == NULL){
621                 return;
622         }
623         x = xstrs[idx]; 
624
625         // fill in the data
626         x->xstr = strdup(string);               
627         if(x->xstr == NULL){
628                 free(x);
629                 xstrs[idx] = NULL;
630                 return;
631         }
632         x->xstr_id = _xstr_id;
633         x->x = _x;
634         x->y = _y;
635         x->assoc = _assoc;
636         x->font_id = _font_id;  
637         x->clr = _color_type;
638         SDL_assert((x->clr >= 0) && (x->clr < UI_NUM_XSTR_COLORS));
639         if((x->clr < 0) || (x->clr >= UI_NUM_XSTR_COLORS)){
640                 x->clr = 0;
641         }       
642 }
643
644 void UI_WINDOW::add_XSTR(UI_XSTR *xstr)
645 {
646         int idx;
647         int found = -1;
648         UI_XSTR *x;
649
650         // try and find a free xstr
651         for(idx=0; idx<MAX_UI_XSTRS; idx++){
652                 if(xstrs[idx] == NULL){
653                         found = idx;
654                         break;
655                 }
656         }
657
658         // if we don't have a free spot
659         if(found < 0){
660                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
661                 return;
662         }
663
664         // allocate a new struct
665         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
666         if(xstrs[idx] == NULL){
667                 return;
668         }
669         x = xstrs[idx]; 
670
671         // fill in the data
672         x->xstr = strdup(xstr->xstr);
673         if(x->xstr == NULL){
674                 free(x);
675                 xstrs[idx] = NULL;
676                 return;
677         }
678         x->xstr_id = xstr->xstr_id;
679         x->x = xstr->x;
680         x->y = xstr->y;
681         x->assoc = xstr->assoc;
682         x->font_id = xstr->font_id;     
683         x->clr = xstr->clr;
684         SDL_assert((x->clr >= 0) && (x->clr < UI_NUM_XSTR_COLORS));
685         if((x->clr < 0) || (x->clr >= UI_NUM_XSTR_COLORS)){
686                 x->clr = 0;
687         }       
688 }
689
690 void UI_WINDOW::draw_one_xstr(UI_XSTR *x, int frame)
691 {
692         font *f_backup = NULL;          
693         char str[255] = "";
694
695         // sanity
696         if((x == NULL) || (x->xstr == NULL)){
697                 return;
698         }
699
700         // if it has an associated gadet that is hidden, do nothing
701         if((x->assoc != NULL) && (x->assoc->hidden)){
702                 return;
703         }
704         
705         // maybe set the font
706         if(x->font_id >= 0){
707                 // backup the current font
708                 SDL_assert(Current_font != NULL);
709                 f_backup = Current_font;
710
711                 // set the new font
712                 gr_set_font(x->font_id);
713         }
714
715         // set the color
716         if(x->assoc == NULL){                   
717                 gr_set_color_fast(&Color_normal);
718         } else {
719                 // just buttons for now
720                 switch(x->assoc->kind){
721                 case UI_KIND_BUTTON:                                    
722                         // override case
723                         if((frame != -1) && (frame < 3)){
724                                 gr_set_color_fast(Xstr_colors[x->clr][frame]);
725                         }
726                         // normal checking
727                         else {
728                                 // if the button is pressed
729                                 if(((UI_BUTTON*)x->assoc)->button_down()){
730                                         gr_set_color_fast(Xstr_colors[x->clr][2]);
731                                 } 
732                                 // if the mouse is just over it
733                                 else if(x->assoc->is_mouse_on()){
734                                         gr_set_color_fast(Xstr_colors[x->clr][1]);
735                                 } else {
736                                         gr_set_color_fast(Xstr_colors[x->clr][0]);
737                                 }
738                                 break;
739                         }
740                         break;
741
742                 // all other controls just draw the normal frame
743                 default :
744                         if((frame != -1) && (frame < 3)){
745                                 gr_set_color_fast(Xstr_colors[x->clr][frame]);
746                         } else {
747                                 gr_set_color_fast(Xstr_colors[x->clr][0]);
748                         }
749                         break;
750                 }               
751
752                 // if the gadget disabled, just draw the normal nonhighlighted frame
753                 if(x->assoc->disabled()){
754                         gr_set_color_fast(Xstr_colors[x->clr][0]);
755                 }
756         }
757
758         // print this puppy out 
759         int xoffset = lcl_get_xstr_offset(x->xstr_id, gr_screen.res);
760         strncpy(str, XSTR(x->xstr, x->xstr_id), 254);
761         if(str[0] == '&'){
762                 if(strlen(str) > 1){                    
763                         gr_string((x->x) + xoffset, x->y, str + 1);
764                 }
765         } else {
766                 gr_string((x->x) + xoffset, x->y, str);
767         }
768
769         // maybe restore the old font
770         if(f_backup != NULL){
771                 Current_font = f_backup;
772         }                       
773 }
774
775 void UI_WINDOW::draw_xstrs()
776 {
777         int idx = 0;
778         
779         // draw the xstrs
780         do {
781                 draw_one_xstr(xstrs[idx], -1);          
782
783                 // next xstr
784                 idx++;
785         } while(idx < MAX_UI_XSTRS);
786 }
787
788 // TEST CODE 
789
790 void UI_WINDOW::do_dump_check()
791 {
792 #if 0
793         if ( keypress == KEY_SHIFTED+KEY_CTRLED+KEY_ALTED+SDLK_F12 ) {
794                 FILE *fp;
795
796                 last_keypress = keypress = 0;
797
798                 mprintf(( "\n========== WINDOW GADGETS =========\n" ));
799                 mprintf(( "(Also dumped to ui.out)\n" ));
800
801                 fp = fopen( "ui.out", "wt" );
802                 tmp = first_gadget;
803                 do      {
804                         if ( tmp->parent == NULL ) {    
805                                 switch ( tmp->kind ) {
806                                 case UI_KIND_BUTTON:
807                                         mprintf(( "UI: Button at %d,%d\n", tmp->x, tmp->y ));
808                                         fprintf( fp, "UI: Button at %d,%d\n", tmp->x, tmp->y );
809                                         break;
810                                 case UI_KIND_KEYTRAP:
811                                         mprintf(( "UI: Keytrap at %d,%d\n", tmp->x, tmp->y ));
812                                         fprintf( fp, "UI: Keytrap at %d,%d\n", tmp->x, tmp->y );
813                                         break;
814                                 case UI_KIND_CHECKBOX:
815                                         mprintf(( "UI: Checkbox at %d,%d\n", tmp->x, tmp->y ));
816                                         fprintf( fp, "UI: Checkbox at %d,%d\n", tmp->x, tmp->y );
817                                         break;
818                                 case UI_KIND_RADIO:
819                                         mprintf(( "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y ));
820                                         fprintf( fp, "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y );
821                                         break;
822                                 case UI_KIND_SCROLLBAR:
823                                         mprintf(( "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y ));
824                                         fprintf( fp, "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y );
825                                         break;
826                                 case UI_KIND_LISTBOX:
827                                         mprintf(( "UI: Listbox at %d,%d\n", tmp->x, tmp->y ));
828                                         fprintf( fp, "UI: Listbox at %d,%d\n", tmp->x, tmp->y );
829                                         break;
830                                 case UI_KIND_INPUTBOX:
831                                         mprintf(( "UI: Inputbox at %d,%d\n", tmp->x, tmp->y ));
832                                         fprintf( fp, "UI: Inputbox at %d,%d\n", tmp->x, tmp->y );
833                                         break;
834                                 default:
835                                         mprintf(( "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y ));
836                                         fprintf( fp, "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y );
837                                 }
838                         }
839                         tmp = tmp->next;
840                 } while( tmp != first_gadget );
841                 fclose(fp);
842                 mprintf(( "===================================\n" ));
843         }
844 #endif
845 }
846
847 /*
848 void parse_tooltip(int n)
849 {
850         char buf[MESSAGE_LENGTH];
851
852         stuff_int(&Tooltips[n].hotspot);
853         stuff_string(buf, F_MESSAGE, NULL);
854         Tooltips[n].text = strdup(buf);
855 }
856
857 int parse_tooltips_group(int group, int n)
858 {
859         char buf[NAME_LENGTH];
860
861         SDL_assert(group < MAX_TOOLTIP_GROUPS);
862         required_string("$Mask Filename:");
863         stuff_string(buf, F_NAME, NULL);
864         Tooltip_groups[group].mask = strdup(buf);
865         Tooltip_groups[group].start = n;
866
867         while (1) {
868                 if (check_for_string("#") || check_for_string("$")) {
869                         Tooltip_groups[group].end = n;
870                         return n;
871                 }
872
873                 SDL_assert(n < MAX_TOOLTIPS);
874                 parse_tooltip(n++);
875         }
876 }
877
878 void parse_ship_tooltip(int n)
879 {
880 }
881
882 void parse_weapon_tooltip(int n)
883 {
884 }
885
886 void parse_tooltips()
887 {
888         int n;
889
890         // open localization
891         lcl_ext_open();
892
893         read_file_text("tooltips.tbl");
894
895         n = Num_tooltip_groups = 0;
896         reset_parse();
897
898         if (optional_string("#UI"))
899                 while (required_string_either("#", "$")) {
900                         n = parse_tooltips_group(Num_tooltip_groups, n);
901                         Num_tooltip_groups++;
902                 }
903
904         if (optional_string("#Ships"))
905                 while (required_string_either("#", "$")) {
906                         parse_ship_tooltip(Num_ship_tooltips);
907                         Num_ship_tooltips++;
908                 }
909
910         if (optional_string("#Weapons"))
911                 while (required_string_either("#", "$")) {
912                         parse_ship_tooltip(Num_weapon_tooltips);
913                         Num_weapon_tooltips++;
914                 }
915
916         required_string("#End");
917
918         // close localization
919         lcl_ext_close();
920 }
921
922 void init_tooltips()
923 {
924         static int inited = 0;
925
926         if (!inited) {
927                 int rval;
928
929                 if ((rval = setjmp(parse_abort)) != 0) {
930
931                 } else {                        
932 #ifndef DEMO
933                         parse_tooltips();
934 #endif
935                 }
936
937                 inited = 1;
938         }
939 }
940 */
941
942 void ok_clicked()
943 {
944         mprintf(( "OK Clicked!\n" ));
945 }
946
947 void do_help()
948 {
949         mprintf(( "Help!\n" ));
950 }
951