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