2 * $Logfile: /Freespace2/code/Ui/WINDOW.cpp $
7 * Routines to handle UI windows.
10 * Revision 1.1 2002/05/03 03:28:11 root
14 * 30 10/14/99 2:52p Jefff
15 * localization fixes. added support for hi-res specific xstr offsets
17 * 29 8/16/99 4:06p Dave
18 * Big honking checkin.
20 * 28 7/16/99 1:50p Dave
21 * 8 bit aabitmaps. yay.
23 * 27 7/15/99 3:07p Dave
24 * 32 bit detection support. Mouse coord commandline.
26 * 26 7/13/99 5:38p Jefff
27 * Added support for x offsets when drawing strings
29 * 25 6/25/99 11:59a Dave
30 * Multi options screen.
32 * 24 6/22/99 7:03p Dave
33 * New detail options screen.
35 * 23 6/19/99 2:46p Dave
36 * New control config screen.
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.
42 * 21 6/04/99 11:32a Dave
43 * Added reset text to ship select screen. Fixed minor xstr bug in ui
46 * 20 6/02/99 6:18p Dave
47 * Fixed TNT lockup problems! Wheeeee!
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.
53 * 18 5/22/99 5:35p Dave
54 * Debrief and chatbox screens. Fixed small hi-res HUD bug.
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.
60 * 16 5/17/99 11:28a Dave
62 * 15 5/17/99 9:25a Dave
63 * Updated PXO screen. Still needs popups.
65 * 14 5/03/99 8:33p Dave
66 * New version of multi host options screen.
68 * 13 4/16/99 5:22p Neilk
69 * Fixed UI_SLIDER2 bug
71 * 12 2/21/99 6:02p Dave
72 * Fixed standalone WSS packets.
74 * 11 2/01/99 5:55p Dave
75 * Removed the idea of explicit bitmaps for buttons. Fixed text
76 * highlighting for disabled gadgets.
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.
82 * 9 1/29/99 12:47a Dave
83 * Put in sounds for beam weapon. A bunch of interface screens (tech
86 * 8 12/18/98 1:13a Dave
87 * Rough 1024x768 support for Direct3D. Proper detection and usage through
90 * 7 12/02/98 5:47p Dave
91 * Put in interface xstr code. Converted barracks screen to new format.
93 * 6 11/30/98 1:07p Dave
94 * 16 bit conversion, first run.
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.
100 * 4 10/13/98 9:29a Dave
101 * Started neatening up freespace.h. Many variables renamed and
102 * reorganized. Added AlphaColors.[h,cpp]
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
109 * 2 10/07/98 10:54a Dave
112 * 1 10/07/98 10:51a Dave
121 #include "freespace.h"
126 #include "alphacolors.h"
128 #include "localize.h"
131 // global xstr colors
132 color *Xstr_colors[UI_NUM_XSTR_COLORS][3] = {
133 { // UI_XSTR_COLOR_GREEN
135 &Color_ui_light_green,
138 { // UI_XSTR_COLOR_PINK
140 &Color_ui_light_pink,
145 // --------------------------------------------------------------------
146 // UI_WINDOW constructor
149 UI_WINDOW::UI_WINDOW()
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
161 // NULL all the xstring structs
162 for(idx=0; idx<MAX_UI_XSTRS; idx++){
167 // --------------------------------------------------------------------
168 // UI_WINDOW destructor
171 UI_WINDOW::~UI_WINDOW()
175 // --------------------------------------------------------------------
176 // UI_WINDOW::set_mask_bmap()
178 // Specify the filename for the mask bitmap to use. This has the hotspots
179 // for all the different controls.
181 void UI_WINDOW::set_mask_bmap(char *fname)
185 bmap = bm_load(fname);
188 Error(LOCATION, "Could not load in %s!", fname);
191 set_mask_bmap(bmap, fname);
195 void UI_WINDOW::set_mask_bmap(int bmap, char *name)
202 if (bmap != mask_bmap_id) {
203 if (mask_bmap_id >= 0){
204 bm_unlock(mask_bmap_id);
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 );
216 for (i=0; i<Num_tooltip_groups; i++){
217 if (!stricmp(Tooltip_groups[i].mask, name)){
223 nprintf(("UI", "Warning: tried to switch bitmap mask to the same bitmap\n"));
227 // --------------------------------------------------------------------
228 // UI_WINDOW::set_foreground_bmap()
230 // Specify the filename for the mask bitmap to display on the ui window as
233 void UI_WINDOW::set_foreground_bmap(char *fname)
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);
240 #ifndef HARDWARE_ONLY
241 palette_use_bm_palette(foreground_bmap_id);
246 void UI_WINDOW::create( int _x, int _y, int _w, int _h, int _flags )
254 selected_gadget = NULL;
255 tooltip_handler = NULL; // pointer to function to handle custom tooltips
257 use_hack_to_get_around_stupid_problem_flag = 0;
259 f_id = gr_init_font("font01.vf");
263 if (_x + _w - 1 >= gr_screen.max_w)
264 _x = gr_screen.max_w - _w;
267 if (_y + _h - 1 >= gr_screen.max_h)
268 _y = gr_screen.max_h - _h;
273 void UI_WINDOW::release_bitmaps()
276 // done with the mask bitmap, so unlock it
277 bm_unlock(mask_bmap_id);
279 // unload the bitmaps
280 if (mask_bmap_id >= 0) {
281 bm_release(mask_bmap_id);
285 mask_bmap_ptr = NULL;
288 if (foreground_bmap_id >= 0) {
289 bm_release(foreground_bmap_id);
290 foreground_bmap_id = -1;
294 void UI_WINDOW::destroy()
299 // free up any bitmaps
302 // destroy all gadgets
309 } while (cur != first_gadget);
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);
325 void UI_WINDOW::draw()
332 if (foreground_bmap_id >= 0) {
333 gr_set_bitmap(foreground_bmap_id);
337 if (flags & WIN_FILLED) {
338 ui_draw_box_out(x, y, x+w-1, y+h-1);
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);
353 } while (tmp != first_gadget);
359 if (!tmp->hidden && (tmp->kind == UI_KIND_BUTTON) && ((UI_BUTTON *) tmp)->button_down()){
364 } while (tmp != first_gadget);
373 // convenient debug code for showing mouse coords
374 if(Cmdline_mouse_coords){
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);
383 void UI_WINDOW::draw_XSTR_forced(UI_GADGET *owner, int frame)
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);
395 int UI_WINDOW::get_current_hotspot()
397 int offset, pixel_val;
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);
409 void UI_WINDOW::draw_tooltip()
412 // tooltip_group *ptr;
419 // ptr = &Tooltip_groups[tt_group];
420 hotspot = get_current_hotspot();
422 // mprintf(("HOTSPOT: %d [%d]\n",hotspot, Framecount));
425 if (hotspot != last_tooltip_hotspot) {
426 last_tooltip_hotspot = hotspot;
427 last_tooltip_time = timer_get_milliseconds();
431 } else if (timer_get_milliseconds() - last_tooltip_time < TOOLTIP_DELAY)
436 gadget = first_gadget;
438 if (gadget->get_hotspot() == hotspot)
439 if (gadget->hidden) // if control is hidden, don't draw tooltip for it.
444 gadget = gadget->next;
446 } while (gadget != first_gadget);
450 for (i=ptr->start; i<ptr->end; i++) {
451 if (Tooltips[i].hotspot == hotspot) {
455 str = Tooltips[i].text;
457 if (!tooltip_handler)
458 Error(LOCATION, "No tooltip handler for screen with mask \"%s\"", ptr->mask);
460 str = (*tooltip_handler)(str); // Let the screen handle the custom tooltips
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;
478 void UI_WINDOW::render_tooltip(char *str)
482 gr_get_string_size(&w, &h, str);
483 Assert(w < gr_screen.max_w - 4 && h < gr_screen.max_h - 4);
491 if (ttx + w + 2 > gr_screen.max_w)
492 ttx = gr_screen.max_w - w;
494 if (tty + h + 2 > gr_screen.max_h)
495 tty = gr_screen.max_h - h;
497 gr_set_color_fast(&Color_black);
498 gr_rect(ttx - 1, tty - 1, w + 2, h + 1);
500 gr_set_color_fast(&Color_bright_white);
501 gr_string(ttx, tty, str);
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)
509 // only does stuff in non THREADED mode
517 keypress = game_check_key();
522 last_keypress = keypress;
524 if (mouse_captured_gadget && B1_RELEASED){
525 mouse_captured_gadget = NULL;
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.
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;
541 use_hack_to_get_around_stupid_problem_flag = 0;
542 return last_keypress;
545 check_focus_switch_keys();
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 ) {
553 if ( !tmp->check_move() )
558 } while (tmp != first_gadget);
561 use_hack_to_get_around_stupid_problem_flag = 0;
562 return last_keypress;
565 void UI_WINDOW::check_focus_switch_keys()
570 void UI_WINDOW::capture_mouse(UI_GADGET *gadget)
572 mouse_captured_gadget = gadget;
575 void UI_WINDOW::set_ignore_gadgets(int state)
577 ignore_gadgets = state;
580 void UI_WINDOW::add_XSTR(char *string, int _xstr_id, int _x, int _y, UI_GADGET *_assoc, int _color_type, int _font_id)
586 // try and find a free xstr
587 for(idx=0; idx<MAX_UI_XSTRS; idx++){
588 if(xstrs[idx] == NULL){
594 // if we don't have a free spot
596 Int3(); // aieee! we need to up the max # of xstrs allowed in a window.
600 // allocate a new struct
601 xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
602 if(xstrs[idx] == NULL){
608 x->xstr = strdup(string);
614 x->xstr_id = _xstr_id;
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)){
626 void UI_WINDOW::add_XSTR(UI_XSTR *xstr)
632 // try and find a free xstr
633 for(idx=0; idx<MAX_UI_XSTRS; idx++){
634 if(xstrs[idx] == NULL){
640 // if we don't have a free spot
642 Int3(); // aieee! we need to up the max # of xstrs allowed in a window.
646 // allocate a new struct
647 xstrs[idx] = (UI_XSTR*)malloc(sizeof(UI_XSTR));
648 if(xstrs[idx] == NULL){
654 x->xstr = strdup(xstr->xstr);
660 x->xstr_id = xstr->xstr_id;
663 x->assoc = xstr->assoc;
664 x->font_id = xstr->font_id;
666 Assert((x->clr >= 0) && (x->clr < UI_NUM_XSTR_COLORS));
667 if((x->clr < 0) || (x->clr >= UI_NUM_XSTR_COLORS)){
672 void UI_WINDOW::draw_one_xstr(UI_XSTR *x, int frame)
674 font *f_backup = NULL;
678 if((x == NULL) || (x->xstr == NULL)){
682 // if it has an associated gadet that is hidden, do nothing
683 if((x->assoc != NULL) && (x->assoc->hidden)){
687 // maybe set the font
689 // backup the current font
690 Assert(Current_font != NULL);
691 f_backup = Current_font;
694 gr_set_font(x->font_id);
698 if(x->assoc == NULL){
699 gr_set_color_fast(&Color_normal);
701 // just buttons for now
702 switch(x->assoc->kind){
705 if((frame != -1) && (frame < 3)){
706 gr_set_color_fast(Xstr_colors[x->clr][frame]);
710 // if the button is pressed
711 if(((UI_BUTTON*)x->assoc)->button_down()){
712 gr_set_color_fast(Xstr_colors[x->clr][2]);
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]);
718 gr_set_color_fast(Xstr_colors[x->clr][0]);
724 // all other controls just draw the normal frame
726 if((frame != -1) && (frame < 3)){
727 gr_set_color_fast(Xstr_colors[x->clr][frame]);
729 gr_set_color_fast(Xstr_colors[x->clr][0]);
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]);
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);
745 gr_string((x->x) + xoffset, x->y, str + 1);
748 gr_string((x->x) + xoffset, x->y, str);
751 // maybe restore the old font
752 if(f_backup != NULL){
753 Current_font = f_backup;
757 void UI_WINDOW::draw_xstrs()
763 draw_one_xstr(xstrs[idx], -1);
767 } while(idx < MAX_UI_XSTRS);
772 void UI_WINDOW::do_dump_check()
775 if ( keypress == KEY_SHIFTED+KEY_CTRLED+KEY_ALTED+KEY_F12 ) {
778 last_keypress = keypress = 0;
780 mprintf(( "\n========== WINDOW GADGETS =========\n" ));
781 mprintf(( "(Also dumped to ui.out)\n" ));
783 fp = fopen( "ui.out", "wt" );
786 if ( tmp->parent == NULL ) {
787 switch ( tmp->kind ) {
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 );
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 );
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 );
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 );
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 );
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 );
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 );
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 );
822 } while( tmp != first_gadget );
824 mprintf(( "===================================\n" ));
830 void parse_tooltip(int n)
832 char buf[MESSAGE_LENGTH];
834 stuff_int(&Tooltips[n].hotspot);
835 stuff_string(buf, F_MESSAGE, NULL);
836 Tooltips[n].text = strdup(buf);
839 int parse_tooltips_group(int group, int n)
841 char buf[NAME_LENGTH];
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;
850 if (check_for_string("#") || check_for_string("$")) {
851 Tooltip_groups[group].end = n;
855 Assert(n < MAX_TOOLTIPS);
860 void parse_ship_tooltip(int n)
864 void parse_weapon_tooltip(int n)
868 void parse_tooltips()
875 read_file_text("tooltips.tbl");
877 n = Num_tooltip_groups = 0;
880 if (optional_string("#UI"))
881 while (required_string_either("#", "$")) {
882 n = parse_tooltips_group(Num_tooltip_groups, n);
883 Num_tooltip_groups++;
886 if (optional_string("#Ships"))
887 while (required_string_either("#", "$")) {
888 parse_ship_tooltip(Num_ship_tooltips);
892 if (optional_string("#Weapons"))
893 while (required_string_either("#", "$")) {
894 parse_ship_tooltip(Num_weapon_tooltips);
895 Num_weapon_tooltips++;
898 required_string("#End");
900 // close localization
906 static int inited = 0;
911 if ((rval = setjmp(parse_abort)) != 0) {
926 mprintf(( "OK Clicked!\n" ));
931 mprintf(( "Help!\n" ));