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