/************************************
*      HP100LX GRAPHICS LIBRARY     *
*            Version 2.1            *
*           Sept. 7, 1994           *
*         by: Harry Konstas         *
*                                   *
*   The following is the windows &  *
* menu environment source code for  *
* creating a library (OBJ) that you *
* can have along with the other     *
* libraries of your compiler. NOT to*
* be included in a program! Compile *
* it along to create your library   *
************************************/

#include <dos.h>
#include <bios.h>
#include <stdlib.h>

/* Constant declaration */

#define BLACK_COLOR 1
#define WHITE_COLOR 0

#define AN_LEFT 0x20
#define AN_RIGHT 0x60

#define SMALL_FONT 0x0808
#define MEDIUM_FONT 0x0a0b
#define LARGE_FONT 0x100c

#define FORCE_RULE 0
#define AND_RULE 1
#define OR_RULE 2
#define XOR_RULE 3
#define INVFOR_RULE 4
#define INVAND_RULE 5
#define INVOR_RULE 6
#define INVXOR_RULE 7
#define TXT_RULE 8

#define OUTLINE_FILL 0
#define SOLID_FILL 1
#define PATTERN_FILL 2

/* FUNCTION DECLARATIONS */


/*****************
* Misc functions *
*****************/

void is100(void);
void announ(int position);
void toplin(char far *string);
void botlin(char far *labels);
void terminate(void);


/*******************************
* Low level graphics functions *
*******************************/

void setgra(void);
void setmda(void);
void setfon(int size);
void setpos(int horiz,int vert);
void setcol(int color);
void setrul(int rule);
void setlin(unsigned int line_type);
void setmsk(char far *fill_mask);
void putimg(int horiz,int vert,int rule,char far *buffer);
void getimg(int from_horiz,int from_vert,int to_horiz,int to_vert,char far *buffer);
void wrtext(int horiz,int vert,char far *string);


/********************************
* High level graphics functions *
********************************/

void line(int from_horiz,int from_vert,int to_horiz,int to_vert);
void rectan(int from_horiz,int from_vert,int to_horiz,int to_vert,int fill);
void revblk(int from_horiz,int from_vert,int to_horiz,int to_vert);


/*******************
* Window functions *
*******************/

void errwin(char far *message);
void open_win(int winid,int from_horiz,int from_vert,int to_horiz,int to_vert,char far *message);
void close_win(int winid);
void window(int from_horiz,int from_vert,int to_horiz,int to_vert,char far *message);


/*****************
* Menu functions *
*****************/

void open_mbar(void);
void close_mbar(void);
void sel_menu(int menuid);
int  open_menu(int menuid);
void close_menu();
void sel_opt(int optnum);
int navigate(int menum);


/********************************************
* Global (environment) variable definitions *
********************************************/

int  menupos;               /* Menu position register      */
int  menuend;               /* Menu end position           */
int  wposhor[15];           /* Window horiz pos. registers */
int  wposver[15];           /* Window vert pos. registers  */
char *winbuf[10];           /* Window buffer pointers      */
char mbarmes[80];           /* Menu bar message            */
char *menitm[8][10];        /* Menu items                  */


/* Fill mask definition (for window shadows) */

char fmask[]=
{'\x55','\xaa','\x55','\xaa','\x55','\xaa','\x55','\xaa','\x0'};


/***************
* IS IT 100LX? *
***************/

is100(void)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.ax=0x4dd4;
    int86x(0x15,&inregs,&outregs,&segregs);
    if (outregs.x.bx != 0x4850) not100();
    if (outregs.x.cx > 0x102) not100();
}

not100()
{
    printf("This program runs only on the HP100LX palmtop.\n");
    exit(1);
}

/*************************
* ANNOUNCIATORS POSITION *
*************************/

announ(int position)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.h.al = position;
    inregs.h.ah = 0x61;
    int86x(0x15,&inregs,&outregs,&segregs);
}

/********************
* SET GRAPHICS MODE *
********************/

setgra()

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.ax = 6;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/****************
* SET TEXT MODE *
****************/

setmda()

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.ax = 3;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/***********
* SET FONT *
***********/

setfon(int size)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.cx=size;
    inregs.h.ah=0x10;
    int86x(0x5f,&inregs,&outregs,&segregs);
    segregs.es=outregs.x.dx;
    inregs.x.di=outregs.x.ax;
    inregs.h.ah=0x11;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/*******************
* SET PEN POSITION *
*******************/

setpos(int horiz,int vert)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.cx=horiz;
    inregs.x.dx=vert;
    inregs.h.ah=8;
    inregs.h.al=0;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/***********************
* SET REPLACEMENT RULE *
***********************/

