]> icculus.org git repositories - btb/d2x.git/blob - main/newmenu.c
added fixedfont menu functions
[btb/d2x.git] / main / newmenu.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  * $Source: /cvs/cvsroot/d2x/main/newmenu.c,v $
16  * $Revision: 1.7 $
17  * $Author: bradleyb $
18  * $Date: 2002-02-11 07:39:11 $
19  *
20  * FIXME: put description here
21  *
22  * $Log: not supported by cvs2svn $
23  *
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #include <conf.h>
28 #endif
29
30 #ifdef WINDOWS
31 #include "desw.h"
32 #endif
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <stdarg.h>
38 #include <ctype.h>
39 #include <unistd.h>
40
41 #include "pa_enabl.h"                   //$$POLY_ACC
42 #include "error.h"
43 #include "pstypes.h"
44 #include "gr.h"
45 #include "mono.h"
46 #include "songs.h"
47 #include "key.h"
48 #include "palette.h"
49 #include "game.h"
50 #include "text.h"
51 #include "findfile.h"
52
53 #include "menu.h"
54 #include "newmenu.h"
55 #include "gamefont.h"
56 #include "gamepal.h"
57 #ifdef NETWORK
58 #include "network.h"
59 #endif
60 #include "iff.h"
61 #include "pcx.h"
62 #include "u_mem.h"
63 #include "mouse.h"
64 #include "joy.h"
65 #include "digi.h"
66
67 #include "multi.h"
68 #include "endlevel.h"
69 #include "screens.h"
70 #include "config.h"
71 #include "player.h"
72 #include "newdemo.h"
73 #include "kconfig.h"
74 #include "strutil.h"
75
76 #ifdef MACINTOSH
77 #include <Events.h>
78 #endif
79
80 #if defined (TACTILE)
81  #include "tactile.h"
82 #endif
83
84 #if defined(POLY_ACC)
85 #include "poly_acc.h"
86 #endif
87
88 #define MAXDISPLAYABLEITEMS 15
89
90 #define LHX(x)          ((x)*(MenuHires?2:1))
91 #define LHY(y)          ((y)*(MenuHires?2.4:1))
92
93 #define TITLE_FONT              HUGE_FONT
94 #define NORMAL_FONT     MEDIUM1_FONT            //normal, non-highlighted item
95 #define SELECTED_FONT   MEDIUM2_FONT            //highlighted item
96 #define SUBTITLE_FONT   MEDIUM3_FONT
97
98 #define NORMAL_CHECK_BOX        "\81"
99 #define CHECKED_CHECK_BOX       "\82"    
100
101 #define NORMAL_RADIO_BOX        "\7f"
102 #define CHECKED_RADIO_BOX       "\80"
103 #define CURSOR_STRING           "_"
104 #define SLIDER_LEFT                     "\83"             // 131
105 #define SLIDER_RIGHT                    "\84"             // 132
106 #define SLIDER_MIDDLE           "\85"             // 133
107 #define SLIDER_MARKER           "\86"             // 134
108 #define UP_ARROW_MARKER       "\87"    // 135
109 #define DOWN_ARROW_MARKER       "\88"      // 136
110
111 int newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename, int width, int height, int TinyMode );
112 void show_extra_netgame_info(int choice);
113
114
115 int Newmenu_first_time = 1;
116 //--unused-- int Newmenu_fade_in = 1;
117
118 typedef struct bkg {
119         WINDOS (dd_grs_canvas *menu_canvas, grs_canvas * menu_canvas);
120         grs_bitmap * saved;                     // The background under the menu.
121         grs_bitmap * background;
122 } bkg;
123
124 grs_bitmap nm_background,nm_background_save;
125
126 #define MESSAGEBOX_TEXT_SIZE 300                // How many characters in messagebox
127 #define MAX_TEXT_WIDTH  200                             // How many pixels wide a input box can be
128
129 extern void gr_bm_bitblt(int w, int h, int dx, int dy, int sx, int sy, grs_bitmap * src, grs_bitmap * dest);
130
131 ubyte MenuReordering=0;
132 ubyte SurfingNet=0;
133 char Pauseable_menu=0;
134 char already_showing_info=0;
135
136
137 void newmenu_close()    {
138         if ( nm_background.bm_data )
139                 d_free(nm_background.bm_data);
140
141         if ( nm_background_save.bm_data )
142                 d_free(nm_background_save.bm_data);
143         Newmenu_first_time = 1;
144 }
145
146 ubyte background_palette[768];
147
148 //should be called whenever the palette changes
149 void nm_remap_background()
150 {
151         if (!Newmenu_first_time) {
152                 if (!nm_background.bm_data)
153                         nm_background.bm_data = d_malloc(nm_background.bm_w * nm_background.bm_h);
154
155                 memcpy(nm_background.bm_data,nm_background_save.bm_data,nm_background.bm_w * nm_background.bm_h);
156
157                 gr_remap_bitmap_good( &nm_background, background_palette, -1, -1 );
158         }
159 }
160
161 #include <math.h>
162
163 extern char last_palette_loaded[];
164
165 void nm_draw_background1(char * filename)
166 {
167         int pcx_error;
168         grs_bitmap *bmp;
169         ubyte pal[256*3];
170
171         //@@//I think this only gets called to fill the whole screen
172         //@@Assert(grd_curcanv->cv_bitmap.bm_w == 320);
173         //@@Assert(grd_curcanv->cv_bitmap.bm_h == 200);
174
175         bmp = gr_create_bitmap(grd_curcanv->cv_bitmap.bm_w,grd_curcanv->cv_bitmap.bm_h);
176
177         pcx_error = pcx_read_bitmap(filename,bmp,bmp->bm_type,pal);
178         Assert(pcx_error == PCX_ERROR_NONE);
179
180         //@@gr_remap_bitmap_good( bmp, pal, -1, -1 );
181
182
183         {       //remap stuff. this code is kindof a hack
184
185                 //now, before we bring up the menu, we need to 
186                 //do some stuff to make sure the palette is ok.  First, we need to
187                 //get our current palette into the 2d's array, so the remapping will
188                 //work.  Second, we need to remap the fonts.  Third, we need to fill 
189                 //in part of the fade tables so the darkening of the menu edges works
190
191                 gr_copy_palette(gr_palette, pal, sizeof(gr_palette));
192                 remap_fonts_and_menus(1);
193
194         }
195
196 WIN(DDGRLOCK(dd_grd_curcanv));
197 #if defined(POLY_ACC)
198     pa_save_clut();
199     pa_update_clut(gr_palette, 0, 256, 0);
200 #endif
201         gr_bitmap(0,0,bmp);
202 #if defined(POLY_ACC)
203     pa_restore_clut();
204 #endif
205 WIN(DDGRUNLOCK(dd_grd_curcanv));
206
207         gr_free_bitmap(bmp);
208
209         strcpy(last_palette_loaded,"");         //force palette load next time
210
211 }
212
213 #ifdef SHAREWARE
214 #define MENU_BACKGROUND_BITMAP "scores.pcx"
215 #else
216 #ifdef RELEASE
217 #define MENU_BACKGROUND_BITMAP (MenuHires?"\x01scoresb.pcx":"\x01scores.pcx")           //read only from hog file
218 #else
219 #define MENU_BACKGROUND_BITMAP (MenuHires?"scoresb.pcx":"scores.pcx")
220 #endif
221 #endif
222
223 int Background_hires;
224 int No_darkening=0;
225
226 void nm_draw_background(int x1, int y1, int x2, int y2 )
227 {
228         int w,h;
229
230         if (Newmenu_first_time || MenuHires!=Background_hires)  {
231                 int pcx_error;
232
233                 if (Newmenu_first_time) {
234                         atexit( newmenu_close );
235                         Newmenu_first_time = 0;
236                         nm_background_save.bm_data=NULL;                
237                 }
238                 else {
239                         if (nm_background_save.bm_data)
240                                 d_free(nm_background_save.bm_data);
241                         if (nm_background.bm_data)
242                                 d_free(nm_background.bm_data);
243                 }
244
245                 pcx_error = pcx_read_bitmap(MENU_BACKGROUND_BITMAP,&nm_background_save,BM_LINEAR,background_palette);
246                 Assert(pcx_error == PCX_ERROR_NONE);
247
248                 nm_background = nm_background_save;
249                 nm_background.bm_data=NULL;             
250                 nm_remap_background();
251
252                 Background_hires = MenuHires;
253         }
254
255         if ( x1 < 0 ) x1 = 0;
256         if ( y1 < 0 ) y1 = 0;
257
258         w = x2-x1+1;
259         h = y2-y1+1;
260
261         if ( w > nm_background.bm_w ) w = nm_background.bm_w;
262         if ( h > nm_background.bm_h ) h = nm_background.bm_h;
263         
264         x2 = x1 + w - 1;
265         y2 = y1 + h - 1;
266
267 WIN(DDGRLOCK(dd_grd_curcanv));
268         if (No_darkening)
269                 gr_bm_bitblt(w, h, x1, y1, LHX(10), LHY(10), &nm_background, &(grd_curcanv->cv_bitmap) );
270         else
271                 gr_bm_bitblt(w, h, x1, y1, 0, 0, &nm_background, &(grd_curcanv->cv_bitmap) );
272
273
274 if (!No_darkening)
275  {
276         Gr_scanline_darkening_level = 2*7;
277
278
279         gr_setcolor( BM_XRGB(0,0,0) );
280         gr_urect( x2-5, y1+5, x2-5, y2-5 );
281         gr_urect( x2-4, y1+4, x2-4, y2-5 );
282         gr_urect( x2-3, y1+3, x2-3, y2-5 );
283         gr_urect( x2-2, y1+2, x2-2, y2-5 );
284         gr_urect( x2-1, y1+1, x2-1, y2-5 );
285         gr_urect( x2+0, y1+0, x2-0, y2-5 );
286
287         gr_urect( x1+5, y2-5, x2, y2-5 );
288         gr_urect( x1+4, y2-4, x2, y2-4 );
289         gr_urect( x1+3, y2-3, x2, y2-3 );
290         gr_urect( x1+2, y2-2, x2, y2-2 );
291         gr_urect( x1+1, y2-1, x2, y2-1 );
292         gr_urect( x1+0, y2, x2, y2-0 );
293  }
294 WIN(DDGRUNLOCK(dd_grd_curcanv));
295
296         Gr_scanline_darkening_level = GR_FADE_LEVELS;
297 }
298
299 void nm_restore_background( int x, int y, int w, int h )
300 {
301         int x1, x2, y1, y2;
302
303         x1 = x; x2 = x+w-1;
304         y1 = y; y2 = y+h-1;
305
306         if ( x1 < 0 ) x1 = 0;
307         if ( y1 < 0 ) y1 = 0;
308
309         if ( x2 >= nm_background.bm_w ) x2=nm_background.bm_w-1;
310         if ( y2 >= nm_background.bm_h ) y2=nm_background.bm_h-1;
311
312         w = x2 - x1 + 1;
313         h = y2 - y1 + 1;
314
315         WIN(DDGRLOCK(dd_grd_curcanv));
316                 gr_bm_bitblt(w, h, x1, y1, x1, y1, &nm_background, &(grd_curcanv->cv_bitmap) );
317         WIN(DDGRUNLOCK(dd_grd_curcanv));
318 }
319
320 // Draw a left justfied string
321 void nm_string( bkg * b, int w1,int x, int y, char * s)
322 {
323    int w,h,aw,tx=0,t=0,i;
324         char *p,*s1,measure[2];
325    int XTabs[]={15,87,124,162,228,253};
326    
327    p=s1=NULL;
328
329         for (i=0;i<6;i++)
330          {
331           XTabs[i]=(LHX(XTabs[i]));
332      XTabs[i]+=x;
333          }      
334  
335         measure[1]=0;
336
337         if (!SurfingNet)
338          {
339            p = strchr( s, '\t' );
340            if (p && (w1>0) ) {
341                                         *p = '\0';
342                                         s1 = p+1;
343                }
344          }
345
346         gr_get_string_size(s, &w, &h, &aw  );
347
348         if (w1 > 0)
349                 w = w1;
350
351                 // CHANGED
352                 gr_bm_bitblt(b->background->bm_w-15, h+2, 5, y-1, 5, y-1, b->background, &(grd_curcanv->cv_bitmap) );
353                 //gr_bm_bitblt(w, h, x, y, x, y, b->background, &(grd_curcanv->cv_bitmap) );
354
355                 if (SurfingNet)
356         {
357                 for (i=0;i<strlen(s);i++)
358         {
359                         if (s[i]=='\t' && SurfingNet)
360             {
361                 x=XTabs[t];
362                  t++;
363                     continue;
364                 }
365                         measure[0]=s[i];
366                 gr_get_string_size(measure,&tx,&h,&aw);
367                 gr_string(x,y,measure);
368                 x+=tx;
369                 }
370                 }
371       else      gr_string (x,y,s);
372          
373         if (!SurfingNet && p && (w1>0) )       {
374                         gr_get_string_size(s1, &w, &h, &aw  );
375
376                         gr_string( x+w1-w, y, s1 );
377
378                         *p = '\t';
379                 }
380 }
381
382 // Draw a slider and it's string
383 void nm_string_slider( bkg * b, int w1,int x, int y, char * s )
384 {
385         int w,h,aw;
386         char *p,*s1;
387
388         s1=NULL;
389
390         p = strchr( s, '\t' );
391         if (p)  {
392                 *p = '\0';
393                 s1 = p+1;
394         }
395
396         gr_get_string_size(s, &w, &h, &aw  );
397         // CHANGED
398
399                 gr_bm_bitblt(b->background->bm_w-15, h, 5, y, 5, y, b->background, &(grd_curcanv->cv_bitmap) );
400                 //gr_bm_bitblt(w, h, x, y, x, y, b->background, &(grd_curcanv->cv_bitmap) );
401
402                 gr_string( x, y, s );
403
404                 if (p)  {
405                         gr_get_string_size(s1, &w, &h, &aw  );
406
407                         // CHANGED
408                         gr_bm_bitblt(w, 1, x+w1-w, y, x+w1-w, y, b->background, &(grd_curcanv->cv_bitmap) );
409                         // CHANGED
410                         gr_bm_bitblt(w, 1, x+w1-w, y+h-1, x+w1-w, y, b->background, &(grd_curcanv->cv_bitmap) );
411
412                         gr_string( x+w1-w, y, s1 );
413
414                         *p = '\t';
415                 }
416 }
417
418
419 // Draw a left justfied string with black background.
420 void nm_string_black( bkg * b, int w1,int x, int y, char * s )
421 {
422         int w,h,aw;
423         gr_get_string_size(s, &w, &h, &aw  );
424         b = b;                                  
425         if (w1 == 0) w1 = w;
426
427         WIN(DDGRLOCK(dd_grd_curcanv));
428                 gr_setcolor( BM_XRGB(2,2,2) );
429                 gr_rect( x-1, y-1, x-1, y+h-1 );
430                 gr_rect( x-1, y-1, x+w1-1, y-1 );
431
432          
433                 gr_setcolor( BM_XRGB(5,5,5) );
434                 gr_rect( x, y+h, x+w1, y+h);
435                 gr_rect( x+w1, y-1, x+w1, y+h );
436      
437                 gr_setcolor( BM_XRGB(0,0,0) );
438                 gr_rect( x, y, x+w1-1, y+h-1 );
439         
440                 gr_string( x+1, y+1, s );
441         WIN(DDGRUNLOCK(dd_grd_curcanv));
442 }
443
444
445 // Draw a right justfied string
446 void nm_rstring( bkg * b,int w1,int x, int y, char * s )
447 {
448         int w,h,aw;
449         gr_get_string_size(s, &w, &h, &aw  );
450         x -= 3;
451
452         if (w1 == 0) w1 = w;
453
454         //mprintf( 0, "Width = %d, string='%s'\n", w, s );
455
456         // CHANGED
457         WIN(DDGRLOCK(dd_grd_curcanv));
458                 gr_bm_bitblt(w1, h, x-w1, y, x-w1, y, b->background, &(grd_curcanv->cv_bitmap) );
459                 gr_string( x-w, y, s );
460         WIN(DDGRUNLOCK(dd_grd_curcanv));
461 }
462
463 #include "timer.h"
464
465 //for text items, constantly redraw cursor (to achieve flash)
466 void update_cursor( newmenu_item *item)
467 {
468         int w,h,aw;
469         fix time = timer_get_approx_seconds();
470         int x,y;
471         char * text = item->text;
472
473         Assert(item->type==NM_TYPE_INPUT_MENU || item->type==NM_TYPE_INPUT);
474
475         while( *text )  {
476                 gr_get_string_size(text, &w, &h, &aw  );
477                 if ( w > item->w-10 )
478                         text++;
479                 else
480                         break;
481         }
482         if (*text==0) 
483                 w = 0;
484         x = item->x+w; y = item->y;
485
486 WIN(DDGRLOCK(dd_grd_curcanv));
487         if (time & 0x8000)
488                 gr_string( x, y, CURSOR_STRING );
489         else {
490                 gr_setcolor( BM_XRGB(0,0,0) );
491                 gr_rect( x, y, x+grd_curcanv->cv_font->ft_w-1, y+grd_curcanv->cv_font->ft_h-1 );
492         }
493 WIN(DDGRUNLOCK(dd_grd_curcanv));
494 }
495
496 void nm_string_inputbox( bkg *b, int w, int x, int y, char * text, int current )
497 {
498         int w1,h1,aw;
499
500         while( *text )  {
501                 gr_get_string_size(text, &w1, &h1, &aw  );
502                 if ( w1 > w-10 )
503                         text++;
504                 else
505                         break;
506         }
507         if ( *text == 0 )
508                 w1 = 0;
509
510    nm_string_black( b, w, x, y, text );
511                 
512         if ( current )  {
513                 gr_string( x+w1+1, y, CURSOR_STRING );
514         }
515 }
516
517 void draw_item( bkg * b, newmenu_item *item, int is_current,int tiny )
518 {
519        if (tiny)
520         {
521          if (is_current)
522           gr_set_fontcolor(gr_find_closest_color_current(57,49,20),-1);
523          else
524           gr_set_fontcolor(gr_find_closest_color_current(29,29,47),-1);
525
526          if (item->text[0]=='\t')
527           gr_set_fontcolor (gr_find_closest_color_current(63,63,63),-1);
528         }
529        else
530         {
531          if (is_current)
532           grd_curcanv->cv_font = SELECTED_FONT;
533          else
534           grd_curcanv->cv_font = NORMAL_FONT;
535
536                 #ifdef WINDOWS
537                         if (is_current && item->type == NM_TYPE_TEXT) 
538                                 grd_curcanv->cv_font = NORMAL_FONT;
539                 #endif
540         }
541
542 WIN(DDGRLOCK(dd_grd_curcanv));  
543         switch( item->type )    {
544         case NM_TYPE_TEXT:
545       // grd_curcanv->cv_font=TEXT_FONT;
546                 // fall through on purpose
547
548         case NM_TYPE_MENU:
549                 nm_string( b, item->w, item->x, item->y, item->text );
550                 break;
551         case NM_TYPE_SLIDER:    {
552                 int j;
553                 if (item->value < item->min_value) item->value=item->min_value;
554                 if (item->value > item->max_value) item->value=item->max_value;
555                 sprintf( item->saved_text, "%s\t%s", item->text, SLIDER_LEFT );
556                 for (j=0; j<(item->max_value-item->min_value+1); j++ )  {
557                         sprintf( item->saved_text, "%s%s", item->saved_text,SLIDER_MIDDLE );
558                 }
559                 sprintf( item->saved_text, "%s%s", item->saved_text,SLIDER_RIGHT );
560                 
561                 item->saved_text[item->value+1+strlen(item->text)+1] = SLIDER_MARKER[0];
562                 
563                 nm_string_slider( b, item->w, item->x, item->y, item->saved_text );
564                 }
565                 break;
566         case NM_TYPE_INPUT_MENU:
567                 if ( item->group==0 )           {
568                         nm_string( b, item->w, item->x, item->y, item->text );
569                 } else {
570                         nm_string_inputbox( b, item->w, item->x, item->y, item->text, is_current );
571                 }
572                 break;
573         case NM_TYPE_INPUT:
574                 nm_string_inputbox( b, item->w, item->x, item->y, item->text, is_current );
575                 break;
576         case NM_TYPE_CHECK:
577                 nm_string( b, item->w, item->x, item->y, item->text );
578                 if (item->value)
579                         nm_rstring( b,item->right_offset,item->x, item->y, CHECKED_CHECK_BOX );
580                 else                                                                                                              
581                         nm_rstring( b,item->right_offset,item->x, item->y, NORMAL_CHECK_BOX );
582                 break;
583         case NM_TYPE_RADIO:
584                 nm_string( b, item->w, item->x, item->y, item->text );
585                 if (item->value)
586                         nm_rstring( b,item->right_offset, item->x, item->y, CHECKED_RADIO_BOX );
587                 else
588                         nm_rstring( b,item->right_offset, item->x, item->y, NORMAL_RADIO_BOX );
589                 break;
590         case NM_TYPE_NUMBER:    {
591                 char text[10];
592                 if (item->value < item->min_value) item->value=item->min_value;
593                 if (item->value > item->max_value) item->value=item->max_value;
594                 nm_string( b, item->w, item->x, item->y, item->text );
595                 sprintf( text, "%d", item->value );
596                 nm_rstring( b,item->right_offset,item->x, item->y, text );
597                 }
598                 break;
599         }
600 WIN(DDGRUNLOCK(dd_grd_curcanv));
601
602 }
603
604 char *Newmenu_allowed_chars=NULL;
605
606 //returns true if char is allowed
607 int char_allowed(char c)
608 {
609         char *p = Newmenu_allowed_chars;
610
611         if (!p)
612                 return 1;
613
614         while (*p) {
615                 Assert(p[1]);
616
617                 if (c>=p[0] && c<=p[1])
618                         return 1;
619
620                 p += 2;
621         }
622
623         return 0;
624 }
625
626 void strip_end_whitespace( char * text )
627 {
628         int i,l;
629         l = strlen( text );
630         for (i=l-1; i>=0; i-- ) {
631                 if ( isspace(text[i]) )
632                         text[i] = 0;
633                 else
634                         return;
635         }
636 }
637
638 int newmenu_do( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem) )
639 {
640         return newmenu_do3( title, subtitle, nitems, item, subfunction, 0, NULL, -1, -1 );
641 }
642 int newmenu_dotiny( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem) )
643 {
644         return newmenu_do4( title, subtitle, nitems, item, subfunction, 0, NULL, LHX(310), -1, 1 );
645 }
646
647
648 int newmenu_dotiny2( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem) )
649 {
650         return newmenu_do4( title, subtitle, nitems, item, subfunction, 0, NULL, -1, -1, 1 );
651 }
652
653
654 int newmenu_do1( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem )
655 {
656         return newmenu_do3( title, subtitle, nitems, item, subfunction, citem, NULL, -1, -1 );
657 }
658
659
660 int newmenu_do2( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename )
661 {
662         return newmenu_do3( title, subtitle, nitems, item, subfunction, citem, filename, -1, -1 );
663 }
664 int newmenu_do3( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename, int width, int height )
665  {
666   return newmenu_do4( title, subtitle, nitems, item, subfunction, citem, filename, width, height,0 );
667  } 
668
669 int newmenu_do_fixedfont( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename, int width, int height){
670         set_screen_mode(SCREEN_MENU);//hafta set the screen mode before calling or fonts might get changed/freed up if screen res changes
671         return newmenu_do3_real( title, subtitle, nitems, item, subfunction, citem, filename, width,height, GAME_FONT, GAME_FONT, GAME_FONT, GAME_FONT);
672 }
673
674 //returns 1 if a control device button has been pressed
675 int check_button_press()
676 {
677         int i;
678
679         switch (Config_control_type) {
680         case    CONTROL_JOYSTICK:
681         case    CONTROL_FLIGHTSTICK_PRO:
682         case    CONTROL_THRUSTMASTER_FCS:
683         case    CONTROL_GRAVIS_GAMEPAD:
684                 for (i=0; i<4; i++ )    
685                         if (joy_get_button_down_cnt(i)>0) return 1;
686                 break;
687         case    CONTROL_MOUSE:
688         case    CONTROL_CYBERMAN:
689         #ifndef MACINTOSH                       // don't allow mouse to continue from menu
690                 for (i=0; i<3; i++ )    
691                         if (mouse_button_down_count(i)>0) return 1;
692                 break;
693         #endif
694         case    CONTROL_WINJOYSTICK:
695         #ifdef WINDOWS  
696                 for (i=0; i<4; i++ )    
697                         if (joy_get_button_down_cnt(i)>0) return 1;
698         #endif  
699                 break;
700         case    CONTROL_NONE:           //keyboard only
701                 #ifdef APPLE_DEMO
702                         if (key_checkch())      return 1;                       
703                 #endif
704
705                 break;
706         default:
707                 Error("Bad control type (Config_control_type):%i",Config_control_type);
708         }
709
710         return 0;
711 }
712
713 extern int network_request_player_names(int);
714 extern int RestoringMenu;
715
716 #if defined(WINDOWS) || defined(MACINTOSH)
717 ubyte Hack_DblClick_MenuMode=0;
718 #endif
719
720 MAC(extern ubyte joydefs_calibrating;)
721
722 #define CLOSE_X         15
723 #define CLOSE_Y         15
724 #define CLOSE_SIZE      10
725
726 void draw_close_box(int x,int y)
727 {
728         WIN (DDGRLOCK(dd_grd_curcanv));
729         gr_setcolor( BM_XRGB(0, 0, 0) );
730         gr_rect(x + CLOSE_X, y + CLOSE_Y, x + CLOSE_X + CLOSE_SIZE, y + CLOSE_Y + CLOSE_SIZE);
731         gr_setcolor( BM_XRGB(21, 21, 21) );
732         gr_rect( x + CLOSE_X + 2, y + CLOSE_Y + 2, x + CLOSE_X + CLOSE_SIZE - 2, y + CLOSE_Y + CLOSE_SIZE - 2 );
733         WIN (DDGRUNLOCK(dd_grd_curcanv));
734 }
735
736 int newmenu_do4( char * title, char * subtitle, int nitems, newmenu_item * item, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int citem, char * filename, int width, int height, int TinyMode )
737 {
738         int old_keyd_repeat, done;
739         int  choice,old_choice,i,j,x,y,w,h,aw, tw, th, twidth,fm,right_offset;
740         int k, nmenus, nothers,ScrollOffset=0,LastScrollCheck=-1,MaxDisplayable,sx,sy;
741         grs_font * save_font;
742         int string_width, string_height, average_width;
743         int ty;
744         bkg bg;
745         int all_text=0;         //set true if all text items
746         int sound_stopped=0,time_stopped=0;
747    int TopChoice,IsScrollBox=0;   // Is this a scrolling box? Set to false at init
748    char *Temp,TempVal;
749         int dont_restore=0;
750    int MaxOnMenu=MAXDISPLAYABLEITEMS;
751         WINDOS(dd_grs_canvas *save_canvas, grs_canvas *save_canvas );   
752 #if defined(MACINTOSH) || defined(WINDOWS)
753         int mouse_state, omouse_state, dblclick_flag=0;
754         int mx=0, my=0, x1, x2, y1, y2;
755         int close_box=0;
756 #endif
757 #ifdef MACINTOSH
758         EventRecord event;              // looking for disk inserted events for CD mounts
759 #endif
760
761         PA_DFX (pa_set_frontbuffer_current());
762         PA_DFX (pa_set_front_to_read());
763
764         WIN(if (!_AppActive) return -1);                // Don't draw message if minimized!
765         WIN(HideCursorW());
766         MAC(hide_cursor();)
767
768         if (nitems < 1 )
769     {
770                 return -1;
771     } 
772
773         WIN(mouse_set_mode(0));         //disable centering mode
774
775         MaxDisplayable=nitems;
776
777 #ifdef OGL
778         set_screen_mode(SCREEN_MENU);
779 #endif
780         set_popup_screen();
781
782         if ( Function_mode == FMODE_GAME && !(Game_mode & GM_MULTI)) {
783                 digi_pause_digi_sounds();
784                 sound_stopped = 1;
785         }
786
787         if (!((Game_mode & GM_MULTI) && (Function_mode == FMODE_GAME) && (!Endlevel_sequence)) )
788         {
789                 time_stopped = 1;
790                 stop_time();
791                 #ifdef TACTILE 
792                   if (TactileStick)     
793                           DisableForces();      
794                 #endif
795         }
796
797 #ifdef WINDOWS
798 RePaintNewmenu4:
799 #endif
800         WINDOS( save_canvas = dd_grd_curcanv, save_canvas = grd_curcanv );
801
802         WINDOS( dd_gr_set_current_canvas(NULL), gr_set_current_canvas(NULL) );
803
804         save_font = grd_curcanv->cv_font;
805
806         tw = th = 0;
807
808         if ( title )    {
809                 grd_curcanv->cv_font = TITLE_FONT;
810                 gr_get_string_size(title,&string_width,&string_height,&average_width );
811                 tw = string_width;
812                 th = string_height;
813         }
814         if ( subtitle ) {
815                 grd_curcanv->cv_font = SUBTITLE_FONT;
816                 gr_get_string_size(subtitle,&string_width,&string_height,&average_width );
817                 if (string_width > tw )
818                         tw = string_width;
819                 th += string_height;
820         }
821
822         th += LHY(8);           //put some space between titles & body
823
824         if (TinyMode)
825         grd_curcanv->cv_font = SMALL_FONT;
826         else 
827         grd_curcanv->cv_font = NORMAL_FONT;
828
829         w = aw = 0;
830         h = th;
831         nmenus = nothers = 0;
832
833         // Find menu height & width (store in w,h)
834         for (i=0; i<nitems; i++ )       {
835                 item[i].redraw=1;
836                 item[i].y = h;
837                 gr_get_string_size(item[i].text,&string_width,&string_height,&average_width );
838                 item[i].right_offset = 0;
839                 
840                 if (SurfingNet)
841                         string_height+=LHY(3);
842
843                 item[i].saved_text[0] = '\0';
844
845                 if ( item[i].type == NM_TYPE_SLIDER )   {
846                         int w1,h1,aw1;
847                         nothers++;
848                         sprintf( item[i].saved_text, "%s", SLIDER_LEFT );
849                         for (j=0; j<(item[i].max_value-item[i].min_value+1); j++ )      {
850                                 sprintf( item[i].saved_text, "%s%s", item[i].saved_text,SLIDER_MIDDLE );
851                         }
852                         sprintf( item[i].saved_text, "%s%s", item[i].saved_text,SLIDER_RIGHT );
853                         gr_get_string_size(item[i].saved_text,&w1,&h1,&aw1 );
854                         string_width += w1 + aw;
855                 }
856
857                 if ( item[i].type == NM_TYPE_MENU )     {
858                         nmenus++;
859                 }
860
861                 if ( item[i].type == NM_TYPE_CHECK )    {
862                         int w1,h1,aw1;
863                         nothers++;
864                         gr_get_string_size(NORMAL_CHECK_BOX, &w1, &h1, &aw1  );
865                         item[i].right_offset = w1;
866                         gr_get_string_size(CHECKED_CHECK_BOX, &w1, &h1, &aw1  );
867                         if (w1 > item[i].right_offset)
868                                 item[i].right_offset = w1;
869                 }
870                 
871                 if (item[i].type == NM_TYPE_RADIO ) {
872                         int w1,h1,aw1;
873                         nothers++;
874                         gr_get_string_size(NORMAL_RADIO_BOX, &w1, &h1, &aw1  );
875                         item[i].right_offset = w1;
876                         gr_get_string_size(CHECKED_RADIO_BOX, &w1, &h1, &aw1  );
877                         if (w1 > item[i].right_offset)
878                                 item[i].right_offset = w1;
879                 }
880
881                 if  (item[i].type==NM_TYPE_NUMBER )     {
882                         int w1,h1,aw1;
883                         char test_text[20];
884                         nothers++;
885                         sprintf( test_text, "%d", item[i].max_value );
886                         gr_get_string_size( test_text, &w1, &h1, &aw1 );
887                         item[i].right_offset = w1;
888                         sprintf( test_text, "%d", item[i].min_value );
889                         gr_get_string_size( test_text, &w1, &h1, &aw1 );
890                         if ( w1 > item[i].right_offset)
891                                 item[i].right_offset = w1;
892                 }
893
894                 if ( item[i].type == NM_TYPE_INPUT )    {
895                         Assert( strlen(item[i].text) < NM_MAX_TEXT_LEN );
896                         strcpy(item[i].saved_text, item[i].text );
897                         nothers++;
898                         string_width = item[i].text_len*grd_curcanv->cv_font->ft_w+((MenuHires?3:1)*item[i].text_len);
899                         if ( string_width > MAX_TEXT_WIDTH ) 
900                                 string_width = MAX_TEXT_WIDTH;
901                         item[i].value = -1;
902                 }
903
904                 if ( item[i].type == NM_TYPE_INPUT_MENU )       {
905                         Assert( strlen(item[i].text) < NM_MAX_TEXT_LEN );
906                         strcpy(item[i].saved_text, item[i].text );
907                         nmenus++;
908                         string_width = item[i].text_len*grd_curcanv->cv_font->ft_w+((MenuHires?3:1)*item[i].text_len);
909                         item[i].value = -1;
910                         item[i].group = 0;
911                 }
912
913                 item[i].w = string_width;
914                 item[i].h = string_height;
915
916                 if ( string_width > w )
917                         w = string_width;               // Save maximum width
918                 if ( average_width > aw )
919                         aw = average_width;
920                 h += string_height+1;           // Find the height of all strings
921         }
922    
923    // Big hack for allowing the netgame options menu to spill over
924
925    MaxOnMenu=MAXDISPLAYABLEITEMS;
926    if (ExtGameStatus==GAMESTAT_NETGAME_OPTIONS || ExtGameStatus==GAMESTAT_MORE_NETGAME_OPTIONS) 
927                 MaxOnMenu++;
928  
929    if (!TinyMode && (h>((MaxOnMenu+1)*(string_height+1))+(LHY(8))))
930     {
931      IsScrollBox=1;
932      h=(MaxOnMenu*(string_height+1)+LHY(8));
933      MaxDisplayable=MaxOnMenu;
934      mprintf ((0,"Hey, this is a scroll box!\n"));
935     }
936    else
937     IsScrollBox=0;
938
939         right_offset=0;
940
941         if ( width > -1 )
942                 w = width;
943
944         if ( height > -1 )
945                 h = height;
946
947         for (i=0; i<nitems; i++ )       {
948                 item[i].w = w;
949                 if (item[i].right_offset > right_offset )
950                         right_offset = item[i].right_offset;
951         }
952         if (right_offset > 0 )
953                 right_offset += 3;
954
955         //gr_get_string_size("",&string_width,&string_height,&average_width );
956
957         w += right_offset;
958
959
960         twidth = 0;
961         if ( tw > w )   {
962                 twidth = ( tw - w )/2;
963                 w = tw;
964         }
965
966    if (RestoringMenu)
967          { right_offset=0; twidth=0;}
968         
969         mprintf(( 0, "Right offset = %d\n", right_offset ));
970
971                         
972         // Find min point of menu border
973 //      x = (grd_curscreen->sc_w-w)/2;
974 //      y = (grd_curscreen->sc_h-h)/2;
975
976         w += MenuHires?60:30;
977         h += MenuHires?60:30;
978
979         if ( w > grd_curcanv->cv_bitmap.bm_w ) w = grd_curcanv->cv_bitmap.bm_w;
980         if ( h > grd_curcanv->cv_bitmap.bm_h ) h = grd_curcanv->cv_bitmap.bm_h;
981
982         x = (grd_curcanv->cv_bitmap.bm_w-w)/2;
983         y = (grd_curcanv->cv_bitmap.bm_h-h)/2;
984
985         if ( x < 0 ) x = 0;
986         if ( y < 0 ) y = 0;
987                 
988         if ( filename != NULL ) {
989                 nm_draw_background1( filename );
990                 gr_palette_load(gr_palette);
991         }
992
993 // Save the background of the display
994 //              Win95 must refer to the screen as a dd_grs_canvas, so...
995         WINDOS (        bg.menu_canvas = dd_gr_create_sub_canvas( dd_grd_screencanv, x, y, w, h ),
996                         bg.menu_canvas = gr_create_sub_canvas( &grd_curscreen->sc_canvas, x, y, w, h )
997         );
998         WINDOS (        dd_gr_set_current_canvas( bg.menu_canvas ), 
999                         gr_set_current_canvas(bg.menu_canvas)   );
1000
1001         if ( filename == NULL ) {
1002                 // Save the background under the menu...
1003                 #ifdef TACTILE
1004                         if (TactileStick)
1005                                 DisableForces();
1006                 #endif
1007                 
1008 #if defined(POLY_ACC)
1009                 bg.saved = gr_create_bitmap2( w, h, grd_curcanv->cv_bitmap.bm_type, NULL );
1010 #else
1011                 bg.saved = gr_create_bitmap( w, h );
1012 #endif
1013                 Assert( bg.saved != NULL );
1014
1015                 WIN (DDGRLOCK(dd_grd_curcanv));
1016                         gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg.saved );
1017                 WIN (DDGRUNLOCK(dd_grd_curcanv));
1018
1019                 WINDOS (        dd_gr_set_current_canvas(NULL), 
1020                                         gr_set_current_canvas( NULL ) 
1021                 );
1022
1023                 nm_draw_background(x,y,x+w-1,y+h-1);
1024
1025                 WINDOS (        dd_gr_set_current_canvas(bg.menu_canvas),
1026                                         gr_set_current_canvas( bg.menu_canvas )
1027                 );
1028
1029                 bg.background = gr_create_sub_bitmap(&nm_background,0,0,w,h);
1030
1031         } else {
1032                 bg.saved = NULL;
1033 #if defined(POLY_ACC)
1034                 bg.background = gr_create_bitmap2( w, h, grd_curcanv->cv_bitmap.bm_type, NULL );
1035 #else
1036                 bg.background = gr_create_bitmap( w, h );
1037 #endif
1038                 Assert( bg.background != NULL );
1039                 
1040                 WIN (DDGRLOCK(dd_grd_curcanv));
1041                         gr_bm_bitblt(w, h, 0, 0, 0, 0, &grd_curcanv->cv_bitmap, bg.background );
1042                 WIN (DDGRUNLOCK(dd_grd_curcanv));
1043         }
1044
1045 // ty = 15 + (yborder/4);
1046
1047         ty = MenuHires?30:15;
1048
1049         if ( title )    {
1050                 grd_curcanv->cv_font = TITLE_FONT;
1051                 gr_set_fontcolor( GR_GETCOLOR(31,31,31), -1 );
1052                 gr_get_string_size(title,&string_width,&string_height,&average_width );
1053                 tw = string_width;
1054                 th = string_height;
1055                 WIN (DDGRLOCK(dd_grd_curcanv));
1056                         gr_printf( 0x8000, ty, title );
1057                 WIN (DDGRUNLOCK(dd_grd_curcanv));
1058                 ty += th;
1059         }
1060
1061         if ( subtitle ) {
1062                 grd_curcanv->cv_font = SUBTITLE_FONT;
1063                 gr_set_fontcolor( GR_GETCOLOR(21,21,21), -1 );
1064                 gr_get_string_size(subtitle,&string_width,&string_height,&average_width );
1065                 tw = string_width;
1066                 th = string_height;
1067                 WIN (DDGRLOCK(dd_grd_curcanv));
1068                         gr_printf( 0x8000, ty, subtitle );
1069                 WIN (DDGRUNLOCK(dd_grd_curcanv));
1070                 ty += th;
1071         }
1072
1073         if (TinyMode)
1074         grd_curcanv->cv_font = SMALL_FONT;
1075         else 
1076         grd_curcanv->cv_font = NORMAL_FONT;
1077         
1078         // Update all item's x & y values.
1079         for (i=0; i<nitems; i++ )       {
1080                 item[i].x = (MenuHires?30:15) + twidth + right_offset;
1081                 item[i].y += (MenuHires?30:15);
1082                 if ( item[i].type==NM_TYPE_RADIO )      {
1083                         fm = -1;        // find first marked one
1084                         for ( j=0; j<nitems; j++ )      {
1085                                 if ( item[j].type==NM_TYPE_RADIO && item[j].group==item[i].group )      {
1086                                         if (fm==-1 && item[j].value)
1087                                                 fm = j;
1088                                         item[j].value = 0;
1089                                 }
1090                         }
1091                         if ( fm>=0 )    
1092                                 item[fm].value=1;
1093                         else
1094                                 item[i].value=1;
1095                 }
1096         }
1097
1098         old_keyd_repeat = keyd_repeat;
1099         keyd_repeat = 1;
1100
1101         if (citem==-1)  {
1102                 choice = -1;
1103         } else {
1104                 if (citem < 0 ) citem = 0;
1105                 if (citem > nitems-1 ) citem = nitems-1;
1106                 choice = citem;
1107         
1108         #if defined(WINDOWS) || defined(MACINTOSH) 
1109                 dblclick_flag = 1;
1110         #endif
1111
1112                 while ( item[choice].type==NM_TYPE_TEXT )       {
1113                         choice++;
1114                         if (choice >= nitems ) {
1115                                 choice=0; 
1116                         }
1117                         if (choice == citem ) {
1118                                 choice=0; 
1119                                 all_text=1;
1120                                 break; 
1121                         }
1122                 }
1123         } 
1124         done = 0;
1125    TopChoice=choice;
1126
1127         gr_update();
1128         // Clear mouse, joystick to clear button presses.
1129         game_flush_inputs();
1130
1131 #if defined(WINDOWS) || defined(MACINTOSH)
1132         mouse_state = omouse_state = 0;
1133         if (filename == NULL && !MenuReordering) {
1134                 draw_close_box(0,0);
1135                 close_box = 1;
1136         }
1137 #endif
1138
1139 #ifdef WINDOWS
1140         if (!MenuReordering) {
1141                 ShowCursorW();
1142                 SetCursor (LoadCursor(NULL,IDC_ARROW));
1143         }
1144 #endif
1145
1146 #ifdef MACINTOSH  
1147         if (!joydefs_calibrating)
1148                 show_cursor();
1149 #endif
1150
1151    mprintf ((0,"Set to true!\n"));
1152
1153         while(!done)    {
1154         #ifdef WINDOWS
1155                 MSG msg;
1156
1157                 DoMessageStuff(&msg);
1158
1159                 if (_RedrawScreen) {
1160                         _RedrawScreen = FALSE;
1161                 
1162                         if (!filename) {
1163                                 gr_free_bitmap(bg.saved);
1164                                 d_free( bg.background );
1165                         }
1166                         else    
1167                                 gr_free_bitmap(bg.background);
1168
1169                         dd_gr_free_sub_canvas( bg.menu_canvas );
1170                         grd_curcanv->cv_font = save_font;
1171                         dd_grd_curcanv = save_canvas;
1172
1173                         goto RePaintNewmenu4;
1174                 }
1175
1176                 DDGRRESTORE;
1177
1178         #endif
1179
1180         
1181 #ifdef MACINTOSH
1182                 omouse_state = mouse_state;     
1183                 mouse_state = mouse_button_state(0);
1184                 if (!joydefs_calibrating)
1185                         show_cursor();          // possibly hidden
1186 #endif
1187
1188 #ifdef WINDOWS
1189                 omouse_state = mouse_state;     
1190                 if (!MenuReordering)
1191                         mouse_state = mouse_button_state(0);
1192 //@@      mprintf ((0,"mouse state:%d\n",mouse_state));
1193 #endif
1194
1195                 //see if redbook song needs to be restarted
1196                 songs_check_redbook_repeat();
1197
1198                 //network_listen();
1199
1200                 k = key_inkey();
1201
1202         if (subfunction)
1203         (*subfunction)(nitems,item,&k,choice);
1204
1205 #ifdef NETWORK
1206                 if (!time_stopped)      {
1207                         // Save current menu box
1208                         if (multi_menu_poll() == -1)
1209                                 k = -2;
1210                 }
1211 #endif
1212
1213                 if ( k<-1 ) {
1214                         dont_restore = (k == -3);               //-3 means don't restore
1215                         choice = k;
1216                         k = -1;
1217                         done = 1;
1218                 }
1219 #ifndef WINDOWS
1220                 if (check_button_press())
1221                         done = 1;
1222 #endif
1223
1224 //              if ( (nmenus<2) && (k>0) && (nothers==0) )
1225 //                      done=1;
1226
1227                 old_choice = choice;
1228         
1229                 switch( k )     {
1230
1231 #ifdef NETWORK
1232                 case KEY_I:
1233                  if (SurfingNet && !already_showing_info)
1234                    {
1235                          show_extra_netgame_info(choice-2);
1236                    }
1237                  if (SurfingNet && already_showing_info)
1238                         {
1239                          done=1;
1240                          choice=-1;
1241                         }
1242                  break;
1243                 case KEY_U:
1244                  if (SurfingNet && !already_showing_info)
1245                    {
1246                          network_request_player_names(choice-2);
1247                    }
1248                  if (SurfingNet && already_showing_info)
1249                         {
1250                          done=1;
1251                          choice=-1;
1252                         }
1253                  break;
1254 #endif
1255                 case KEY_PAUSE:
1256                  if (Pauseable_menu)
1257                    {    
1258                          Pauseable_menu=0;
1259                          done=1;
1260                          choice=-1;
1261                    }
1262                  break;
1263                 case KEY_TAB + KEY_SHIFTED:
1264                 case KEY_UP:
1265                 case KEY_PAD8:
1266                         if (all_text) break;
1267                         do {
1268                                 choice--;
1269
1270                 if (IsScrollBox)
1271                 {
1272                         LastScrollCheck=-1;
1273                 mprintf ((0,"Scrolling! Choice=%d\n",choice));
1274                                    
1275                 if (choice<TopChoice)
1276                         { choice=TopChoice; break; }
1277
1278                 if (choice<ScrollOffset)
1279                {
1280                         for (i=0;i<nitems;i++)
1281                                 item[i].redraw=1;
1282                      ScrollOffset--;
1283                      mprintf ((0,"ScrollOffset=%d\n",ScrollOffset));
1284                }
1285                 }
1286                 else
1287                 {
1288                         if (choice >= nitems ) choice=0;
1289                 if (choice < 0 ) choice=nitems-1;
1290                 }
1291                         } while ( item[choice].type==NM_TYPE_TEXT );
1292                         if ((item[choice].type==NM_TYPE_INPUT) && (choice!=old_choice)) 
1293                                 item[choice].value = -1;
1294                         if ((old_choice>-1) && (item[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=choice))     {
1295                                 item[old_choice].group=0;
1296                                 strcpy(item[old_choice].text, item[old_choice].saved_text );
1297                                 item[old_choice].value = -1;
1298                         }
1299                         if (old_choice>-1) 
1300                                 item[old_choice].redraw = 1;
1301                         item[choice].redraw=1;
1302                         break;
1303                 case KEY_TAB:
1304                 case KEY_DOWN:
1305                 case KEY_PAD2:
1306         // ((0,"Pressing down! IsScrollBox=%d",IsScrollBox));
1307                 if (all_text) break;
1308                         do {
1309                                 choice++;
1310
1311                         if (IsScrollBox)
1312                 {
1313                 LastScrollCheck=-1;
1314                 mprintf ((0,"Scrolling! Choice=%d\n",choice));
1315                                    
1316                 if (choice==nitems)
1317                 { choice--; break; }
1318
1319                 if (choice>=MaxOnMenu+ScrollOffset)
1320                 {
1321                 for (i=0;i<nitems;i++)
1322                                 item[i].redraw=1;
1323                   ScrollOffset++;
1324                   mprintf ((0,"ScrollOffset=%d\n",ScrollOffset));
1325                 }
1326                 }
1327             else
1328             {
1329                         if (choice < 0 ) choice=nitems-1;
1330                         if (choice >= nitems ) choice=0;
1331                 }
1332
1333                         } while ( item[choice].type==NM_TYPE_TEXT );
1334                                                       
1335                         if ((item[choice].type==NM_TYPE_INPUT) && (choice!=old_choice)) 
1336                                 item[choice].value = -1;
1337                         if ( (old_choice>-1) && (item[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=choice))    {
1338                                 item[old_choice].group=0;
1339                                 strcpy(item[old_choice].text, item[old_choice].saved_text );    
1340                                 item[old_choice].value = -1;
1341                         }
1342                         if (old_choice>-1)
1343                                 item[old_choice].redraw=1;
1344                         item[choice].redraw=1;
1345                         break;
1346                 case KEY_SPACEBAR:
1347                         if ( choice > -1 )      {
1348                                 switch( item[choice].type )     {
1349                                 case NM_TYPE_MENU:
1350                                 case NM_TYPE_INPUT:
1351                                 case NM_TYPE_INPUT_MENU:
1352                                         break;
1353                                 case NM_TYPE_CHECK:
1354                                         if ( item[choice].value )
1355                                                 item[choice].value = 0;
1356                                         else
1357                                                 item[choice].value = 1;
1358                                         mprintf ((0,"ISB=%d MDI=%d SO=%d choice=%d\n",IsScrollBox,MAXDISPLAYABLEITEMS,ScrollOffset,choice));
1359                                         if (IsScrollBox)
1360                                          {
1361                                                 if (choice==(MaxOnMenu+ScrollOffset-1) || choice==ScrollOffset)
1362                                                  {
1363                                                    mprintf ((0,"Special redraw!\n"));
1364                                                         LastScrollCheck=-1;                                     
1365                                                  }
1366                                          }
1367                                 
1368                                         item[choice].redraw=1;
1369                                         break;
1370                                 case NM_TYPE_RADIO:
1371                                         for (i=0; i<nitems; i++ )       {
1372                                                 if ((i!=choice) && (item[i].type==NM_TYPE_RADIO) && (item[i].group==item[choice].group) && (item[i].value) )    {
1373                                                         item[i].value = 0;
1374                                                         item[i].redraw = 1;
1375                                                 }
1376                                         }
1377                                         item[choice].value = 1;
1378                                         item[choice].redraw = 1;
1379                                         break;
1380                                 }       
1381                         }
1382                         break;
1383
1384                 case KEY_SHIFTED+KEY_UP:
1385                  if (MenuReordering && choice!=TopChoice)
1386                   {
1387                    Temp=item[choice].text;
1388                    TempVal=item[choice].value;
1389                    item[choice].text=item[choice-1].text;
1390                    item[choice].value=item[choice-1].value;
1391                    item[choice-1].text=Temp;
1392                    item[choice-1].value=TempVal;
1393                    item[choice].redraw=1;
1394                    item[choice-1].redraw=1;
1395                    choice--;
1396                   }
1397                  break;
1398                 case KEY_SHIFTED+KEY_DOWN:
1399                  if (MenuReordering && choice!=(nitems-1))
1400                   {
1401                    Temp=item[choice].text;
1402                    TempVal=item[choice].value;
1403                    item[choice].text=item[choice+1].text;
1404                    item[choice].value=item[choice+1].value;
1405                    item[choice+1].text=Temp;
1406                    item[choice+1].value=TempVal;
1407                    item[choice].redraw=1;
1408                    item[choice+1].redraw=1;
1409                    choice++;
1410                   }
1411                  break;
1412                 
1413                 case KEY_ENTER:
1414                 case KEY_PADENTER:
1415                         if ( (choice>-1) && (item[choice].type==NM_TYPE_INPUT_MENU) && (item[choice].group==0)) {
1416                                 item[choice].group = 1;
1417                                 item[choice].redraw = 1;
1418                                 if ( !strnicmp( item[choice].saved_text, TXT_EMPTY, strlen(TXT_EMPTY) ) )       {
1419                                         item[choice].text[0] = 0;
1420                                         item[choice].value = -1;
1421                                 } else {        
1422                                         strip_end_whitespace(item[choice].text);
1423                                 }
1424                         } else
1425                                 done = 1;
1426                         break;
1427
1428                 case KEY_ESC:
1429                         if ( (choice>-1) && (item[choice].type==NM_TYPE_INPUT_MENU) && (item[choice].group==1)) {
1430                                 item[choice].group=0;
1431                                 strcpy(item[choice].text, item[choice].saved_text );    
1432                                 item[choice].redraw=1;
1433                                 item[choice].value = -1;
1434                         } else {
1435                                 done = 1;
1436                                 choice = -1;
1437                         }
1438                         break;
1439
1440                 MAC(case KEY_COMMAND+KEY_SHIFTED+KEY_3:)
1441                 case KEY_PRINT_SCREEN:
1442                         MAC(hide_cursor());
1443                         save_screen_shot(0);
1444                         PA_DFX (pa_set_frontbuffer_current());
1445                         PA_DFX (pa_set_front_to_read());
1446                         for (i=0;i<nitems;i++)
1447                                 item[i].redraw=1;
1448                         
1449                         MAC(show_cursor());
1450                         MAC(key_flush());
1451                         break;
1452
1453                 #ifdef MACINTOSH
1454
1455                 case KEY_COMMAND+KEY_RIGHT:
1456                         songs_goto_next_song();
1457                         break;
1458                 case KEY_COMMAND+KEY_LEFT:
1459                         songs_goto_prev_song();
1460                         break;
1461                 case KEY_COMMAND+KEY_UP:
1462                         songs_play_level_song(1);
1463                         break;
1464                 case KEY_COMMAND+KEY_DOWN:
1465                         songs_stop_redbook();
1466                         break;
1467
1468                 case KEY_COMMAND+KEY_M:
1469                         k = -1;
1470                         #if !defined(SHAREWARE) || defined(APPLE_DEMO)
1471                         if ( (Game_mode & GM_MULTI) )           // don't process in multiplayer games
1472                                 break;
1473
1474                         key_close();            // no processing of keys with keyboard handler.. jeez                           
1475                         stop_time();
1476                         hide_cursor();
1477                         show_boxed_message ("Mounting CD\nESC to quit");        
1478                         RBAMountDisk();         // OS has totaly control of the CD.
1479                         if (Function_mode == FMODE_MENU)
1480                                 songs_play_song(SONG_TITLE,1);
1481                         else if (Function_mode == FMODE_GAME)
1482                                 songs_play_level_song( Current_level_num );
1483                         clear_boxed_message();
1484                         show_cursor();
1485                         key_init();
1486                         key_flush();
1487                         start_time();
1488                         #endif
1489                         
1490                         break;
1491
1492                 case KEY_COMMAND+KEY_E:
1493                         songs_stop_redbook();
1494                         RBAEjectDisk();
1495                         k = -1;         // force key not to register
1496                         break;
1497                         
1498                 case KEY_COMMAND+KEY_Q: {
1499                         extern void macintosh_quit();
1500                         
1501                         if ( !(Game_mode & GM_MULTI) )
1502                                 macintosh_quit();
1503                         if (!joydefs_calibrating)
1504                                 show_cursor();
1505                         k = -1;         // force key not to register
1506                         break;
1507                 }
1508                 #endif
1509
1510                 #ifndef NDEBUG
1511                 case KEY_BACKSP:        
1512                         if ( (choice>-1) && (item[choice].type!=NM_TYPE_INPUT)&&(item[choice].type!=NM_TYPE_INPUT_MENU))
1513                                 Int3(); 
1514                         break;
1515                 #endif
1516
1517                 }
1518
1519 #if defined(MACINTOSH) || defined(WINDOWS) // for mouse selection of menu's etc.
1520                 WIN(Sleep(100));
1521                 if ( !done && mouse_state && !omouse_state && !all_text ) {
1522                         mouse_get_pos(&mx, &my);
1523                         for (i=0; i<nitems; i++ )       {
1524                                 x1 = grd_curcanv->cv_bitmap.bm_x + item[i].x - item[i].right_offset - 6;
1525                                 x2 = x1 + item[i].w;
1526                                 y1 = grd_curcanv->cv_bitmap.bm_y + item[i].y;
1527                                 y2 = y1 + item[i].h;
1528                                 if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
1529                                         if (i+ScrollOffset != choice) {
1530                                                 if(Hack_DblClick_MenuMode) dblclick_flag = 0; 
1531                                         }
1532                                         
1533                                         choice = i + ScrollOffset;
1534
1535                                         switch( item[choice].type )     {
1536                                         case NM_TYPE_CHECK:
1537                                                 if ( item[choice].value )
1538                                                         item[choice].value = 0;
1539                                                 else
1540                                                         item[choice].value = 1;
1541                                                 item[choice].redraw=1;
1542
1543                                                 if (IsScrollBox)
1544                                                         LastScrollCheck=-1;
1545 #if 0
1546                                                 if (IsScrollBox)
1547                                                  {
1548                                                         if (choice==(MaxOnMenu+ScrollOffset-1) || choice==ScrollOffset)
1549                                                          {
1550                                                            mprintf ((0,"Special redraw!\n"));
1551                                                                 LastScrollCheck=-1;                                     
1552                                                          }
1553                                                  }
1554 #endif
1555                                                 break;
1556                                         case NM_TYPE_RADIO:
1557                                                 for (i=0; i<nitems; i++ )       {
1558                                                         if ((i!=choice) && (item[i].type==NM_TYPE_RADIO) && (item[i].group==item[choice].group) && (item[i].value) )    {
1559                                                                 item[i].value = 0;
1560                                                                 item[i].redraw = 1;
1561                                                         }
1562                                                 }
1563                                                 item[choice].value = 1;
1564                                                 item[choice].redraw = 1;
1565                                                 break;
1566                                         }
1567                                         item[old_choice].redraw=1;
1568                                         break;
1569                                 }
1570                         }
1571                 }
1572
1573                 if (mouse_state && all_text)
1574                         done = 1;
1575                 
1576                 if ( !done && mouse_state && !all_text ) {
1577                         mouse_get_pos(&mx, &my);
1578                         
1579                         // check possible scrollbar stuff first
1580                         if (IsScrollBox) {
1581                                 int arrow_width, arrow_height, aw;
1582                                 
1583                                 if (ScrollOffset != 0) {
1584                                         gr_get_string_size(UP_ARROW_MARKER, &arrow_width, &arrow_height, &aw);
1585                                         x2 = grd_curcanv->cv_bitmap.bm_x + item[ScrollOffset].x-(MenuHires?24:12);
1586                                 y1 = grd_curcanv->cv_bitmap.bm_y + item[ScrollOffset].y-((string_height+1)*ScrollOffset);
1587                                         x1 = x1 - arrow_width;
1588                                         y2 = y1 + arrow_height;
1589                                         if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
1590                                                 choice--;
1591                                         LastScrollCheck=-1;
1592                                 mprintf ((0,"Scrolling! Choice=%d\n",choice));
1593                                                    
1594                                 if (choice<ScrollOffset)
1595                                {
1596                                         for (i=0;i<nitems;i++)
1597                                                 item[i].redraw=1;
1598                                      ScrollOffset--;
1599                                      mprintf ((0,"ScrollOffset=%d\n",ScrollOffset));
1600                                }
1601                                         }
1602                                 }
1603                                 if (ScrollOffset+MaxDisplayable<nitems) {
1604                                         gr_get_string_size(DOWN_ARROW_MARKER, &arrow_width, &arrow_height, &aw);
1605                                         x2 = grd_curcanv->cv_bitmap.bm_x + item[ScrollOffset+MaxDisplayable-1].x-(MenuHires?24:12);
1606                                         y1 = grd_curcanv->cv_bitmap.bm_y + item[ScrollOffset+MaxDisplayable-1].y-((string_height+1)*ScrollOffset);
1607                                         x1 = x1 - arrow_width;
1608                                         y2 = y1 + arrow_height;
1609                                         if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
1610                                                 choice++;
1611                                 LastScrollCheck=-1;
1612                                 mprintf ((0,"Scrolling! Choice=%d\n",choice));
1613                                                    
1614                                 if (choice>=MaxOnMenu+ScrollOffset)
1615                                 {
1616                                 for (i=0;i<nitems;i++)
1617                                                 item[i].redraw=1;
1618                                   ScrollOffset++;
1619                                   mprintf ((0,"ScrollOffset=%d\n",ScrollOffset));
1620                                 }
1621                                         }
1622                                 }
1623                         }
1624                         
1625                         for (i=0; i<nitems; i++ )       {
1626                                 x1 = grd_curcanv->cv_bitmap.bm_x + item[i].x - item[i].right_offset - 6;
1627                                 x2 = x1 + item[i].w;
1628                                 y1 = grd_curcanv->cv_bitmap.bm_y + item[i].y;
1629                                 y2 = y1 + item[i].h;
1630                                 if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && (item[i].type != NM_TYPE_TEXT) ) {
1631                                         if (i+ScrollOffset != choice) {
1632                                                 if(Hack_DblClick_MenuMode) dblclick_flag = 0; 
1633                                         }
1634
1635                                         choice = i + ScrollOffset;
1636
1637                                         if ( item[choice].type == NM_TYPE_SLIDER ) {
1638                                                 char slider_text[NM_MAX_TEXT_LEN+1], *p, *s1;
1639                                                 int slider_width, height, aw, sleft_width, sright_width, smiddle_width;
1640                                                 
1641                                                 strcpy(slider_text, item[choice].saved_text);
1642                                                 p = strchr(slider_text, '\t');
1643                                                 if (p) {
1644                                                         *p = '\0';
1645                                                         s1 = p+1;
1646                                                 }
1647                                                 if (p) {
1648                                                         gr_get_string_size(s1, &slider_width, &height, &aw);
1649                                                         gr_get_string_size(SLIDER_LEFT, &sleft_width, &height, &aw);
1650                                                         gr_get_string_size(SLIDER_RIGHT, &sright_width, &height, &aw);
1651                                                         gr_get_string_size(SLIDER_MIDDLE, &smiddle_width, &height, &aw);
1652
1653                                                         x1 = grd_curcanv->cv_bitmap.bm_x + item[choice].x + item[choice].w - slider_width;
1654                                                         x2 = x1 + slider_width + sright_width;
1655                                                         if ( (mx > x1) && (mx < (x1 + sleft_width)) && (item[choice].value != item[choice].min_value) ) {
1656                                                                 item[choice].value = item[choice].min_value;
1657                                                                 item[choice].redraw = 2;
1658                                                         } else if ( (mx < x2) && (mx > (x2 - sright_width)) && (item[choice].value != item[choice].max_value) ) {
1659                                                                 item[choice].value = item[choice].max_value;
1660                                                                 item[choice].redraw = 2;
1661                                                         } else if ( (mx > (x1 + sleft_width)) && (mx < (x2 - sright_width)) ) {
1662                                                                 int num_values, value_width, new_value;
1663                                                                 
1664                                                                 num_values = item[choice].max_value - item[choice].min_value + 1;
1665                                                                 value_width = (slider_width - sleft_width - sright_width) / num_values;
1666                                                                 new_value = (mx - x1 - sleft_width) / value_width;
1667                                                                 if ( item[choice].value != new_value ) {
1668                                                                         item[choice].value = new_value;
1669                                                                         item[choice].redraw = 2;
1670                                                                 }
1671                                                         }
1672                                                         *p = '\t';
1673                                                 }
1674                                         }
1675                                         if (choice == old_choice)
1676                                                 break;
1677                                         if ((item[choice].type==NM_TYPE_INPUT) && (choice!=old_choice)) 
1678                                                 item[choice].value = -1;
1679                                         if ((old_choice>-1) && (item[old_choice].type==NM_TYPE_INPUT_MENU) && (old_choice!=choice))     {
1680                                                 item[old_choice].group=0;
1681                                                 strcpy(item[old_choice].text, item[old_choice].saved_text );
1682                                                 item[old_choice].value = -1;
1683                                         }
1684                                         if (old_choice>-1) 
1685                                                 item[old_choice].redraw = 1;
1686                                         item[choice].redraw=1;
1687                                         break;
1688                                 }
1689                         }
1690                 }
1691                 
1692                 if ( !done && !mouse_state && omouse_state && !all_text && (choice != -1) && (item[choice].type == NM_TYPE_MENU) ) {
1693                         mouse_get_pos(&mx, &my);
1694                         x1 = grd_curcanv->cv_bitmap.bm_x + item[choice].x;
1695                         x2 = x1 + item[choice].w;
1696                         y1 = grd_curcanv->cv_bitmap.bm_y + item[choice].y;
1697                         y2 = y1 + item[choice].h;
1698                         if (((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2))) {
1699                                 if (Hack_DblClick_MenuMode) {
1700                                         if (dblclick_flag) done = 1;
1701                                         else dblclick_flag = 1;
1702                                 }
1703                                 else done = 1;
1704                         }
1705                 }
1706                 
1707                 if ( !done && !mouse_state && omouse_state && (choice>-1) && (item[choice].type==NM_TYPE_INPUT_MENU) && (item[choice].group==0))        {
1708                         item[choice].group = 1;
1709                         item[choice].redraw = 1;
1710                         if ( !strnicmp( item[choice].saved_text, TXT_EMPTY, strlen(TXT_EMPTY) ) )       {
1711                                 item[choice].text[0] = 0;
1712                                 item[choice].value = -1;
1713                         } else {        
1714                                 strip_end_whitespace(item[choice].text);
1715                         }
1716                 }
1717                 
1718                 if ( !done && !mouse_state && omouse_state && close_box ) {
1719                         mouse_get_pos(&mx, &my);
1720                         x1 = grd_curcanv->cv_bitmap.bm_x + CLOSE_X;
1721                         x2 = x1 + CLOSE_SIZE;
1722                         y1 = grd_curcanv->cv_bitmap.bm_y + CLOSE_Y;
1723                         y2 = y1 + CLOSE_SIZE;
1724                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
1725                                 choice = -1;
1726                                 done = 1;
1727                         }
1728                 }
1729
1730 //       HACK! Don't redraw loadgame preview
1731                 if (RestoringMenu) item[0].redraw = 0;
1732 #endif          // ifdef MACINTOSH
1733
1734                 if ( choice > -1 )      {
1735                         int ascii;
1736
1737                         if ( ((item[choice].type==NM_TYPE_INPUT)||((item[choice].type==NM_TYPE_INPUT_MENU)&&(item[choice].group==1)) )&& (old_choice==choice) ) {
1738                                 if ( k==KEY_LEFT || k==KEY_BACKSP || k==KEY_PAD4 )      {
1739                                         if (item[choice].value==-1) item[choice].value = strlen(item[choice].text);
1740                                         if (item[choice].value > 0)
1741                                                 item[choice].value--;
1742                                         item[choice].text[item[choice].value] = 0;
1743                                         item[choice].redraw = 1;        
1744                                 } else {
1745                                         ascii = key_to_ascii(k);
1746                                         if ((ascii < 255 ) && (item[choice].value < item[choice].text_len ))
1747                                         {
1748                                                 int allowed;
1749
1750                                                 if (item[choice].value==-1) {
1751                                                         item[choice].value = 0;
1752                                                 }
1753
1754                                                 allowed = char_allowed(ascii);
1755
1756                                                 if (!allowed && ascii==' ' && char_allowed('_')) {
1757                                                         ascii = '_';
1758                                                         allowed=1;
1759                                                 }
1760
1761                                                 if (allowed) {
1762                                                         item[choice].text[item[choice].value++] = ascii;
1763                                                         item[choice].text[item[choice].value] = 0;
1764                                                         item[choice].redraw=1;  
1765                                                 }
1766                                         }
1767                                 }
1768                         } else if ((item[choice].type!=NM_TYPE_INPUT) && (item[choice].type!=NM_TYPE_INPUT_MENU) ) {
1769                                 ascii = key_to_ascii(k);
1770                                 if (ascii < 255 ) {
1771                                         int choice1 = choice;
1772                                         ascii = toupper(ascii);
1773                                         do {
1774                                                 int i,ch;
1775                                                 choice1++;
1776                                                 if (choice1 >= nitems ) choice1=0;
1777                                                 for (i=0;(ch=item[choice1].text[i])!=0 && ch==' ';i++);
1778                                                 if ( ( (item[choice1].type==NM_TYPE_MENU) ||
1779                                                                  (item[choice1].type==NM_TYPE_CHECK) ||
1780                                                                  (item[choice1].type==NM_TYPE_RADIO) ||
1781                                                                  (item[choice1].type==NM_TYPE_NUMBER) ||
1782                                                                  (item[choice1].type==NM_TYPE_SLIDER) )
1783                                                                 && (ascii==toupper(ch)) )       {
1784                                                         k = 0;
1785                                                         choice = choice1;
1786                                                         if (old_choice>-1)
1787                                                                 item[old_choice].redraw=1;
1788                                                         item[choice].redraw=1;
1789                                                 }
1790                                         } while (choice1 != choice );
1791                                 }       
1792                         }
1793
1794                         if ( (item[choice].type==NM_TYPE_NUMBER) || (item[choice].type==NM_TYPE_SLIDER))        {
1795                                 int ov=item[choice].value;
1796                                 switch( k ) {
1797                                 case KEY_PAD4:
1798                                 case KEY_LEFT:
1799                                 case KEY_MINUS:
1800                                 case KEY_MINUS+KEY_SHIFTED:
1801                                 case KEY_PADMINUS:
1802                                         item[choice].value -= 1;
1803                                         break;
1804                                 case KEY_RIGHT:
1805                                 case KEY_PAD6:
1806                                 case KEY_EQUAL:
1807                                 case KEY_EQUAL+KEY_SHIFTED:
1808                                 case KEY_PADPLUS:
1809                                         item[choice].value++;
1810                                         break;
1811                                 case KEY_PAGEUP:
1812                                 case KEY_PAD9:
1813                                 case KEY_SPACEBAR:
1814                                         item[choice].value += 10;
1815                                         break;
1816                                 case KEY_PAGEDOWN:
1817                                 case KEY_BACKSP:
1818                                 case KEY_PAD3:
1819                                         item[choice].value -= 10;
1820                                         break;
1821                                 }
1822                                 if (ov!=item[choice].value)
1823                                         item[choice].redraw=1;
1824                         }
1825         
1826                 }
1827
1828                 WINDOS (        dd_gr_set_current_canvas(bg.menu_canvas),
1829                                 gr_set_current_canvas(bg.menu_canvas));
1830
1831         // Redraw everything...
1832         for (i=ScrollOffset; i<MaxDisplayable+ScrollOffset; i++ )
1833         {
1834         if (item[i].redraw) // warning! ugly hack below                  
1835                 {
1836                 item[i].y-=((string_height+1)*ScrollOffset);
1837                 MAC(hide_cursor());
1838                                 WIN(HideCursorW());
1839                 draw_item( &bg, &item[i], (i==choice && !all_text),TinyMode );
1840                                 item[i].redraw=0;
1841                                 MAC(if (!joydefs_calibrating) show_cursor());
1842                                 WIN(if (!MenuReordering) ShowCursorW());
1843             item[i].y+=((string_height+1)*ScrollOffset);
1844                 }   
1845          if (i==choice && (item[i].type==NM_TYPE_INPUT || (item[i].type==NM_TYPE_INPUT_MENU && item[i].group)))
1846                                 update_cursor( &item[i]);
1847                 }
1848         gr_update();
1849
1850       if (IsScrollBox)
1851         {
1852         //grd_curcanv->cv_font = NORMAL_FONT;
1853         
1854                 if (LastScrollCheck!=ScrollOffset)
1855          {
1856                 LastScrollCheck=ScrollOffset;
1857                 grd_curcanv->cv_font = SELECTED_FONT;
1858                                 
1859                 sy=item[ScrollOffset].y-((string_height+1)*ScrollOffset);
1860                 sx=item[ScrollOffset].x-(MenuHires?24:12);
1861                                 
1862           
1863                 if (ScrollOffset!=0)
1864                         nm_rstring( &bg, (MenuHires?20:10), sx, sy, UP_ARROW_MARKER );
1865                 else
1866                         nm_rstring( &bg, (MenuHires?20:10), sx, sy, "  " );
1867
1868                 sy=item[ScrollOffset+MaxDisplayable-1].y-((string_height+1)*ScrollOffset);
1869                 sx=item[ScrollOffset+MaxDisplayable-1].x-(MenuHires?24:12);
1870           
1871                 if (ScrollOffset+MaxDisplayable<nitems)
1872                         nm_rstring( &bg, (MenuHires?20:10), sx, sy, DOWN_ARROW_MARKER );
1873                 else
1874                 nm_rstring( &bg, (MenuHires?20:10), sx, sy, "  " );
1875
1876         }
1877
1878         }   
1879
1880                 if ( !dont_restore && gr_palette_faded_out )    {
1881                         gr_palette_fade_in( gr_palette, 32, 0 );
1882                 }
1883         }
1884         
1885         MAC(hide_cursor());
1886         WIN(HideCursorW());
1887         
1888         // Restore everything...
1889
1890         WINDOS (        dd_gr_set_current_canvas(bg.menu_canvas),
1891                         gr_set_current_canvas(bg.menu_canvas));
1892
1893         if ( filename == NULL ) {
1894                 // Save the background under the menu...
1895                 WIN (DDGRLOCK(dd_grd_curcanv));
1896                         gr_bitmap(0, 0, bg.saved);      
1897                 WIN (DDGRUNLOCK(dd_grd_curcanv));
1898                 gr_free_bitmap(bg.saved);
1899                 d_free( bg.background );
1900         } else {
1901                 if (!dont_restore)      //info passed back from subfunction
1902                 {
1903                         WIN (DDGRLOCK(dd_grd_curcanv));
1904                         gr_bitmap(0, 0, bg.background);
1905                         WIN (DDGRUNLOCK(dd_grd_curcanv));       
1906                 }
1907                 gr_free_bitmap(bg.background);
1908         }
1909
1910         WINDOS (        dd_gr_free_sub_canvas(bg.menu_canvas),
1911                         gr_free_sub_canvas( bg.menu_canvas ) );
1912
1913         WINDOS (dd_gr_set_current_canvas(NULL), gr_set_current_canvas( NULL ));                 
1914         grd_curcanv->cv_font    = save_font;
1915         WINDOS (dd_gr_set_current_canvas(NULL), gr_set_current_canvas( save_canvas ));                  
1916         keyd_repeat = old_keyd_repeat;
1917
1918         game_flush_inputs();
1919
1920         if (time_stopped) 
1921      {
1922                 start_time();
1923                 #ifdef TACTILE
1924                         if (TactileStick)
1925                                 EnableForces();
1926                 #endif
1927           }
1928
1929         if ( sound_stopped )
1930                 digi_resume_digi_sounds();
1931
1932         WIN(mouse_set_mode(1));                         //re-enable centering mode
1933
1934         return choice;
1935         
1936 }
1937
1938
1939 int nm_messagebox1( char *title, void (*subfunction)(int nitems,newmenu_item * items, int * last_key, int citem), int nchoices, ... )
1940 {
1941         int i;
1942         char * format;
1943         va_list args;
1944         char *s;
1945         char nm_text[MESSAGEBOX_TEXT_SIZE];
1946         newmenu_item nm_message_items[5];
1947
1948         va_start(args, nchoices );
1949
1950         Assert( nchoices <= 5 );
1951
1952         for (i=0; i<nchoices; i++ )     {
1953                 s = va_arg( args, char * );
1954                 nm_message_items[i].type = NM_TYPE_MENU; nm_message_items[i].text = s;
1955         }
1956         format = va_arg( args, char * );
1957         strcpy( nm_text, "" );
1958         vsprintf(nm_text,format,args);
1959         va_end(args);
1960
1961         Assert(strlen(nm_text) < MESSAGEBOX_TEXT_SIZE);
1962
1963         return newmenu_do( title, nm_text, nchoices, nm_message_items, subfunction );
1964 }
1965
1966 int nm_messagebox( char *title, int nchoices, ... )
1967 {
1968         int i;
1969         char * format;
1970         va_list args;
1971         char *s;
1972         char nm_text[MESSAGEBOX_TEXT_SIZE];
1973         newmenu_item nm_message_items[5];
1974
1975         va_start(args, nchoices );
1976
1977         Assert( nchoices <= 5 );
1978
1979         for (i=0; i<nchoices; i++ )     {
1980                 s = va_arg( args, char * );
1981                 nm_message_items[i].type = NM_TYPE_MENU; nm_message_items[i].text = s;
1982         }
1983         format = va_arg( args, char * );
1984         strcpy( nm_text, "" );
1985         vsprintf(nm_text,format,args);
1986         va_end(args);
1987
1988         Assert(strlen(nm_text) < MESSAGEBOX_TEXT_SIZE );
1989
1990         return newmenu_do( title, nm_text, nchoices, nm_message_items, NULL );
1991 }
1992
1993
1994
1995
1996 void newmenu_file_sort( int n, char *list )
1997 {
1998         int i, j, incr;
1999         char t[14];
2000
2001         incr = n / 2;
2002         while( incr > 0 )               {
2003                 for (i=incr; i<n; i++ )         {
2004                         j = i - incr;
2005                         while (j>=0 )                   {
2006                                 if (strncmp(&list[j*14], &list[(j+incr)*14], 12) > 0)                           {
2007                                         memcpy( t, &list[j*14], FILENAME_LEN );
2008                                         memcpy( &list[j*14], &list[(j+incr)*14], FILENAME_LEN );
2009                                         memcpy( &list[(j+incr)*14], t, FILENAME_LEN );
2010                                         j -= incr;
2011                                 }
2012                                 else
2013                                         break;
2014                         }
2015                 }
2016                 incr = incr / 2;
2017         }
2018 }
2019
2020 void delete_player_saved_games(char * name)
2021 {
2022         int i;
2023         char filename[16];
2024         
2025         for (i=0;i<10; i++)     {
2026 #ifndef MACINTOSH
2027                 sprintf( filename, "%s.sg%d", name, i );
2028 #else
2029                 sprintf( filename, ":Players:%s.sg%d", name, i );
2030 #endif
2031                 unlink( filename );
2032         }
2033 }
2034
2035 #define MAX_FILES 300
2036
2037 int MakeNewPlayerFile(int allow_abort);
2038
2039 int newmenu_get_filename( char * title, char * filespec, char * filename, int allow_abort_flag )
2040 {
2041         int i;
2042         FILEFINDSTRUCT find;
2043         int NumFiles=0, key,done, citem, ocitem;
2044         char * filenames = NULL;
2045         int NumFiles_displayed = 8;
2046         int first_item = -1, ofirst_item;
2047         int old_keyd_repeat = keyd_repeat;
2048         int player_mode=0;
2049         int demo_mode=0;
2050         int demos_deleted=0;
2051         int initialized = 0;
2052         int exit_value = 0;
2053         int w_x, w_y, w_w, w_h, title_height;
2054         int box_x, box_y, box_w, box_h;
2055         bkg bg;         // background under listbox
2056 #if defined(MACINTOSH) || defined(WINDOWS)
2057         int mx, my, x1, x2, y1, y2, mouse_state, omouse_state;
2058         int mouse2_state, omouse2_state;
2059         int dblclick_flag=0;
2060    int simukey=0;
2061         int show_up_arrow=0,show_down_arrow=0;
2062 #endif
2063 WIN(int win_redraw=0);
2064
2065         w_x=w_y=w_w=w_h=title_height=0;
2066         box_x=box_y=box_w=box_h=0;
2067
2068         filenames = d_malloc( MAX_FILES * 14 );
2069         if (filenames==NULL) return 0;
2070
2071         citem = 0;
2072         keyd_repeat = 1;
2073
2074         WIN(mouse_set_mode(0));                         //disable centering mode
2075
2076         if (strstr( filespec, "*.plr" ))
2077                 player_mode = 1;
2078         else if (strstr( filespec, "*.dem" ))
2079                 demo_mode = 1;
2080
2081 ReadFileNames:
2082         done = 0;
2083         NumFiles=0;
2084         
2085 #if !defined(APPLE_DEMO)                // no new pilots for special apple oem version
2086         if (player_mode)        {
2087                 strncpy( &filenames[NumFiles*14], TXT_CREATE_NEW, FILENAME_LEN );
2088                 NumFiles++;
2089         }
2090 #endif
2091
2092         if( !FileFindFirst( filespec, &find ) ) {
2093                 do      {
2094                         if (NumFiles<MAX_FILES) {
2095                                 strncpy( &filenames[NumFiles*14], find.name, FILENAME_LEN );
2096                                 if ( player_mode )      {
2097                                         char * p;
2098                                         p = strchr(&filenames[NumFiles*14],'.');
2099                                         if (p) *p = '\0';
2100                                 }
2101                                 NumFiles++;
2102                         } else {
2103                                 break;
2104                         }
2105                 } while( !FileFindNext( &find ) );
2106                 FileFindClose();
2107         }
2108
2109         if ( (NumFiles < 1) && demos_deleted )  {
2110                 exit_value = 0;
2111                 goto ExitFileMenu;
2112         }
2113         if ( (NumFiles < 1) && demo_mode ) {
2114                 nm_messagebox( NULL, 1, TXT_OK, "%s %s\n%s", TXT_NO_DEMO_FILES, TXT_USE_F5, TXT_TO_CREATE_ONE);
2115                 exit_value = 0;
2116                 goto ExitFileMenu;
2117         }
2118
2119         #ifndef APPLE_DEMO
2120         if ( (NumFiles < 2) && player_mode ) {
2121                 citem = 0;
2122                 goto ExitFileMenuEarly;
2123         }
2124         #endif
2125
2126
2127         if ( NumFiles<1 )       {
2128                 #ifndef APPLE_DEMO
2129                         nm_messagebox( NULL, 1, "Ok", "%s\n '%s' %s", TXT_NO_FILES_MATCHING, filespec, TXT_WERE_FOUND);
2130                 #endif
2131                 exit_value = 0;
2132                 goto ExitFileMenu;
2133         }
2134
2135         if (!initialized) {     
2136 //              set_screen_mode(SCREEN_MENU);
2137                 set_popup_screen();
2138
2139         #ifdef WINDOWS
2140 RePaintNewmenuFile:
2141
2142                 dd_gr_set_current_canvas(NULL);
2143         #else
2144                 gr_set_current_canvas(NULL);
2145         #endif
2146
2147                 WIN(DDGRLOCK(dd_grd_curcanv))                                   //mwa put these here -- are these needed Samir???
2148                 {
2149                         grd_curcanv->cv_font = SUBTITLE_FONT;
2150                 }
2151                 WIN(DDGRUNLOCK(dd_grd_curcanv));
2152
2153                 w_w = 0;
2154                 w_h = 0;
2155
2156                 for (i=0; i<NumFiles; i++ ) {
2157                         int w, h, aw;
2158                         gr_get_string_size( &filenames[i*14], &w, &h, &aw );            
2159                         if ( w > w_w )
2160                                 w_w = w;
2161                 }
2162                 if ( title ) {
2163                         int w, h, aw;
2164                         gr_get_string_size( title, &w, &h, &aw );               
2165                         if ( w > w_w )
2166                                 w_w = w;
2167                         title_height = h + (grd_curfont->ft_h*2);               // add a little space at the bottom of the title
2168                 }
2169
2170                 box_w = w_w;
2171                 box_h = ((grd_curfont->ft_h + 2) * NumFiles_displayed);
2172
2173                 w_w += (grd_curfont->ft_w * 4);
2174                 w_h = title_height + box_h + (grd_curfont->ft_h * 2);           // more space at bottom
2175
2176                 if ( w_w > grd_curcanv->cv_w ) w_w = grd_curcanv->cv_w;
2177                 if ( w_h > grd_curcanv->cv_h ) w_h = grd_curcanv->cv_h;
2178         
2179                 w_x = (grd_curcanv->cv_w-w_w)/2;
2180                 w_y = (grd_curcanv->cv_h-w_h)/2;
2181         
2182                 if ( w_x < 0 ) w_x = 0;
2183                 if ( w_y < 0 ) w_y = 0;
2184
2185                 box_x = w_x + (grd_curfont->ft_w*2);                    // must be in sync with w_w!!!
2186                 box_y = w_y + title_height;
2187
2188 // save the screen behind the menu.
2189
2190                 bg.saved = NULL;
2191
2192         #if !defined(WINDOWS)
2193                 if ( (VR_offscreen_buffer->cv_w >= w_w) && (VR_offscreen_buffer->cv_h >= w_h) ) 
2194                         bg.background = &VR_offscreen_buffer->cv_bitmap;
2195                 else
2196         #endif
2197 #if defined(POLY_ACC)
2198                         bg.background = gr_create_bitmap2( w_w, w_h, grd_curcanv->cv_bitmap.bm_type, NULL );
2199 #else
2200                         bg.background = gr_create_bitmap( w_w, w_h );
2201 #endif
2202
2203                 Assert( bg.background != NULL );
2204
2205
2206                 WIN(DDGRLOCK(dd_grd_curcanv));
2207                 gr_bm_bitblt(w_w, w_h, 0, 0, w_x, w_y, &grd_curcanv->cv_bitmap, bg.background );
2208                 WIN(DDGRUNLOCK(dd_grd_curcanv));
2209
2210 #if 0
2211                 WINDOS(
2212                         dd_gr_blt_notrans(dd_grd_curcanv, 0, 0, 
2213                                 _DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh, 
2214                                 dd_VR_offscreen_buffer, 0, 0, 
2215                                 _DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh),
2216                         gr_bm_bitblt(grd_curcanv->cv_w, grd_curcanv->cv_h, 0, 0, 0, 0, &(grd_curcanv->cv_bitmap), &(VR_offscreen_buffer->cv_bitmap) )
2217                 );
2218 #endif
2219
2220                 nm_draw_background( w_x,w_y,w_x+w_w-1,w_y+w_h-1 );
2221                 
2222                 WIN(DDGRLOCK(dd_grd_curcanv))
2223                 {       
2224                         gr_string( 0x8000, w_y+10, title );
2225                 }
2226                 WIN(DDGRUNLOCK(dd_grd_curcanv));
2227
2228                 WIN(DDGRRESTORE);
2229          
2230                 initialized = 1;
2231         }
2232
2233         if ( !player_mode )     {
2234                 newmenu_file_sort( NumFiles, filenames );
2235         } else {
2236                 #if defined(MACINTOSH) && defined(APPLE_DEMO)
2237                 newmenu_file_sort( NumFiles, filenames );
2238                 #else
2239                 newmenu_file_sort( NumFiles-1, &filenames[14] );                // Don't sort first one!
2240                 #endif
2241                 for ( i=0; i<NumFiles; i++ )    {
2242                         if (!stricmp(Players[Player_num].callsign, &filenames[i*14]) )  {
2243                         #if defined(WINDOWS) || defined(MACINTOSH) 
2244                                 dblclick_flag = 1;
2245                         #endif
2246                                 citem = i;
2247                         }
2248                 }
2249         }
2250         
2251 #if defined(MACINTOSH) || defined(WINDOWS)
2252         mouse_state = omouse_state = 0;
2253         mouse2_state = omouse2_state = 0;
2254         draw_close_box(w_x,w_y);
2255    #ifdef MACINTOSH
2256                 show_cursor();
2257         #else
2258                 ShowCursorW();
2259         #endif
2260 #endif
2261
2262         while(!done)    {
2263         #ifdef WINDOWS
2264                 MSG msg;
2265
2266                 DoMessageStuff(&msg);
2267
2268                 if (_RedrawScreen) {
2269                         _RedrawScreen = FALSE;
2270
2271                         if ( bg.background != &VR_offscreen_buffer->cv_bitmap )
2272                                 gr_free_bitmap(bg.background);
2273         
2274                         win_redraw = 1;         
2275                         goto RePaintNewmenuFile;
2276                 }
2277
2278                 DDGRRESTORE
2279         #endif
2280
2281                 ocitem = citem;
2282                 ofirst_item = first_item;
2283                 gr_update();
2284
2285 #if defined(MACINTOSH) || defined(WINDOWS)
2286                 omouse_state = mouse_state;
2287                 omouse2_state = mouse2_state;
2288                 mouse_state = mouse_button_state(0);
2289                 mouse2_state = mouse_button_state(1);
2290 #endif
2291
2292                 //see if redbook song needs to be restarted
2293                 songs_check_redbook_repeat();
2294
2295                 #ifdef WINDOWS
2296                 if (!mouse2_state && omouse2_state)
2297                         key = KEY_CTRLED+KEY_D;         //fake ctrl-d
2298                 else
2299                 #endif
2300                         //NOTE LINK TO ABOVE ELSE
2301                         key = key_inkey();
2302
2303         #ifdef WINDOWS
2304                 if (simukey==-1)
2305                         key=KEY_UP;
2306                 else if (simukey==1)
2307                    key=KEY_DOWN;
2308                 simukey=0;
2309         #endif
2310                         
2311                 switch(key)     {
2312                 MAC(case KEY_COMMAND+KEY_SHIFTED+KEY_3:)
2313                 case KEY_PRINT_SCREEN:
2314                         MAC(hide_cursor());
2315                         save_screen_shot(0);
2316                         PA_DFX (pa_set_frontbuffer_current());
2317                         PA_DFX (pa_set_front_to_read());
2318                         
2319                         MAC(show_cursor());
2320                         MAC(key_flush());
2321                         break;
2322
2323                 case KEY_CTRLED+KEY_D:
2324                         #if defined(MACINTOSH) && defined(APPLE_DEMO)
2325                         break;
2326                         #endif
2327
2328                         if ( ((player_mode)&&(citem>0)) || ((demo_mode)&&(citem>=0)) )  {
2329                                 int x = 1;
2330                                 MAC(hide_cursor());
2331                                 #ifdef WINDOWS
2332                                 mouse_set_mode(1);                              //re-enable centering mode
2333                                 HideCursorW();
2334                                 #endif
2335                                 if (player_mode)
2336                                         x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_PILOT, &filenames[citem*14]+((player_mode && filenames[citem*14]=='$')?1:0) );
2337                                 else if (demo_mode)
2338                                         x = nm_messagebox( NULL, 2, TXT_YES, TXT_NO, "%s %s?", TXT_DELETE_DEMO, &filenames[citem*14]+((demo_mode && filenames[citem*14]=='$')?1:0) );
2339                                 MAC(show_cursor());
2340                                 #ifdef WINDOWS
2341                                 mouse_set_mode(0);                              //disenable centering mode
2342                                 ShowCursorW();
2343                                 #endif
2344                                 if (x==0)       {
2345                                         char * p;
2346                                         int ret;
2347                                         char name[_MAX_PATH],dir[_MAX_DIR];
2348
2349                                         p = &filenames[(citem*14)+strlen(&filenames[citem*14])];
2350                                         if (player_mode)
2351                                                 *p = '.';
2352
2353                                         _splitpath(filespec,name,dir,NULL,NULL);
2354                                         strcat(name,dir);
2355                                         strcat(name,&filenames[citem*14]);
2356                                         
2357                                         #ifdef MACINTOSH
2358                                         {
2359                                                 int i;
2360                                                 char *p;
2361                                                 
2362                                                 if ( !strncmp(name, ".\\", 2) )
2363                                                         for (i = 0; i < strlen(name); i++)              // don't subtract 1 from strlen to get the EOS marker
2364                                                                 name[i] = name[i+1];
2365                                                 while ( (p = strchr(name, '\\')) )
2366                                                         *p = ':';
2367                                         }
2368                                         #endif
2369                                 
2370                                         ret = unlink( name );
2371                                         if (player_mode)
2372                                                 *p = 0;
2373
2374                                         if ((!ret) && player_mode)      {
2375                                                 delete_player_saved_games( &filenames[citem*14] );
2376                                         }
2377
2378                                         if (ret) {
2379                                                 if (player_mode)
2380                                                         nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_PILOT, &filenames[citem*14]+((player_mode && filenames[citem*14]=='$')?1:0) );
2381                                                 else if (demo_mode)
2382                                                         nm_messagebox( NULL, 1, TXT_OK, "%s %s %s", TXT_COULDNT, TXT_DELETE_DEMO, &filenames[citem*14]+((demo_mode && filenames[citem*14]=='$')?1:0) );
2383                                         } else if (demo_mode)
2384                                                 demos_deleted = 1;
2385                                         first_item = -1;
2386                                         goto ReadFileNames;
2387                                 }
2388                         }
2389                         break;
2390                 case KEY_HOME:
2391                 case KEY_PAD7:
2392                         citem = 0;
2393                         break;
2394                 case KEY_END:
2395                 case KEY_PAD1:
2396                         citem = NumFiles-1;
2397                         break;
2398                 case KEY_UP:
2399                 case KEY_PAD8:
2400                         citem--;                        
2401                         break;
2402                 case KEY_DOWN:
2403                 case KEY_PAD2:
2404                         citem++;                        
2405                         break;
2406                 case KEY_PAGEDOWN:
2407                 case KEY_PAD3:
2408                         citem += NumFiles_displayed;
2409                         break;
2410                 case KEY_PAGEUP:
2411                 case KEY_PAD9:
2412                         citem -= NumFiles_displayed;
2413                         break;
2414                 case KEY_ESC:
2415                         if (allow_abort_flag) {
2416                                 citem = -1;
2417                                 done = 1;
2418                         }
2419                         break;
2420                 case KEY_ENTER:
2421                 case KEY_PADENTER:
2422                         done = 1;
2423                         break;
2424                         
2425                 #ifdef MACINTOSH
2426                 case KEY_COMMAND+KEY_Q: {
2427                         extern void macintosh_quit();
2428                         
2429                         if ( !(Game_mode & GM_MULTI) )
2430                                 macintosh_quit();
2431                         show_cursor();
2432                         key_flush();
2433                         break;
2434                 }
2435                 #endif
2436                 
2437                 default:        
2438                         {
2439
2440                                 int ascii = key_to_ascii(key);
2441                                 if ( ascii < 255 )      {
2442                                         int cc,cc1;
2443                                         cc=cc1=citem+1;
2444                                         if (cc1 < 0 )  cc1 = 0;
2445                                         if (cc1 >= NumFiles )  cc1 = 0;
2446                                         while(1) {
2447                                                 if ( cc < 0 ) cc = 0;
2448                                                 if ( cc >= NumFiles ) cc = 0;
2449                                                 if ( citem == cc ) break;
2450         
2451                                                 if ( toupper(filenames[cc*14]) == toupper(ascii) )      {
2452                                                         citem = cc;
2453                                                         break;
2454                                                 }
2455                                                 cc++;
2456                                         }
2457                                 }
2458                         }
2459                 }
2460                 if ( done ) break;
2461
2462
2463                 if (citem<0)
2464                         citem=0;
2465
2466                 if (citem>=NumFiles)
2467                         citem = NumFiles-1;
2468
2469                 if (citem< first_item)
2470                         first_item = citem;
2471
2472                 if (citem>=( first_item+NumFiles_displayed))
2473                 {
2474                         first_item = citem-NumFiles_displayed+1;
2475                 }
2476
2477 #ifdef WINDOWS
2478                 if (NumFiles>first_item+NumFiles_displayed)
2479                         show_down_arrow=1;
2480                 else 
2481                         show_down_arrow=0;
2482                 if (first_item>0)
2483                         show_up_arrow=1;
2484                 else    
2485                         show_up_arrow=0;
2486 #endif
2487                         
2488
2489                 if (NumFiles <= NumFiles_displayed )
2490                          first_item = 0;
2491
2492                 if (first_item>NumFiles-NumFiles_displayed)
2493                 {
2494                         first_item = NumFiles-NumFiles_displayed;
2495                 }
2496
2497                 if (first_item < 0 ) first_item = 0;
2498
2499 #if defined(MACINTOSH) || defined(WINDOWS)
2500                 WIN(Sleep(100));
2501                 if (mouse_state || mouse2_state) {
2502                         int w, h, aw;
2503
2504                         mouse_get_pos(&mx, &my);
2505                         for (i=first_item; i<first_item+NumFiles_displayed; i++ )       {
2506                                 gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
2507                                 x1 = box_x;
2508                                 x2 = box_x + box_w - 1;
2509                                 y1 = (i-first_item)*(grd_curfont->ft_h + 2) + box_y;
2510                                 y2 = y1+h+1;
2511                                 if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
2512                                         if (i == citem && !mouse2_state) {
2513                                                 break;
2514                                         }
2515                                         citem = i;
2516                                         dblclick_flag = 0;
2517                                         break;
2518                                 }
2519                         }
2520                 }
2521                 
2522                 if (!mouse_state && omouse_state) {
2523                         int w, h, aw;
2524
2525                         gr_get_string_size(&filenames[citem*14], &w, &h, &aw  );
2526                         mouse_get_pos(&mx, &my);
2527                         x1 = box_x;
2528                         x2 = box_x + box_w - 1;
2529                         y1 = (citem-first_item)*(grd_curfont->ft_h + 2) + box_y;
2530                         y2 = y1+h+1;
2531                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
2532                                 if (dblclick_flag) done = 1;
2533                                 else dblclick_flag = 1;
2534                         }
2535                 }
2536
2537                 if ( !mouse_state && omouse_state ) {
2538                         mouse_get_pos(&mx, &my);
2539                         x1 = w_x + CLOSE_X + 2;
2540                         x2 = x1 + CLOSE_SIZE - 2;
2541                         y1 = w_y + CLOSE_Y + 2;
2542                         y2 = y1 + CLOSE_SIZE - 2;
2543                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
2544                                 citem = -1;
2545                                 done = 1;
2546                         }
2547                    #ifdef WINDOWS
2548                         x1 = box_x-LHX(10);
2549                         x2 = x1 + LHX(10);
2550                         y1 = box_y;
2551                         y2 = box_y+LHY(7);
2552                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && show_up_arrow ) 
2553                                 simukey = -1;
2554                         y1 = box_y+box_h-LHY(7);
2555                         y2 = box_y+box_h;
2556                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && show_down_arrow) 
2557                                 simukey = 1;
2558                    #endif
2559                 }
2560
2561 #endif
2562   
2563         WIN(DDGRLOCK(dd_grd_curcanv));
2564                 gr_setcolor( BM_XRGB(2,2,2));
2565                 //gr_rect( box_x - 1, box_y-2, box_x + box_w, box_y-2 );
2566                 gr_setcolor( BM_XRGB( 0,0,0)  );
2567
2568         #ifdef WINDOWS
2569                 if (ofirst_item != first_item || win_redraw)    {
2570                         win_redraw = 0;
2571         #else
2572                 if (ofirst_item != first_item)  {
2573         #endif
2574                         MAC(hide_cursor());
2575                         WIN(HideCursorW());
2576                         gr_setcolor( BM_XRGB( 0,0,0)  );
2577                         for (i=first_item; i<first_item+NumFiles_displayed; i++ )       {
2578                                 int w, h, aw, y;
2579                                 y = (i-first_item)*(grd_curfont->ft_h + 2) + box_y;
2580                         
2581                                 if ( i >= NumFiles )    {
2582
2583                                         gr_setcolor( BM_XRGB(5,5,5));
2584                                         gr_rect( box_x + box_w, y-1, box_x + box_w, y + grd_curfont->ft_h + 1);
2585                                         //gr_rect( box_x, y + grd_curfont->ft_h + 2, box_x + box_w, y + grd_curfont->ft_h + 2);
2586                                         
2587                                         gr_setcolor( BM_XRGB(2,2,2));
2588                                         gr_rect( box_x - 1, y - 1, box_x - 1, y + grd_curfont->ft_h + 2 );
2589                                         
2590                                         gr_setcolor( BM_XRGB(0,0,0));
2591                                         gr_rect( box_x, y - 1, box_x + box_w - 1, y + grd_curfont->ft_h + 1);
2592                                         
2593                                 } else {
2594                                         if ( i == citem )       
2595                                                 grd_curcanv->cv_font = SELECTED_FONT;
2596                                         else    
2597                                                 grd_curcanv->cv_font = NORMAL_FONT;
2598                                         gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
2599
2600                                         gr_setcolor( BM_XRGB(5,5,5));
2601                                   //    gr_rect( box_x, y + h + 2, box_x + box_w, y + h + 2);
2602                                         gr_rect( box_x + box_w, y - 1, box_x + box_w, y + h + 1);
2603                                         
2604                                         gr_setcolor( BM_XRGB(2,2,2));
2605                                         gr_rect( box_x - 1, y - 1, box_x - 1, y + h + 1);
2606                                         gr_setcolor( BM_XRGB(0,0,0));
2607                                                         
2608                                         gr_rect( box_x, y-1, box_x + box_w - 1, y + h + 1 );
2609                                         gr_string( box_x + 5, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
2610                                 }
2611                         }        
2612                         WIN(ShowCursorW());
2613                         MAC(show_cursor());
2614                 } else if ( citem != ocitem )   {
2615                         int w, h, aw, y;
2616
2617                         MAC(hide_cursor());
2618                         WIN(HideCursorW());
2619                         i = ocitem;
2620                         if ( (i>=0) && (i<NumFiles) )   {
2621                                 y = (i-first_item)*(grd_curfont->ft_h+2)+box_y;
2622                                 if ( i == citem )       
2623                                         grd_curcanv->cv_font = SELECTED_FONT;
2624                                 else    
2625                                         grd_curcanv->cv_font = NORMAL_FONT;
2626                                 gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
2627                                 gr_rect( box_x, y-1, box_x + box_w - 1, y + h + 1 );
2628                                 gr_string( box_x + 5, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
2629                         }
2630                         i = citem;
2631                         if ( (i>=0) && (i<NumFiles) )   {
2632                                 y = (i-first_item)*(grd_curfont->ft_h+2)+box_y;
2633                                 if ( i == citem )       
2634                                         grd_curcanv->cv_font = SELECTED_FONT;
2635                                 else    
2636                                         grd_curcanv->cv_font = NORMAL_FONT;
2637                                 gr_get_string_size(&filenames[i*14], &w, &h, &aw  );
2638                                 gr_rect( box_x, y-1, box_x + box_x - 1, y + h + 1 );
2639                                 gr_string( box_x + 5, y, (&filenames[i*14])+((player_mode && filenames[i*14]=='$')?1:0)  );
2640                         }
2641                         WIN(ShowCursorW());
2642                         MAC(show_cursor());
2643                 }
2644
2645         #ifdef WINDOWS   
2646                         grd_curcanv->cv_font = NORMAL_FONT;
2647                         if (show_up_arrow)
2648                                 gr_string( box_x-LHX(10), box_y ,UP_ARROW_MARKER );
2649                         else
2650                         {
2651                                 No_darkening=1;
2652                                 nm_draw_background (box_x-LHX(10),box_y,box_x-2,box_y+LHY(7));
2653                                 No_darkening=0;
2654                         }
2655
2656                         if (show_down_arrow)
2657                         gr_string( box_x-LHX(10), box_y+box_h-LHY(7) ,DOWN_ARROW_MARKER );
2658                         else
2659                         {
2660                                 No_darkening=1;
2661                                 nm_draw_background (box_x-LHX(10),box_y+box_h-LHY(7),box_x-2,box_y+box_h);
2662                                 No_darkening=0;
2663                         }
2664
2665         #endif
2666
2667
2668
2669         WIN(DDGRUNLOCK(dd_grd_curcanv));
2670         }
2671
2672 ExitFileMenuEarly:
2673         MAC(hide_cursor());
2674         if ( citem > -1 )       {
2675                 strncpy( filename, (&filenames[citem*14])+((player_mode && filenames[citem*14]=='$')?1:0), FILENAME_LEN );
2676                 exit_value = 1;
2677         } else {
2678                 exit_value = 0;
2679         }                                                                                        
2680
2681 ExitFileMenu:
2682         keyd_repeat = old_keyd_repeat;
2683
2684         if ( initialized )      {
2685                         if (Newdemo_state != ND_STATE_PLAYBACK) //horrible hack to prevent restore when screen has been cleared
2686                         {
2687                         WIN (DDGRLOCK(dd_grd_curcanv));
2688                                 gr_bm_bitblt(w_w, w_h, w_x, w_y, 0, 0, bg.background, &grd_curcanv->cv_bitmap );
2689                         WIN (DDGRUNLOCK(dd_grd_curcanv));       
2690                         }
2691                         if ( bg.background != &VR_offscreen_buffer->cv_bitmap )
2692                                 gr_free_bitmap(bg.background);
2693 #if 0
2694                 WINDOS(
2695                         dd_gr_blt_notrans(dd_VR_offscreen_buffer,
2696                                 0,0,_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh,
2697                                 dd_grd_curcanv,
2698                                 0,0,_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh),
2699                         gr_bm_bitblt(grd_curcanv->cv_w, grd_curcanv->cv_h, 0, 0, 0, 0, &(VR_offscreen_buffer->cv_bitmap), &(grd_curcanv->cv_bitmap) )
2700                 );
2701 #endif
2702
2703                 WIN(DDGRRESTORE);
2704         }
2705
2706         if ( filenames )
2707                 d_free(filenames);
2708
2709         WIN(mouse_set_mode(1));                         //re-enable centering mode
2710         WIN(HideCursorW());
2711
2712         return exit_value;
2713
2714 }
2715
2716
2717 // Example listbox callback function...
2718 // int lb_callback( int * citem, int *nitems, char * items[], int *keypress )
2719 // {
2720 //      int i;
2721 // 
2722 //      if ( *keypress = KEY_CTRLED+KEY_D )     {
2723 //              if ( *nitems > 1 )      {
2724 //                      unlink( items[*citem] );                // Delete the file
2725 //                      for (i=*citem; i<*nitems-1; i++ )       {
2726 //                              items[i] = items[i+1];
2727 //                      }
2728 //                      *nitems = *nitems - 1;
2729 //                      d_free( items[*nitems] );
2730 //                      items[*nitems] = NULL;
2731 //                      return 1;       // redraw;
2732 //              }
2733 //                      *keypress = 0;
2734 //      }                       
2735 //      return 0;
2736 // }
2737
2738 #define LB_ITEMS_ON_SCREEN 8
2739
2740 int newmenu_listbox( char * title, int nitems, char * items[], int allow_abort_flag, int (*listbox_callback)( int * citem, int *nitems, char * items[], int *keypress ) )
2741 {
2742         return newmenu_listbox1( title, nitems, items, allow_abort_flag, 0, listbox_callback );
2743 }
2744
2745 int newmenu_listbox1( char * title, int nitems, char * items[], int allow_abort_flag, int default_item, int (*listbox_callback)( int * citem, int *nitems, char * items[], int *keypress ) )
2746 {
2747         int i;
2748         int done, ocitem,citem, ofirst_item, first_item, key, redraw;
2749         int old_keyd_repeat = keyd_repeat;
2750         int width, height, wx, wy, title_height, border_size;
2751         int total_width,total_height;
2752         bkg bg;
2753 #if defined(MACINTOSH) || defined(WINDOWS)
2754         int mx, my, x1, x2, y1, y2, mouse_state, omouse_state;  //, dblclick_flag;
2755         int close_x,close_y;
2756    int simukey=0,show_up_arrow=0,show_down_arrow=0;
2757 #endif
2758 WIN(int win_redraw=0);
2759
2760         keyd_repeat = 1;
2761
2762    PA_DFX (pa_set_frontbuffer_current());
2763         PA_DFX (pa_set_front_to_read());
2764         WIN(mouse_set_mode(0));                         //disable centering mode
2765
2766 //      set_screen_mode(SCREEN_MENU);
2767         set_popup_screen();
2768
2769 #ifdef WINDOWS
2770 RePaintNewmenuListbox:
2771  
2772         dd_gr_set_current_canvas(NULL);
2773 #else
2774         gr_set_current_canvas(NULL);
2775 #endif
2776
2777         grd_curcanv->cv_font = SUBTITLE_FONT;
2778
2779         width = 0;
2780         for (i=0; i<nitems; i++ )       {
2781                 int w, h, aw;
2782                 gr_get_string_size( items[i], &w, &h, &aw );            
2783                 if ( w > width )
2784                         width = w;
2785         }
2786         height = (grd_curfont->ft_h + 2) * LB_ITEMS_ON_SCREEN;
2787
2788         {
2789                 int w, h, aw;
2790                 gr_get_string_size( title, &w, &h, &aw );               
2791                 if ( w > width )
2792                         width = w;
2793                 title_height = h + 5;
2794         }
2795
2796         border_size = grd_curfont->ft_w;
2797    WIN (border_size=grd_curfont->ft_w*2);
2798                 
2799         width += (grd_curfont->ft_w);
2800         if ( width > grd_curcanv->cv_w - (grd_curfont->ft_w * 3) )
2801                 width = grd_curcanv->cv_w - (grd_curfont->ft_w * 3);
2802
2803         wx = (grd_curcanv->cv_bitmap.bm_w-width)/2;
2804         wy = (grd_curcanv->cv_bitmap.bm_h-(height+title_height))/2 + title_height;
2805         if ( wy < title_height )
2806                 wy = title_height;
2807
2808         total_width = width+2*border_size;
2809         total_height = height+2*border_size+title_height;
2810
2811         bg.saved = NULL;
2812
2813 #if !defined(WINDOWS)
2814         if ( (VR_offscreen_buffer->cv_w >= total_width) && (VR_offscreen_buffer->cv_h >= total_height) )
2815                 bg.background = &VR_offscreen_buffer->cv_bitmap;
2816         else
2817 #endif
2818                 //bg.background = gr_create_bitmap( width, (height + title_height) );
2819 #if defined(POLY_ACC)
2820                 bg.background = gr_create_bitmap2(total_width, total_height, grd_curcanv->cv_bitmap.bm_type, NULL);
2821 #else
2822                 bg.background = gr_create_bitmap(total_width,total_height);
2823 #endif
2824         Assert( bg.background != NULL );
2825                 
2826         WIN (DDGRLOCK(dd_grd_curcanv));
2827                 //gr_bm_bitblt(wx+width+border_size, wy+height+border_size, 0, 0, wx-border_size, wy-title_height-border_size, &grd_curcanv->cv_bitmap, bg.background );
2828                 gr_bm_bitblt(total_width,total_height, 0, 0, wx-border_size, wy-title_height-border_size, &grd_curcanv->cv_bitmap, bg.background );
2829         WIN (DDGRUNLOCK(dd_grd_curcanv));
2830
2831 #if 0
2832         WINDOS(
2833                 dd_gr_blt_notrans(dd_grd_curcanv, 0, 0, 
2834                                 _DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh, 
2835                                 dd_VR_offscreen_buffer, 0, 0, 
2836                                 _DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh),
2837                 gr_bm_bitblt(grd_curcanv->cv_w, grd_curcanv->cv_h, 0, 0, 0, 0, &(grd_curcanv->cv_bitmap), &(VR_offscreen_buffer->cv_bitmap) )
2838         );
2839 #endif
2840
2841         nm_draw_background( wx-border_size,wy-title_height-border_size,wx+width+border_size-1,wy+height+border_size-1 );
2842
2843         WIN(DDGRLOCK(dd_grd_curcanv));
2844                 gr_string( 0x8000, wy - title_height, title );
2845         WIN(DDGRUNLOCK(dd_grd_curcanv));        
2846
2847         WIN(DDGRRESTORE);
2848
2849         done = 0;
2850         citem = default_item;
2851         if ( citem < 0 ) citem = 0;
2852         if ( citem >= nitems ) citem = 0;
2853
2854         first_item = -1;
2855
2856 #if defined(MACINTOSH) || defined(WINDOWS)
2857         mouse_state = omouse_state = 0; //dblclick_flag = 0;
2858         close_x = wx-border_size;
2859         close_y = wy-title_height-border_size;
2860         draw_close_box(close_x,close_y);
2861         #ifdef MACINTOSH
2862                 show_cursor();
2863    #else
2864                 ShowCursorW();
2865         #endif
2866 #endif
2867
2868         while(!done)    {
2869         #ifdef WINDOWS
2870                 MSG msg;
2871
2872                 DoMessageStuff(&msg);
2873
2874                 if (_RedrawScreen) {
2875                         _RedrawScreen = FALSE;
2876
2877                         if ( bg.background != &VR_offscreen_buffer->cv_bitmap )
2878                                 gr_free_bitmap(bg.background);
2879                         win_redraw = 1;                 
2880                         goto RePaintNewmenuListbox;
2881                 }
2882
2883                 DDGRRESTORE;
2884         #endif
2885   
2886                 ocitem = citem;
2887                 ofirst_item = first_item;
2888 #if defined(MACINTOSH) || defined(WINDOWS)
2889                 omouse_state = mouse_state;
2890                 mouse_state = mouse_button_state(0);
2891 #endif
2892                 //see if redbook song needs to be restarted
2893                 songs_check_redbook_repeat();
2894
2895                 key = key_inkey();
2896
2897                 if ( listbox_callback )
2898                         redraw = (*listbox_callback)(&citem, &nitems, items, &key );
2899                 else
2900                         redraw = 0;
2901
2902         #ifdef WINDOWS
2903                 if (win_redraw) {
2904                         redraw = 1;
2905                         win_redraw = 0;
2906                 }
2907         #endif
2908
2909                 if ( key<-1 ) {
2910                         citem = key;
2911                         key = -1;
2912                         done = 1;
2913                 }
2914
2915
2916         #ifdef WINDOWS
2917                 if (simukey==-1)
2918                         key=KEY_UP;
2919                 else if (simukey==1)
2920                    key=KEY_DOWN;
2921                 simukey=0;
2922         #endif
2923                 
2924                 switch(key)     {
2925                 MAC(case KEY_COMMAND+KEY_SHIFTED+KEY_3:)
2926                 case KEY_PRINT_SCREEN:          
2927                         MAC(hide_cursor());
2928                         save_screen_shot(0); 
2929                         PA_DFX (pa_set_frontbuffer_current());
2930                         PA_DFX (pa_set_front_to_read());
2931                         
2932                         MAC(show_cursor());
2933                         MAC(key_flush());
2934                         break;
2935                 case KEY_HOME:
2936                 case KEY_PAD7:
2937                         citem = 0;
2938                         break;
2939                 case KEY_END:
2940                 case KEY_PAD1:
2941                         citem = nitems-1;
2942                         break;
2943                 case KEY_UP:
2944                 case KEY_PAD8:
2945                         citem--;                        
2946                         break;
2947                 case KEY_DOWN:
2948                 case KEY_PAD2:
2949                         citem++;                        
2950                         break;
2951                 case KEY_PAGEDOWN:
2952                 case KEY_PAD3:
2953                         citem += LB_ITEMS_ON_SCREEN;
2954                         break;
2955                 case KEY_PAGEUP:
2956                 case KEY_PAD9:
2957                         citem -= LB_ITEMS_ON_SCREEN;
2958                         break;
2959                 case KEY_ESC:
2960                         if (allow_abort_flag) {
2961                                 citem = -1;
2962                                 done = 1;
2963                         }
2964                         break;
2965                 case KEY_ENTER:
2966                 case KEY_PADENTER:
2967                         done = 1;
2968                         break;
2969
2970                 #ifdef MACINTOSH
2971                 case KEY_COMMAND+KEY_Q: {
2972                         extern void macintosh_quit();
2973                         
2974                         if ( !(Game_mode & GM_MULTI) )
2975                                 macintosh_quit();
2976                         show_cursor();
2977                         key_flush();
2978                         break;
2979                 }
2980                 #endif
2981
2982                 default:        
2983                         if ( key > 0 )  {
2984                                 int ascii = key_to_ascii(key);
2985                                 if ( ascii < 255 )      {
2986                                         int cc,cc1;
2987                                         cc=cc1=citem+1;
2988                                         if (cc1 < 0 )  cc1 = 0;
2989                                         if (cc1 >= nitems )  cc1 = 0;
2990                                         while(1) {
2991                                                 if ( cc < 0 ) cc = 0;
2992                                                 if ( cc >= nitems ) cc = 0;
2993                                                 if ( citem == cc ) break;
2994         
2995                                                 if ( toupper( items[cc][0] ) == toupper(ascii) )        {
2996                                                         citem = cc;
2997                                                         break;
2998                                                 }
2999                                                 cc++;
3000                                         }
3001                                 }
3002                         }
3003                 }
3004                 if ( done ) break;
3005
3006                 if (citem<0)
3007                         citem=0;
3008
3009                 if (citem>=nitems)
3010                         citem = nitems-1;
3011
3012                 if (citem< first_item)
3013                         first_item = citem;
3014
3015                 if (citem>=( first_item+LB_ITEMS_ON_SCREEN))
3016                         first_item = citem-LB_ITEMS_ON_SCREEN+1;
3017
3018                 if (nitems <= LB_ITEMS_ON_SCREEN )
3019                          first_item = 0;
3020
3021                 if (first_item>nitems-LB_ITEMS_ON_SCREEN)
3022                         first_item = nitems-LB_ITEMS_ON_SCREEN;
3023                 if (first_item < 0 ) first_item = 0;
3024
3025 #ifdef WINDOWS
3026                 if (nitems>first_item+LB_ITEMS_ON_SCREEN)
3027                         show_down_arrow=1;
3028                 else 
3029                         show_down_arrow=0;
3030                 if (first_item>0)
3031                         show_up_arrow=1;
3032                 else    
3033                         show_up_arrow=0;
3034 #endif
3035
3036
3037 #if defined(MACINTOSH) || defined(WINDOWS)
3038                 WIN(Sleep(100));
3039                 if (mouse_state) {
3040                         int w, h, aw;
3041
3042                         mouse_get_pos(&mx, &my);
3043                         for (i=first_item; i<first_item+LB_ITEMS_ON_SCREEN; i++ )       {
3044                                 if (i > nitems)
3045                                         break;
3046                                 gr_get_string_size(items[i], &w, &h, &aw  );
3047                                 x1 = wx;
3048                                 x2 = wx + width;
3049                                 y1 = (i-first_item)*(grd_curfont->ft_h+2)+wy;
3050                                 y2 = y1+h+1;
3051                                 if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
3052                                         //if (i == citem) {
3053                                         //      break;
3054                                         //}
3055                                         //dblclick_flag= 0;
3056                                         citem = i;
3057                                         done = 1;
3058                                         break;
3059                                 }
3060                         }
3061                 }
3062
3063                 //no double-click stuff for listbox
3064                 //@@if (!mouse_state && omouse_state) {
3065                 //@@    int w, h, aw;
3066                 //@@
3067                 //@@    gr_get_string_size(items[citem], &w, &h, &aw  );
3068                 //@@    mouse_get_pos(&mx, &my);
3069                 //@@    x1 = wx;
3070                 //@@    x2 = wx + width;
3071                 //@@    y1 = (citem-first_item)*(grd_curfont->ft_h+2)+wy;
3072                 //@@    y2 = y1+h+1;
3073                 //@@    if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
3074                 //@@            if (dblclick_flag) done = 1;
3075                 //@@    }
3076                 //@@}
3077
3078                 //check for close box clicked
3079                 if ( !mouse_state && omouse_state ) {
3080                         mouse_get_pos(&mx, &my);
3081                         x1 = close_x + CLOSE_X + 2;
3082                         x2 = x1 + CLOSE_SIZE - 2;
3083                         y1 = close_y + CLOSE_Y + 2;
3084                         y2 = y1 + CLOSE_SIZE - 2;
3085                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) ) {
3086                                 citem = -1;
3087                                 done = 1;
3088                         }
3089
3090                    #ifdef WINDOWS
3091                         x1 = wx-LHX(10);
3092                         x2 = x1 + LHX(10);
3093                         y1 = wy;
3094                         y2 = wy+LHY(7);
3095                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && show_up_arrow) 
3096                                 simukey = -1;
3097                         y1 = total_height-LHY(7);
3098                         y2 = total_height;
3099                         if ( ((mx > x1) && (mx < x2)) && ((my > y1) && (my < y2)) && show_down_arrow ) 
3100                                 simukey = 1;
3101                    #endif
3102
3103                         
3104                 }
3105 #endif
3106
3107                 if ( (ofirst_item != first_item) || redraw)     {
3108                         MAC(hide_cursor());
3109                         WIN(HideCursorW());
3110                         WIN(DDGRLOCK(dd_grd_curcanv));
3111
3112                         gr_setcolor( BM_XRGB( 0,0,0)  );
3113                         for (i=first_item; i<first_item+LB_ITEMS_ON_SCREEN; i++ )       {
3114                                 int w, h, aw, y;
3115                                 y = (i-first_item)*(grd_curfont->ft_h+2)+wy;
3116                                 if ( i >= nitems )      {
3117                                         gr_setcolor( BM_XRGB(0,0,0));
3118                                         gr_rect( wx, y-1, wx+width-1, y+grd_curfont->ft_h + 1 );
3119                                 } else {
3120                                         if ( i == citem )       
3121                                                 grd_curcanv->cv_font = SELECTED_FONT;
3122                                         else    
3123                                                 grd_curcanv->cv_font = NORMAL_FONT;
3124                                         gr_get_string_size(items[i], &w, &h, &aw  );
3125                                         gr_rect( wx, y-1, wx+width-1, y+h+1 );
3126                                         gr_string( wx+5, y, items[i]  );
3127                                 }
3128                         }               
3129
3130                                 
3131                         // If Win95 port, draw up/down arrows on left side of menu
3132                         #ifdef WINDOWS   
3133                                 grd_curcanv->cv_font = NORMAL_FONT;
3134                         if (show_up_arrow)
3135                                 gr_string( wx-LHX(10), wy ,UP_ARROW_MARKER );
3136                         else
3137                         {
3138                                 No_darkening=1;
3139                                 nm_draw_background (wx-LHX(10),wy,wx-2,wy+LHY(7));
3140                                 No_darkening=0;
3141                         }
3142
3143                         if (show_down_arrow)
3144                         gr_string( wx-LHX(10), wy+total_height-LHY(7) ,DOWN_ARROW_MARKER );
3145                         else
3146                         {
3147                                 No_darkening=1;
3148                                 nm_draw_background (wx-LHX(10),wy+total_height-LHY(7),wx-2,wy+total_height);
3149                                 No_darkening=0;
3150                         }
3151
3152                         #endif
3153
3154
3155                         WIN(DDGRUNLOCK(dd_grd_curcanv));
3156                         WIN(ShowCursorW());
3157                         MAC(show_cursor());
3158                         gr_update();
3159                 } else if ( citem != ocitem )   {
3160                         int w, h, aw, y;
3161
3162                         MAC(hide_cursor());
3163                         WIN(HideCursorW());
3164
3165                         WIN(DDGRLOCK(dd_grd_curcanv));
3166
3167                         i = ocitem;
3168                         if ( (i>=0) && (i<nitems) )     {
3169                                 y = (i-first_item)*(grd_curfont->ft_h+2)+wy;
3170                                 if ( i == citem )       
3171                                         grd_curcanv->cv_font = SELECTED_FONT;
3172                                 else    
3173                                         grd_curcanv->cv_font = NORMAL_FONT;
3174                                 gr_get_string_size(items[i], &w, &h, &aw  );
3175                                 gr_rect( wx, y-1, wx+width-1, y+h+1 );
3176                                 gr_string( wx+5, y, items[i]  );
3177
3178                         }
3179                         i = citem;
3180                         if ( (i>=0) && (i<nitems) )     {
3181                                 y = (i-first_item)*(grd_curfont->ft_h+2)+wy;
3182                                 if ( i == citem )       
3183                                         grd_curcanv->cv_font = SELECTED_FONT;
3184                                 else    
3185                                         grd_curcanv->cv_font = NORMAL_FONT;
3186                                 gr_get_string_size( items[i], &w, &h, &aw  );
3187                                 gr_rect( wx, y-1, wx+width-1, y+h );
3188                                 gr_string( wx+5, y, items[i]  );
3189                         }
3190                         WIN(DDGRUNLOCK(dd_grd_curcanv));
3191
3192                         WIN(ShowCursorW());
3193                         MAC(show_cursor());
3194                         gr_update();
3195                 }
3196         }
3197         MAC(hide_cursor());
3198         WIN(HideCursorW());     
3199
3200         keyd_repeat = old_keyd_repeat;
3201
3202         WIN (DDGRLOCK(dd_grd_curcanv));
3203         gr_bm_bitblt(total_width,total_height, wx-border_size, wy-title_height-border_size, 0, 0, bg.background, &grd_curcanv->cv_bitmap );
3204         WIN (DDGRUNLOCK(dd_grd_curcanv));       
3205
3206         if ( bg.background != &VR_offscreen_buffer->cv_bitmap )
3207                 gr_free_bitmap(bg.background);
3208
3209 #if 0
3210         WINDOS(
3211                 dd_gr_blt_notrans(dd_VR_offscreen_buffer,
3212                                 0,0,_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh,
3213                                 dd_grd_curcanv,
3214                                 0,0,_DDModeList[W95DisplayMode].rw, _DDModeList[W95DisplayMode].rh),
3215                 gr_bm_bitblt(grd_curcanv->cv_w, grd_curcanv->cv_h, 0, 0, 0, 0, &(VR_offscreen_buffer->cv_bitmap), &(grd_curcanv->cv_bitmap) )
3216         );
3217 #endif
3218
3219         WIN(DDGRRESTORE);
3220
3221         WIN(mouse_set_mode(1));                         //re-enable centering mode
3222
3223         return citem;
3224 }
3225
3226 int newmenu_filelist( char * title, char * filespec, char * filename )
3227 {
3228         int i, NumFiles;
3229         char * Filenames[MAX_FILES];
3230         char FilenameText[MAX_FILES][14];
3231         FILEFINDSTRUCT find;
3232
3233         NumFiles = 0;
3234         if( !FileFindFirst( filespec, &find ) ) {
3235                 do      {
3236                         if (NumFiles<MAX_FILES) {
3237                                 strncpy( FilenameText[NumFiles], find.name, FILENAME_LEN);
3238                                 Filenames[NumFiles] = FilenameText[NumFiles];
3239                                 NumFiles++;
3240                         } else {
3241                                 break;
3242                         }
3243                 } while( !FileFindNext( &find ) );
3244                 FileFindClose();
3245         }
3246
3247         i = newmenu_listbox( title, NumFiles, Filenames, 1, NULL );
3248         if ( i > -1 )   {
3249                 strcpy( filename, Filenames[i] );
3250                 return 1;
3251         } 
3252         return 0;
3253 }
3254
3255 //added on 10/14/98 by Victor Rachels to attempt a fixedwidth font messagebox
3256 int nm_messagebox_fixedfont( char *title, int nchoices, ... )
3257 {
3258         int i;
3259         char * format;
3260         va_list args;
3261         char *s;
3262         char nm_text[MESSAGEBOX_TEXT_SIZE];
3263         newmenu_item nm_message_items[5];
3264
3265         va_start(args, nchoices );
3266
3267         Assert( nchoices <= 5 );
3268
3269         for (i=0; i<nchoices; i++ )     {
3270                 s = va_arg( args, char * );
3271                 nm_message_items[i].type = NM_TYPE_MENU; nm_message_items[i].text = s;
3272         }
3273         format = va_arg( args, char * );
3274         //sprintf(        nm_text, "" ); // adb: ?
3275         vsprintf(nm_text,format,args);
3276         va_end(args);
3277
3278         Assert(strlen(nm_text) < MESSAGEBOX_TEXT_SIZE );
3279
3280         return newmenu_do_fixedfont( title, nm_text, nchoices, nm_message_items, NULL, 0, NULL, -1, -1 );
3281 }
3282 //end this section addition - Victor Rachels
3283
3284 #ifdef NETWORK
3285 extern netgame_info Active_games[];
3286 extern int NumActiveNetgames;
3287
3288 void show_extra_netgame_info(int choice)
3289  {
3290         newmenu_item m[5];
3291    char mtext[5][50];
3292         int i,num=0;
3293
3294         if (choice>=NumActiveNetgames)
3295                 return;
3296         
3297    for (i=0;i<5;i++)
3298         {
3299          m[i].text=(char *)&mtext[i];
3300     m[i].type=NM_TYPE_TEXT;             
3301         }
3302
3303    sprintf (mtext[num],"Game: %s",Active_games[choice].game_name); num++;
3304    sprintf (mtext[num],"Mission: %s",Active_games[choice].mission_title); num++;
3305         sprintf (mtext[num],"Current Level: %d",Active_games[choice].levelnum); num++;
3306         sprintf (mtext[num],"Difficulty: %s",MENU_DIFFICULTY_TEXT(Active_games[choice].difficulty)); num++;
3307
3308         already_showing_info=1; 
3309         newmenu_dotiny2( NULL, "Netgame Information", num, m, NULL);
3310         already_showing_info=0; 
3311  }
3312
3313 #endif // NETWORK
3314
3315 /* Spiffy word wrap string formatting function */
3316
3317 void nm_wrap_text(char *dbuf, char *sbuf, int line_length)
3318 {
3319         int col;
3320         char *wordptr;
3321         char *tbuf;
3322
3323         tbuf = (char *)d_malloc(strlen(sbuf)+1);
3324         strcpy(tbuf, sbuf);
3325
3326         wordptr = strtok(tbuf, " ");
3327         if (!wordptr) return;
3328         col = 0;
3329         dbuf[0] = 0;
3330
3331         while (wordptr)
3332         {
3333                 col = col+strlen(wordptr)+1;
3334                 if (col >=line_length) {
3335                         col = 0;
3336                         sprintf(dbuf, "%s\n%s ", dbuf, wordptr);
3337                 }
3338                 else {
3339                         sprintf(dbuf, "%s%s ", dbuf, wordptr);
3340                 }
3341                 wordptr = strtok(NULL, " ");
3342         }
3343
3344         d_free(tbuf);
3345 }
3346                                 
3347         
3348
3349
3350