MENU.CPP
资源名称:commutil.zip [点击查看]
上传用户:xr_qian
上传日期:2007-01-05
资源大小:443k
文件大小:25k
源码类别:
通讯/手机编程
开发平台:
DOS
- // ******************************************************************** //
- // //
- // MENU.CPP //
- // Copyright (c) 1993, Michael Holmes and Bob Flanders //
- // C++ Communication Utilities //
- // //
- // Chapter 7: Receiving a FAX //
- // Last changed in chapter 2 //
- // //
- // This file contains the definition and interface for //
- // the menu class. //
- // //
- // ******************************************************************** //
- #define ALLOW_ALT 1 // allow alt key in get_key()
- #define NO_ALT 0 // ..and supress alt key
- /* ******************************************************************** *
- *
- * Globals
- *
- * ******************************************************************** */
- int menu_cn = MIX(WHITE, CYAN), // default normal menu colors
- menu_cr = MIX(WHITE, BLUE); // ..and reverse colors
- int NotYet(int c, int r); // null routine definition
- char get_scan(unsigned char); // get scan code for character
- /* ******************************************************************** *
- *
- * Menu class definition
- *
- * ******************************************************************** */
- class Menu
- {
- public:
- Menu(char *s, // create first menu entry
- int (*f)(int, int) = NotYet, // ..function to call
- char c = ' '); // ..special key character
- Menu(Menu *m, // add a menu entry to list
- char *s, // ..label to add
- int (*f)(int, int) = NotYet, // ..function to call
- int t = 0, // ..submenu flag
- char c = ' '); // ..special key character
- void SetColors(int cn, int cr), // new norm and rev colors
- Display(int c); // process a main menu
- Menu *ValidateKey(int c); // validate key in menu
- ~Menu(); // destructor
- private:
- void EntryInit(char *s, // initialize a menu entry
- int (*f)(int c, int r), // ..with runtime routine
- char c); // ..special key character
- int DisplayMenu(Menu *n, // display menu bar
- Window *w), // ..highlighting an entry
- DisplaySub(int c, int r), // process a submenu
- DisplaySubMenu(Menu *n, // display submenu column
- Window *w), // ..and handle keystrokes
- DoMenuAction(Menu *m, // process menu entry
- int c, int r); // ..using column and row
- Menu *Find(char c), // find entry by char
- *FindAlt(char alt_c), // find entry by alt char
- *Left(Menu *m), // find an entry's left
- *Right(Menu *m); // ..and its right
- int Count(void), // count the entries
- MaxWidth(void); // find the max width label
- char *item, // menu item label
- key, // normal selection character
- alt_key; // ..and alt selection char
- int (*fnc)(int c, int r); // runtime menu entry fnc
- Menu *next, // next item pointer
- *sub; // submenu pointer
- };
- /* ******************************************************************** *
- *
- * Menu -- build the first menu entry
- *
- * ******************************************************************** */
- Menu::Menu(char *s, // new menu item
- int (*f)(int c, int r), // runtime routine
- char c) // special key character
- {
- EntryInit(s, f, c); // initialize new instance
- }
- /* ******************************************************************** **
- *
- * Menu -- add an entry to the menu list
- *
- * ******************************************************************** */*
- Menu::Menu(Menu *m, // menu to chain into
- char *s, // new menu item
- int (*f)(int c, int r), // runtime routine
- int t, // type, 0 = at same level
- // 1 = submenu
- char c) // special key character
- {
- EntryInit(s, f, c); // build base instance
- if (t) // q. submenu definition?
- m->sub = this; // a. yes .. store in parent
- else
- {
- while (m->next) // loop thru and ..
- m = m->next; // ..then end of the list
- m->next = this; // put this at the end
- }
- }
- /* ******************************************************************** *
- *
- * EntryInit -- initialize menu entry instance
- *
- * ******************************************************************** */
- void Menu::EntryInit(char *s, // menu label to set up
- int (*f)(int, int), // runtime function
- char c) // special key character
- {
- item = new char[strlen(s) + 1]; // get memory for label
- strcpy(item, s); // ..and copy into instance
- key = c ? c : *s; // ASCII selection key
- alt_key = get_scan(key); // alt selection key
- fnc = f ? f : NotYet; // runtime function
- next = sub = 0; // clear forward pointers
- }
- /* ******************************************************************** *
- *
- * Display -- display and process a menu at the top of the screen
- *
- * ******************************************************************** */
- void Menu::Display(int c) // initial keystroke
- {
- int col, // offset of selected entry
- k; // keystroke
- Menu *m, *n; // work menu pointer
- NOCURSOR(); // no cursor while in menu
- Window w(1, 1, 80, 3, menu_cn, menu_cr); // define menu window
- w.Open(double_line); // open window
- if ((m = ValidateKey(c)) != 0) // q. find initial selection?
- k = (c == 0x100) ? 0 : CR; // a. yes .. set up for entry
- else
- {
- m = this; // else .. use first entry
- k = 0; // ..in menu and clear key
- }
- for (;;) // loop 'til exit requested
- {
- col = DisplayMenu(m, &w); // display and highlight
- if (NOT k) // q. need a new key?
- while ((k = get_key(NO_ALT)) == 0) // a. yes .. wait for a key
- ;
- switch (k) // handle user's keystroke
- {
- case CR: // carriage return
- k = DoMenuAction(m, col, 2); // process menu entry
- if (k < 0) // q. need to exit the menu?
- {
- CURSOR(); // a. yes .. set cursor back
- return; // ..to normal and return
- }
- break; // else .. wait for next key
- case LEFT: // left arrow
- m = Left(m); // get entry to the left
- k = 0; // clear keystroke
- break; // ..then wait for next key
- case RIGHT: // right arrow
- m = Right(m); // get entry to the right
- k = 0; // clear keystroke
- break; // ..then wait for next key
- case ESC: // escape key
- CURSOR(); // set cursor back to normal
- return; // ..exit loop and return
- default: // error case
- if ((n = ValidateKey(k)) != 0) // q. valid menu key?
- {
- m = n; // a. yes .. set up as current
- k = CR; // ..and force a <cr>
- }
- else
- {
- printf(BELL); // else .. ring bell
- k = 0; // finally, clear keystroke
- }
- }
- }
- }
- /* ******************************************************************** *
- *
- * DisplayMenu -- write out a menu's entries
- *
- * ******************************************************************** */
- int Menu::DisplayMenu(Menu *n, // entry to highlight
- Window *w) // window to display in
- {
- int w_offset = 2, // offset in menu bar
- s_offset; // offset of selected entry
- Menu *m = this; // work menu pointer
- w->GotoXY(1, 1); // start from the beginning
- for (;;)
- {
- w->Display(" "); // put some space out
- if (m == n) // q. find entry?
- {
- w->DisplayReverse(m->item); // a. yes .. highlight it
- s_offset = w_offset; // ..and save field offset
- }
- else
- w->Display(m->item); // else .. display normally
- w_offset += strlen(m->item) + 2; // get offset of next item
- if ((m = m->next) == 0) // q. end of list?
- break; // a. yes .. exit loop
- }
- return(s_offset); // return with entry's offset
- }
- /* ******************************************************************** *
- *
- * DisplaySub -- display a submenu
- *
- * ******************************************************************** */
- int Menu::DisplaySub(int c, int r) // upper left coordinates
- {
- int k = 0, // keystroke
- r_current; // current row
- Menu *m = this, // current menu entry
- *n; // work menu pointer
- Window w(c, r, c + 3 + MaxWidth(), // define menu window
- r + 2 + Count(), // ..to hold whole submenu
- menu_cn, menu_cr); // ..using default colors
- w.Open(single_line); // open submenu window
- for (;;) // loop 'til exit requested
- {
- r_current = DisplaySubMenu(m, &w); // display and highlight
- if (NOT k) // q. need a new key?
- while ((k = get_key(NO_ALT)) == 0) // a. yes .. wait for a key
- ;
- switch (k) // handle user's keystroke
- {
- case CR: // carriage return
- k = DoMenuAction(m, c, // process menu entry
- r + r_current);
- if (k != 0) // q. need to exit the menu?
- return(k); // a. yes .. rtn w/keystroke
- break; // else .. wait for next key
- case UP: // up arrow
- m = Left(m); // get entry above this one
- k = 0; // clear keystroke
- break; // ..then wait for next key
- case DOWN: // down arrow
- m = Right(m); // get entry beneath
- k = 0; // clear keystroke
- break; // ..then wait for next key
- case LEFT: // left arrow
- return(LEFT); // ..then return w/left key
- case RIGHT: // right arrow
- return(RIGHT); // ..then return w/right key
- case ESC: // escape key
- return(0); // ..then return one level
- default: // error case
- if ((n = ValidateKey(k)) != 0) // q. valid menu key?
- {
- m = n; // a. yes .. set up as current
- k = CR; // ..and force a <cr>
- }
- else
- {
- printf(BELL); // else .. ring bell
- k = 0; // finally, clear keystroke
- }
- }
- }
- }
- /* ******************************************************************** *
- *
- * DisplaySubMenu -- write out a submenu's entries
- *
- * ******************************************************************** */
- int Menu::DisplaySubMenu(Menu *n, // entry to highlight
- Window *w) // window to display in
- {
- int w_row = 1, // work row in menu bar
- s_row; // row of selected entry
- Menu *m = this; // work menu pointer
- for (;;) // loop 'til all done
- {
- w->AtSay(1, w_row, " "); // put some space out
- if (m == n) // q. find entry?
- {
- w->DisplayReverse(m->item); // a. yes .. highlight it
- s_row = w_row; // ..and save row number
- }
- else
- w->Display(m->item); // else .. display normally
- w_row++; // next row number
- if ((m = m->next) == 0) // q. end of list?
- break; // a. yes .. exit loop
- }
- return(s_row); // return with entry's row
- }
- /* ******************************************************************** *
- *
- * DoMenuAction -- process menu entry
- *
- * ******************************************************************** */
- int Menu::DoMenuAction(Menu *m, // selected menu entry
- int c, int r) // column and row
- {
- c += 2; // new column number
- r++; // ..and row number
- if (m->sub == 0) // q. submenu present?
- { // a. no .. continue
- if (m->fnc != 0) // q. function available?
- return((*(m->fnc))(c, r)); // a. yes .. call it
- else
- return(0); // else .. just return
- }
- else
- return(m->sub->DisplaySub(c, r)); // else .. do submenu
- }
- /* ******************************************************************** *
- *
- * Find -- find a menu entry by key
- *
- * ******************************************************************** */
- Menu *Menu::Find(char c) // key to search for
- {
- Menu *m = this; // work menu pointer
- c = toupper(c); // force uppercase search
- for (;;) // loop thru the list
- {
- if (toupper(m->key) == c) // q. find the entry?
- return(m); // a. yes .. quit here
- if ((m = m->next) == 0) // q. end of list?
- break; // a. yes .. exit loop
- }
- return(0); // else return empty-handed
- }
- /* ******************************************************************** *
- *
- * FindAlt -- find a menu entry by alt character (scan code)
- *
- * ******************************************************************** */
- Menu *Menu::FindAlt(char alt_c) // scan code to search
- {
- Menu *m = this; // work menu pointer
- for (;;) // loop thru the list
- {
- if (m->alt_key == alt_c) // q. find the entry?
- return(m); // a. yes .. quit here
- if ((m = m->next) == 0) // q. end of list?
- break; // a. yes .. exit loop
- }
- return(0); // else return empty-handed
- }
- /* ******************************************************************** *
- *
- * Left -- find a menu entry's left
- *
- * ******************************************************************** */
- Menu *Menu::Left(Menu *m) // source menu entry
- {
- Menu *t = this, // target menu pointer
- *last; // last processed entry
- for (;;) // loop thru the list
- {
- if (t->next == m) // q. find the entry?
- return(t); // a. yes .. quit here
- last = t; // save last one
- if ((t = t->next) == 0) // q. end of list?
- return(last); // a. yes .. exit w/last one
- }
- }
- /* ******************************************************************** *
- *
- * Right -- find a menu entry's right
- *
- * ******************************************************************** */
- Menu *Menu::Right(Menu *m) // source menu entry
- {
- return(m->next ? m->next : this); // either next or 1st in list
- }
- /* ******************************************************************** *
- *
- * MaxWidth -- find the widest menu label
- *
- * ******************************************************************** */
- int Menu::MaxWidth(void)
- {
- int x = 0, // max width
- w; // working width
- Menu *m = this; // work pointer
- for (;;) // loop thru the list
- {
- w = strlen(m->item); // get length of this entry
- if (x < w) // q. find a larger one?
- x = w; // a. yes .. save larger
- if ((m = m->next) == 0) // q. end of list?
- return(x); // a. yes .. exit loop
- }
- }
- /* ******************************************************************** *
- *
- * Count -- find the count of menu items
- *
- * ******************************************************************** */
- int Menu::Count(void)
- {
- int i; // loop counter
- Menu *m = this; // work pointer
- for (i = 0; m->next; i++, m = m->next) // count number of entries
- ;
- return(i); // ..and return w/count
- }
- /* ******************************************************************** *
- *
- * SetColors -- set global menu colors
- *
- * ******************************************************************** */
- void Menu::SetColors(int cn, // new normal color combo
- int cr) // ..and reverse color combo
- {
- menu_cn = cn; // set up new global
- menu_cr = cr; // ..color scheme
- }
- /* ******************************************************************** *
- *
- * ValidateKey -- validate key for a menu
- *
- * ******************************************************************** */
- Menu *Menu::ValidateKey(int c) // char to check
- {
- if (c == 0x100) // q. just alt key?
- return(this); // a. yes .. use first entry
- if (c > 0x100) // q. alt key?
- return(FindAlt(c)); // a. yes .. check alt list
- else
- return(Find(c)); // else .. check regular list
- }
- /* ******************************************************************** *
- *
- * ~Menu -- object destructor
- *
- * ******************************************************************** */
- Menu::~Menu()
- {
- delete item; // de-allocate string memory
- }
- /* ******************************************************************** *
- *
- * get_key() -- get a key (including function keys)
- *
- * ******************************************************************** */
- int get_key(int alt_key) // nonzero = allow alt_key
- {
- static
- int k; // local key variable
- if ((k = bioskey(1)) != 0) // q. key available?
- { // a. yes .. process it
- if (k == -1) // q. control break?
- {
- k = 0; // a. yes .. clear key,
- wait(1); // ..wait a tick, then return
- }
- else
- {
- k = bioskey(0); // else .. get waiting key
- if (NOT (k & 0xff)) // q. fnc or extended key?
- k = 0x100 + (k >> 8); // a. yes .. show special key
- else
- k &= 0xff; // else .. force regular key
- }
- }
- else if (alt_key && // q. allowing alt key?
- (_bios_keybrd(_KEYBRD_SHIFTSTATUS) // ..and one pressed?
- & 0x08))
- k = 0x100; // a. yes .. special key
- else
- k = 0; // else .. nothing available
- return(k); // return w/key if available
- }
- /* ******************************************************************** *
- *
- * get_scan() -- get scan code for a printable character
- *
- * ******************************************************************** */
- char get_scan(unsigned char c) // ASCII character to convert
- {
- static
- char scan_codes[] = // scan codes for ! thru ~
- {
- 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d,
- 0x33, 0x0c, 0x34, 0x35, 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 0x03, 0x1e,
- 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
- 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
- 0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x07, 0x0c, 0x29, 0x1e, 0x30,
- 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32,
- 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d,
- 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x29
- };
- return((c >= '!' && c <= '~') ? // if valid rtn scan code
- scan_codes[c - '!'] : 0); // ..else return a zero
- }
- /* ******************************************************************** *
- *
- * NotYet -- null routine for incomplete menu entries
- *
- * ******************************************************************** */
- int NotYet(int c, int r) // column and row of window
- {
- Window ny_win(c, r, c + 28, r + 3, // define not yet window
- menu_cn, menu_cr); // ..using default colors
- ny_win.Open(single_line); // open window with a border
- ny_win.Display(" ** Not Yet Implemented **" //display the not yet message
- "nr"
- " Press any key to continue");
- while (NOT get_key(NO_ALT)) // wait for a key
- ; // ..before closing down
- return(0); // return to menu system
- }