setrul(int rule)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.h.al=rule;
    inregs.h.ah=0x0a;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/************
* SET COLOR *
************/

setcol(int color)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.h.ah=9;
    inregs.h.al=color;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/****************
* SET LINE TYPE *
****************/

setlin(unsigned int line_type)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.h.ah=0x0b;
    inregs.x.cx=line_type;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/****************
* SET FILL MASK *
****************/

setmsk(char far *fill_mask)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.di=FP_OFF(fill_mask);
    segregs.es=FP_SEG(fill_mask);
    inregs.h.ah=1;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/*****************
* DRAW RECTANGLE *
*****************/

rectan(int from_horiz,int from_vert,int to_horiz,int to_vert,int fill)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    setpos(from_horiz,from_vert);
    inregs.x.cx=to_horiz;
    inregs.x.dx=to_vert;
    inregs.h.ah=5;
    inregs.h.al=fill;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/************
* DRAW LINE *
************/

line(int from_horiz,int from_vert,int to_horiz,int to_vert)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.cx=from_horiz;
    inregs.x.dx=from_vert;
    inregs.h.ah=8;
    inregs.h.al=0;
    int86x(0x5f,&inregs,&outregs,&segregs);

    inregs.x.cx=to_horiz;
    inregs.x.dx=to_vert;
    inregs.h.ah=6;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/****************
* REVERSE BLOCK *
****************/

revblk(int from_horiz,int from_vert,int to_horiz,int to_vert)

{
    setrul(XOR_RULE);
    rectan(from_horiz,from_vert,to_horiz,to_vert,SOLID_FILL);
    setrul(FORCE_RULE);
}

/*************
* WRITE TEXT *
*************/

wrtext(int horiz,int vert,char far *string)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.cx=horiz;
    inregs.x.dx=vert;
    inregs.x.di=FP_OFF(string);
    segregs.es=FP_SEG(string);
    inregs.h.ah=15;
    inregs.h.al=0;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/******************
* PUT IMAGE BLOCK *
******************/

putimg(int horiz,int vert,int rule,char far *buffer)

{
    union REGS inregs,outregs;
    struct SREGS segregs;
    inregs.x.cx=horiz;
    inregs.x.dx=vert;
    inregs.x.di=FP_OFF(buffer);
    segregs.es=FP_SEG(buffer);
    inregs.h.ah=14;
    inregs.h.al=rule;
    int86x(0x5f,&inregs,&outregs,&segregs);
}

/******************
* GET IMAGE BLOCK * int86x() function doesn't support the BP register...
******************/

getimg(int from_horiz,int from_vert,int to_horiz,int to_vert,char far *buffer)

{

    char get_asm[]={
    
  '\x06',                /*   push    es                      */
  '\x8B','\x0F',         /*   mov     cx,[bx] ; X 1st corner  */
  '\x83','\xC3','\x02',  /*   add     bx,2                    */
  '\x8B','\x17',         /*   mov     dx,[bx] ; Y 1st corner  */
  '\x83','\xC3','\x02',  /*   add     bx,2                    */
  '\x8B','\x37',         /*   mov     si,[bx] ; X 2nd corner  */
  '\x83','\xC3','\x02',  /*   add     bx,2                    */
  '\x8B','\x2F',         /*   mov     bp,[bx] ; Y 2nd corner  */
  '\x83','\xC3','\x02',  /*   add     bx,2                    */
  '\x8B','\x3F',         /*   mov     di,[bx] ; buffer offset */
  '\x8C','\xC8',         /*   mov     ax,cs                   */
  '\x8E','\xC0',         /*   mov     es,ax   ; buffer segment*/
  '\xB4','\x0D',         /*   mov     ah,13                   */
  '\xCD','\x5F',         /*   int     5fh     ; call get_image*/
  '\x07',                /*   pop     es                      */
  '\xC3'      };         /*   ret             ; returns AX    */


    struct {
        int x_1;
        int y_1;
        int x_2;
        int y_2;
        int boff;
        int bseg;
    }param;

    param.x_1=from_horiz;
    param.y_1=from_vert;
    param.x_2=to_horiz;
    param.y_2=to_vert;
    param.boff=FP_OFF(buffer);
    param.bseg=FP_SEG(buffer);

/* Note: some compilers may not support the following 'asm'
         function as my compiler does. Please modify accordingly.
         In the mean time I will find a way to replace it with
         something more standard.     */

    asm(get_asm,&param);
}

/******************
* WINDOW CREATION *
******************/

window(int from_horiz,int from_vert,int to_horiz,int to_vert,char far *message)

