//       ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
//       º                        NPSGUI.LIB                         º
//       º         Copyright 93-94, Nearly Perfect Software.         Ç¿
//       º                    All Rights Reserved                    º³
//       º                þ Written by Brad Broerman                 º³
//       º                þ Last Modified: 04/08/94                  º³
//       º                þ Revision 2.5                             º³
//       ÈÍÑÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ³
//         ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ

#include <stdio.h>
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <io.h>
#include <dos.h>
#include <malloc.h>
#include <fcntl.h>
#include <math.h>
#include <time.h>
#include <sys\types.h>
#include "npsgui.h"
#include "emmlib.h"

extern gmouse mouse;       // Your instance of gmouse MUST be called mouse!!!
extern int directvideo=1;  // Used for faster output.

struct Event {             // This structure is the Event Queue Node.
			int X,Y;     // The location of the event.
			int Btns;    // The button status: bit 1 = left, bit2 = right.
		  };

Event EventQueue[50];      // An array of 50 events. This is a circular queue.
int EventSize = 0,         // The Size of the queue.
	 EventHead = 0,         // The offset of the head and tail nodes.
	 EventTail = 0;


// This is the standard PCX header.
typedef struct
  {
	char	manufacturer;
	char	version;
	char	encoding;
	char	bits_per_pixel;
	int  	xmin, ymin;
	int  	xmax, ymax;
	int  	hres;
	int  	vres;
	unsigned char	palette[48];
	char	reserved;
	char	color_planes;
	int	bytes_per_line;
	int	palette_type;
	char	filler[58];
  } PCXHDR;

//   Data for mouse cursor shapes below. They consist of 2 16x16 bitmaps. The
// first one is AND'ed with the background to produce a 'hole', and the second
// one is OR'ed with that to produce the cursor shape.

static unsigned int arrowptr [32]={0xFFFF,0x8FFF,0x8FFF,0x87FF,0x83FF,0x81FF,0x80FF,0x807F,
				 0x803F,0x801F,0x800F,0x801F,0x807F,0x887F,0xDC3F,0xFC3F,
				 0x0000,0x0000,0x2000,0x3000,0x3800,0x3C00,0x3E00,0x3F00,
			    0x3F80,0x3FC0,0x3FE0,0x3E00,0x3300,0x2300,0x0180,0x0180};
static unsigned int uparrow [32] ={0xF9FF,0xF0FF,0xE07F,0xE07F,0xC03F,0xC03F,0x801F,0x801F,
			    0x000F,0x000F,0xF0FF,0xF0FF,0xF0FF,0xF0FF,0xF0FF,0xF0FF,
			    0x0000,0x0600,0x0F00,0x0F00,0x1F80,0x1F80,0x3FC0,0x3FC0,
			    0x7FE0,0x0600,0x0600,0x0600,0x0600,0x0600,0x0600,0x0600};
