/* menu.c */ #include #include #include #include"PcMag.h" /* screen colors: * NORMAL_VID value for ordinary characters, * HIGHLITE for reverse */ #define NORMAL_VID 0x1700 /* white text, blue field */ #define HIGHLITE_VID 0x7000 /* black text, white field */ /* Ascii key definitions */ #define ENTER 13 #define SPACE 32 #define ESC 27 /* Scan key redefinitions */ #define RIGHT_ARROW 77+'z' #define LEFT_ARROW 75+'z' /* limitations: */ #define MAXMENUITEMS 25 /* number of menu items */ #define NAME_ROW 2 /* row number of item name */ #define NAME_COL 1 /* column number for name */ #define DESCRIPTION_ROW 3 /* description row number */ #define DESCRIPTION_COL 2 /* description column */ /* macros to make the code more readable, don't touch these */ #define SCREEN_SIZE 2000 /* screen size @ 2000 words */ #define ring_bell() putch(7) /* bell-ringing macro */ #define VIDEO_INT 0x10 /* Bios video interrupt */ #define SET_CURSOR_SIZE 0x01 /* Int 10 function 1 */ #define GET_CURSOR_POS 0x02 /* Int 10 function 2 */ #define READ_CURSOR 0x03 /* Int 10 function 3 */ #define GET_VID_MODE 0x0f /* Int 10 function F */ #define MONO_MODE 7 /* monochrome video mode # */ #define MONO_SCREEN 0xb0000000 /* address of mono screen */ #define COLOR_SCREEN 0xb8000000 /* address of color screen */ #define CURSOR_SAVE 0 /* macro for cursor save */ #define CURSOR_RESTORE 1 /* macro for cursor store */ /* global objects: */ int far *screen; /* pointer to screen buffer */ int old_screen[SCREEN_SIZE]; /* store old screen here */ /* list of function declarations for cue_function */ int addf(), subf(), mulf(), divf(), exitf(); /* array of structures with names, descriptions and function pointers */ struct _cue { char *cue_name; /* name to be displayed */ char *cue_description; /* description */ int (*cue_function)(); /* function to be called */ } cue[MAXMENUITEMS] = { /* --1234567890--------1234567890123456789012-----for alignment */ " Add ", "Explain addition ", addf, " Subtract ", "Discuss subtraction ", subf, " Multiply ", "Portray multiplication", mulf, " Divide ", "Characterize division ", divf, " Exit ", "Exit to system ", exitf, /* you can add more items here in the same fashion - * up to MAXMENUITEMS total */ NULL,NULL,NULL }; /* functions */ /* cls() * clears the screen by writing blanks to screen buffer */ cls() { int pos=0; while(pos < SCREEN_SIZE) /* for each word in screen */ *(screen + pos++) = NORMAL_VID; /* set it to NORMAL_VID */ } /* print() * prints a null-terminated string at row,col with attributes * returns next available column */ print(str, row, col, att) char *str; int row, col, att; { while(*str) *(screen+row*80+col++) = att + *str++; return (col); } /* four test functions */ addf() { cls(); print("In Add, press a key for menu",2,1,HIGHLITE_VID); getch(); } subf() { cls(); print("In Subtract, press a key for menu",2,1,HIGHLITE_VID); getch(); } mulf() { cls(); print("In Multiply, press a key for menu",2,1,HIGHLITE_VID); getch(); } divf() { cls(); print("In Divide, press a key for menu",2,1,HIGHLITE_VID); getch(); } exitf() { int i; for( i = 0; i < SCREEN_SIZE; i++) /* restore original screen */ *(screen+i) = old_screen[i]; cursor(CURSOR_RESTORE); /* reset cursor size/posit.*/ } /* Run() * runs the appropriate test function at cue[itemnumber].cue_function. * This could be modified to use spawn() to run other programs. */ Run(itemnumber) int itemnumber; { return (cue[itemnumber].cue_function)(); } /* cursor() * cursor operations: saves the current cursor size and position in * the statics, or restores the cursor size and position previously * saved. */ cursor(op) { union REGS r; static int oldcurrow,oldcurcol,oldcurstart,oldcurend; if(op) /* restore cursor */ { r.h.ah = SET_CURSOR_POS; /* cursor position function */ r.h.dh = oldcurrow; /* set the row */ r.h.dl = oldcurcol; /* set the column */ r.h.bh = 0; /* for video page 0 */ int86(VIDEO_INT,&r,&r); /* call the bios */ r.h.ah = SET_CURSOR_SIZE; /* cursor size function */ r.h.ch = oldcurstart; /* set the start */ r.h.cl = oldcurend; /* set the end */ r.h.bh = 0; /* for video page 0 */ int86(VIDEO_INT,&r,&r); /* call the bios */ } else /* save the cursor */ { r.h.ah = READ_CURSOR; /* cursor read function */ r.h.bh = 0; /* page 0 */ int86(VIDEO_INT,&r,&r); /* call the bios */ oldcurrow = r.h.dh; /* save the cursor row */ oldcurcol = r.h.dl = 0; /* save the cursor column */ oldcurstart = r.h.ch; /* save the cursor start */ oldcurend = r.h.cl; /* save the cursor end */ r.h.ah = SET_CURSOR_SIZE; /* cursor size function */ r.h.ch = 0x20; /* set bit 5 to hide cursor */ int86(VIDEO_INT,&r,&r); /* call the bios */ } } /* initialize() * initializes the initials array, sets number of choices found, and * saves the screen buffer in the old_screen array */ initialize(choices,initials) int *choices; char *initials; { int i; get_screen_mode(); /* set screen pointer */ /* initialize the initials */ for( i = 0; cue[i].cue_name && i < MAXMENUITEMS; i++) initials[i] = tolower(cue[i].cue_name[1]); initials[i] = NULL; *choices = i; /* save old screen */ for( i = 0; i < SCREEN_SIZE; i++) old_screen[i] = *(screen+i); } /* get_screen_mode() * returns the current screen mode in AL, and sets the screen pointer * to the appropriate video buffer address. */ get_screen_mode() { union REGS r; r.h.ah = GET_VID_MODE; /* get video mode function */ int86(VIDEO_INT,&r,&r); /* call the bios */ /* set screen pointer */ screen = (int far *)((r.h.al == MONO_MODE) ? MONO_SCREEN : COLOR_SCREEN); } /* menu() * main menu creation function, callable from anywhere in a program. * Performs the following tasks: * 1. saves the current screen and cursor * 2. clears the screen * 3. loops until the exit function is called through the following: * 1. prints the menu items (highlights current selection) * 2. prints the description of the highlighted selection * 3. gets a key from the user (adjusts for non-ascii keys) * 4. takes the appropriate actions for , , * , , , or the first * letter of the menu item. * Assumes last item is exit item and returns when that is executed. */ menu() { static int mark = 0; int col, i, key, choices; char *match, initials[MAXMENUITEMS]; initialize(&choices,initials); /* initialize & save screen */ cursor(CURSOR_SAVE); /* save the cursor */ cls(); /* clear the screen */ while(TRUE) /* main loop */ { col = NAME_COL; /* print the names and highlight the current selection */ for( i = 0; i < choices; i++) col = print(cue[i].cue_name, NAME_ROW, col, (mark == i) ? HIGHLITE_VID : NORMAL_VID); /* print description */ print(cue[mark].cue_description, DESCRIPTION_ROW, DESCRIPTION_COL, NORMAL_VID); if(!(key = tolower(getch()))) /* get key, and lowercase */ key = (getch() + 'z'); /* Not Ascii? get scan code */ switch(key) /* which key was pressed? */ { case ENTER: /* if ENTER */ Run(mark); /* run function at mark */ break; case RIGHT_ARROW: /* if RIGHT_ARROW/SPACE bar */ case SPACE: mark = ((mark+1) % choices); /* move to next choice */ break; case LEFT_ARROW: /* if LEFT_ARROW */ /* move to previous choice */ mark = ((mark+choices-1) % choices); break; case ESC: /* if ESC */ return Run(choices-1); /* select last choice (exit)*/ break; default: /* if initials match */ if(match = strchr(initials,key)) { mark = (match-initials); Run(match-initials); } else ring_bell(); /* bad choice, ring the bell*/ break; } } } main() /* main program */ { menu(); /* called as needed */ } /* End of Menu.c */