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