static unsigned int lftarrow [32]={0xFE1F,0xF01F,0x0000,0x0000,0x0000,0xF01F,0xFE1F,0xFFFF,
			    0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
			    0x0000,0x00C0,0x07C0,0x7FFE,0x07C0,0x00C0,0x0000,0x0000,
			    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
static unsigned int chekmark [32]={0xFFF0,0xFFE0,0xFFC0,0xFF81,0xFF03,0x0607,0x000F,0x001F,
			    0xC03F,0xF07F,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,
			    0x0000,0x0006,0x000C,0x0018,0x0030,0x0060,0x70C0,0x1D80,
			    0x0700,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000};
static unsigned int pointhand[32]={0xE1FF,0xE1FF,0xE1FF,0xE1FF,0xE1FF,0xE000,0xE000,0xE000,
			    0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
			    0x1E00,0x1200,0x1200,0x1200,0x1200,0x13FF,0x1249,0x1249,
			    0xF249,0x9001,0x9001,0x9001,0x9002,0x8001,0x8001,0xFFFF};
static unsigned int hourglass[32]={0x0000,0x0000,0x0000,0x0000,0x8001,0xC003,0xE007,0xF00F,
			    0xE007,0xC003,0x8001,0x0000,0x0000,0x0000,0x0000,0xFFFF,
				 0x0000,0x7FFE,0x6006,0x300C,0x1818,0x0C30,0x0660,0x03C0,
			    0x0660,0x0C30,0x1998,0x33CC,0x67E6,0x7FFE,0x0000,0x0000};

// The Screen Class. This class sets up BGI graphics in a VGA mode.

screen::screen(int mode)
 {
  init(mode);
 }

void screen::init(int mode)
 {
  int errorcode;

  registerfarbgidriver(EGAVGA_driver_far);
  gdriver = VGA;
  errorcode = graphresult();
  if (errorcode != grOk)  /* an error occurred */
   {
    cerr << "Graphics load error: "<<grapherrormsg(errorcode)<<endl;
    cerr << "Press any key to halt:";
    getkey();
    exit(1); /* terminate with an error code */
   }
  gmode=mode;
  initgraph( &gdriver , &gmode, "");
  errorcode = graphresult();
  if (errorcode != grOk)  /* an error occurred */
   {
    cerr << "Graphics init error: "<<grapherrormsg(errorcode)<<endl;
    cerr << "Press any key to halt:";
    getkey();
    exit(1); /* terminate with an error code */
   }
  directvideo=1;
  mouse.init();
 }

screen::~screen()
 {
  close();
 }

void screen::close()
 {
  mouse.hide();
  closegraph();
  mouse.init();
 }

// The GBase Class. This is the basis for all the graphic objects.
gbase::gbase(int x, int y, int w, int h, int k)
 {
  BackBuffer = NULL;
  BkgPages = 0;
  BkgHndl = 0;
  X=x;
  Y=y;
  Height=h;
  Width=w;
  KeepBkg=k;
  isShown=0;
 }

gbase::~gbase()
 {
  if (BackBuffer)
   {
    if (BkgPages)
     emm_free(BkgHndl);
    else
     farfree (BackBuffer);
	}
 }

void gbase::ReSize(int w, int h)
 {
  if (isShown)
   {
    hide();
    Width = w;
    Height = h;
    show();
   }
  else
   {
	 Width = w;
    Height = h;
   }
 }

void gbase::getbkg()
 {
  size_t       size;
  unsigned int L_P_P,
	       offset;
  int          i;

  if ((!KeepBkg) || (isShown))
   return;
  if (BackBuffer)
   {
    if (BkgPages)
     emm_free (BkgHndl);
    else
     farfree(BackBuffer);
    BackBuffer = NULL;
    BkgHndl = 0;
   }
  size = imagesize(X, Y, X+Width-1, Y+Height-1);
  L_P_P = ((16 * 1024) - 8)/ Width;
  BkgPages = ceil((float)Height / (float)L_P_P);
  if ((emm_type()) && (emm_pgsleft() >= BkgPages) && ((BkgHndl = emm_maloc(BkgPages)) != 0))
   {
    for (offset = 0,i = 0;offset < Height; ++i, offset += L_P_P)
     {
      BackBuffer = emm_map(BkgHndl,1,i);
      if (!BackBuffer)
       {
	closegraph();
	cerr<<"Error allocating memory for background."<<endl;
	exit(1);
       }
      if ((offset+L_P_P) < Height)
		 getimage(X,Y+offset,X+Width-1,Y+offset+L_P_P-1,BackBuffer);
      else
       getimage(X,Y+offset,X+Width-1,Y+Height-1,BackBuffer);
     }
   }
  else
   {
    BkgPages = 0;
    if (!(BackBuffer = (char far *)farmalloc(size)))
     {
      closegraph();
      cerr<<"Error allocating memory for background."<<endl;
      exit(1);
     }
	 getimage (X,Y,X+Width-1,Y+Height-1,BackBuffer);
   }
 }

void gbase::hide()
 {
  int i,
      offset,
      L_P_P;

  if (isShown)
   {
	 mouse.hide();
    L_P_P = ((16 * 1024) - 8)/ Width;
    if (BackBuffer)
     {
      if (BkgPages)
       {
	for (offset = 0,i = 0;i < BkgPages; ++i, offset += L_P_P)
	 {
	  BackBuffer = emm_map(BkgHndl,1,i);
	  if (BackBuffer)
	   putimage(X,Y+offset,BackBuffer,COPY_PUT);
	 }
       }
      else
       putimage (X,Y,BackBuffer,COPY_PUT);
     }
    if (BackBuffer)
     {
      if (BkgPages)
       emm_free (BkgHndl);
      else
       farfree(BackBuffer);
      BackBuffer = NULL;
      BkgHndl = 0;
     }
    isShown=0;
	 mouse.show();
   }
 }

int gbase::hit()
 {
  if (isShown)
   if ((mouse.getmX() >=X) && (mouse.getmX() <= X+Width-1))
    if ((mouse.getmY() >=Y) && (mouse.getmY() <= Y+Height-1))
     return(1);
  return (0);
 }

void gbase::moveto(int x, int y)
 {
  if (isShown)
   {
    hide();
    X=x; Y=y;
    show();
   }
  else
   {
    X=x; Y=y;
   }
 }

bitmap::bitmap(int x, int y,int mode, char *fname, int k):gbase(x,y,0,0,k)
 {
  ImageSize = 0;
  Buffer = NULL;
  load(fname,mode);
 }

bitmap::~bitmap()
 {
  hide();
  if (Buffer)
	free(Buffer);
 }

int ReadPcxLine(char *pointer, long count , ifstream &F)
 {
  char byte;
  int run, index = 0;

  memset(pointer,0,count);
  while(index < count)
	{
	 F.get(byte);
	 if ((byte & 0xc0) == 0xc0)
	  {
		run = byte & 0x3f;
		F.get(byte);
		while (run--) pointer[index++] = (char)byte;
	  }
	 else
	  pointer[index++] = byte;
	}
  return index;
 }

char bitmap::get_imgpxl(int x, int y)
 {
  // Gets the color value for a pixel in an image buffer.
  unsigned int offset, bytes_per_line;
  char mask, retval;

  bytes_per_line = (Width+7)/8;
  offset = (y*bytes_per_line*4)+x/8;
  mask = 0x01 << (x%8);
  retval = 0;

  if (*(Buffer+offset+4) & mask)
   retval |= 0x08;
  if (*(Buffer+offset+4+bytes_per_line) & mask)
   retval |= 0x04;
  if (*(Buffer+offset+4+bytes_per_line*2) & mask)
   retval |= 0x02;
  if (*(Buffer+offset+4+bytes_per_line*3) & mask)
   retval |= 0x01;

  return retval;
 }

void bitmap::put_imgpxl(int x, int y, char color)
 {
  // Places a pixel of the appropriate color at x,y in the buffer.
  unsigned int offset, bytes_per_line;
  char mask;

  bytes_per_line = (Width+7)/8;
  offset = (y*bytes_per_line*4)+x/8+4;
  mask = 0x01 << (x%8);

  if (color & 0x08)
   *(Buffer+offset) |= mask;
  else
   *(Buffer+offset) &= ~mask;
  if (color & 0x04)
   *(Buffer+offset+bytes_per_line) |= mask;
  else
   *(Buffer+offset+bytes_per_line) &= ~mask;
  if (color & 0x02)
   *(Buffer+offset+bytes_per_line*2) |= mask;
  else
   *(Buffer+offset+bytes_per_line*2) &= ~mask;
  if (color & 0x01)
   *(Buffer+offset+bytes_per_line*3) |= mask;
  else
   *(Buffer+offset+bytes_per_line*3) &= ~mask;
 }

void bitmap::load(char *fname, int mode)
 {
  PCXHDR header;
  RGBPAL cur_pal;
  struct palettetype EGA_Palette;
  int Palette_Map[16]={0,4,2,6,1,5,3,8,7,12,10,14,9,13,11,15},
      min_indx,
      pcx_entry,
      n,
      i,
      j;
  unsigned int gw, gh, bytes;
  long FE;
  unsigned long dist, min_dist;

  ifstream F(fname,ios::binary);
  if (!F)
	{
	 Buffer = NULL;
	 Width = Height = 0;
	 return;
	}
  if (mode == 0) // Load a npg file.
	{
	 F.seekg(0,istream::end);
	 FE = F.tellg();
	 F.seekg(0,istream::beg);
	 ImageSize = FE-F.tellg()+1;
	 F.close();
	 if (Buffer)
	  free (Buffer);
	 Buffer = (char far*)farmalloc(ImageSize);
	 if (!Buffer)
	  {
		closegraph();
		cerr<<"Memory allocation error while loading graphic image."<<endl;
		exit(1);
	  }
	 F.open(fname,ios::binary);
	 F.read (Buffer,ImageSize);
	 F.close();
	 gw=*(Buffer+1)*256+*(Buffer);
	 gh=*(Buffer+3)*256+*(Buffer+2);
	 Height = gh+1;
	 Width = gw+1;
	}
  else if (mode == 1) // Load a pcx file.
	{
	 F.seekg(0,istream::beg);
	 F.read((char *)&header, sizeof(header));
     // lets make sure it's a valid 16 color PCX file...
     if ((header.manufacturer != 0x0A) || (header.encoding != 1) ||
         (header.bits_per_pixel != 1) || (header.color_planes != 4))
      {
 	   Buffer = NULL;
	   Width = Height = 0;
	   return;
      }
     Width = gw  = header.xmax-header.xmin+1;
	 Height = gh = header.ymax-header.ymin+1;
	 bytes  = header.bytes_per_line;
	 ImageSize = 4+gh*bytes*header.color_planes;
     Buffer = (char far*)farmalloc(ImageSize);
	 if (!Buffer)
	  {
		closegraph();
		F.close();
		cerr<<"Memory allocation error while loading graphic image."<<endl;
		exit(1);
	  }
	 Buffer[0] = (char)(gw-1);
	 Buffer[1] = (char)((gw-1) >> 8);
	 Buffer[2] = (char)(gh-1);
	 Buffer[3] = (char)((gh-1) >> 8);
	 for (i=0, n=0; i < gh; ++i)
	  {
		j=header.color_planes;
		ReadPcxLine(Buffer+4+(bytes*(n + --j)), bytes, F);
		ReadPcxLine(Buffer+4+(bytes*(n + --j)), bytes, F);
		ReadPcxLine(Buffer+4+(bytes*(n + --j)), bytes, F);
		ReadPcxLine(Buffer+4+(bytes*(n + --j)), bytes, F);
		n += header.color_planes;
	  }
	 F.close();
     // Now that the image is in memory, we need to map it's colors over.
     for (i=0; i < (bytes*8); ++i)
      for (n=0; n < Height; ++n)
       put_imgpxl(i,n,Palette_Map[get_imgpxl(i,n)]);
	}
 }

void bitmap::show()
 {
  if (!Buffer)
	return;
  mouse.hide();
  getbkg();
  putimage(X, Y, Buffer,COPY_PUT);
  isShown=1;
  mouse.show();
 }

int bitmap::getW()
 {
  return (Width);
 }

int bitmap::getH()
 {
  return (Width);
 }

 panel::panel(int x,int y,int w,int h, int d, int io, int c, int k)
  :gbase(x-d,y-d,w+2*d,h+2*d,k)
  {
   Depth = d;
   InorOut=!(io == 0);
   Color=c;
  }

 panel::~panel() { }

 void panel::show ()
  {
   unsigned int size;
   int top_left[14],
       btm_right[14],
       orig_color;
   struct fillsettingstype orig_settings;
   struct linesettingstype orig_line;

   mouse.hide();
   orig_color=getcolor();
   getfillsettings(&orig_settings);
   getlinesettings(&orig_line);
   setlinestyle(0,1,0);
   top_left[0]=X; top_left[1]=Y;
   top_left[2]=X+Width-1; top_left[3]=Y;
   top_left[4]=X+Width-Depth-1; top_left[5]=Y+Depth;
   top_left[6]=X+Depth; top_left[7]=Y+Depth;
   top_left[8]=X+Depth; top_left[9]=Y+Height-Depth-1;
   top_left[10]=X; top_left[11]=Y+Height-1;
   top_left[12]=X; top_left[13]=Y;
   btm_right[0]=X+Width-1; btm_right[1]=Y+Height-1;
   btm_right[2]=X+Width-1; btm_right[3]=Y+1;
   btm_right[4]=X+Width-Depth-1; btm_right[5]=Y+Depth+1;
   btm_right[6]=X+Width-Depth-1; btm_right[7]=Y+Height-Depth-1;
   btm_right[8]=X+Depth+1; btm_right[9]=Y+Height-Depth-1;
   btm_right[10]=X+1; btm_right[11]=Y+Height-1;
   btm_right[12]=X+Width-1;btm_right[13]=Y+Height-1;
   getbkg();
   if (InorOut)
    {
     setcolor (Color+8); setfillstyle(SOLID_FILL,Color+8);
     fillpoly(7,top_left);
     setcolor (DARKGRAY); setfillstyle(SOLID_FILL,DARKGRAY);
     fillpoly(7,btm_right);
    }
   else
    {
     setcolor (DARKGRAY); setfillstyle(SOLID_FILL,DARKGRAY);
     fillpoly(7,top_left);
     setcolor (Color+8); setfillstyle(SOLID_FILL,Color+8);
     fillpoly(7,btm_right);
    }
   setcolor (Color); setfillstyle(SOLID_FILL,Color);
   bar(X+Depth,Y+Depth,X+Width-Depth-1,Y+Height-Depth-1);
   isShown=1;
   setcolor(orig_color);
   setfillstyle(orig_settings.pattern, orig_settings.color);
   setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
   mouse.show();
  }

void panel::setbkgclr(int c)
 {
  Color = c;
 }

void panel::resize(int w, int h)
 { ReSize(w+2*Depth,h+2*Depth); }

void panel::moveto(int x, int y)
 {
  gbase::moveto(x-Depth,y-Depth);
 }

bevel::bevel(int x, int y, int w, int h, int d, int bw, int c, int k)
 :panel(x-d-bw,y-d-bw,w+2*(bw+d),h+2*(bw+d),d,1,c,k)
 {
  inner = new panel(x,y,w,h,d,0,c,0);
  BWidth = bw;
 }

bevel::~bevel()
 {
  delete inner;
 }

void bevel::show ()
 {
  panel::show();
  inner->show();
 }

void bevel::resize(int w, int h)
 {
  if (isShown)
   {
    hide();
    panel::resize(w+2*(BWidth+Depth),h+2*(BWidth+Depth));
    inner->resize(w,h);
    show();
   }
  else
   {
    panel::resize(w+2*(BWidth+Depth),h+2*(BWidth+Depth));
    inner->resize(w,h);
   }
 }

void bevel::moveto(int x, int y)
 {
  if (isShown)
   {
    hide();
    panel::moveto(x-Depth-BWidth,y-Depth-BWidth);
    inner->moveto(x,y);
    show();
   }
  else
   {
    panel::moveto(x-Depth-BWidth,y-Depth-BWidth);
    inner->moveto(x,y);
   }
 }

button::button (int x, int y, int w, int h, int d, int c,int b,int m, char* strn, int k)
 : panel(x,y,w,h,d+b,OUT,c,k)

 {
  int slen;

  HkHiClr = TxtClr = WHITE;
  Mode=m;
  Border = b;
  if (Mode==0)
   {
    String = NULL;
    slen = strlen(strn);
    if (slen > 0)
     {
      String = (char *)calloc(1,slen+2);
      if (!String)
       {
		  closegraph();
		  cerr<<"Memory allocation error in button setup."<<endl;
		  exit(1);
		 }
		strncpy(String,strn,slen);
	  }
	}
  else
	{
	 Bgraphic = new graphic(X+Depth,Y+Depth,0,m-1,strn);
	}
 }

button::~button()
 {
  if (!Mode)
	free(String);
  else
	delete Bgraphic;
 }

void button::setextclr(int clr)
 {
  TxtClr = clr;
 }

void button::sethkhiclr(int clr)
 {
  HkHiClr = clr;
 }

void button::show()
 {
  int top_left[14],
		btm_right[14],
		i,
		Tild,
		j,
		j2,
		orig_color;
  char temp[2] = " ";
  unsigned int gw,
			 gh,
			 size;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  if (Mode==0)
	{
	 if (String != NULL)
	  {
		Tild = 0;
		for (i=0; *(char *)(String+i) != (char)0x00 ; ++i)
		 if (*(char *)(String+i) == '~')
		++ Tild;
		Tild *= textwidth("~");
		if (textheight((char *)String)+2 > Height-2*Depth)
		 Height=textheight((char *)String)+2*Depth+2;
		if (textwidth((char *)String)+2-Tild > Width-2*Depth)
		 Width=textwidth((char *)String)+2*Depth+2-Tild;
	  }
	}
  else
	{
	 if (Bgraphic->getH() > Height-2*Depth)
	  Height=Bgraphic->getH()+2*Depth;
	 if (Bgraphic->getW() > Width-2*Depth)
	  Width=Bgraphic->getW()+2*Depth;
	}
  panel::show();
  setcolor(BLACK);
  for (i=1; i<Border+1 ; ++i)
   rectangle(X+i-1,Y+i-1,X+Width-i,Y+Height-i);
  if (!Mode)
	{
	 setcolor (TxtClr);
	 settextjustify(LEFT_TEXT,CENTER_TEXT);
	 if (String != NULL)
	  {
		for (j = 0, j2 = 0; (char)*(String+j) != (char)0x00 ;++j, ++ j2)
		 {
	strncpy(temp,(char *)(String+j),1);
	if (*(char *)(String+j) == '~')
	 {
	  strncpy(temp,(char *)(String+(++j)),1);
	  setcolor(HkHiClr);
	  outtextxy(X+(Width/2)-((textwidth((char *)String)-Tild)/2)+j2*textwidth("A"), Y+(Height/2)+1,temp);
	  setcolor(TxtClr);
	 }
	else
	 outtextxy(X+(Width/2)-((textwidth((char *)String)-Tild)/2)+j2*textwidth("A"), Y+(Height/2)+1,temp);
       }
     }
   }
  else
   {
    Bgraphic->moveto(X+(Width-Bgraphic->getW())/2,Y+(Height-Bgraphic->getW())/2);
    Bgraphic->show();
   }
  Selected=0;
  settextjustify(textinfo.horiz,textinfo.vert);
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void button::select()
 {
  int top_left[14],
		btm_right[14],
		i,
		j,
		j2,
		Tild,
		orig_color;
  char temp[2] = " ";
  unsigned int gw,
			 gh;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if (!isShown)
	return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  top_left[0]=X; top_left[1]=Y;
  top_left[2]=X+Width-1; top_left[3]=Y;
  top_left[4]=X+Width-Depth-1; top_left[5]=Y+Depth;
  top_left[6]=X+Depth; top_left[7]=Y+Depth;
  top_left[8]=X+Depth; top_left[9]=Y+Height-Depth-1;
  top_left[10]=X; top_left[11]=Y+Height-1;
  top_left[12]=X; top_left[13]=Y;
  btm_right[0]=X+Width-1; btm_right[1]=Y+Height-1;
  btm_right[2]=X+Width-1; btm_right[3]=Y+1;
  btm_right[4]=X+Width-Depth-1; btm_right[5]=Y+Depth+1;
  btm_right[6]=X+Width-Depth-1; btm_right[7]=Y+Height-Depth-1;
  btm_right[8]=X+Depth+1; btm_right[9]=Y+Height-Depth-1;
  btm_right[10]=X+1; btm_right[11]=Y+Height-1;
  btm_right[12]=X+Width-1;btm_right[13]=Y+Height-1;
  setcolor (DARKGRAY); setfillstyle(SOLID_FILL,DARKGRAY);
  fillpoly(7,top_left);
  fillpoly(7,btm_right);
  setcolor (Color); setfillstyle(SOLID_FILL,Color);
  bar(X+Depth+1,Y+Depth+1,X+Width-Depth,Y+Height-Depth);
  setcolor(BLACK);
  for (i=1; i<Border+1 ; ++i)
   rectangle(X+i-1,Y+i-1,X+Width-i,Y+Height-i);
  if (!Mode)
	{
	 if (String != NULL)
	  {
		Tild = 0;
		for (i=0; *(char *)(String+i) != (char)0x00 ; ++i)
		 if (*(char *)(String+i) == '~')
	++ Tild;
		Tild *= textwidth("~");
		setcolor(TxtClr);
		settextjustify(LEFT_TEXT,CENTER_TEXT);
		for (j = 0, j2 = 0; (char)*(String+j) != (char)0x00 ;++j, ++ j2)
		 {
	strncpy(temp,(char *)(String+j),1);
	if (*(char *)(String+j) == '~')
	 {
	  strncpy(temp,(char *)(String+(++j)),1);
	  setcolor(HkHiClr);
	  outtextxy(X+(Width/2)-((textwidth((char *)String)-Tild)/2)+j2*textwidth("A")+1, Y+(Height/2)+2,temp);
	  setcolor(TxtClr);
	 }
	else
	 outtextxy(X+(Width/2)-((textwidth((char *)String)-Tild)/2)+j2*textwidth("A")+1, Y+(Height/2)+2,temp);
       }
     }
   }
  else
   {
    Bgraphic->moveto(X+(Width-Bgraphic->getW())/2+1,Y+(Height-Bgraphic->getW())/2+1);
    Bgraphic->show();
   }
  Selected=1;
  settextjustify(textinfo.horiz,textinfo.vert);
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

int button::is_selected()
 {
  return (Selected);
 }

void button::setborder(int b)
 {
  if ((b >= 0) && (b <= 5))
	if (isShown)
	 {
	  if (is_selected())
		{
		 hide();
		 resize(Width-2*Depth-Border+b,Height-2*Depth-Border+b);
		 Depth = Depth - Border+b;
		 Border = b;
		 show();
		 select();
		}
	  else
		{
		 hide();
		 resize(Width-2*Depth-Border+b,Height-2*Depth-Border+b);
		 Depth = Depth - Border+b;
		 Border = b;
		 show();
		}
	 }
	else
	 {
	  resize(Width-2*Depth-Border+b,Height-2*Depth-Border+b);
	  Depth = Depth - Border+b;
	  Border = b;
	 }
 }

graphic::graphic(int x, int y, int k,int mode, char *fname) : bitmap(x,y,mode,fname,k)
 { }

graphic::~graphic()
 { }

void graphic::save(char *fname)
 {
  ofstream F(fname,ios::binary);
  F.write(Buffer,ImageSize);
  F.flush();
  F.close();
 }

void graphic::capture(int x, int y, int x1, int y1)
 {
  mouse.hide();
  if (Buffer)
   {
    free(Buffer);
    Buffer = NULL;
   }
  ImageSize=imagesize(x,y,x1,y1);
  Buffer = (char far*)farmalloc(ImageSize);
  if (!Buffer)
   {
    closegraph();
    cerr<<"Memory allocation error during graphic capture."<<endl;
    exit(1);
   }
  getimage(x,y,x1,y1,Buffer);
  X=x; Y=y; Width=x1-x+1; Height=y1-y+1;
  isShown=1;
  mouse.show();
 }

gmouse::~gmouse()
 {
  mouse.hide();
  mouse.init();
 }

void gmouse::init()
 {
  unsigned int btns;
  asm { mov ax,0x0000
	mov bx,0x0000
	int 0x33
	mov btns,bx
      }
  show_lvl=-100;
  num_btns=(int)btns;
 }

void gmouse::arm() { show_lvl=0; }

void gmouse::disarm() {show_lvl=-100;}

void gmouse::show()
 {
  if (show_lvl == 0)
   {
    asm { mov  ax,0x0001
	  int 0x33
	};
   }
  ++show_lvl;
 }

void gmouse::hide()
 {
  if (show_lvl == 1)
   {
    asm { mov ax,0x0002
	  int 0x33
	};
   }
  --show_lvl;
 }

int gmouse::getmX()
 {
  unsigned int mouseX;

  asm { mov ax,0x0003
	int 0x33
	mov mouseX,cx
      };
  return ((int)mouseX);
 }

int gmouse::getmY()
 {
  unsigned int mouseY;

  asm { mov ax,0x0003
	int 0x33
	mov mouseY,dx
      };
  return ((int)mouseY);
 }

int gmouse::getbutton( int btn)
 {
  unsigned int bstat;

  asm { mov ax,0x0003
	int 0x33
	mov bstat,bx
      };
  if (bstat & btn)
   return (1);
  return (0);
 }

int gmouse::btnpressed()
 {
  unsigned int bstat;

  asm { mov ax,0x0003
	int 0x33
	mov bstat,bx
      };
  if (bstat & 7)
   return (1);
  return (0);
 }

void gmouse::moveptr(int X, int Y)
 {
  asm { mov ax,0x0004
	mov cx,X
	mov dx,Y
	int 0x33
      };
 }

void gmouse::setbounds(int left, int right, int top, int btm)
 {
  asm { mov ax,0x0007
	mov cx,left
	mov dx,right
	int 0x33
	mov ax,0x0008
	mov cx,top
	mov dx,btm
	int 0x33
      };
 }

void gmouse::setexclarea(int left, int right, int top, int btm)
 {
  asm { mov ax,0x0010
	mov cx,left
	mov si,right
	mov dx,top
	mov di,btm
	int 0x33
      };
 }

void gmouse::newpointer(int Type=0)
 {
  unsigned int *Ptr, X, Y;
  if ((Type < 1) || (Type > 6))
   return;

  switch (Type)
   {
    case 1:  X=1; Y=1; Ptr=arrowptr; break;
    case 2:  X=5; Y=1; Ptr=uparrow; break;
    case 3:  X=0; Y=3; Ptr=lftarrow; break;
    case 4:  X=6; Y=7; Ptr=chekmark; break;
    case 5:  X=5; Y=0; Ptr=pointhand; break;
    case 6:  X=7; Y=7; Ptr=hourglass; break;
   }
  custmpointer(X,Y,Ptr);

 }

void gmouse::custmpointer(int X, int Y, unsigned int *Ptr)
 {
  unsigned int sg, ofst;

  sg =(unsigned)(void _seg *)(void far *)Ptr;
  ofst =(unsigned)Ptr;

  asm { mov AX,0x0009
	mov BX,X
	mov CX,Y
	mov DX,ofst
	mov ES,sg
	int 0x33
      };
 }

int gmouse::getrecentX()
 {
  unsigned int recX;

  asm { mov ax,0x000B
	int 0x33
	mov recX,cx
      };
  return ((int) recX);
 }

int gmouse::getrecentY()
 {
  unsigned int recY;

  asm { mov ax,0x000B
	int 0x33
	mov recY,dx
      };
  return ((int) recY);
 }

void gmouse::setevnthndlr( unsigned int mask, void far *pointer)
 {
  unsigned int sg,ofst;

  sg =(unsigned)(void _seg *)(void far *)pointer;
  ofst =(unsigned)pointer;
  asm { mov ax,0x000C
	mov cx,mask
	mov dx,ofst
	mov es,sg
	int 0x33
      };
 }

static int mx,my,mb;
static int InProgress = 0;

interrupt MouseInterruptHndlr(...)
 {
  if (!InProgress)
   {
    asm { mov mx,cx             // Place the X coordinate into the record.
	  mov my,dx             // Place the Y coordinate into the record.
	  mov mb,ax             // Place the button status into the record.
	}
    ++InProgress;
    if (EventSize+1 < 50)
     {
      ++EventSize;
      ++EventHead;
      if (EventHead == 50) EventHead = 0;
      EventQueue[EventHead].X = mx;
      EventQueue[EventHead].Y = my;
      EventQueue[EventHead].Btns = mb;
     }
    --InProgress;
   }
 }
void gmouse::setdefhndlr()
 {
  setevnthndlr(6,MouseInterruptHndlr);
 }

int gmouse::nextevent(int &X, int &Y, int &Btn)
 {
  if (EventSize == 0)
   return 0;
  X = EventQueue[EventHead].X;
  Y = EventQueue[EventHead].Y;
  Btn = EventQueue[EventHead++].Btns;
  --EventSize;
  if (EventHead == 50)
   EventHead = 0;
  return 1;
 }

void gmouse::setsens( unsigned int X, unsigned int Y)
 {
  asm { mov ax,0x000F
	mov cx,X
	mov dx,Y
	int 0x33
      };
 }

checkbox::checkbox(int x, int y, int w, int h, int d, int c, int k)
 : panel (x,y,w,h,d,IN,c,k)
 {
  LineWidth=0;
  Selected=0;
 }

checkbox::~checkbox()
 { }

void checkbox::show()
 {
  hide();
  panel::show();
  Selected = 0;
 }

void checkbox::select()
 {
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;

  mouse.hide();
  if (isShown)
   {
    orig_color=getcolor();
    getfillsettings(&orig_settings);
    getlinesettings(&orig_line);
    setlinestyle(0,1,LineWidth);
    setcolor (BLACK);
    line(X+Depth,Y+Depth,(X+Width-Depth-1),(Y+Height-Depth-1));
    line((X+Width-Depth-1),Y+Depth,X+Depth,(Y+Height-Depth-1));
    setcolor(orig_color);
    setfillstyle(orig_settings.pattern, orig_settings.color);
    setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
    Selected=1;
   }
  mouse.show();
  return;
 }

void checkbox::setline(int w)
 {
  LineWidth = w;
 }

int checkbox::is_selected()
 {
  return (Selected);
 }

rbutton::rbutton(int x, int y, int R, int C, int k)
 :gbase(x-R,y-R,2*R+1,2*R+1,k)
 {
  Radius = R;
  Color =C;
  Selected=0;
 }

 rbutton::~rbutton()
  {  }

void rbutton::moveto(int x, int y)
 {
  gbase::moveto(x-Radius,y-Radius);
 }

void rbutton::resize(int R)
 {
  if (isShown)
   {
    hide();
    Radius = R;
    gbase::moveto(X-R,Y-R);
    ReSize(2*R+1,2*R+1);
    show();
   }
  else
   {
    gbase::moveto(X-R,Y-R);
    ReSize(2*R+1,2*R+1);
   }
 }

void rbutton::show()
 {
  size_t size;
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;

  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  setlinestyle(0,1,0);
  getbkg();
  setcolor(LIGHTGRAY);
  setfillstyle(SOLID_FILL,LIGHTGRAY);
  pieslice(X+Radius,Y+Radius,0,360,Radius);
  setcolor(DARKGRAY);
  arc (X+Radius, Y+Radius, 45, 225, Radius);
  setcolor(WHITE);
  arc(X+Radius,Y+Radius,226,360,Radius);
  arc(X+Radius,Y+Radius,0,44,Radius);
  isShown=1;
  Selected=0;
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void rbutton::select()
 {
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;

  if (!isShown)
   return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  setlinestyle(0,1,0);
  setcolor(Color);
  setfillstyle(SOLID_FILL,Color);
  pieslice(X+Radius, Y+Radius, 0, 360, Radius-3);
  setcolor(WHITE);
  arc (X+Radius,Y+Radius,45,225,Radius-3);
  setcolor(DARKGRAY);
  arc (X+Radius,Y+Radius,226,360,Radius-3);
  arc (X+Radius,Y+Radius,0,44,Radius-3);
  Selected=1;
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void rbutton::chgclr(int c)
 {
  Color = c;
 }

int rbutton::is_selected()
 {
  return (Selected);
 }

icon::icon(int x, int y, int mode, char *fname, int k): bitmap(x,y,mode,fname,k)
 {
  Selected = 0;
 }

icon::~icon()
 { }

void icon::show()
 {
  bitmap::show();
  Selected=0;
 }

void icon::select()
 {
  unsigned int size;

  if (!isShown)
   return;
  mouse.hide();
  putimage(X, Y, Buffer, NOT_PUT);
  isShown=1;
  Selected=1;
  mouse.show();
 }

int icon::is_selected()
 {
  return(Selected);
 }

instrn::instrn (int x, int y, int w, int h, int d, int c, int k)
 :panel(x,y,w,h,d,IN,c,k)
 {
  TxtColor=WHITE; CsrColor=BLACK; CsrBlink=1;
  Pointer=0; MaxLen=0;
  instmode=0;
  Buffer=NULL;
  HiClr = RED;
  Hilight_Begin = 0;
  Hilight_End = 0;
 }

instrn::~instrn()
 {
  if (Buffer)
	free (Buffer);
 }

void instrn::settxtclr(int clr)
 {
  TxtColor = clr;
  hide();
  show();
 }

void instrn::setcsrclr (int clr)
 {
  CsrColor=clr;
  hide();
  show();
 }

void instrn::sethiclr(int clr)
 {
  HiClr = clr;
 }

void instrn::setcsrblink(int blk)
 {
  CsrBlink = blk;
 }

void instrn::show()
 {
  int orig_color;
  struct textsettingstype textinfo;

  gettextsettings(&textinfo);
  orig_color=getcolor();
  if (Height < textheight("jgAT")+2)
	{
	 Height = textheight("jgAT")+2;
	}
  panel::show();
  if (Buffer)
	{
	 mouse.hide();
	 setcolor(TxtColor);
	 settextjustify(LEFT_TEXT,CENTER_TEXT);
	 outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
	 mouse.show();
	}
  setcolor(orig_color);
  settextjustify(textinfo.horiz,textinfo.vert);
 }

char instrn::lastkey()
 { return ((char)inkey); }

char *instrn::getinput(int hi_init)
 {
  int newline=0,   // Time to quit this line?
		i=0,         // Counter used for insert/delete loops.
		j = 0,
		orig_color,
		Hilight_Last = 0;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if (!isShown)
	return ("");
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  setcolor(BLACK);
  if (!Buffer)
	{
	 MaxLen=(Width-(2*Depth)-4)/textwidth("A");
	 Buffer = (char *)malloc (MaxLen+1);
	 if (!Buffer)
	  {
		closegraph();
		cerr << "Memory allocation error in instrn::getinput"<<endl;
		exit(1);
	  }
	 for (i=0; i<=MaxLen; ++i)
	  *(Buffer+i) = '\0';
	 Pointer=0;
	 hide();  // erase and re-draw panel to get ready for new input.
	 show();
	}

  // Set Hilight_Begin and Hilight_End.
  if (hi_init == 1)
	 {
	  Hilight_Begin = 0;
	  Hilight_End = strlen(Buffer);
	 }
  // Draw the hilight.
  if (Hilight_Begin != Hilight_End)
	{
	 setcolor(HiClr);
	 setfillstyle(SOLID_FILL,HiClr);
	 mouse.hide();
	 bar(X+Depth+1,Y+Depth,X+Depth+Hilight_End*textwidth("A")+2,Y+Height-Depth-1);
	 if (Buffer)
	  {
		setcolor(TxtColor);
		settextjustify(LEFT_TEXT,CENTER_TEXT);
		outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
	  }
	 mouse.show();
	}
  // Wait for the mouse to release if it's presed
  while (mouse.btnpressed())
	;
  do       // This is the outer MAIN LOOP.
	{
	 do    // This is the IDLE LOOP, blinking the cursor.
	  {
		mouse.hide();
		setcolor(CsrColor);
		line((X+Depth+Pointer*textwidth("A")+2),Y+Depth+2,(X+Depth+Pointer*textwidth("A")+2),Y+Height-Depth-3);
		mouse.show();
		if (CsrBlink)
		 {
		  if (!keyhit() && !(mouse.btnpressed() && !hit()))
			delay(100);
		  mouse.hide();
		  setcolor(Color);
		  line((X+Depth+Pointer*textwidth("A")+2),Y+Depth+1,(X+Depth+Pointer*textwidth("A")+2),Y+Height-Depth-1);
		  mouse.show();
		  if (!keyhit() && !(mouse.btnpressed() && !hit()))
			delay(100);
		 }
	  }
	while (!keyhit() && !mouse.btnpressed())
    ;
	 if (mouse.btnpressed() && hit())
     {
      show();
      Hilight_End = (mouse.getmX()-X)/textwidth("A");
      Hilight_Begin = Hilight_End;
      Hilight_Last = Hilight_End;
      while (mouse.btnpressed() && hit())
       {
        Hilight_End = (mouse.getmX()-X)/textwidth("A");
        if (Hilight_End != Hilight_Last)
         {
			 mouse.hide();
          Hilight_Last = Hilight_End;
          setcolor(Color);
          setfillstyle(SOLID_FILL,Color);
          bar(X+Depth,Y+Depth,X+Width-Depth-1,Y+Height-Depth-1);
			 setcolor(HiClr);
          setfillstyle(SOLID_FILL,HiClr);
          bar(X+Depth+(int)min(Hilight_End, Hilight_Begin)*textwidth("A")+2,Y+Depth,
              X+Depth+(int)max(Hilight_End, Hilight_Begin)*textwidth("A")+2,Y+Height-Depth-1);
			 if (Buffer)
           {
				setcolor(TxtColor);
            settextjustify(LEFT_TEXT,CENTER_TEXT);
            outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
           }
			 mouse.show();
         }
       }
     }
    else if (!(mouse.btnpressed() && !hit()))
     {
      inkey=getkey();
		if (inkey > 255)
       {
	     putbk(inkey);
	     inkey =(char)0;
       }
      else
       inkey = inkey & 0xff;
      switch (inkey)  //Proccess the keystrokes.
       {
		  case 0:     //extended keys!
	      inkey = getkey() & 0xff;
			switch (inkey)
			 {
           case 71:  // HOME key
            Pointer = 0;
            if (getkbflags() & 0x03)
             {
              Hilight_End = Pointer;
             }
            else
             {
              Hilight_Begin = Hilight_End = Pointer;
				 }
            break;
           case 79:     // End Key.
            Pointer = strlen(Buffer);
            if (getkbflags() & 0x03)
             {
              Hilight_End = Pointer;
             }
            else
				 {
              Hilight_Begin = Hilight_End = Pointer;
				 }
            break;
	        case 75:    //left-arrow
            (Pointer > 0) ? --Pointer:0;
            if (getkbflags() & 0x03)
             {
              Hilight_End = Pointer;
             }
				else
             {
              Hilight_Begin = Hilight_End = Pointer;
				 }
             break;
	        case 77:    //right-arrow
            (*(Buffer+Pointer) != '\0') ? ++Pointer:Pointer;
            if (getkbflags() & 0x03)
             {
              Hilight_End = Pointer;
				 }
            else
				 {
              Hilight_Begin = Hilight_End = Pointer;
				 }
            break;
	        case 72:    //up-arrow
             Hilight_Begin = Hilight_End;
	          newline=1; break;
	        case 80:    //down_arrow
             Hilight_Begin = Hilight_End;
	          newline=1; break;
	        case 82:    //insert
	          if (!instmode)
	           instmode=1;
				 else
	           instmode=0;
	          break;
	        case 83:    //delete
				 if (Hilight_End != Hilight_Begin)
              {
               Pointer = (int)min(Hilight_End, Hilight_Begin);
               for (i=Pointer, j=(int) max(Hilight_End, Hilight_Begin);*(Buffer+j) != '\0' ; ++i, ++j)
                *(Buffer+i)=*(Buffer+j);
					for (;i < MaxLen; ++i)
                *(Buffer+i)='\0';
					Hilight_Begin = Hilight_End;
              }
             else
				  {
  	            for (i=Pointer; i < MaxLen ; ++i)
                *(Buffer+i)=*(Buffer+i+1);
               *(Buffer+MaxLen)='\0';
              }
             break;
          };
         break;
		  case 9:       // tab
          Hilight_Begin = Hilight_End;
          newline=1; break;
	     case 13:       // return
          Hilight_Begin = Hilight_End;
          newline=1; break;
	     case 27:      // escape
          Hilight_Begin = Hilight_End;
          newline=1; break;
		  case 8:        //backspace
          if (Hilight_End != Hilight_Begin)
			  {
            Pointer = (int)min(Hilight_End, Hilight_Begin);
            for (i=Pointer, j=(int) max(Hilight_End, Hilight_Begin);*(Buffer+j) != '\0' ; ++i, ++j)
             *(Buffer+i)=*(Buffer+j);
            for (;i < MaxLen; ++i)
             *(Buffer+i)='\0';
            Hilight_Begin = Hilight_End;
           }
          else
           {
				if (Pointer >0)
				 {
	           for (i=Pointer; i <= MaxLen; ++i)
	            *(Buffer+i-1) = *(Buffer+i);
	           *(Buffer+MaxLen) = '\0';
              --Pointer;
             }
	        }
	       break;
    	  default:       //other key pressed (enter char to buffer).
			 if (Hilight_End != Hilight_Begin)
           {
				Pointer = (int)min(Hilight_End, Hilight_Begin);
            for (i=Pointer, j=(int) max(Hilight_End, Hilight_Begin);*(Buffer+j) != '\0' ; ++i, ++j)
             *(Buffer+i)=*(Buffer+j);
            for (;i < MaxLen; ++i)
             *(Buffer+i)='\0';
            if (Pointer > (MaxLen-1))
	          Pointer = MaxLen-1;
				for (i=MaxLen-1; i > Pointer; --i)
	          *(Buffer+i) = *(Buffer+i-1);
            Hilight_Begin = Hilight_End = Pointer+1;
           }
			 else
           {
            if (Pointer > (MaxLen-1))
	          Pointer = MaxLen-1;
	         if (instmode)
	          for (i=MaxLen-1; i > Pointer; --i)
				  *(Buffer+i) = *(Buffer+i-1);
           }
	       *(Buffer+Pointer) = inkey;
			 ++Pointer;
		 }
		mouse.hide();
		setcolor(Color);
		setfillstyle(SOLID_FILL,Color);
		bar(X+Depth,Y+Depth,X+Width-Depth-1,Y+Height-Depth-1);
		if (Hilight_End != Hilight_Begin)
		 {
		  setcolor(HiClr);
		  setfillstyle(SOLID_FILL,HiClr);
		  bar(X+Depth+(int)min(Hilight_End, Hilight_Begin)*textwidth("A")+2,Y+Depth,
				X+Depth+(int)max(Hilight_End, Hilight_Begin)*textwidth("A")+2,Y+Height-Depth-1);
		 }
		setcolor(TxtColor);
		settextjustify(LEFT_TEXT,CENTER_TEXT);
		outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
		mouse.show();
	  }
	 else
	  {
		newline = 1;
		inkey = 0;
	  }
	}
  while (!newline);
  show();
  mouse.hide();
  setcolor(Color);
  setfillstyle(SOLID_FILL,Color);
  bar(X+Depth,Y+Depth,X+Width-Depth-1,Y+Height-Depth-1);
  setcolor(TxtColor);
  settextjustify(LEFT_TEXT,CENTER_TEXT);
  outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
  mouse.show();
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  settextjustify(textinfo.horiz,textinfo.vert);
  return (Buffer);
 }

void instrn::hilight(int start, int end)
 {
  if (Buffer == NULL)
	return;
  // Set Hilight_Begin and Hilight_End.
  if (start < 0)
	start = 0;
  if (end > strlen(Buffer))
	end = strlen(Buffer);

  Hilight_Begin = start;
  Hilight_End = end;

  // Draw the hilight.
  if (Hilight_Begin != Hilight_End)
	{
	 setcolor(HiClr);
	 setfillstyle(SOLID_FILL,HiClr);
	 mouse.hide();
	 bar(X+Depth+1,Y+Depth,X+Depth+Hilight_End*textwidth("A")+2,Y+Height-Depth-1);
	 if (Buffer)
	  {
		setcolor(TxtColor);
		settextjustify(LEFT_TEXT,CENTER_TEXT);
		outtextxy(X+Depth+3,(Y+(Height/2+1)),Buffer);
	  }
	 mouse.show();
	}
 }

void instrn::clear()
 {
  int i;
  if (!Buffer)
	return;
  free (Buffer);
  Buffer = NULL;
  inkey = 0;
  return;
 }

void instrn::preset(char *B)
 {
  if (Buffer)
   free(Buffer);
  MaxLen=(Width-(2*Depth)-4)/textwidth("A");
  Buffer = (char *)malloc (MaxLen+1);
  memset(Buffer,0x00,MaxLen+1);
  strncpy(Buffer,B,MaxLen);
 }

char *instrn::gettext( char *text)
 {
  int len = strlen(Buffer);
  strncpy(text, Buffer, len);
  *(text+len) = (char)0;
  return text;
 }


menubar::menubar(int x, int y, int w, int h, int c, int tc, int hc, int k)
 :panel(x,y,w,h,2,OUT,c,k)
 {
  BX=0; BY=0; BW=0; BH=0;
  TxtColor=tc; HiColor=hc;
  HkHiColor=tc;
  MenuSelected=0;
  ItemSelected=0;
  PulledDown=0;
  Menus = NULL;
  NumMenus = 0;
  NumItems = 0;
  MenuBackBuffer = NULL;
  MenuBkgPages = 0;
  MenuBkgHndl = 0;
 }

menubar::~menubar()
 {
  while (Menus != NULL)
   delmenu(1);
 }

int menubar::find_char (char *str, char fnd, int begin)
 {
  int i;
  for (i= begin; *(str+i) != '\0' ;++i)
   {
    if ( *(str+i) == fnd )
     break;
   }
  if (!(*(str+i) == '\0'))
   return i;
  else
   return -1;
 }

char *menubar::mids (char *strn, int begin, int count)
 {
  int i;
  char *target;
  target =(char *)malloc(count+1);
  if (target != NULL)
   {
    for (i= 0; i<count; ++i)
     *(target+i) = *(strn +i+ begin);
    *(target+i) = '\0';
    return target;
   }
  else
   {
    closegraph();
    cerr << "Memory allocation error in menubar::mids."<<endl;
    exit (-1);
   }
  return (NULL);
 }

void menubar::addmenu(char *heading, char *items, int Key)
 {
  MenuTYPE *newmenu, *tempM;
  itemTYPE *newitem, *tempI;
  char *temp;
  int pos,epos;

  newmenu = new (MenuTYPE);
  if (!newmenu)
   {
    closegraph();
    cerr << "Memory allocation error while making menu item. "<<endl;
    exit(1);
   }
  ++NumMenus;
  memset(newmenu->Heading,0,40);
  strncpy(newmenu->Heading, heading,39);
  newmenu->X=0;
  newmenu->Y=0;
  newmenu->Width=0;
  newmenu->Height=Height;
  newmenu->NextMenu=NULL;
  newmenu->Items = NULL;
  newmenu->hotkey = Key;
  if (Menus==NULL)
   Menus = newmenu;
  else
   {
    tempM = Menus;
    while(tempM->NextMenu != NULL)
     tempM = tempM->NextMenu;
    tempM->NextMenu = newmenu;
   }
  pos = 0;
  epos = 0;
  while (epos != -1)
   {
    epos = find_char(items,',',pos);
    temp = mids(items,pos,((epos == -1) ? strlen(items) : epos)-pos);
    pos = epos + 1;
    newitem = new(itemTYPE);
    if (!newitem)
     {
      closegraph();
      cerr << "Memory allocation error while making menu item."<<endl;
      exit(1);
     }
    memcpy(newitem->Item,0,40);
    strncpy(newitem->Item,temp,39);
    newitem->X=0;
    newitem->Y=0;
    newitem->Width=0;
    newitem->Height=0;
    newitem->NextItem=NULL;
    if (newmenu->Items==NULL)
     newmenu->Items = newitem;
    else
     {
      tempI = newmenu->Items;
      while(tempI->NextItem != NULL)
      tempI = tempI->NextItem;
      tempI->NextItem = newitem;
     }
   }
 }

void menubar::delmenu(int no)
 {
  int i;
  MenuTYPE *tempM, *prevM;
  itemTYPE *tempI, *prevI;
  tempM=Menus;
  prevM=NULL;
  pushup();
  for (i=1; i<no; ++i) // Find the no'th menu. if end reached, return.
   {
    if (tempM==NULL)
     return;
    prevM = tempM;
    tempM = tempM->NextMenu;
   }
  if (tempM==NULL)
   return;
  if (Menus == tempM)
   Menus = tempM->NextMenu;
  else
   prevM->NextMenu = tempM->NextMenu;
  tempI = tempM->Items;
  prevI = NULL;
  while (tempI != NULL)
   {
    prevI = tempI;
    tempI = tempI->NextItem;
    free(prevI);
   }
  free (tempM);
 }

void menubar::setbkgclr(int C)
 {
  Color = C;
 }

void menubar::sethkhiclr(int C)
 {
  HkHiColor = C;
 }

void menubar::settextclr(int C)
 {
  TxtColor = C;
 }

void menubar::sethighclr(int C)
 {
  HiColor = C;
 }


void menubar::show()
 {
  MenuTYPE *tempM;
  int tempX;
  int orig_color;
  int i,
      i2;
  char temp[2] =" ";
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  if (Height-2*Depth < textheight("AjBg")+2)
   Height = textheight("AjBg")+2*Depth+2;
  panel::show();
  tempM = Menus;
  tempX = X+Depth+5;
  while (tempM != NULL)
   {
    setcolor(TxtColor);
    settextjustify(LEFT_TEXT,CENTER_TEXT);
    for (i = 0, i2 = 0; *(tempM->Heading+i) != (char)0x00 ;++i, ++ i2)
     {
      strncpy(temp,tempM->Heading+i,1);
      if (*(tempM->Heading+i) == '~')
       {
	setcolor(HkHiColor);
	strncpy(temp,tempM->Heading+(++i),1);
	outtextxy(tempX+i2*textwidth("A"), Y+(Height/2),temp);
	setcolor(TxtColor);
       }
      else
       outtextxy(tempX+i2*textwidth("A"), Y+(Height/2), temp);
     }
    tempM->X = tempX-4;
    tempM->Y = Y+Depth;
    tempM->Width = textwidth(tempM->Heading)+8;
    tempM->Height = Height-2*Depth;
    tempX = tempX + tempM->Width + 8;
    tempM = tempM->NextMenu;
   }
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  settextjustify(textinfo.horiz,textinfo.vert);
  mouse.show();
  MenuSelected = 0;
 }

void menubar::pulldown()
 {
  MenuTYPE *TempM;
  itemTYPE *TempI;
  int i, Wth, Tht, highlt[10], tempY;
  size_t Sze;
  unsigned int L_P_P,
	       offset;
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  TempM = Menus;
  if ((!MenuSelected) || (!isShown) || (PulledDown))
   return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  NumItems = 0;
  for (i=1; i < MenuSelected; ++i)
   TempM = TempM->NextMenu;
  TempI = TempM->Items;
  Wth = 0;
  while (TempI != NULL)
   {
    if (strcmp(TempI->Item,"LINE"))
     if (Wth < textwidth(TempI->Item))
      Wth = textwidth(TempI->Item);
    TempI = TempI->NextItem;
   }
  TempI = TempM->Items;
  Tht = 0;
  Wth = Wth + 8;
  while (TempI != NULL)
   {
    TempI->Width = Wth;
    TempI->Height = textheight(TempI->Item)+4;
    Tht += strcmp(TempI->Item,"LINE") ? textheight(TempI->Item)+4 : 5;
    TempI = TempI->NextItem;
   }
  Tht = Tht + 11;
  BX=(TempM->X-1);
  BY=(Y+Height-Depth+1);
  BW=(TempM->X+Wth+10);
  BH=(Y+Height-Depth+Tht+1);
  Sze = imagesize(BX,BY,BW,BH);
  L_P_P = ((16 * 1024) - 8)/(BW-BX+1);
  MenuBkgPages = ceil((float)(BH-BY+1) / (float)L_P_P);
  if ((emm_type()) && (emm_pgsleft() >= MenuBkgPages) && ((MenuBkgHndl = emm_maloc(MenuBkgPages)) != 0))
   {
    for (offset = 0,i = 0;i < MenuBkgPages; ++i, offset += L_P_P)
     {
		MenuBackBuffer = emm_map(MenuBkgHndl,1,i);
		if (!MenuBackBuffer)
		 {
		  closegraph();
		  cerr<<"Error allocating memory for PDM background in menubar."<<endl;
		  exit(1);
		 }
		if ((offset+L_P_P) < (BH-BY))
		 getimage(BX,BY+offset,BW,BY+offset+L_P_P-1,MenuBackBuffer);
		else
		 getimage(BX,BY+offset,BW,BH,MenuBackBuffer);
	  }
	}
  else
	{
	 MenuBkgPages = 0;
	 if (!(MenuBackBuffer = (char far *)farmalloc(Sze)))
	  {
		closegraph();
		cerr<<"Error allocating memory for PDM background in menubar."<<endl;
		exit(1);
	  }
	 getimage (BX,BY,BW,BH,MenuBackBuffer);
	}
	 // Header //
  setcolor(Color); // Bar Face
  setfillstyle(SOLID_FILL,Color);
  bar ((TempM->X),(Y+Height-Depth+1),(TempM->X+Wth+8),(Y+Height-Depth+5));
  setcolor(DARKGRAY);  // Bar Shadows.
  setfillstyle(SOLID_FILL,DARKGRAY);
  bar ((TempM->X+3),(Y+Height-Depth+4),(TempM->X+Wth+4),(Y+Height-Depth+5));
  bar ((TempM->X+Wth+8),(Y+Height-Depth+1),(TempM->X+Wth+9),(Y+Height-Depth+5));
  setcolor(Color+8);  // Bar Reflections.
  setfillstyle(SOLID_FILL,Color+8);
  highlt[0] = TempM->X; highlt[1] = Y+Height-Depth+1;
  highlt[2] = highlt[0]-1; highlt[3] = highlt[1]+1;
  highlt[4] = highlt[2] ; highlt[5] = highlt[3]+3;
  highlt[6] = highlt[0] ; highlt[7] = highlt[5];
  highlt[8] = highlt[0] ; highlt[9] = highlt[1];
  fillpoly (5, highlt);
  highlt[0] = highlt[0] + Wth+5; highlt[1] = highlt[1] + 3;
  highlt[2] = highlt[0]-1; highlt[3] = highlt[1]+1;
  highlt[4] = highlt[0]; highlt[5] = highlt[3];
  highlt[6] = highlt[0]; highlt[7] = highlt[1];
  fillpoly(4, highlt);
  tempY = Y+Height-Depth+6;
  TempI = TempM->Items;
  for(TempI = TempM->Items ; TempI != NULL ; TempI = TempI->NextItem)
	{
	 TempI->X = TempM->X+5; TempI->Y = tempY;
	 if (strcmp(TempI->Item,"LINE")) // other than a LINE.
	  {
		if (strcmp(TempI->Item,"")) // If not blank,
		 ++NumItems;                // Increment NumItems in this menu.
		setcolor(Color);
		setfillstyle(SOLID_FILL,Color);
		bar((TempM->X),(tempY),(TempM->X+Wth+9),(tempY+TempI->Height-1));
		setcolor(DARKGRAY);
		setfillstyle(SOLID_FILL,DARKGRAY);
		bar((TempM->X+3),(tempY),(TempM->X+4),(tempY+TempI->Height-1));
		bar((TempM->X+Wth+8),(tempY),TempM->X+Wth+9,(tempY+TempI->Height-1));
		setcolor(Color+8);
		setfillstyle(SOLID_FILL,Color+8);
		bar((TempM->X-1),(tempY),(TempM->X),(tempY+TempI->Height-1));
		bar((TempM->X+Wth+4),(tempY),(TempM->X+Wth+5),(tempY+TempI->Height-1));
		setcolor(TxtColor);
		settextjustify(LEFT_TEXT,CENTER_TEXT);
		outtextxy((TempM->X+8),(tempY+(TempI->Height/2)),TempI->Item);
		tempY = tempY + TempI->Height;
	  }
	 else // it is a LINE.
	  {
		setcolor(Color);
		setfillstyle(SOLID_FILL,Color);
		bar((TempM->X),tempY,(TempM->X+Wth+8),(tempY+4));
		setcolor(DARKGRAY);
		setfillstyle(SOLID_FILL,DARKGRAY);
		bar((TempM->X+3),(tempY+3),(TempM->X+Wth+5),(tempY+4));
		bar((TempM->X+Wth+8),tempY,(TempM->X+Wth+9),(tempY+4));
		setcolor(Color+8);
		setfillstyle(SOLID_FILL,Color+8);
		bar((TempM->X-1),tempY,(TempM->X),(tempY+4));
		bar((TempM->X+3),tempY,(TempM->X+Wth+5),(tempY+1));
		setcolor(DARKGRAY);
		setfillstyle(SOLID_FILL,DARKGRAY);
		highlt[0]=TempM->X+3; highlt[1]=tempY;
		highlt[2]=highlt[0] ; highlt[3]=tempY+1;
		highlt[4]=highlt[0]+1;highlt[5]=highlt[1];
		highlt[6]=highlt[0] ; highlt[7]=highlt[1];
		fillpoly(4,highlt);
		setcolor(Color+8);
		setfillstyle(SOLID_FILL,Color+8);
		highlt[0]=TempM->X+Wth+5 ; highlt[1]=tempY+3;
		highlt[2]=highlt[0]-1 ; highlt[3]=highlt[1]+1;
		highlt[4]=highlt[0] ; highlt[5] = highlt[3];
		highlt[6]=highlt[0] ; highlt[7] = highlt[1];
		fillpoly(4,highlt);
		tempY = tempY + 5;
	  }
	}
  setcolor(DARKGRAY);
  setfillstyle(SOLID_FILL,DARKGRAY);
  bar((TempM->X-1),tempY,(TempM->X+Wth+9),(tempY+5));
  setcolor(Color);
  setfillstyle(SOLID_FILL,Color);
  bar((TempM->X),tempY,(TempM->X+Wth+7),(tempY+3));
  setcolor(Color+8);
  setfillstyle(SOLID_FILL,Color+8);
  bar((TempM->X+3),tempY,(TempM->X+Wth+5),tempY+1);
  highlt[0]=TempM->X-1; highlt[1]=tempY;
  highlt[2]=TempM->X  ; highlt[3]=tempY;
  highlt[4]=highlt[2] ; highlt[5]=tempY+3;
  highlt[6]=highlt[0] ; highlt[7]=tempY+5;
  highlt[8]=highlt[0] ; highlt[9]=highlt[1];
  fillpoly(5,highlt);
  setcolor(DARKGRAY);
  setfillstyle(SOLID_FILL,DARKGRAY);
  highlt[0]=TempM->X+3 ; highlt[1]=tempY;
  highlt[2]=highlt[0]  ; highlt[3]=tempY+1;
  highlt[4]=highlt[0]+1; highlt[5]=highlt[1];
  highlt[6]=highlt[0]  ; highlt[7]=highlt[1];
  fillpoly(4,highlt);
  setcolor(orig_color);
  settextjustify(textinfo.horiz,textinfo.vert);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
  PulledDown=1;
 }

void menubar::pushup()
 {
  unsigned L_P_P,
		offset;
  int      i;

  if ((!MenuSelected) || (!isShown) || (!PulledDown))
	return;
  mouse.hide();
  L_P_P = ((16 * 1024) - 8)/(BW-BX+1);
  if (MenuBackBuffer)
	{
	 if (MenuBkgPages)
	  {
		for (offset = 0,i = 0;i < MenuBkgPages; ++i, offset += L_P_P)
		 {
	MenuBackBuffer = emm_map(MenuBkgHndl,1,i);
	if (MenuBackBuffer)
	 putimage(BX,BY+offset,MenuBackBuffer,COPY_PUT);
		 }
	  }
	 else
	  putimage (BX,BY,MenuBackBuffer,COPY_PUT);
	}
  if (MenuBackBuffer)
	{
	 if (MenuBkgPages)
	  emm_free (MenuBkgHndl);
	 else
	  farfree(MenuBackBuffer);
	 MenuBackBuffer = NULL;
	 MenuBkgHndl = 0;
	}
  mouse.show();
  PulledDown=0;
 }

int menubar::menuhit()
 {
  MenuTYPE *TempM;
  int Number;

  for (TempM = Menus, Number = 1; TempM != NULL ; TempM = TempM->NextMenu, ++Number)
	{
	 if (isShown)
	  if ((mouse.getmX() >= TempM->X) && (mouse.getmX() <= (TempM->X+TempM->Width-1)))
		if ((mouse.getmY() >= TempM->Y) && (mouse.getmY() <= (TempM->Y+TempM->Height-1)))
		 return(Number);
	}
  return (0);
 }

int menubar::pdhit()
 {
  if (PulledDown)
	if ((mouse.getmX() >=BX) && (mouse.getmX() <= BX+BW+-1))
	 if ((mouse.getmY() >=BY) && (mouse.getmY() <= BY+BH-1))
	  return(1);
  return (0);
 }

int menubar::itemhit()
 {
  int i, Number;
  MenuTYPE *TempM;
  itemTYPE *TempI;

  if (!MenuSelected || !isShown)
	return (0);
  TempM = Menus;
  for (i=1; i < MenuSelected; ++i)
	TempM = TempM->NextMenu;
  for ((TempI = TempM->Items), (Number = 1); TempI != NULL; TempI = TempI->NextItem)
	if (strcmp(TempI->Item,"LINE") && strcmp(TempI->Item,""))
	 {
	  if ((mouse.getmX() >= TempI->X) && (mouse.getmX() <= (TempI->X+TempI->Width-1)))
		if ((mouse.getmY() >= TempI->Y) && (mouse.getmY() <= (TempI->Y+TempI->Height-1)))
		 return(Number);
	  ++Number;
	 }
  return (0);
 }

void menubar::menuselect(int no)
 {
  int i,             // Counter for loop
		j,
		j2;
  char temp[2]=" ";
  MenuTYPE *tempM;   // Pointer to current menu.
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if (!isShown || !no)
	return;
  tempM = Menus;
  for (i=1; (i<no) && (tempM != NULL) ; ++i)       // Step 1: Find the right menu.
	tempM = tempM->NextMenu;
  if (tempM == NULL) // that menu doesn't exist.
	return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  setcolor(HiColor);         // Step 2: Draw the highlight bar.
  setfillstyle(SOLID_FILL,HiColor);
  bar((tempM->X+1),(tempM->Y+1),(tempM->X+tempM->Width),(tempM->Y+tempM->Height-2));
  setcolor(TxtColor);        // Step 3: Re-draw tht menu heading.
  settextjustify(LEFT_TEXT,CENTER_TEXT);
  for (j = 0, j2 = 0; *(tempM->Heading+j) != (char)0x00 ;++j, ++ j2)
	{
	 strncpy(temp,tempM->Heading+j,1);
	 if (*(tempM->Heading+j) == '~')
	  {
		setcolor(HkHiColor);
		strncpy(temp,tempM->Heading+(++j),1);
		outtextxy((tempM->X+4)+(j2*textwidth("A")), tempM->Y+(tempM->Height/2), temp);
		setcolor(TxtColor);
	  }
	 else
	  outtextxy((tempM->X+4)+(j2*textwidth("A")), tempM->Y+(tempM->Height/2), temp);
	}
  MenuSelected = no;         // Step 4: Set the appropriate flags.
  setcolor(orig_color);
  settextjustify(textinfo.horiz,textinfo.vert);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void menubar::itemselect(int no)
 {
  int i;             // Counter for loop.
  MenuTYPE *tempM;   // Pointer to current menu.
  itemTYPE *tempI;   // Pointer to current item in the menu.
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if ((!isShown) || (!MenuSelected) || (!PulledDown) || (!no))
	return;
  tempM = Menus;
  for (i=1;(i<MenuSelected) && (tempM != NULL) ; ++i)  // Step 1: Find the right menu.
	tempM = tempM->NextMenu;
  if (tempM == NULL) // That menu doesn't exist.
	return;
  i=0;
  tempI = tempM->Items;
  while (tempI != NULL)         // Step 2: Find the right item, skipping blanks and LINEs.
	{
	 if (strcmp(tempI->Item,"LINE") && strcmp(tempI->Item,""))
	  ++i;
	 if (i == no)
	  break;
	 tempI = tempI->NextItem;
	}
  if (tempI == NULL) // That item doesn't exist.
	return;

  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  setcolor(HiColor);                              // Step 3: Draw the highlight bar.
  setfillstyle(SOLID_FILL,HiColor);
  bar((tempI->X+1),(tempI->Y),(tempI->X+tempI->Width-3),(tempI->Y+tempI->Height-1));
  setcolor(TxtColor);                             // Step 4: Re-draw tht menu item.
  settextjustify(LEFT_TEXT,CENTER_TEXT);
  outtextxy((tempI->X+3),(tempI->Y+(tempI->Height/2)),tempI->Item);
  ItemSelected = no;                              // Step 5: Set the appropriate flags.
  setcolor(orig_color);
  settextjustify(textinfo.horiz,textinfo.vert);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void menubar::itemclear()
 {
  int i;             // Counter for loop.
  MenuTYPE *tempM;   // Pointer to current menu.
  itemTYPE *tempI;   // Pointer to current item in the menu.
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if ((!isShown) || (!MenuSelected) || (!ItemSelected)|| (!PulledDown))
	return;
  tempM = Menus;
  for (i=1; (i<MenuSelected) && (tempM != NULL) ; ++i)  // Step 1: Find the right menu.
	tempM = tempM->NextMenu;
  if (tempM == NULL) // That menu doesn't exist.
	return;
  i=0;
  tempI = tempM->Items;
  while (tempI != NULL)  // Step 2: Find the right item, skipping blanks and LINEs.
	{
	 if (strcmp(tempI->Item,"LINE") && strcmp(tempI->Item,""))
	  ++i;
	 if (i == ItemSelected)
	  break;
	 tempI = tempI->NextItem;
	}
  if (tempI == NULL) // That item doesn't exist.
	return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  setlinestyle(0,1,0);
  setcolor(Color);                             // Step 3: Erase the highlight bar.
  setfillstyle(SOLID_FILL,Color);
  bar((tempI->X+1),(tempI->Y),(tempI->X+tempI->Width-3),(tempI->Y+tempI->Height-1));
  setcolor(TxtColor);                             // Step 4: Re-draw tht menu item.
  settextjustify(LEFT_TEXT,CENTER_TEXT);
  outtextxy((tempI->X+3),(tempI->Y+(tempI->Height/2)),tempI->Item);
  ItemSelected = 0;                               // Step 5: Set the appropriate flags.
  setcolor(orig_color);
  settextjustify(textinfo.horiz,textinfo.vert);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  mouse.show();
 }

void menubar::menuclear()
 {
  int i;             // Counter for loop
  int j,
      j2;
  char temp[2] = " ";
  MenuTYPE *tempM;   // Pointer to current menu.
  int orig_color;
  struct fillsettingstype orig_settings;
  struct linesettingstype orig_line;
  struct textsettingstype textinfo;

  if (!isShown || !MenuSelected)
   return;
  tempM = Menus;
  for (i=1; (i<MenuSelected) && (tempM != NULL) ; ++i)       // Step 1: Find the right menu.
   tempM = tempM->NextMenu;
  if (tempM == NULL) // That menu doesn't exist.
   return;
  mouse.hide();
  orig_color=getcolor();
  getfillsettings(&orig_settings);
  getlinesettings(&orig_line);
  gettextsettings(&textinfo);
  NumItems = 0;
  setlinestyle(0,1,0);
  setcolor(Color);         // Step 2: Erase the highlight bar.
  setfillstyle(SOLID_FILL,Color);
  bar((tempM->X+1),(tempM->Y+1),(tempM->X+tempM->Width),(tempM->Y+tempM->Height-2));
  setcolor(TxtColor);        // Step 3: Re-draw tht menu heading.
  settextjustify(LEFT_TEXT,CENTER_TEXT);
  for (j = 0, j2 = 0; *(tempM->Heading+j) != (char)0x00 ;++j, ++ j2)
   {
    strncpy(temp,tempM->Heading+j,1);
    if (*(tempM->Heading+j) == '~')
     {
      setcolor(HkHiColor);
      strncpy(temp,tempM->Heading+(++j),1);
      outtextxy((tempM->X+4)+(j2*textwidth("A")), tempM->Y+(tempM->Height/2), temp);
      setcolor(TxtColor);
     }
    else
     outtextxy((tempM->X+4)+(j2*textwidth("A")), tempM->Y+(tempM->Height/2), temp);
   }
  MenuSelected = 0;         // Step 4: Set the appropriate flags.
  setcolor(orig_color);
  setfillstyle(orig_settings.pattern, orig_settings.color);
  setlinestyle(orig_line.linestyle, orig_line.upattern, orig_line.thickness);
  settextjustify(textinfo.horiz,textinfo.vert);
  mouse.show();
 }

int menubar::itemselected()
 {
  return(ItemSelected);
 }

int menubar::menuselected()
 {
  return(MenuSelected);
 }

void menubar::checkforevent()
 {
  int chr;
  MenuTYPE *MenuPtr;
  int i,
      MenuNo;

  lastMenuSelected = 0;
  lastItemSelected = 0;
  if (keyhit() || (mouse.getbutton(LEFT_BTN) && menuhit()) ||
      (menuselected())) // If event happening, continue.
   {
    if (keyhit())     // If it's a keyboard event
     {
      if (( chr = getkey()) > 255)  // See if it's an extended key.
       {
	chr = chr & 0xff;
	if (chr == 68)            // Is is F-10?
	 menuselect(1);         // If so, just select menu 1
	else                    // if not, see if it's a hotkey!
	 {
	  MenuPtr = Menus;
	  MenuNo = 0;
	  while (MenuPtr != NULL) // Check all the menus if need be.
	   {
	    ++MenuNo;
	    if (chr == MenuPtr->hotkey) // Is this the one we want?
	     {
	      menuselect(MenuNo);     // Select it.
	      pulldown();
	      break;
	     }
	    MenuPtr = MenuPtr->NextMenu; // If not, go to the next one.
		}
	  if (MenuPtr == NULL) // If that was not a hotkey
		{
		 putbk(chr+256);
		 return;       // and return.
		}
	 }
		 }
		else // If it wasn't an extened key in the first place,
		 {
	putbk(chr);  // Put it back
	return;       // And return.
		 }
	  }
	 while (1) // The Menu/Item select loop.
	  {
		if (menuhit() && mouse.getbutton(LEFT_BTN)) // If the mouse clicks on a menu
		 {
	pushup();                  // Clear any previous menu
	menuclear();
	menuselect(menuhit());     // Select the new menu
	pulldown();                // Pull it down
	itemselect(1);
	do{}while(mouse.btnpressed()); // Wait for button release.
		 }
		if (itemhit() && mouse.getbutton(LEFT_BTN)) // If the mouse clicks on an item
		 {
	itemclear();                     // Clear any previous item.
	itemselect(itemhit());           // Select the new one.
	do{}while(mouse.btnpressed());   // Wait for button release.
	lastItemSelected = ItemSelected; // Indicate the selection
	lastMenuSelected = MenuSelected;
	itemclear();                     // Clean up the menubar
	pushup();
	menuclear();
	return;                          // and return.
		 }
		if (mouse.getbutton(LEFT_BTN) && (!menuhit() || !pdhit()))
		 {
	// If clicked outside the menubar area.
	itemclear();          // clear everything
	pushup();
	menuclear();
	lastItemSelected = 0;
	lastMenuSelected = 0;
	return;               // and return.
		 }
		if (keyhit())              // If it's a keyboard selection,
		 {
	chr = getkey();            // get the key.
	if (chr == 27)            // If it's the escape key,
	 {
	  itemclear();          // clear everything
	  pushup();
	  menuclear();
	  lastItemSelected = 0;
	  lastMenuSelected = 0;
	  return;               // and return.
	 }
	if (chr == 13)            // If it's the ENTER key,
	 {
	  if (!PulledDown)      // and no menu is selected,
	   {
	    pulldown();         // Select it.
	    itemselect(1);
	   }
	  else                  // Otherwise indicate the selected item,
	   {
	    lastItemSelected = ItemSelected;
	    lastMenuSelected = MenuSelected;
	    itemclear();        // Clean up the menubar,
	    pushup();
	    menuclear();
	    return;             // and return.
	   }
	 }
	if (chr  > 255)  // If it's an extended key, check for the arrows.
	 {
	  chr = chr & 0xff;
	  if (chr == 72) // If it's an up arrow,
	   {
	    i = ItemSelected;
	    itemclear();      // Clear the old item.
	    itemselect(((i-1)>0) ? (i-1) : 1); // Select the previous item.
	   }
	  else if (chr == 80) // If it's a down arrow
	   {
	    if (PulledDown)   // and a menu's pulled down,
	     {
	      i = ItemSelected; // Clear the old item selected
	      itemclear();
	      itemselect(((i+1)<=NumItems) ? (i+1) : NumItems);  // and select the next one down.
		  }
	    else     // But if no menu's selected,
	     {
	      pulldown();    // Select one.
	      itemselect(1);
	     }
	   }
	  else if (chr == 77) // If it's a right arrow,
	   {
	    i = MenuSelected; // Get the old menu
	    if (PulledDown)
	     {
	      itemclear();   // Clean up the menubar,
	      pushup();
	      menuclear();
	      menuselect (((i+1)<=NumMenus) ? (i+1) : NumMenus); // and select the next menu over.
	      pulldown();
	      itemselect(1);
	     }
	    else
	     {
	      menuclear();
	      menuselect (((i+1)<=NumMenus) ? (i+1) : NumMenus); // and select the next menu over.
	     }
	   }
	  else if (chr == 75) // If it's a left arrow,
	   {
	    i = MenuSelected; // Get the old one,
	    if (PulledDown)
	     {
	      itemclear();      // Clear it
	      pushup();
	      menuclear();
	      menuselect (((i-1) >0) ? (i-1) : 1); // and select the next one over.
	      pulldown();
			itemselect(1);
	     }
	    else
	     {
	      menuclear();
	      menuselect (((i-1) >0) ? (i-1) : 1); // and select the next one over.
	     }
	   }
	  else // check for a hotkey for another menu.
	   {
	    MenuPtr = Menus;
	    MenuNo = 0;
	    while (MenuPtr != NULL) // Check all the menus if need be.
	     {
	      ++MenuNo;
	      if (chr == MenuPtr->hotkey) // Is this the one we want?
	       {
		itemclear();
		pushup();
		menuclear();
		menuselect(MenuNo);     // Select it.
		pulldown();
		break;
	       }
	      MenuPtr = MenuPtr->NextMenu; // If not, go to the next one.
	     }
	   }
	 }
       }
     } // end while(1).
   }
 }

int menubar::lastevntitem()
 {
  return (lastItemSelected);
 }

int menubar::lastevntmenu()
 {
  return (lastMenuSelected);
 }

int menubar::htkypressed()
 {
  int chr;
  MenuTYPE *MenuPtr;
  int MenuNo = 0;

  if (keyhit())     // If it's a keyboard event
   {
    if ((chr = getkey()) > 255)  // See if it's an extended key.
     {
      chr = chr & 0xff;  // Get the actual code.
      MenuPtr = Menus;
      MenuNo = 0;
      while (MenuPtr != NULL) // Check all the menus if need be.
       {
	++MenuNo;
	if (chr == MenuPtr->hotkey) // Is this the one we want?
	 {
	  putbk(chr + 256);
	  break;
	 }
	MenuPtr = MenuPtr->NextMenu; // If not, go to the next one.
       }
      if (MenuPtr == NULL) // If that was not a hotkey
       {
	putbk(chr + 256);
	return 0;
		 }
     }
    else // If it wasn't an extened key in the first place,
     {
      putbk (chr);  // Put it back
      return 0;       // And return.
     }
   }
  return MenuNo;  // Finally, If it was a hotkey, return the menu number.
 }

int menubar::ishtkey(int keypd)
 {
  char chr;
  MenuTYPE *MenuPtr;
  int MenuNo;

  chr = (char)keypd; // Get just the lower byte.
  MenuPtr = Menus;
  MenuNo = 0;
  while (MenuPtr != NULL) // Check all the menus if need be.
   {
    ++MenuNo;
    if (chr == MenuPtr->hotkey) // Is this the one we want?
     break;
    MenuPtr = MenuPtr->NextMenu; // If not, go to the next one.
   }
  if (MenuPtr == NULL) // If that was not a hotkey
   return 0;       // and return.
  return MenuNo;  // Finally, If it was a hotkey, return the menu number.
 }

static int KBBUF;

int getkbflags()
 {
  REGS regs;
  regs.h.ah = 0x02;
  int86(0x16,&regs,&regs);
  return (int)regs.h.al;
 }

int keyhit()
 {
  int Rdy;
  REGS regs;
  if (KBBUF != 0)
   return 1;
  regs.h.ah = 0x01;
  int86 (0x16,&regs,&regs);
  if (regs.x.flags & 0x0040)
   return 0;
  return 1;
 }

int getkey()
 {
  int keypd;
  REGS regs;

  if (KBBUF != 0)
   keypd = KBBUF;
  else
   {
    regs.h.ah = 0x00;
    int86(0x16,&regs,&regs);
    if (regs.h.al == 0x00)
     keypd = 256 + regs.h.ah;
    else
     keypd = regs.h.al;
   }
  KBBUF = 0;
  return keypd;
 }

int putbk(int keypb)
 {
  if (KBBUF == 0)
	{
    KBBUF = keypb;
    return 1;
   }
  return 0;
 }

vscroll::vscroll(int x, int y, int w, int h, int hdh, int bht, int bc, int hc, int bkgc, int k)
 : panel (x+1,y+1,w-2,h-2,1,IN,bkgc,k)
 {
  int error = 0;
  char UpChr[2] = {24,0},
       DnChr[2] = {25,0};

  Min_Position = 0;
  Max_Position = 100;
  Curr_Position = 0;
  Lines_Per_Page = 5;
  if ((bht < 10) || (w < 14))
   {
    strcpy(UpChr,"");
    strcpy(DnChr,"");
   }
  Dn = new button(x+2,y+h-bht-1,w-4,bht,2,bc,0,TEXT,DnChr,0);
   if (!Dn)
    error = 1;
  Up = new button(x+2,y+1,w-4,bht,2,bc,0,TEXT,UpChr,0);
   if (!Up)
    error = 1;
  Hnd = new panel(x+2,y+bht+5,w-4,hdh,1,OUT,hc,1);
   if (!Hnd)
    error = 1;
  HDH = hdh;
  BTH = bht;
  if (error)
   {
    if (Up)
     delete Up;
	 if (Dn)
	  delete Dn;
	 if (Hnd)
	  delete Hnd;
	 closegraph();
	 cerr << "Memory allocation error in vscroll::vscroll." << endl;
	}
 }

vscroll::~vscroll()
 {
  delete Up;
  delete Dn;
  delete Hnd;
 }

void vscroll::setrange(int min, int max)
 {
  Min_Position = min;
  Max_Position = max;
  if (Curr_Position < Min_Position)
   Curr_Position = Min_Position;
  if (Curr_Position > Max_Position)
   Curr_Position = Max_Position;
 }

void vscroll::hide(void)
 {
  if (!isShown)
	return;
  Hnd->hide();
  Up->hide();
  Dn->hide();
  panel::hide();
 }

void vscroll::show(void)
 {
  float Step_Size;
  int Ycord;

  panel::show();
  Up->show();
  Dn->show();
  Hnd->show();
  if ((Max_Position-Min_Position) == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Height-8-(2*BTH)-HDH)/(float)(Max_Position-Min_Position);
  Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
  Ycord = (Ycord > 0) ? Ycord : 0;
  Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-8-(2*BTH)-HDH);
  Hnd->moveto(X+2,Y+BTH+4+Ycord);
 }

void vscroll::setpos(int p)
 {
  float Step_Size;
  int Ycord;
  if ((Max_Position-Min_Position) == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Height-8-(2*BTH)-HDH)/(float)(Max_Position-Min_Position);
  Curr_Position = (p >= Min_Position)? p : Min_Position;
  Curr_Position = (p <= Max_Position)? Curr_Position  : Max_Position;
  Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
  Ycord = (Ycord > 0) ? Ycord : 0;
  Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-8-(2*BTH)-HDH);
  Hnd->moveto(X+2,Y+BTH+4+Ycord);
 }

int vscroll::getpos(void)
 {
  return Curr_Position;
 }

int vscroll::uphit(void)
 {
  return Up->hit();
 }

int vscroll::dnhit(void)
 {
  return Dn->hit();
 }

int vscroll::hndhit(void)
 {
  return Hnd->hit();
 }

void vscroll::uppres(void)
 {
  Up->select();
 }

void vscroll::dnpres(void)
 {
  Dn->select();
 }

void vscroll::uprels(void)
 {
  Up->show();
 }

void vscroll::dnrels(void)
 {
  Dn->show();
 }

int vscroll::getevent(void)
 {
  time_t Intl;
  float Step_Size;
  int Ycord,
      Last_Y;

  if ((Max_Position-Min_Position) == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Height-8-(2*BTH)-HDH)/(float)(Max_Position-Min_Position);
  if (mouse.getbutton(LEFT_BTN) & panel::hit())
   {
    if (Up->hit())
     {
      Up->select();
      Curr_Position = (Curr_Position > Min_Position) ? --Curr_Position : Min_Position;
      Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
      Ycord = (Ycord > 0) ? Ycord : 0;
      Hnd->moveto(X+2,Y+BTH+4+Ycord);
      Intl = clock();
      while (mouse.btnpressed())
       while (((clock()-Intl) > CLK_TCK ) && mouse.btnpressed() && Up->hit())
        {
         Curr_Position = (Curr_Position > Min_Position) ? --Curr_Position : Min_Position;
         Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
         Ycord = (Ycord > 0) ? Ycord : 0;
         Hnd->moveto(X+2,Y+BTH+4+Ycord);
         delay(50);
        }
       Up->show();
       Last_Y = Ycord;
     }
    else if (Dn->hit())
     {
      Dn->select();
      Curr_Position = (Curr_Position < Max_Position)? ++Curr_Position  : Max_Position;
      Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
      Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-8-(2*BTH)-HDH);
      Hnd->moveto(X+2,Y+BTH+4+Ycord);
      Intl = clock();
      while (mouse.btnpressed())
       while (((clock()-Intl) > CLK_TCK) && mouse.btnpressed() && Dn->hit())
        {
         Curr_Position = (Curr_Position < Max_Position)? ++Curr_Position  : Max_Position;
         Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
         Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-6-(2*BTH)-HDH);
         Hnd->moveto(X+2,Y+BTH+4+Ycord);
         delay(50);
        }
       Dn->show();
       Last_Y = Ycord;
     }
    else if (hit() && !Dn->hit() && !Up->hit() && !Hnd->hit())
     {
      if (mouse.getmY() < Hnd->getY()) // Clicked on Page Up.
       {
        Curr_Position = (Curr_Position >= Min_Position+Lines_Per_Page) ? (Curr_Position - Lines_Per_Page) : Min_Position;
        Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
        Ycord = (Ycord > 0) ? Ycord : 0;
        Hnd->moveto(X+2,Y+BTH+4+Ycord);
        Intl = clock();
        while (mouse.btnpressed())
         while (((clock()-Intl) > CLK_TCK ) && mouse.btnpressed() && hit())
          {
           Curr_Position = (Curr_Position >= Min_Position+Lines_Per_Page) ? (Curr_Position - Lines_Per_Page) : Min_Position;
           Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
           Ycord = (Ycord > 0) ? Ycord : 0;
           Hnd->moveto(X+2,Y+BTH+4+Ycord);
           delay(50);
          }
        Last_Y = Ycord;
       }
      else // else, clicked Page Down.
       {
        Curr_Position = (Curr_Position <= Max_Position-Lines_Per_Page)? (Curr_Position + Lines_Per_Page)  : Max_Position;
        Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
        Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-8-(2*BTH)-HDH);
        Hnd->moveto(X+2,Y+BTH+4+Ycord);
        Intl = clock();
        while (mouse.btnpressed())
         while (((clock()-Intl) > CLK_TCK) && mouse.btnpressed() && hit())
          {
           Curr_Position = (Curr_Position <= Max_Position-Lines_Per_Page)? (Curr_Position + Lines_Per_Page)  : Max_Position;
           Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
           Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-6-(2*BTH)-HDH);
           Hnd->moveto(X+2,Y+BTH+4+Ycord);
           delay(50);
          }
         Last_Y = Ycord;
       }
     }
    else if (Hnd->hit())
     {
      while (mouse.btnpressed())
       {
        Ycord = mouse.getmY();
        if (Step_Size == 0)
         Curr_Position = Min_Position;
        else
         {
          Curr_Position = ((Ycord-Y-BTH-8-HDH/2)/ Step_Size)+Min_Position;
          Curr_Position = (Curr_Position >= Min_Position)? Curr_Position : Min_Position;
          Curr_Position = (Curr_Position <= Max_Position)? Curr_Position : Max_Position;
         }
        Ycord = (int)(Step_Size*(Curr_Position-Min_Position));
        Ycord = (Ycord > 0) ? Ycord : 0;
        Ycord = (Ycord < Height-8-(2*BTH)-HDH) ? Ycord : (Height-8-(2*BTH)-HDH);
        if (Ycord != Last_Y)
         {
          Hnd->moveto(X+2,Y+BTH+4+Ycord);
          Last_Y = Ycord;
         }
       }
     }
    return 1;
   }
  return 0;
 }

void vscroll::resize (int w, int h)
 {
  if (isShown)
   {
    hide();
    Up->resize(w-2,BTH);
    Dn->resize(w-2,BTH);
    Dn->moveto(X+2,Y+h-BTH);
    Hnd->resize(w-2,HDH);
    panel::resize(w,h);
    show();
   }
  else
   {
    Up->resize(w-2,BTH);
    Dn->resize(w-2,BTH);
    Dn->moveto(X+2,Y+h-BTH);
    Hnd->resize(w-2,HDH);
    panel::resize(w,h);
   }
 }

void vscroll::setpagesize(int LPP)
 {
  Lines_Per_Page = LPP;
 }

void vscroll::moveto (int x, int y)
 {
  int Ycord;

  if (isShown)
   {
    hide();
    Up->moveto(x+2,y+2);
    Dn->moveto(x+2,y+Height-2-BTH);
    panel::moveto(x+1,y+1);
    show();
   }
  else
   {
    Up->moveto(x+2,y+2);
    Dn->moveto(x+2,y+Height-2-BTH);
    panel::moveto(x+1,y+1);
   }
 }

void vscroll::setbkgclr(int c)
 {
  panel::setbkgclr(c);
 }

void vscroll::setbtnclr(int c)
 {
  Up->setbkgclr(c);
  Dn->setbkgclr(c);
 }

void vscroll::sethdlclr(int c)
 {
  Hnd->setbkgclr(c);
 }

void vscroll::setarrclr(int c)
 {
  Up->setextclr(c);
  Dn->setextclr(c);
 }

hscroll::hscroll(int x, int y, int w, int h, int hdw, int bhw, int bc, int hc, int bkgc, int k)
 : panel (x+1,y+1,w-2,h-2,1,IN,bkgc,k)
 {
  int error = 0;
  char LfChr[2] = {27,0},
       RtChr[2] = {26,0};

  Lines_Per_Page = 5;
  Min_Position = 0;
  Max_Position = 100;
  Curr_Position = 0;
  if ((bhw < 10) || (h < 14))
   {
    strcpy(LfChr,"");
    strcpy(RtChr,"");
   }
  Lf = new button(x+2,y+2,bhw,h-4,2,bc,0,TEXT,LfChr,0);
  if (!Lf)
   error = 1;
  Rt = new button(x+w-bhw-2,y+2,bhw,h-4,2,bc,0,TEXT,RtChr,0);
  if (!Rt)
   error = 1;
  Hnd = new panel(x+5+bhw,y+2,hdw,h-4,1,OUT,hc,1);
  if (!Hnd)
   error = 1;
  HDW = hdw;
  BTW = bhw;
  if (error)
   {
    if (Lf)
     delete Lf;
    if (Rt)
     delete Rt;
    if (Hnd)
     delete Hnd;
    closegraph();
    cerr << "Memory allocation error in hscroll::hscroll." << endl;
   }
 }

hscroll::~hscroll()
 {
  delete Lf;
  delete Rt;
  delete Hnd;
 }

void hscroll::show(void)
 {
  float Step_Size;
  int Xcord;

  panel::show();
  Lf->show();
  Rt->show();
  Hnd->show();
  if (Max_Position-Min_Position == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Width-10-(2*BTW)-HDW)/(float)(Max_Position-Min_Position);
  Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
  Xcord = (Xcord > 0) ? Xcord : 0;
  Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
  Hnd->moveto(X+5+BTW+Xcord,Y+2);
 }

void hscroll::hide(void)
 {
  if (!isShown)
   return;
  Hnd->hide();
  Lf->hide();
  Rt->hide();
  panel::hide();
 }

void hscroll::setpos(int p)
 {
  float Step_Size;
  int Xcord;

  if (Max_Position-Min_Position == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Width-10-(2*BTW)-HDW)/(float)(Max_Position-Min_Position);
  Curr_Position = (p >= Min_Position)? p : Min_Position;
  Curr_Position = (p <= Max_Position)? Curr_Position  : Max_Position;
  Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
  Xcord = (Xcord > 0) ? Xcord : 0;
  Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
  Hnd->moveto(X+5+BTW+Xcord,Y+2);
 }

int hscroll::getpos(void)
 {
  return Curr_Position;
 }


int hscroll::lfhit(void)
{
 return Lf->hit();
}

int hscroll::rthit(void)
{
 return Rt->hit();
}

int hscroll::hndhit(void)
{
 return Hnd->hit();
}

void hscroll::lfpres(void)
{
 Lf->select();
}

void hscroll::rtpres(void)
{
 Rt->select();
}

void hscroll::lfrels(void)
{
 Lf->show();
}

void hscroll::rtrels(void)
{
 Rt->show();
}

void hscroll::setbkgclr(int c)
 {
  panel::setbkgclr(c);
 }

void hscroll::setbtnclr(int c)
 {
  Lf->setbkgclr(c);
  Rt->setbkgclr(c);
 }

void hscroll::sethdlclr(int c)
 {
  Hnd->setbkgclr(c);
 }

void hscroll::setarrclr(int c)
 {
  Lf->setextclr(c);
  Rt->setextclr(c);
 }

int hscroll::getevent(void)
 {
  time_t Intl;
  float Step_Size;
  int Xcord,
      Last_X;

  if (Max_Position-Min_Position == 0)
   Step_Size = 0;
  else
   Step_Size = (float)(Width-10-(2*BTW)-HDW)/(float)(Max_Position-Min_Position);
  if (mouse.getbutton(LEFT_BTN) & panel::hit())
   {
    if (Lf->hit())
     {
      Lf->select();
      Curr_Position = (Curr_Position > Min_Position) ? --Curr_Position : Min_Position;
      Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
      Xcord = (Xcord > 0) ? Xcord : 0;
      Hnd->moveto(X+5+BTW+Xcord,Y+2);
      Intl = clock();
      while (mouse.btnpressed())
       while (((clock()-Intl) > CLK_TCK ) && mouse.btnpressed() && Lf->hit())
	{
         Curr_Position = (Curr_Position > Min_Position) ? --Curr_Position : Min_Position;
         Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
         Xcord = (Xcord > 0) ? Xcord : 0;
         Hnd->moveto(X+5+BTW+Xcord,Y+2);
	 delay(50);
	}
      Last_X = Xcord;
      Lf->show();
     }
    else if (Rt->hit())
     {
      Rt->select();
      Curr_Position = (Curr_Position < Max_Position)? ++Curr_Position  : Max_Position;
      Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
      Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
      Hnd->moveto(X+5+BTW+Xcord,Y+2);
      Intl = clock();
      while (mouse.btnpressed())
       while (((clock()-Intl) > CLK_TCK) && mouse.btnpressed() && Rt->hit())
	{
         Curr_Position = (Curr_Position < Max_Position)? ++Curr_Position  : Max_Position;
         Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
         Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
         Hnd->moveto(X+5+BTW+Xcord,Y+2);
	 delay(50);
	}
      Last_X = Xcord;
      Rt->show();
     }
    else if (hit() && !Rt->hit() && !Lf->hit() && !Hnd->hit())
     {
      if (mouse.getmX() < Hnd->getX()) // Clicked on Page Left.
       {
        Curr_Position = (Curr_Position >= Min_Position+Lines_Per_Page) ? Curr_Position-Lines_Per_Page : Min_Position;
        Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
        Xcord = (Xcord > 0) ? Xcord : 0;
        Hnd->moveto(X+5+BTW+Xcord,Y+2);
        Intl = clock();
        while (mouse.btnpressed())
         while (((clock()-Intl) > CLK_TCK ) && mouse.btnpressed() && Lf->hit())
	       {
           Curr_Position = (Curr_Position >= Min_Position+Lines_Per_Page) ? Curr_Position-Lines_Per_Page : Min_Position;
           Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
           Xcord = (Xcord > 0) ? Xcord : 0;
           Hnd->moveto(X+5+BTW+Xcord,Y+2);
	        delay(50);
        	 }
        Last_X = Xcord;
       }
      else   // Else, clicked on Page Right.
       {
        Curr_Position = (Curr_Position <= Max_Position-Lines_Per_Page)? Curr_Position+Lines_Per_Page : Max_Position;
        Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
        Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
        Hnd->moveto(X+5+BTW+Xcord,Y+2);
        Intl = clock();
        while (mouse.btnpressed())
         while (((clock()-Intl) > CLK_TCK) && mouse.btnpressed() && Rt->hit())
          {
           Curr_Position = (Curr_Position <= Max_Position-Lines_Per_Page)? Curr_Position+Lines_Per_Page : Max_Position;
           Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
           Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
           Hnd->moveto(X+5+BTW+Xcord,Y+2);
           delay(50);
          }
        Last_X = Xcord;
       }
     }
    else if (Hnd->hit())
     {
      while (mouse.btnpressed())
       {
        Xcord = mouse.getmX();
        if (Step_Size == 0)
         Curr_Position = Min_Position;
        else
         {
          Curr_Position = ((Xcord-X-BTW-5-HDW/2)/ Step_Size)+Min_Position;
          Curr_Position = (Curr_Position >= Min_Position)? Curr_Position  : Min_Position;
          Curr_Position = (Curr_Position <= Max_Position)? Curr_Position  : Max_Position;
         }
        Xcord = (int)(Step_Size*(Curr_Position-Min_Position));
        Xcord = (Xcord < Width-10-(2*BTW)-HDW) ? Xcord : (Width-10-(2*BTW)-HDW);
        if (Last_X != Xcord)
         {
          Hnd->moveto(X+5+BTW+Xcord,Y+2);
          Last_X = Xcord;
         }
       }
     }
    return 1;
   }
  return 0;
 }

void hscroll::moveto (int x, int y)
 {
  if (isShown)
   {
    hide();
    Lf->moveto(x+2,y+2);
    Rt->moveto(x+Width-2-BTW,y+2);
    panel::moveto(x+1,y+1);
    show();
   }
  else
   {
    Lf->moveto(x+2,y+2);
    Rt->moveto(x+Width-2-BTW,y+2);
    panel::moveto(x+1,y+1);
   }
 }

void hscroll::resize (int w, int h)
 {
  int Xoff;

  if (isShown)
   {
    hide();
    Lf->resize(BTW,h-2);
    Rt->resize(BTW,h-2);
    Rt->moveto(X+w-2-BTW,Y+2);
    Hnd->resize(w-2,HDW);
    panel::resize(w,h);
    show();
   }
  else
   {
    Lf->resize(BTW,h-2);
    Rt->resize(BTW,h-2);
    Rt->moveto(X+w-2-BTW,Y+2);
    Hnd->resize(w-2,HDW);
    panel::resize(w,h);
   }
 }

void hscroll::setrange(int min, int max)
 {
  Min_Position = min;
  Max_Position = max;
  if (Curr_Position < Min_Position)
    Curr_Position = Min_Position;
  if (Curr_Position > Max_Position)
    Curr_Position = Max_Position;
 }

void hscroll::setpagesize(int LPP)
 {
  Lines_Per_Page = LPP;
 }