{
    int horiz_tab;

    setmsk(fmask);
    setrul(FORCE_RULE);

    rectan(to_horiz+1,from_vert+4,to_horiz+6,to_vert+4,PATTERN_FILL);
    rectan(from_horiz+5,to_vert+1,to_horiz+6,to_vert+4,PATTERN_FILL);

    setcol(WHITE_COLOR);
    rectan(from_horiz,from_vert,to_horiz,to_vert,SOLID_FILL);

    setcol(BLACK_COLOR);
    rectan(from_horiz,from_vert,to_horiz,to_vert,OUTLINE_FILL);

    if(message!=0)
    {
        horiz_tab=(((to_horiz-from_horiz)/8)-strlen(message));
        horiz_tab=(horiz_tab*4)+from_horiz;
        setfon(SMALL_FONT);
        wrtext(horiz_tab,from_vert+2,message);
        revblk(from_horiz+1,from_vert+1,to_horiz-1,from_vert+10);
        setfon(MEDIUM_FONT);
    }

}

/*********************
* TOP LINE FORMATION *
*********************/

toplin(char far *string)

{
    setrul(TXT_RULE);
    setcol(BLACK_COLOR);
    setfon(SMALL_FONT);
    wrtext(0,1,string);
    revblk(0,0,639,9);
    setrul(FORCE_RULE);
    rectan(0,0,639,9,OUTLINE_FILL);
    setfon(MEDIUM_FONT);
}

/************************
* BOTTOM LINE FORMATION *
************************/

botlin(char far *labels)

{
int from_horiz,from_vert,to_horiz,to_vert;

    from_horiz=31;
    from_vert=190;
    to_horiz=88;
    to_vert=199;

    setfon(SMALL_FONT);
    setcol(BLACK_COLOR);
    setrul(FORCE_RULE);

    rectan(from_horiz,from_vert,to_horiz,to_vert,SOLID_FILL);
    from_horiz=to_horiz+3;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+64;

    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+64;

    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);
    from_horiz=from_horiz+60;
    rectan(from_horiz,190,from_horiz+57,199,SOLID_FILL);

    setrul(XOR_RULE);
    wrtext(39,191,labels);
}

/***************
* ERROR WINDOW *
***************/

errwin(char far *message)

{
    int horiz_tab;

    horiz_tab=(((480-160)/8)-strlen(message));
    horiz_tab=(horiz_tab*4)+160;

    open_win(0,160,60,480,120,"ERROR");
    wrtext(horiz_tab,87,message);
    sound(150,10);
    while (!kbhit());                /* Wait for a key */
    close_win(0);
}

/**************
* OPEN WINDOW *
**************/

void open_win(int winid,int from_horiz,int from_vert,int to_horiz,int to_vert,char far *message)

{
    unsigned int buflen,horlen,verlen;
    char *buf_pnt;

    horlen=to_horiz-from_horiz+14;
    verlen=to_vert-from_vert+7;
    buflen=10+((horlen/8)*verlen);

    buf_pnt=malloc(buflen);
    if(buf_pnt==NULL) abort();   /* abort if not enough memory */

    getimg(from_horiz,from_vert,to_horiz+6,to_vert+6,buf_pnt);
    window(from_horiz,from_vert,to_horiz,to_vert,message);

    winbuf[winid]=buf_pnt;
    wposhor[winid]=from_horiz;
    wposver[winid]=from_vert;
}

/***************
* CLOSE WINDOW *
***************/

close_win(int winid)

{
    putimg(wposhor[winid],wposver[winid],FORCE_RULE,winbuf[winid]);
    free(winbuf[winid]);

}


/****************
* OPEN MENU BAR *
****************/

open_mbar()

{
   open_win(11,0,9,633,28,0);
   setfon(MEDIUM_FONT);
   wrtext(10,14,mbarmes);
}


/*****************
* CLOSE MENU BAR *
*****************/

close_mbar()

{
   close_win(11);
}


/**************
* SELECT MENU *
**************/

sel_menu(int menuid)


{
    int f,cpos,lpos,rpos;
    cpos=0;

        for(f=1;f<=menuid;f++)
        {
            lpos=cpos;
            while(mbarmes[cpos++]!=32);
            rpos=cpos-1;
            while(mbarmes[cpos++]==32);
            cpos--;
        }

    lpos=1+(lpos*10);
    rpos=18+(rpos*10);
    revblk(lpos,10,rpos,27);
    menupos = lpos;
}

/************
* OPEN MENU *
************/

int open_menu(int menuid)

