]> 4ch.mooo.com Git - 16.git/blobdiff - 16/ted5/MENU.C
ted5 added
[16.git] / 16 / ted5 / MENU.C
diff --git a/16/ted5/MENU.C b/16/ted5/MENU.C
new file mode 100755 (executable)
index 0000000..63f47a6
--- /dev/null
@@ -0,0 +1,1877 @@
+/////////////////////////////////////////////////////////////////
+//
+// Pull-Down Menu Interface
+// by John Romero (C) 1991 Id Software
+//
+/////////////////////////////////////////////////////////////////
+#include "ted5.h"
+#pragma hdrstop
+
+#define NUMFLASHES     10
+#define ALT            0x38
+#define CTRL           0x1d
+
+#define CGASIZE                0x4000
+#define EGA1SIZE       0x2000
+#define EGA2SIZE       0x9600
+#define EGA3SIZE       60000
+#define VGASIZE                64000
+
+void (*HookRoutine)(int x,int y);
+void (*ItemRoutine)(void);
+char MenuStr[20][80],tempstr[80];
+memptr Background[10];
+int WhichBack;
+struct { int savex,savey,savew,saveh;  } Back[10];
+MBarDef *MBarPtr;
+MInfoType MenuInfo[10];
+int ScreenWidth,OpenMenu,NumMenus,ItemOn,KeybdOn;
+
+void HandleOpenMenu(void (*UserRoutine)(void),int which);
+void HandleCloseMenu(void (*UserRoutine)(void));
+void HandleHighlight(void (*UserRoutine)(void));
+int  DetectMenu(int x,int y);
+void ChangeItem(int newitem);
+void ClearScreen(void);
+void RedrawDesktop(void);
+char *PassScancode(int sc);
+
+/////////////////////////////////////////////////////////////////
+//
+// Desktop Event Loop
+//
+/////////////////////////////////////////////////////////////////
+void DeskEventLoop(void (*UserRoutine)(void),void (*ConstantRoutine)(void))
+{
+ int buttonstatus=0,oldmenu,olditem;
+ enum clicks {upup,updown,downup,downdown};
+
+ if (KeybdOn)
+   {
+    HandleOpenMenu(UserRoutine,2);
+    ChangeItem(1);
+   }
+
+ MouseShow();
+ while(1)
+   {
+    int temp=MouseButton()&1,temp1=(MouseButton()>>1)&1;
+
+    sx=0;
+    sy=3;
+
+    if (!OpenMenu)
+      ConstantRoutine();
+    switch(buttonstatus=((buttonstatus<<1)|temp|temp1)&3)
+      {
+       case upup: break;
+       case updown: HandleOpenMenu(UserRoutine,0);
+                   break;
+       case downdown: HandleHighlight(UserRoutine);
+                     break;
+       case downup: HandleCloseMenu(UserRoutine);
+                   if (ItemOn && ItemRoutine)
+                     ItemRoutine();
+                   ItemOn=0;
+                   break;
+      }
+
+    if (bioskey(1))
+      {
+       char key=bioskey(1)>>8;
+       int nitems;
+
+       if (OpenMenu)
+        {
+         bioskey(0);
+
+         nitems=(MBarPtr+OpenMenu-1)->num_items;
+
+         switch(key)
+           {
+            case 0x48: if (OpenMenu)
+                         if (ItemOn)
+                           if (ItemOn==1)
+                             ChangeItem(nitems);
+                           else
+                             ChangeItem(ItemOn-1);
+                       break;
+            case 0x50: if (OpenMenu)
+                         if (ItemOn)
+                           if (ItemOn==nitems)
+                             ChangeItem(1);
+                           else
+                             ChangeItem(ItemOn+1);
+                       break;
+            case 0x1c: oldmenu=OpenMenu;
+                       olditem=ItemOn;
+                       HandleCloseMenu(UserRoutine);
+                       if (ItemOn)
+                         ItemRoutine();
+
+                       break;
+            case 0x4b: if (OpenMenu)
+                         {
+                          int newmenu;
+
+                          ItemOn=0;
+                          if (OpenMenu==1)
+                            newmenu=NumMenus;
+                          else
+                            newmenu=OpenMenu-1;
+
+                          HandleCloseMenu(UserRoutine);
+                          HandleOpenMenu(UserRoutine,newmenu);
+
+                          ChangeItem(1);
+                         }
+                       break;
+            case 0x4d: if (OpenMenu)
+                         {
+                          int newmenu;
+
+                          ItemOn=0;
+                          if (OpenMenu==NumMenus)
+                            newmenu=1;
+                          else
+                            newmenu=OpenMenu+1;
+
+                          HandleCloseMenu(UserRoutine);
+                          HandleOpenMenu(UserRoutine,newmenu);
+
+                          ChangeItem(1);
+                         }
+                       break;
+            case 0x01: if (!OpenMenu)
+                         {
+                          HandleOpenMenu(UserRoutine,oldmenu);
+                          ChangeItem(olditem);
+                         }
+                       break;
+           }
+        }
+       else
+        {
+         int i,j,numitems,run=0;
+         MenuDef *items;
+
+         for (i=0;i<NumMenus;i++)
+           {
+            numitems=(MBarPtr+i)->num_items;
+            items=(MBarPtr+i)->menu_def;
+
+            for (j=0;j<numitems;j++)
+              if ((items+j)->hotkey==key && (items+j)->hotkey)
+                {
+                 if (((items+j)->shiftflag) &&
+                     (!keydown[(items+j)->shiftflag]))
+                   continue;
+
+                 ItemRoutine=(items+j)->routine;
+                 ItemRoutine();
+                 run=1;
+                 break;
+                }
+            if (run)
+              {
+               if (bioskey(1))
+                 bioskey(0);
+               break;
+              }
+           }
+         if (!run)
+           UserRoutine();
+        }
+      }
+   }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// See if a menu was opened
+//
+/////////////////////////////////////////////////////////////////
+void HandleOpenMenu(void (*UserRoutine)(void),int which)
+{
+ int x,y,loop,flag,tempx,tempw,maxw,loopsize;
+ MenuDef *items;
+
+ if (!which)
+   {
+    MouseCoords(&x,&y);
+    if (y>8 && !OpenMenu)
+      {
+       UserRoutine();
+       return;
+      }
+
+    flag=DetectMenu(x,y);
+    if (!flag) return;
+   }
+ else
+   flag=which;
+
+
+ tempx=MenuInfo[flag-1].menux;
+ tempw=MenuInfo[flag-1].menuwidth;
+ items=(MBarPtr+flag-1)->menu_def;
+
+ sx=tempx+1;
+ sy=0;
+ maxw=0;
+
+ MouseHide();
+
+
+ //
+ // BUILD MENU STRINGS
+ //
+ loopsize=(MBarPtr+flag-1)->num_items;
+
+ for (loop=0;loop<loopsize;loop++)
+   {
+    int len;
+
+    memset(MenuStr[loop],0,80);
+
+    MenuStr[loop][0]=4;        // leftedge
+    strcat(MenuStr[loop],(items+loop)->item_name);
+
+    len=strlen(MenuStr[loop]);
+    memset(&MenuStr[loop][len],' ',tempw-len+1);
+
+    switch((items+loop)->shiftflag)
+      {
+       case ALT: strcat(MenuStr[loop]," ALT-"); break;
+       case CTRL:strcat(MenuStr[loop],"CTRL-");
+      }
+
+    strcat(MenuStr[loop],PassScancode((items+loop)->hotkey));
+
+    len=strlen(MenuStr[loop]);
+    if (len>maxw)
+      maxw=len;
+   }
+
+ if (tempx+maxw>ScreenWidth)
+   tempx=ScreenWidth-1-maxw;
+ SaveBackground(tempx*8,0,(maxw+1)*8,(MBarPtr+flag-1)->num_items*8+16);
+
+ //
+ // PRINT MENU STRINGS
+ //
+ xormask=0xffff;
+ print((MBarPtr+flag-1)->menu_name);
+ xormask=0;
+
+ for (loop=0;loop<loopsize;loop++)
+   {
+    int len;
+
+    len=strlen(MenuStr[loop]);
+    if (len<maxw)
+      memset(&MenuStr[loop][len],' ',maxw-len);
+    strcat(MenuStr[loop],"\x5");
+
+    sx=tempx;
+    sy=loop+1;
+    print(MenuStr[loop]);
+   }
+
+  sx=tempx;
+  sy=loopsize+1;
+  print("\x6");
+  bar(sx,sy,sx+maxw-2,sy,7);
+  sx=tempx+maxw;
+  print("\x8");
+
+ MouseShow();
+ OpenMenu=flag;
+ ItemOn=0;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Detect whether a menu is clicked on or not
+//
+/////////////////////////////////////////////////////////////////
+int DetectMenu(int x,int y)
+{
+ int flag,loop;
+
+ if (y>10)
+   return 0;
+
+ flag=0;
+ for (loop=0;loop<NumMenus;loop++)
+   if (x/8>=MenuInfo[loop].menux && x/8<MenuInfo[loop].menux+MenuInfo[loop].menunamelen)
+     {
+      flag=loop+1;
+      break;
+     }
+ return flag;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Highlight & De-highlight items
+//
+/////////////////////////////////////////////////////////////////
+void HandleHighlight(void (*UserRoutine)(void))
+{
+ int x,y,nitems,tempx,tempw,tempy,opmen;
+
+ if (!OpenMenu)
+   {
+    UserRoutine();
+    return;
+   }
+
+ MouseCoords(&x,&y);
+ nitems=(MBarPtr+OpenMenu-1)->num_items;
+ tempx=MenuInfo[OpenMenu-1].menux;
+ tempw=strlen(MenuStr[0])-5;
+ if (tempx+tempw+5>ScreenWidth)
+   tempx=ScreenWidth-tempw-5;
+
+ opmen=DetectMenu(x,y);
+ if (opmen && opmen!=OpenMenu)
+   {
+    OpenMenu=0;
+    RestoreBackground();
+    HandleOpenMenu(UserRoutine,0);
+    return;
+   }
+
+ //
+ // IS USER IN A MENU?
+ //
+
+ if (x/8>tempx && x/8<tempx+tempw+4 && y>8 && y<(nitems+1)*8)
+   {
+    if (y/8==ItemOn)
+      return;  // EXIT IF ON SAME ITEM
+
+    //
+    // IF AN ITEM IS CURRENTLY SELECTED, DEHIGHLIGHT IT
+    // AND HIGHLIGHT A NEW ITEM
+    //
+
+    ChangeItem(y/8);
+   }
+ else
+   //
+   // USER MOVED POINTER OUTSIDE OF MENU; DEHIGHLIGHT ITEM
+   //
+
+   if (ItemOn)
+     {
+      MouseHide();
+
+      sx=tempx;
+      sy=ItemOn;
+      print(MenuStr[ItemOn-1]);
+
+      ItemOn=0;
+      MouseShow();
+     }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Set new item highlighted
+//
+/////////////////////////////////////////////////////////////////
+void ChangeItem(int newitem)
+{
+ int tempx,tempw;
+ MenuDef *items;
+ char tempstr[80]="";
+
+ tempx=MenuInfo[OpenMenu-1].menux;
+ if (tempx+strlen(MenuStr[0])>ScreenWidth)
+   tempx=ScreenWidth-strlen(MenuStr[0]);
+
+ MouseHide();
+ if (ItemOn)
+   {
+    sx=tempx;
+    sy=ItemOn;
+    print(MenuStr[ItemOn-1]);
+   }
+
+ xormask=0xffff;
+ ItemOn=newitem;
+ strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
+ sx=tempx+1;
+ sy=ItemOn;
+ print(tempstr);
+ xormask=0;
+
+ MouseShow();
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// See if a menu was closed
+//
+/////////////////////////////////////////////////////////////////
+void HandleCloseMenu(void (*UserRoutine)(void))
+{
+ MenuDef *items;
+ int loop,tempx;
+ char tempstr[80]="";
+
+ if (!OpenMenu)
+   {
+    UserRoutine();
+    return;
+   }
+
+ if (ItemOn)
+   {
+    items=(MBarPtr+OpenMenu-1)->menu_def;
+    tempx=MenuInfo[OpenMenu-1].menux;
+    if (tempx+strlen(MenuStr[0])>ScreenWidth)
+      tempx=ScreenWidth-strlen(MenuStr[0]);
+
+    for (loop=0;loop<NUMFLASHES;loop++)
+      {
+       xormask^=0xffff;
+       MouseHide();
+
+       strncpy(tempstr,&MenuStr[ItemOn-1][1],strlen(MenuStr[ItemOn-1])-2);
+       sx=tempx+1;
+       sy=ItemOn;
+       print(tempstr);
+
+       MouseShow();
+       WaitVBL(3);
+      }
+    xormask=0;
+    ItemRoutine=(items+ItemOn-1)->routine;
+   }
+
+ OpenMenu=0;
+ RestoreBackground();
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Save the background
+//
+/////////////////////////////////////////////////////////////////
+void SaveBackground(int x,int y,int w,int h)
+{
+ long size;
+ unsigned loc,loop,loop1,seg,planelen;
+
+ Back[WhichBack].savex=x;
+ Back[WhichBack].savey=y;
+ Back[WhichBack].savew=w;
+ Back[WhichBack].saveh=h;
+
+ MouseHide();
+ switch (videomode)
+   {
+    case CGA:
+      MMAllocate(&Background[WhichBack],(w/4)*h);
+
+      for(loop=y;loop<y+h;loop++)
+       {
+        loc=(loop/2)*80+0x2000*(loop&1)+x/4;
+        movedata(0xb800,loc,(unsigned)Background[WhichBack],(loop-y)*(w/4),w/4);
+       }
+      break;
+
+    case EGA2:
+    case EGA1:
+      {
+       unsigned tempw=w/8,tempx=x/8,psize;
+
+       planelen=tempw*h;
+       MMAllocate(&Background[WhichBack],5L*planelen);
+       outport(GCindex,GCmode);
+       for (loop=0;loop<4;loop++)
+        {
+         psize=loop*planelen;
+
+         outport(GCindex,GCreadmap | loop*256);
+         for (loop1=y;loop1<y+h;loop1++)
+           movedata(0xa000,((unsigned)loop1*ScreenWidth)+tempx,
+             ((unsigned)Background[WhichBack])+(psize/16),
+             (psize&15)+((loop1-y)*tempw),tempw);
+        }
+      }
+      break;
+
+    case VGA:
+      MMAllocate(&Background[WhichBack],(long)w*h);
+      for(loop=y;loop<y+h;loop++)
+       movedata(0xa000,loop*320+x,(unsigned)Background[WhichBack],(loop-y)*w,w);
+   }
+ MouseShow();
+ if (WhichBack<10)
+   WhichBack++;
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Restore the background
+//
+/////////////////////////////////////////////////////////////////
+void setfarmem(char huge *mem,unsigned char val,unsigned len)
+{
+ int i;
+ for (i=0;i<len;i++)
+   *(mem+i)=val;
+}
+
+void RestoreBackground(void)
+{
+ long size;
+ unsigned loc,loop1,x,y,w,h,loop,planelen;
+
+ if (!Back[WhichBack-1].savex &&
+     !Back[WhichBack-1].savey &&
+     !Back[WhichBack-1].savew &&
+     !Back[WhichBack-1].saveh)
+   Quit("Can't RestoreBackground with no information!");
+
+ x=Back[WhichBack-1].savex;
+ y=Back[WhichBack-1].savey;
+ w=Back[WhichBack-1].savew;
+ h=Back[WhichBack-1].saveh;
+
+ MouseHide();
+ switch (videomode)
+   {
+    case CGA:
+      for(loop=y;loop<y+h;loop++)
+       {
+        loc=(loop/2)*80+0x2000*(loop&1)+x/4;
+        movedata((unsigned)Background[WhichBack-1],(loop-y)*(w/4),0xb800,loc,w/4);
+       }
+      break;
+
+    case EGA2:
+    case EGA1:
+      planelen=(w/8)*h;
+      outport(GCindex,GCmode);
+      for (loop=0;loop<4;loop++)
+       {
+        outport(SCindex,SCmapmask | (1<<loop)*256);
+        for (loop1=y;loop1<y+h;loop1++)
+          movedata(((unsigned)Background[WhichBack-1])+((loop*planelen)/16),
+            ((loop*planelen)&15)+(loop1-y)*(w/8),
+            0xa000,loop1*ScreenWidth+x/8,w/8);
+       }
+      break;
+
+    case VGA:
+      for(loop=y;loop<y+h;loop++)
+       movedata((unsigned)Background[WhichBack-1],(loop-y)*w,0xa000,loop*320+x,w);
+   }
+
+ MMFreePtr(&Background[WhichBack-1]);
+
+ MouseShow();
+
+ WhichBack--;
+ Back[WhichBack].savex=0;
+ Back[WhichBack].savey=0;
+ Back[WhichBack].savew=0;
+ Back[WhichBack].saveh=0;
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Draw the Desktop
+//
+/////////////////////////////////////////////////////////////////
+void RedrawDesktop(void)
+{
+ int flag,count,i;
+
+ ClearScreen();
+
+ sx=sy=0;
+ bar(0,0,ScreenWidth-1,0,' ');
+
+ flag=0;
+ count=0;
+ NumMenus=0;
+ while((MBarPtr+count)->num_items && !flag)
+   {
+    int len,max_width,loop;
+    MenuDef *the_item;
+    char string[80];
+
+    //
+    // First, determine xcoord & namewidth & print
+    //
+
+    strcpy(string,(MBarPtr+count)->menu_name);
+    len=strlen(string);
+    MenuInfo[NumMenus].menux=sx;
+    MenuInfo[NumMenus].menunamelen=len+2;
+    if (len+sx>ScreenWidth-1)
+      {
+       string[ScreenWidth-1-sx]=0;
+       MenuInfo[NumMenus].menunamelen=ScreenWidth-1-sx;
+       MenuInfo[NumMenus].menux=ScreenWidth-MenuInfo[NumMenus].menunamelen;
+       flag++;
+      }
+
+    drawchar(sx++,sy,' ');
+    print(string);
+    drawchar(sx++,sy,' ');
+
+    //
+    // Now, figure out length of widest item
+    //
+
+    max_width=0;
+    the_item=(MBarPtr+count)->menu_def;
+
+    for (loop=0;loop<(MBarPtr+count)->num_items;loop++)
+      {
+       int len;
+
+       len=strlen((the_item+loop)->item_name);
+       if (len>max_width)
+        max_width=len;
+      }
+
+    MenuInfo[NumMenus].menuwidth=max_width+1;
+
+    count++;
+    NumMenus++;
+   }
+
+ //
+ // clear bottom line of menubar
+ //
+ switch(videomode)
+ {
+  case CGA:
+    {
+     unsigned huge *CGAmem=MK_FP(0xb800,240+0x2000);
+     for(i=0;i<40;i++)
+       *(CGAmem+i)=0;
+    }
+    break;
+  case EGA1:
+  case EGA2:
+    {
+    char huge *EGAmem=MK_FP(0xa000,0);
+    outport(GCindex,GCmode);
+    outport(SCindex,0x0f00 | SCmapmask);
+    for (i=0;i<ScreenWidth;i++)
+      *(EGAmem+7*ScreenWidth+i)=0;
+    }
+    break;
+  case VGA:
+    {
+    unsigned huge *VGAmem=MK_FP(0xa000,320*7);
+    for (i=0;i<160;i++)
+      *(VGAmem+i)=0;
+    }
+ }
+}
+
+
+
+/////////////////////////////////////////////////////////////////
+//
+// Init Desktop
+//
+/////////////////////////////////////////////////////////////////
+void InitDesktop(MBarDef *menubar,int initmouse)
+{
+ switch(videomode)
+   {
+    case CGA: ScreenWidth=40; break;
+    case EGA1: ScreenWidth=40; break;
+    case EGA2: ScreenWidth=80; break;
+    case VGA: ScreenWidth=40;
+   }
+
+ MBarPtr=menubar;
+ RedrawDesktop();
+ if (initmouse)
+   MouseInit();
+ OpenMenu=KeybdOn=0;
+ if (!MouseStatus)
+   KeybdOn=1;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Clear the current screen
+//
+////////////////////////////////////////////////////////////////////
+void ClearScreen(void)
+{
+ unsigned size,segment;
+
+ segment=0xa000;
+ switch(videomode)
+   {
+    case CGA: segment=0xb800; size=CGASIZE/2; break;
+    case EGA1: size=EGA1SIZE/2; break;
+    case EGA2: size=EGA2SIZE/2; break;
+    case VGA: size=VGASIZE/2;
+   }
+
+ MouseHide();
+
+ asm   push    di
+ asm   push    es
+ asm   xor     di,di
+ asm   mov     ax,segment
+ asm   mov     es,ax
+ asm   mov     cx,size
+ asm   cld
+ asm   xor     ax,ax
+ asm   rep stosw
+ asm   pop     es
+ asm   pop     di
+
+ MouseShow();
+}
+
+
+
+/////////////////////////////////////////////////////////
+//
+// print a representation of the scan code key
+//
+/////////////////////////////////////////////////////////
+char *PassScancode(int sc)
+{
+ char smallstr[2];
+ char static chartable[128] =
+ {' ',' ','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
+  'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
+  'D','F','G','H','J','K','L',';','"',' ',' ',' ','Z','X','C','V',
+  'B','N','M',',','.','/','?',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ', 15,' ','-', 14,'5', 31,'+',' ',
+   19,' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
+  ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' '};
+
+ sc = sc & 0x7f;
+
+ if (sc==1)
+   strcpy(tempstr,"ESC");
+ else if (sc==0x48)
+   strcpy(tempstr,"\xb");
+ else if (sc==0x50)
+   strcpy(tempstr,"\xc");
+ else if (sc==0xe)
+   strcpy(tempstr,"BKSP");
+ else if (sc==0xf)
+   strcpy(tempstr,"TAB");
+ else if (sc==0x1d)
+   strcpy(tempstr,"CTRL");
+ else if (sc==0x2A)
+   strcpy(tempstr,"LSHIFT");
+ else if (sc==0x39)
+   strcpy(tempstr,"SPACE");
+ else if (sc==0x3A)
+   strcpy(tempstr,"CAPSLK");
+ else if (sc>=0x3b && sc<=0x44)
+ {
+   char str[3];
+   strcpy(tempstr,"F");
+   itoa (sc-0x3a,str,10);
+   strcat(tempstr,str);
+ }
+ else if (sc==0x57)
+   strcpy(tempstr,"F11");
+ else if (sc==0x59)
+   strcpy(tempstr,"F12");
+ else if (sc==0x46)
+   strcpy(tempstr,"SCRLLK");
+ else if (sc==0x1c)
+   strcpy(tempstr,"ENTER");
+ else if (sc==0x36)
+   strcpy(tempstr,"RSHIFT");
+ else if (sc==0x37)
+   strcpy(tempstr,"PRTSC");
+ else if (sc==0x38)
+   strcpy(tempstr,"ALT");
+ else if (sc==0x47)
+   strcpy(tempstr,"HOME");
+ else if (sc==0x49)
+   strcpy(tempstr,"PGUP");
+ else if (sc==0x4f)
+   strcpy(tempstr,"END");
+ else if (sc==0x51)
+   strcpy(tempstr,"PGDN");
+ else if (sc==0x52)
+   strcpy(tempstr,"INS");
+ else if (sc==0x53)
+   strcpy(tempstr,"DEL");
+ else if (sc==0x45)
+   strcpy(tempstr,"NUMLK");
+ else
+   {
+    smallstr[0]=chartable[sc];
+    smallstr[1]=0;
+    strcpy(tempstr,smallstr);
+   }
+
+ return tempstr;
+}
+
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+//
+//
+// DIALOG MANAGER CODE
+//
+//
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////
+//
+// Dialog Boxes!
+//
+/////////////////////////////////////////////////////////
+int DoDialog(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ MouseHide();
+ SaveBackground((screencenterx-TheDialog->width/2)*8,
+   (screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
+   (TheDialog->height+2)*8);
+
+ xormask=0;
+ centerwindow(TheDialog->width,TheDialog->height);
+ ox=sx;
+ oy=sy;
+ print(TheDialog->text);
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=sx=ox+(TheButton+i)->xoff;
+    yc[i]=sy=oy+(TheButton+i)->yoff;
+    xx=sx-1;
+    yy=sy-1;
+    print((TheButton+i)->text);
+    wid[i]=strlen((TheButton+i)->text);
+
+    if ((TheButton+i)->border)
+      DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
+   }
+
+ if (TheDialog->hook)
+   {
+    HookRoutine=(void (*)(int x,int y))TheDialog->hook;
+    HookRoutine(ox,oy);
+   }
+ MouseShow();
+
+ clearkeys();
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+
+ RestoreBackground();
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just CHECK a Dialog Box's BUTTONS
+//
+/////////////////////////////////////////////////////////
+int CheckButtons(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ ox=screencenterx-TheDialog->width/2+1;
+ oy=screencentery-TheDialog->height/2+1;
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=ox+(TheButton+i)->xoff;
+    yc[i]=oy+(TheButton+i)->yoff;
+    wid[i]=strlen((TheButton+i)->text);
+   }
+
+
+ clearkeys();
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+ clearkeys();
+
+ if (Clicked)
+ {
+  sx=xc[Clicked-1];
+  sy=yc[Clicked-1];
+  MouseHide();
+  print((TheButton+Clicked-1)->text);
+  MouseShow();
+ }
+
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just CHECK a Dialog Box's BUTTONS
+// BUT!...RETURN IF MOUSE BUTTON IS PRESSED OUTSIDE DIALOG BUTTON!
+//
+/////////////////////////////////////////////////////////
+int CheckButtonsRet(DialogDef *TheDialog)
+{
+ btype *TheButton;
+ int i,ox,oy,Float=0,Released=0,Clicked=0,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ ox=screencenterx-TheDialog->width/2+1;
+ oy=screencentery-TheDialog->height/2+1;
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=ox+(TheButton+i)->xoff;
+    yc[i]=oy+(TheButton+i)->yoff;
+    wid[i]=strlen((TheButton+i)->text);
+   }
+
+ do
+ {
+  char temp;
+  int mx,my;
+
+  temp=((temp<<1)|(MouseButton()&1))&3;
+  if (MouseButton()&2)
+    return -1;
+
+  MouseCoords(&mx,&my);
+  mx/=8;
+  my/=8;
+
+  //
+  // ENTER press
+  //
+  if (keydown[0x1c])
+    for(i=0;i<TheDialog->numbuttons;i++)
+      {
+       TheButton=TheDialog->buttons;
+       if ((TheButton+i)->border==2)
+        {
+         Clicked=i+1;
+         Released=1;
+         temp=Float=0;
+         while(keydown[0x1c]);
+         clearkeys();
+        }
+      }
+
+  //
+  // ESC press
+  //
+  if (keydown[1])
+    {
+     temp=Float=Clicked=0;
+     Released=1;
+     while(keydown[1]);
+    }
+
+  //
+  // arrows or PgUp/PgDn/Home/End
+  //
+  if (keydown[0x48] || keydown[0x50] || keydown[0x4b] || keydown[0x4d] ||
+      keydown[0x49] || keydown[0x51] || keydown[0x47] || keydown[0x4f] ||
+      keydown[0x39] || keydown[0x2e])
+    return -1;
+
+  switch(temp)
+  {
+   case 0: // upup (no press)
+     break;
+   case 3: // downdown (held down)
+     if (!Float && Clicked && (mx<xc[Clicked-1] ||
+        mx>xc[Clicked-1]+wid[Clicked-1]-1 || my!=yc[Clicked-1]))
+       {
+       xormask=0;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=1;
+       Float=1;
+       }
+     else
+     if (Float && mx>=xc[Clicked-1] &&
+        mx<xc[Clicked-1]+wid[Clicked-1] && my==yc[Clicked-1])
+       {
+       xormask=1;
+       sx=xc[Clicked-1];
+       sy=yc[Clicked-1];
+       MouseHide();
+       print((TheButton+Clicked-1)->text);
+       MouseShow();
+       xormask=0;
+       Float=0;
+       }
+     break;
+   case 1: // updown (press)
+     for (i=0;i<TheDialog->numbuttons;i++)
+       {
+       if (mx>=xc[i] && mx<xc[i]+wid[i] && my==yc[i])
+         {
+          Clicked=i+1;
+          xormask=1;
+          sx=xc[i];
+          sy=yc[i];
+          MouseHide();
+          print((TheButton+i)->text);
+          MouseShow();
+          xormask=0;
+          break;
+         }
+       }
+
+     if (!Clicked)     // MOD TO ORIGINAL CHECKBUTTONS
+       return -1;
+
+     break;
+   case 2: // downup (release)
+     if (Clicked && !Float)
+       Released++;
+  }
+ } while (!Released);
+ clearkeys();
+ return Clicked;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Just DRAW a Dialog Box
+//
+/////////////////////////////////////////////////////////
+void DrawDialog(DialogDef *TheDialog,int saveback)
+{
+ btype *TheButton;
+ int i,ox,oy,xc[30],yc[30],wid[30];
+
+ for (i=0;i<30;i++)
+   xc[i]=yc[i]=wid[i]=0;
+
+ MouseHide();
+ if (saveback)
+   SaveBackground((screencenterx-TheDialog->width/2)*8,
+     (screencentery-TheDialog->height/2)*8,(TheDialog->width+2)*8,
+     (TheDialog->height+2)*8);
+
+ xormask=0;
+ centerwindow(TheDialog->width,TheDialog->height);
+ ox=sx;
+ oy=sy;
+ print(TheDialog->text);
+ for (i=0;i<TheDialog->numbuttons;i++)
+   {
+    int xx,yy,j;
+
+    TheButton=TheDialog->buttons;
+
+    xc[i]=sx=ox+(TheButton+i)->xoff;
+    yc[i]=sy=oy+(TheButton+i)->yoff;
+    xx=sx-1;
+    yy=sy-1;
+    print((TheButton+i)->text);
+    wid[i]=strlen((TheButton+i)->text);
+
+    if ((TheButton+i)->border)
+      DrawBorder(xx,yy,wid[i]+1,2,(TheButton+i)->border);
+   }
+
+ if (TheDialog->hook)
+   {
+    HookRoutine=(void (*)(int x,int y))TheDialog->hook;
+    HookRoutine(ox,oy);
+   }
+
+ MouseShow();
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Error Dialog Box
+//
+/////////////////////////////////////////////////////////
+char errstring[200],bstring[20];
+btype ERROKb={bstring,0,0,2};
+DialogDef ERRR={errstring,0,0,1,&ERROKb,NULL};
+
+void ErrDialog(char *string,char *bstr)
+{
+ int maxw=0,width=0,height=1,i;
+
+ if (strlen(string)>200)
+   Quit("Programmer Error: ErrDialog string is too long!");
+
+ for (i=0;i<strlen(string);i++)
+   {
+    width++;
+    if (width>maxw)
+      maxw=width;
+
+    if (string[i]=='\n')
+      {
+       height++;
+       width=0;
+      }
+   }
+ height+=3;    // add for button!
+
+ if (strlen(bstr)>maxw)
+   Quit("Programmer Error: ErrDialog BUTTONstring is longer than dialog!");
+
+ strcpy(bstring,bstr);
+ strcpy(errstring,string);
+ ERRR.width=maxw;
+ ERRR.height=height;
+ ERRR.numbuttons=1;
+ if (!bstr[0])
+   {
+    ERRR.numbuttons=0;
+    ERRR.height-=3;
+   }
+
+ ERROKb.xoff=(maxw/2)-(strlen(bstr)/2);
+ ERROKb.yoff=height-2;
+
+ if (bstr[0])
+   DoDialog(&ERRR);
+ else
+   DrawDialog(&ERRR,1);
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Draw a border
+//
+/////////////////////////////////////////////////////////
+void DrawBorder(int x,int y,int w,int h,int b)
+{
+ int xx=x,yy=y,j;
+
+ if (b==2)
+   {
+    drawchar(xx,yy,15);
+    drawchar(xx+w,yy,17);
+    drawchar(xx,yy+h,20);
+    drawchar(xx+w,yy+h,22);
+
+    for (j=yy+1;j<yy+h;j++)
+      {
+       drawchar(xx,j,18);
+       drawchar(xx+w,j,19);
+      }
+    for (j=xx+1;j<xx+w;j++)
+      {
+       drawchar(j,yy,16);
+       drawchar(j,yy+h,21);
+      }
+   }
+
+ if (b==1)
+   {
+    drawchar(xx,yy,23);
+    drawchar(xx+w,yy,25);
+    drawchar(xx,yy+h,28);
+    drawchar(xx+w,yy+h,30);
+
+    for (j=yy+1;j<yy+h;j++)
+      {
+       drawchar(xx,j,26);
+       drawchar(xx+w,j,27);
+      }
+    for (j=xx+1;j<xx+w;j++)
+      {
+       drawchar(j,yy,24);
+       drawchar(j,yy+h,29);
+      }
+   }
+
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Get the XY coords of a dialog's button
+//
+/////////////////////////////////////////////////////////
+void GetButtonXY(DialogDef *TheDialog,int button,unsigned *x,unsigned *y)
+{
+ btype *TheButton;
+
+ TheButton=TheDialog->buttons;
+
+ *x=(TheButton+button)->xoff+screencenterx-TheDialog->width/2+1;
+ *y=(TheButton+button)->yoff+screencentery-TheDialog->height/2+1;
+}
+
+
+/////////////////////////////////////////////////////////
+//
+// Get the XY coords of a dialog
+//
+/////////////////////////////////////////////////////////
+void GetDialogXY(DialogDef *TheDialog,unsigned *x,unsigned *y)
+{
+ *x=screencenterx-TheDialog->width/2+1;
+ *y=screencentery-TheDialog->height/2+1;
+}
+
+
+////////////////////////////////////////////////////
+//
+// Allow user to select a list item (like the menus)
+//
+////////////////////////////////////////////////////
+int CheckList(int x,int y,int w,int h,void (*oncode)(),void (*offcode)(),int blink)
+{
+ enum {upup,updown,downup,downdown} clicks;
+ static char bpress=0;
+ unsigned mx,my,i;
+ int high=-1;
+
+
+ while(1)
+ {
+  MouseCoords(&(int)mx,&(int)my);
+  mx/=8;
+  my/=8;
+  bpress=((bpress<<1)|(MouseButton()&1))&3;
+  switch(bpress)
+  {
+   case upup:
+     return -1;
+   case updown:
+     if (mx>=x && mx<x+w && my>=y && my<y+h)
+       {
+       high=my-y;
+       MouseHide();
+       oncode(x,my,high);
+       MouseShow();
+       }
+     else
+       return -1;
+
+     break;
+   case downup:
+     if (high!=-1)
+       {
+       if (blink)
+         for(i=0;i<5;i++)
+         {
+          MouseHide();
+          oncode(x,my,high);
+          MouseShow();
+          WaitVBL(3);
+
+          MouseHide();
+          offcode(x,my,high);
+          WaitVBL(3);
+          MouseShow();
+         }
+       }
+     return high;
+
+   case downdown:
+     if (mx>=x && mx<x+w && my>=y && my<y+h)
+       {
+       if (my-y != high && high!=-1)
+         {
+          MouseHide();
+          offcode(x,high+y,high);
+          MouseShow();
+
+         }
+
+       if (my-y != high)
+         {
+          high=my-y;
+          MouseHide();
+          oncode(x,y+high,high);
+          MouseShow();
+         }
+       }
+     else
+       {
+       if (high!=-1)
+         {
+          MouseHide();
+          offcode(x,high+y,high);
+          MouseShow();
+         }
+       high=-1;
+       return -1;
+       }
+  }
+ }
+}
+
+
+/////////////////////////////////////////////////
+//
+// Message dialog
+// Returns: -1=ESC, 0=No, 1=Yes
+//
+/////////////////////////////////////////////////
+char MessStr[200];
+btype MessOKb[]={{" No ",0,0,1},{" Yes ",0,0,2}};
+DialogDef Mess={MessStr,0,0,2,&MessOKb[0],NULL};
+
+int Message(char *string)
+{
+ int maxw=0,width=0,height=1,i;
+
+ if (strlen(string)>200)
+   Quit("Programmer Error: Message string is too long!");
+
+ for (i=0;i<strlen(string);i++)
+   {
+    width++;
+    if (width>maxw)
+      maxw=width;
+
+    if (string[i]=='\n')
+      {
+       height++;
+       width=0;
+      }
+   }
+ height+=3;    // add for buttons!
+
+ strcpy(MessStr,string);
+ Mess.width=maxw;
+ Mess.height=height;
+
+ MessOKb[1].xoff=(maxw/4)-(strlen(MessOKb[0].text)/2);
+ MessOKb[1].yoff=height-2;
+ MessOKb[0].xoff=(maxw/4)*3-(strlen(MessOKb[1].text)/2);
+ MessOKb[0].yoff=height-2;
+
+ return DoDialog(&Mess);
+}
+
+
+/////////////////////////////////////////////////
+//
+// GetPath dialog
+// *path is returned
+// (exit:0 if OK,-1 if Not Successful,-2 if Canceled)
+//
+/////////////////////////////////////////////////
+#define LISTX  1
+#define LISTY  3
+
+char dstr[80];
+btype GPb={"Cancel",15,3,1};
+DialogDef GPd={dstr,22,14,1,&GPb,NULL};
+char NameList[MAXFDNAMES][13];
+int base;
+struct ffblk f;
+
+int GetPath(char *string,char *filter,char *path)
+{
+ char pname[64];
+ unsigned int numnames=0,max,dx,dy,redraw,exit;
+ int select,zset,i;
+
+
+ strcpy(pname,filter);
+ for (zset=0,i=strlen(pname);i>=0;i--)
+   if (pname[i]=='\\')
+     {
+      pname[i+1]=0;
+      zset++;
+      break;
+     }
+ if (!zset)
+   pname[0]=0;
+
+ strcpy(dstr,string);
+ //
+ // FIRST, GET THE NAMES FROM THE DIRECTORY
+ //
+ if (findfirst(filter,&f,FA_ARCH))
+   return -1;
+ strcpy(NameList[numnames++],f.ff_name);
+
+ while(!findnext(&f) && numnames<MAXFDNAMES)
+   strcpy(NameList[numnames++],f.ff_name);
+
+ DrawDialog(&GPd,1);
+ MouseHide();
+ GetDialogXY(&GPd,&dx,&dy);
+ DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
+ MouseShow();
+
+ base=exit=0;
+
+ //
+ // THIS LOOP DRAWS THE DIALOG
+ //
+ do
+ {
+  redraw=0;
+  MouseHide();
+  max=10;
+  if (numnames<10)
+    max=numnames;
+  for (i=0;i<max;i++)
+    {
+     bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
+     FDoff(dx+LISTX,dy+LISTY+i,i);
+    }
+  MouseShow();
+
+  //
+  // THIS LOOP CHECKS INPUT
+  //
+  do
+  {
+   select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
+   if (select>=0)
+     {
+      redraw=exit=1;
+      continue;
+     }
+
+   GetButtonXY(&GPd,0,&sx,&sy);
+   select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
+   if (!select || keydown[1])
+     {
+      RestoreBackground();
+      while(keydown[1]);
+      clearkeys();
+      return -2;
+     }
+
+   //
+   // CHECK ARROWS & PGUP/DN
+   //
+   if (keydown[0x48] && base)
+     {
+      base--;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x48]);
+     }
+   else
+   if (keydown[0x50] && base+10<numnames)
+     {
+      base++;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x50]);
+     }
+   else
+   if (keydown[0x49])
+     {
+      base-=10;
+      if (base<0)
+       base=0;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x49]);
+     }
+   else
+   if (keydown[0x51])
+     {
+      base+=10;
+      if (base+10>numnames)
+       base=numnames-10;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x51]);
+     }
+
+  } while(!redraw);
+ } while(!exit);
+
+ //
+ // RETURN PATHNAME
+ //
+ RestoreBackground();
+ strcpy(path,pname);
+ strcat(path,NameList[select+base]);
+ findfirst(path,&f,FA_ARCH);
+ return 0;
+}
+
+
+static void FDon(int x,int y,int w)
+{
+ xormask=1;
+ FDoff(x,y,w);
+ xormask=0;
+}
+
+static void FDoff(int x,int y,int w)
+{
+ MouseHide();
+ sx=x;
+ sy=y;
+ print(NameList[w+base]);
+ MouseShow();
+}
+
+
+static void CancelOn(int x,int y)
+{
+ xormask=1;
+ CancelOff(x,y);
+ xormask=0;
+}
+
+static void CancelOff(int x,int y)
+{
+ MouseHide();
+ sx=x;
+ sy=y;
+ print("Cancel");
+ MouseShow();
+}
+
+
+/////////////////////////////////////////////////
+//
+// GetList dialog
+// Fill "NameList[?][13]" with your strings
+// (exit:>=0 is selection,-1 if Not Successful,-2 if Canceled)
+//
+/////////////////////////////////////////////////
+int GetList(char *string,int numnames)
+{
+ unsigned int max,dx,dy,redraw,exit,i;
+ int select;
+
+
+ strcpy(dstr,string);
+
+ DrawDialog(&GPd,1);
+ MouseHide();
+ GetDialogXY(&GPd,&dx,&dy);
+ DrawBorder(dx+LISTX-1,dy+LISTY-1,13,11,1);
+ MouseShow();
+
+ base=exit=0;
+
+ //
+ // THIS LOOP DRAWS THE DIALOG
+ //
+ do
+ {
+  redraw=0;
+  MouseHide();
+  max=10;
+  if (numnames<10)
+    max=numnames;
+  for (i=0;i<max;i++)
+    {
+     bar(dx+LISTX,dy+LISTY+i,dx+LISTX+11,dy+LISTY+i,' ');
+     FDoff(dx+LISTX,dy+LISTY+i,i);
+    }
+  MouseShow();
+
+  //
+  // THIS LOOP CHECKS INPUT
+  //
+  do
+  {
+   select=CheckList(dx+LISTX,dy+LISTY,12,max,FDon,FDoff,0);
+   if (select>=0)
+     {
+      redraw=exit=1;
+      continue;
+     }
+
+   GetButtonXY(&GPd,0,&sx,&sy);
+   select=CheckList(sx,sy,strlen(GPb.text),1,CancelOn,CancelOff,0);
+   if (!select || keydown[1])
+     {
+      RestoreBackground();
+      while(keydown[1]);
+      clearkeys();
+      return -2;
+     }
+
+   //
+   // CHECK ARROWS & PGUP/DN
+   //
+   if (keydown[0x48] && base)
+     {
+      base--;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x48]);
+     }
+   else
+   if (keydown[0x50] && base+10<numnames)
+     {
+      base++;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x50]);
+     }
+   else
+   if (keydown[0x49])
+     {
+      base-=10;
+      if (base<0)
+       base=0;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x49]);
+     }
+   else
+   if (keydown[0x51])
+     {
+      base+=10;
+      if (base+10>numnames)
+       base=numnames-10;
+      redraw=1;
+      if (!keydown[0x1d])
+       while(keydown[0x51]);
+     }
+
+  } while(!redraw);
+ } while(!exit);
+
+ //
+ // RETURN SELECTION
+ //
+ RestoreBackground();
+ return select+base;
+}