]> icculus.org git repositories - taylor/freespace2.git/blob - src/ui/window.cpp
fix event and state help text
[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 }
255
256
257 void UI_WINDOW::create( int _x, int _y, int _w, int _h, int _flags )
258 {
259         x = _x;
260         y = _y;
261         w = _w;
262         h = _h;
263         flags = _flags;
264         first_gadget = NULL;
265         selected_gadget = NULL;
266         tooltip_handler = NULL;  // pointer to function to handle custom tooltips
267         ignore_gadgets = 0;
268         use_hack_to_get_around_stupid_problem_flag = 0;
269
270         f_id = gr_init_font("font01.vf");
271
272         if (x < 0)
273                 x = 0;
274         if (x + w - 1 >= gr_screen.max_w)
275                 x = gr_screen.max_w - w;
276         if (y < 0)
277                 y = 0;
278         if (y + h - 1 >= gr_screen.max_h)
279                 y = gr_screen.max_h - h;
280
281         game_flush();
282 }
283
284 void UI_WINDOW::release_bitmaps()
285 {
286         if (mask_bmap_ptr) {
287                 // done with the mask bitmap, so unlock it
288                 bm_unlock(mask_bmap_id);
289
290                 // unload the bitmaps
291                 if (mask_bmap_id >= 0) {
292                         bm_release(mask_bmap_id);
293                         mask_bmap_id = -1;
294                 }
295
296                 mask_bmap_ptr = NULL;
297         }
298
299         if (foreground_bmap_id >= 0) {
300                 bm_release(foreground_bmap_id);
301                 foreground_bmap_id = -1;
302         }
303 }
304
305 void UI_WINDOW::destroy()
306 {
307         UI_GADGET *cur;
308         int idx;
309
310         // free up any bitmaps
311         release_bitmaps();
312
313         // destroy all gadgets
314         if (first_gadget) {
315                 cur = first_gadget;
316                 do {
317                         cur->destroy();
318                         cur = cur->next;
319
320                 } while (cur != first_gadget);
321         }
322
323         // free up all xstrs
324         for(idx=0; idx<MAX_UI_XSTRS; idx++){
325                 // free up this struct
326                 if(xstrs[idx] != NULL){
327                         if(xstrs[idx]->xstr != NULL){
328                                 free((char *)xstrs[idx]->xstr);
329                         }
330                         free(xstrs[idx]);
331                         xstrs[idx] = NULL;
332                 }
333         }
334 }
335
336 void UI_WINDOW::draw()
337 {
338         UI_GADGET *tmp;
339
340         gr_reset_clip();
341         gr_set_font(f_id);
342
343         if (foreground_bmap_id >= 0) {
344                 gr_set_bitmap(foreground_bmap_id, GR_ALPHABLEND_NONE, GR_BITBLT_MODE_NORMAL, 1.0f, -1, -1);
345                 gr_bitmap(x, y);
346         }
347
348         if (flags & WIN_FILLED) {
349                 ui_draw_box_out(x, y, x+w-1, y+h-1);
350         }
351
352         if (flags & WIN_BORDER) {
353                 ui_draw_frame(x-BORDER_WIDTH, y-BORDER_WIDTH, x+w+BORDER_WIDTH-1, y+h+BORDER_WIDTH-1);
354         }
355
356         if (first_gadget) {
357                 tmp = first_gadget;
358                 do      {
359                         if (!tmp->hidden)
360                                 tmp->draw();
361
362                         tmp = tmp->next;
363
364                 } while (tmp != first_gadget);
365         }
366
367         if (first_gadget) {
368                 tmp = first_gadget;
369                 do      {
370                         if (!tmp->hidden && (tmp->kind == UI_KIND_BUTTON) && ((UI_BUTTON *) tmp)->button_down()){
371                                 tmp->draw();
372                         }
373
374                         tmp = tmp->next;
375                 } while (tmp != first_gadget);
376         }
377
378         // draw all xstrs
379         draw_xstrs();
380
381         // draw tooltips
382         draw_tooltip();
383
384         // convenient debug code for showing mouse coords
385         if(Cmdline_mouse_coords){
386                 int mx, my;
387                 mouse_get_pos(&mx, &my);
388                 // mprintf(("MOUSE (%d, %d)\n", mx, my));                                       
389                 gr_set_color_fast(&Color_normal);
390                 gr_printf(mx, my - 12, "%d %d", mx, my);
391         }       
392 }
393
394 void UI_WINDOW::draw_XSTR_forced(UI_GADGET *owner, int frame)
395 {
396         int idx;
397
398         // lookup the xstr and draw it if necessary
399         for(idx=0; idx<MAX_UI_XSTRS; idx++){
400                 if((xstrs[idx] != NULL) && (xstrs[idx]->assoc == owner)){
401                         draw_one_xstr(xstrs[idx], frame);                       
402                 }
403         }       
404 }
405
406 int UI_WINDOW::get_current_hotspot()
407 {
408         int offset, pixel_val;
409
410         if (!mask_data){
411                 return -1;
412         }
413
414         // check the pixel value under the mouse
415         offset = ui_mouse.y * gr_screen.max_w + ui_mouse.x;
416         pixel_val = *( ((ubyte*)mask_data) + offset);
417         return pixel_val;
418 }
419
420 void UI_WINDOW::draw_tooltip()
421 {
422         // int i;
423         // tooltip_group *ptr;
424         int hotspot;    
425         UI_GADGET *gadget;
426
427         if (tt_group < 0)
428                 return;
429
430         // ptr = &Tooltip_groups[tt_group];
431         hotspot = get_current_hotspot();
432
433 //      mprintf(("HOTSPOT: %d [%d]\n",hotspot, Framecount));
434
435         /*
436         if (hotspot != last_tooltip_hotspot) {
437                 last_tooltip_hotspot = hotspot;
438                 last_tooltip_time = timer_get_milliseconds();
439                 ttx = tty = -1;
440                 return;
441
442         } else if (timer_get_milliseconds() - last_tooltip_time < TOOLTIP_DELAY)
443                 return;
444         */
445
446         if (first_gadget) {
447                 gadget = first_gadget;
448                 do      {
449                         if (gadget->get_hotspot() == hotspot) {
450                                 if (gadget->hidden) {  // if control is hidden, don't draw tooltip for it.
451                                         return;
452                                 } else {
453                                         break;
454                                 }
455                         }
456
457                         gadget = gadget->next;
458
459                 } while (gadget != first_gadget);
460         }
461
462         /*
463         for (i=ptr->start; i<ptr->end; i++) {
464                 if (Tooltips[i].hotspot == hotspot) {
465                         char *str;
466                         int w, h;
467
468                         str = Tooltips[i].text;
469                         if (str[0] == '@') {
470                                 if (!tooltip_handler)
471                                         Error(LOCATION, "No tooltip handler for screen with mask \"%s\"", ptr->mask);
472
473                                 str = (*tooltip_handler)(str);  // Let the screen handle the custom tooltips
474                                 if (!str)
475                                         return;
476                         }
477
478                         if (ttx < 0 || tty < 0) {
479                                 gr_get_string_size(&w, &h, str);
480                                 SDL_assert(w < 320 && h < 100);
481                                 ttx = ui_mouse.x - w / 2;
482                                 tty = ui_mouse.y - h;
483                         }
484
485                         render_tooltip(str);
486                 }
487         }
488         */
489 }
490
491 void UI_WINDOW::render_tooltip(const char *str)
492 {
493         int width, height;
494
495         gr_get_string_size(&width, &height, str);
496         SDL_assert(width < gr_screen.max_w - 4 && height < gr_screen.max_h - 4);
497
498         if (ttx < 2)
499                 ttx = 2;
500
501         if (tty < 2)
502                 tty = 2;
503
504         if (ttx + width + 2 > gr_screen.max_w)
505                 ttx = gr_screen.max_w - width;
506
507         if (tty + height + 2 > gr_screen.max_h)
508                 tty = gr_screen.max_h - height;
509
510         gr_set_color_fast(&Color_black);
511         gr_rect(ttx - 1, tty - 1, width + 2, height + 1);
512
513         gr_set_color_fast(&Color_bright_white);
514         gr_string(ttx, tty, str);
515 }
516
517 // key_in: If not -1, this means to use this key as input, and not call game_poll()
518 int UI_WINDOW::process(int key_in,int process_mouse)
519 {
520         UI_GADGET *tmp;
521
522         // only does stuff in non THREADED mode
523         os_poll();
524
525         if (process_mouse){
526                 ui_mouse_process();
527         }
528
529         if (key_in == -1){
530                 keypress = game_check_key();
531         } else {
532                 keypress = key_in;
533         }
534
535         last_keypress = keypress;
536         do_dump_check();
537         if (mouse_captured_gadget && B1_RELEASED){
538                 mouse_captured_gadget = NULL;
539         }
540
541         keypress_text = key_get_text_input();
542
543         // The following code was commented out by NeilK on 4/15/99 to fix a problem we were having with
544         //      the UI_SLIDER2 class not receiving the process event when the mouse was dragging the scroller
545         // but outside the mask region. I checked a handful of other screens and so no adverse affects
546         // of this change at the time.
547
548 /*
549         if (mouse_captured_gadget) {
550                 mouse_captured_gadget->process();  // if a control has captured the mouse, only it gets processed
551                 use_hack_to_get_around_stupid_problem_flag = 0;
552                 return last_keypress;
553         }
554 */
555         if (!first_gadget) {
556                 use_hack_to_get_around_stupid_problem_flag = 0;
557                 return last_keypress;
558         }
559
560         check_focus_switch_keys();
561
562         // run through all top level gadgets and process them (they are responsible for processing
563         // their children, which UI_GADGET will handle if you don't override process() or if you
564         // do, you call UI_GADGET::process()).
565         if ( !ignore_gadgets ) {
566                 tmp = first_gadget;
567                 do      {
568                         if ( !tmp->check_move() )
569                                 tmp->process();
570
571                         tmp = tmp->next;
572
573                 } while (tmp != first_gadget);
574         }
575
576         use_hack_to_get_around_stupid_problem_flag = 0;
577         return last_keypress;
578 }
579
580 void UI_WINDOW::check_focus_switch_keys()
581 {
582         return;
583 }
584
585 void UI_WINDOW::capture_mouse(UI_GADGET *gadget)
586 {
587         mouse_captured_gadget = gadget;
588 }
589
590 void UI_WINDOW::set_ignore_gadgets(int state)
591 {
592         ignore_gadgets = state;
593 }
594
595 void UI_WINDOW::add_XSTR(const char *string, int _xstr_id, int _x, int _y, UI_GADGET *_assoc, int _color_type, int _font_id)
596 {
597         int idx;
598         int found = -1;
599         UI_XSTR *xp;
600
601         // try and find a free xstr
602         for(idx=0; idx<MAX_UI_XSTRS; idx++){
603                 if(xstrs[idx] == NULL){
604                         found = idx;
605                         break;
606                 }
607         }
608
609         // if we don't have a free spot
610         if(found < 0){
611                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
612                 return;
613         }
614
615         // allocate a new struct
616         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
617         if(xstrs[idx] == NULL){
618                 return;
619         }
620         xp = xstrs[idx];        
621
622         // fill in the data
623         xp->xstr = strdup(string);              
624         if(xp->xstr == NULL){
625                 free(xp);
626                 xstrs[idx] = NULL;
627                 return;
628         }
629         xp->xstr_id = _xstr_id;
630         xp->x = _x;
631         xp->y = _y;
632         xp->assoc = _assoc;
633         xp->font_id = _font_id; 
634         xp->clr = _color_type;
635         SDL_assert((xp->clr >= 0) && (xp->clr < UI_NUM_XSTR_COLORS));
636         if((xp->clr < 0) || (xp->clr >= UI_NUM_XSTR_COLORS)){
637                 xp->clr = 0;
638         }       
639 }
640
641 void UI_WINDOW::add_XSTR(UI_XSTR *xstr)
642 {
643         int idx;
644         int found = -1;
645         UI_XSTR *xp;
646
647         // try and find a free xstr
648         for(idx=0; idx<MAX_UI_XSTRS; idx++){
649                 if(xstrs[idx] == NULL){
650                         found = idx;
651                         break;
652                 }
653         }
654
655         // if we don't have a free spot
656         if(found < 0){
657                 Int3();                 // aieee! we need to up the max # of xstrs allowed in a window.
658                 return;
659         }
660
661         // allocate a new struct
662         xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
663         if(xstrs[idx] == NULL){
664                 return;
665         }
666         xp = xstrs[idx];        
667
668         // fill in the data
669         xp->xstr = strdup(xstr->xstr);
670         if(xp->xstr == NULL){
671                 free(xp);
672                 xstrs[idx] = NULL;
673                 return;
674         }
675         xp->xstr_id = xstr->xstr_id;
676         xp->x = xstr->x;
677         xp->y = xstr->y;
678         xp->assoc = xstr->assoc;
679         xp->font_id = xstr->font_id;    
680         xp->clr = xstr->clr;
681         SDL_assert((xp->clr >= 0) && (xp->clr < UI_NUM_XSTR_COLORS));
682         if((xp->clr < 0) || (xp->clr >= UI_NUM_XSTR_COLORS)){
683                 xp->clr = 0;
684         }       
685 }
686
687 void UI_WINDOW::draw_one_xstr(UI_XSTR *xp, int frame)
688 {
689         font *f_backup = NULL;          
690         char str[255] = "";
691
692         // sanity
693         if((xp == NULL) || (xp->xstr == NULL)){
694                 return;
695         }
696
697         // if it has an associated gadet that is hidden, do nothing
698         if((xp->assoc != NULL) && (xp->assoc->hidden)){
699                 return;
700         }
701         
702         // maybe set the font
703         if(xp->font_id >= 0){
704                 // backup the current font
705                 SDL_assert(Current_font != NULL);
706                 f_backup = Current_font;
707
708                 // set the new font
709                 gr_set_font(xp->font_id);
710         }
711
712         // set the color
713         if(xp->assoc == NULL){                  
714                 gr_set_color_fast(&Color_normal);
715         } else {
716                 // just buttons for now
717                 switch(xp->assoc->kind){
718                 case UI_KIND_BUTTON:                                    
719                         // override case
720                         if((frame != -1) && (frame < 3)){
721                                 gr_set_color_fast(Xstr_colors[xp->clr][frame]);
722                         }
723                         // normal checking
724                         else {
725                                 // if the button is pressed
726                                 if(((UI_BUTTON*)xp->assoc)->button_down()){
727                                         gr_set_color_fast(Xstr_colors[xp->clr][2]);
728                                 } 
729                                 // if the mouse is just over it
730                                 else if(xp->assoc->is_mouse_on()){
731                                         gr_set_color_fast(Xstr_colors[xp->clr][1]);
732                                 } else {
733                                         gr_set_color_fast(Xstr_colors[xp->clr][0]);
734                                 }
735                                 break;
736                         }
737                         break;
738
739                 // all other controls just draw the normal frame
740                 default :
741                         if((frame != -1) && (frame < 3)){
742                                 gr_set_color_fast(Xstr_colors[xp->clr][frame]);
743                         } else {
744                                 gr_set_color_fast(Xstr_colors[xp->clr][0]);
745                         }
746                         break;
747                 }               
748
749                 // if the gadget disabled, just draw the normal nonhighlighted frame
750                 if(xp->assoc->disabled()){
751                         gr_set_color_fast(Xstr_colors[xp->clr][0]);
752                 }
753         }
754
755         // print this puppy out 
756         int xoffset = lcl_get_xstr_offset(xp->xstr_id, gr_screen.res);
757         SDL_strlcpy(str, XSTR(xp->xstr, xp->xstr_id), SDL_arraysize(str));
758         if(str[0] == '&'){
759                 if(strlen(str) > 1){                    
760                         gr_string((xp->x) + xoffset, xp->y, str + 1);
761                 }
762         } else {
763                 gr_string((xp->x) + xoffset, xp->y, str);
764         }
765
766         // maybe restore the old font
767         if(f_backup != NULL){
768                 Current_font = f_backup;
769         }                       
770 }
771
772 void UI_WINDOW::draw_xstrs()
773 {
774         int idx = 0;
775         
776         // draw the xstrs
777         do {
778                 draw_one_xstr(xstrs[idx], -1);          
779
780                 // next xstr
781                 idx++;
782         } while(idx < MAX_UI_XSTRS);
783 }
784
785 // TEST CODE 
786
787 void UI_WINDOW::do_dump_check()
788 {
789 #if 0
790         if ( keypress == KEY_SHIFTED+KEY_CTRLED+KEY_ALTED+SDLK_F12 ) {
791                 FILE *fp;
792
793                 last_keypress = keypress = 0;
794
795                 mprintf(( "\n========== WINDOW GADGETS =========\n" ));
796                 mprintf(( "(Also dumped to ui.out)\n" ));
797
798                 fp = fopen( "ui.out", "wt" );
799                 tmp = first_gadget;
800                 do      {
801                         if ( tmp->parent == NULL ) {    
802                                 switch ( tmp->kind ) {
803                                 case UI_KIND_BUTTON:
804                                         mprintf(( "UI: Button at %d,%d\n", tmp->x, tmp->y ));
805                                         fprintf( fp, "UI: Button at %d,%d\n", tmp->x, tmp->y );
806                                         break;
807                                 case UI_KIND_KEYTRAP:
808                                         mprintf(( "UI: Keytrap at %d,%d\n", tmp->x, tmp->y ));
809                                         fprintf( fp, "UI: Keytrap at %d,%d\n", tmp->x, tmp->y );
810                                         break;
811                                 case UI_KIND_CHECKBOX:
812                                         mprintf(( "UI: Checkbox at %d,%d\n", tmp->x, tmp->y ));
813                                         fprintf( fp, "UI: Checkbox at %d,%d\n", tmp->x, tmp->y );
814                                         break;
815                                 case UI_KIND_RADIO:
816                                         mprintf(( "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y ));
817                                         fprintf( fp, "UI: Radiobutton at %d,%d\n", tmp->x, tmp->y );
818                                         break;
819                                 case UI_KIND_SCROLLBAR:
820                                         mprintf(( "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y ));
821                                         fprintf( fp, "UI: Scrollbar at %d,%d\n", tmp->x, tmp->y );
822                                         break;
823                                 case UI_KIND_LISTBOX:
824                                         mprintf(( "UI: Listbox at %d,%d\n", tmp->x, tmp->y ));
825                                         fprintf( fp, "UI: Listbox at %d,%d\n", tmp->x, tmp->y );
826                                         break;
827                                 case UI_KIND_INPUTBOX:
828                                         mprintf(( "UI: Inputbox at %d,%d\n", tmp->x, tmp->y ));
829                                         fprintf( fp, "UI: Inputbox at %d,%d\n", tmp->x, tmp->y );
830                                         break;
831                                 default:
832                                         mprintf(( "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y ));
833                                         fprintf( fp, "UI: Unknown type %d at %d,%d\n", tmp->kind, tmp->x, tmp->y );
834                                 }
835                         }
836                         tmp = tmp->next;
837                 } while( tmp != first_gadget );
838                 fclose(fp);
839                 mprintf(( "===================================\n" ));
840         }
841 #endif
842 }
843
844 /*
845 void parse_tooltip(int n)
846 {
847         char buf[MESSAGE_LENGTH];
848
849         stuff_int(&Tooltips[n].hotspot);
850         stuff_string(buf, F_MESSAGE, NULL);
851         Tooltips[n].text = strdup(buf);
852 }
853
854 int parse_tooltips_group(int group, int n)
855 {
856         char buf[NAME_LENGTH];
857
858         SDL_assert(group < MAX_TOOLTIP_GROUPS);
859         required_string("$Mask Filename:");
860         stuff_string(buf, F_NAME, NULL);
861         Tooltip_groups[group].mask = strdup(buf);
862         Tooltip_groups[group].start = n;
863
864         while (1) {
865                 if (check_for_string("#") || check_for_string("$")) {
866                         Tooltip_groups[group].end = n;
867                         return n;
868                 }
869
870                 SDL_assert(n < MAX_TOOLTIPS);
871                 parse_tooltip(n++);
872         }
873 }
874
875 void parse_ship_tooltip(int n)
876 {
877 }
878
879 void parse_weapon_tooltip(int n)
880 {
881 }
882
883 void parse_tooltips()
884 {
885         int n;
886
887         // open localization
888         lcl_ext_open();
889
890         read_file_text("tooltips.tbl");
891
892         n = Num_tooltip_groups = 0;
893         reset_parse();
894
895         if (optional_string("#UI"))
896                 while (required_string_either("#", "$")) {
897                         n = parse_tooltips_group(Num_tooltip_groups, n);
898                         Num_tooltip_groups++;
899                 }
900
901         if (optional_string("#Ships"))
902                 while (required_string_either("#", "$")) {
903                         parse_ship_tooltip(Num_ship_tooltips);
904                         Num_ship_tooltips++;
905                 }
906
907         if (optional_string("#Weapons"))
908                 while (required_string_either("#", "$")) {
909                         parse_ship_tooltip(Num_weapon_tooltips);
910                         Num_weapon_tooltips++;
911                 }
912
913         required_string("#End");
914
915         // close localization
916         lcl_ext_close();
917 }
918
919 void init_tooltips()
920 {
921         static int inited = 0;
922
923         if (!inited) {
924                 int rval;
925
926                 if ((rval = setjmp(parse_abort)) != 0) {
927
928                 } else {                        
929 #ifndef DEMO
930                         parse_tooltips();
931 #endif
932                 }
933
934                 inited = 1;
935         }
936 }
937 */
938
939 void ok_clicked()
940 {
941         mprintf(( "OK Clicked!\n" ));
942 }
943
944 void do_help()
945 {
946         mprintf(( "Help!\n" ));
947 }
948