{

    int f,width,lenght,horiz,vert,nopt;
    width=0;
    menuid--;

    for(f=0;f<10;f++)
    {
        if(strlen(menitm[menuid][f])==0) break;
        if(width<strlen(menitm[menuid][f]))
        width=strlen(menitm[menuid][f]);
    }

    width=(width+4)*10;
    lenght=29+(f*16);

    if(menupos+width>632)
        menupos=menupos-((menupos+width)-632);
    if(menupos==1) menupos=0;

    open_win(10,menupos,28,menupos+width,lenght,0);

    horiz=menupos+20;
    vert=32;
    nopt=f;

    for(f=0;f<=nopt;f++)
    {
       wrtext(horiz,vert,menitm[menuid][f]);
       vert=vert+16;
    }

    menuend=menupos+width;
    return(nopt);
}

/*************
* CLOSE MENU *
*************/

close_menu()

{
    close_win(10);

}


/****************
* SELECT OPTION *
****************/

sel_opt(int optn)

{
    int vert;
    optn--;
    vert=(optn*16)+29;
    revblk(menupos+1,vert,menuend-1,vert+15);
}


/************************************
* MENU AUTOMATIC NAVIGATION PROCESS * Returns operid (0=nop,255=act,other=operation id.
************************************/

int navigate(int menum)

    {

static  char menuid,mbarflg,omenflg,optnum,optid;
static  int operid,key;

        if(operid!=255) operid=0;
        if(mbarflg==0) operid=0;

        if(inp(0x60)==0x7a) /* MENU key process */
        {
            if (mbarflg==0)
            {
                operid=255;
                open_mbar();
                sel_menu(1);
                mbarflg=1;
                menuid=1;
                while(inp(0x60)==0x7a);
            }
        }


        if(inp(0x60)==0x38)  /* ALT key process */
        {
            if(mbarflg==1)
            {
                if(omenflg==0)
                {
                    operid=0;
                    close_mbar();
                    mbarflg=0;
                    while(inp(0x60)==0x38);
                }
            }

            else
            {
                operid=255;
                open_mbar();
                sel_menu(1);
                mbarflg=1;
                menuid=1;
                while(inp(0x60)==0x38);
            }
        }


        if(inp(0x60)==1)  /* ESC key process */
        {
            if(mbarflg==0) terminate();

            if(mbarflg==1)
            {
                if(omenflg==0)
                {
                    close_mbar();
                    mbarflg=0;
                }

                else
                {
                    close_menu();
                    omenflg=0;
                }
            }
            while(inp(0x60)==1);
        }


        if(mbarflg==1)
        {

            key=getch();

            if(key==0x4d)  /* RightArrow key process */
            {
                key=0;
                if(omenflg==1) close_menu();
                sel_menu(menuid);
                menuid++;
                if(menuid>menum) menuid=1;
                sel_menu(menuid);

                if(omenflg==1)
                {
                    optnum=open_menu(menuid);
                    optid=1;
                    if(optnum!=0) sel_opt(optid);
                }
            }

            if(key==0x4b)   /* LeftArrow key process */
            {
                key=0;
                if(omenflg==1) close_menu();
                sel_menu(menuid);
                menuid--;
                if(menuid==0) menuid=menum;
                sel_menu(menuid);

                if(omenflg==1)
                {
                    optnum=open_menu(menuid);
                    optid=1;
                    if(optnum!=0) sel_opt(optid);
                }
            }


            if(omenflg==0)
            {
                if(key==0x50) /* DownArrow key process */
                {
                    key=0;
                    optnum=open_menu(menuid);
                    optid=1;
                    if(optnum!=0) sel_opt(optid);
                    omenflg=1;
                }

                if(key==0x0d) /* ENTER key process */
                {
                    key=0;
                    optnum=open_menu(menuid);
                    optid=1;
                    if(optnum!=0) sel_opt(optid);
                    omenflg=1;
                }
            }

            if(omenflg==1)
            {
                if(key==0x50)  /* DownArrow key (menu) process */
                {
                    key=0;
                    if(optnum!=0)
                    {

                        sel_opt(optid++);
                        if(optid>optnum) optid=1;
                        sel_opt(optid);
                    }
                }

                if(key==0x48)   /* UpArrow key (menu) process */
                {
                    key=0;
                    if(optnum!=0)
                    {
                        sel_opt(optid--);
                        if(optid==0) optid=optnum;
                        sel_opt(optid);
                    }
                }

                if(key==0x0d) /* ENTER key (menu) process */
                {
                    key=0;
                    operid=(menuid<<4)+optid;
                    close_menu();
                    omenflg=0;
                    close_mbar();
                    mbarflg=0;
                }
            }
        }
        return(operid);
    }


/********************
* TERMINATE PROGRAM *
********************/

terminate(void)

{
    announ(AN_RIGHT);            /* Place announciators right */
    setmda();                    /* Set screen mode to text mode */
    exit(0);                     /* Exit program */
}

