MENU.CPP
上传用户:xr_qian
上传日期:2007-01-05
资源大小:443k
文件大小:25k
源码类别:

通讯/手机编程

开发平台:

DOS

  1. // ******************************************************************** //
  2. //                                                                      //
  3. //      MENU.CPP                                                        //
  4. //      Copyright (c) 1993, Michael Holmes and Bob Flanders             //
  5. //      C++ Communication Utilities                                     //
  6. //                                                                      //
  7. //      Chapter 7: Receiving a FAX                                      //
  8. //      Last changed in chapter 2                                       //
  9. //                                                                      //
  10. //      This file contains the definition and interface for             //
  11. //      the menu class.                                                 //
  12. //                                                                      //
  13. // ******************************************************************** //
  14. #define ALLOW_ALT   1                       // allow alt key in get_key()
  15. #define NO_ALT      0                       // ..and supress alt key
  16. /* ******************************************************************** *
  17.  *
  18.  *  Globals
  19.  *
  20.  * ******************************************************************** */
  21. int     menu_cn = MIX(WHITE, CYAN),         // default normal menu colors
  22.         menu_cr = MIX(WHITE, BLUE);         // ..and reverse colors
  23. int     NotYet(int c, int r);               // null routine definition
  24. char    get_scan(unsigned char);            // get scan code for character
  25. /* ******************************************************************** *
  26.  *
  27.  *  Menu class definition
  28.  *
  29.  * ******************************************************************** */
  30. class Menu
  31.     {
  32.     public:
  33.         Menu(char *s,                       // create first menu entry
  34.              int  (*f)(int, int) = NotYet,  // ..function to call
  35.              char c = '');                // ..special key character
  36.         Menu(Menu *m,                       // add a menu entry to list
  37.              char *s,                       // ..label to add
  38.              int  (*f)(int, int) = NotYet,  // ..function to call
  39.              int  t = 0,                    // ..submenu flag
  40.              char c = '');                // ..special key character
  41.         void SetColors(int cn, int cr),     // new norm and rev colors
  42.              Display(int c);                // process a main menu
  43.         Menu *ValidateKey(int c);           // validate key in menu
  44.        ~Menu();                             // destructor
  45.     private:
  46.         void EntryInit(char *s,             // initialize a menu entry
  47.                 int  (*f)(int c, int r),    // ..with runtime routine
  48.                 char c);                    // ..special key character
  49.         int  DisplayMenu(Menu *n,           // display menu bar
  50.                 Window *w),                 // ..highlighting an entry
  51.              DisplaySub(int c, int r),      // process a submenu
  52.              DisplaySubMenu(Menu *n,        // display submenu column
  53.                 Window *w),                 // ..and handle keystrokes
  54.              DoMenuAction(Menu *m,          // process menu entry
  55.                 int c, int r);              // ..using column and row
  56.         Menu *Find(char c),                 // find entry by char
  57.              *FindAlt(char alt_c),          // find entry by alt char
  58.              *Left(Menu *m),                // find an entry's left
  59.              *Right(Menu *m);               // ..and its right
  60.         int  Count(void),                   // count the entries
  61.              MaxWidth(void);                // find the max width label
  62.         char *item,                         // menu item label
  63.               key,                          // normal selection character
  64.               alt_key;                      // ..and alt selection char
  65.         int  (*fnc)(int c, int r);          // runtime menu entry fnc
  66.         Menu *next,                         // next item pointer
  67.              *sub;                          // submenu pointer
  68.     };
  69. /* ******************************************************************** *
  70.  *
  71.  *  Menu -- build the first menu entry
  72.  *
  73.  * ******************************************************************** */
  74. Menu::Menu(char *s,                         // new menu item
  75.            int  (*f)(int c, int r),         // runtime routine
  76.            char c)                          // special key character
  77. {
  78. EntryInit(s, f, c);                         // initialize new instance
  79. }
  80. /* ******************************************************************** **
  81.  *
  82.  *  Menu -- add an entry to the menu list
  83.  *
  84.  * ******************************************************************** */*
  85. Menu::Menu(Menu *m,                         // menu to chain into
  86.            char *s,                         // new menu item
  87.            int  (*f)(int c, int r),         // runtime routine
  88.            int  t,                          // type, 0 = at same level
  89.                                             //       1 = submenu
  90.            char c)                          // special key character
  91. {
  92. EntryInit(s, f, c);                         // build base instance
  93. if (t)                                      // q. submenu definition?
  94.     m->sub = this;                          // a. yes .. store in parent
  95.  else
  96.     {
  97.     while (m->next)                         // loop thru and ..
  98.         m = m->next;                        // ..then end of the list
  99.     m->next = this;                         // put this at the end
  100.     }
  101. }
  102. /* ******************************************************************** *
  103.  *
  104.  *  EntryInit -- initialize menu entry instance
  105.  *
  106.  * ******************************************************************** */
  107. void Menu::EntryInit(char *s,               // menu label to set up
  108.                      int  (*f)(int, int),   // runtime function
  109.                      char c)                // special key character
  110. {
  111. item = new char[strlen(s) + 1];             // get memory for label
  112. strcpy(item, s);                            // ..and copy into instance
  113. key = c ? c : *s;                           // ASCII selection key
  114. alt_key = get_scan(key);                    // alt selection key
  115. fnc = f ? f : NotYet;                       // runtime function
  116. next = sub = 0;                             // clear forward pointers
  117. }
  118. /* ******************************************************************** *
  119.  *
  120.  *  Display -- display and process a menu at the top of the screen
  121.  *
  122.  * ******************************************************************** */
  123. void    Menu::Display(int c)                // initial keystroke
  124. {
  125. int  col,                                   // offset of selected entry
  126.      k;                                     // keystroke
  127. Menu *m, *n;                                // work menu pointer
  128. NOCURSOR();                                 // no cursor while in menu
  129. Window w(1, 1, 80, 3, menu_cn, menu_cr);    // define menu window
  130. w.Open(double_line);                        // open window
  131. if ((m = ValidateKey(c)) != 0)              // q. find initial selection?
  132.     k = (c == 0x100) ? 0 : CR;              // a. yes .. set up for entry
  133.  else
  134.     {
  135.     m = this;                               // else .. use first entry
  136.     k = 0;                                  // ..in menu and clear key
  137.     }
  138. for (;;)                                    // loop 'til exit requested
  139.     {
  140.     col = DisplayMenu(m, &w);               // display and highlight
  141.     if (NOT k)                              // q. need a new key?
  142.         while ((k = get_key(NO_ALT)) == 0)  // a. yes .. wait for a key
  143.             ;
  144.     switch (k)                              // handle user's keystroke
  145.         {
  146.         case CR:                            // carriage return
  147.             k = DoMenuAction(m, col, 2);    // process menu entry
  148.             if (k < 0)                      // q. need to exit the menu?
  149.                 {
  150.                 CURSOR();                   // a. yes .. set cursor back
  151.                 return;                     // ..to normal and return
  152.                 }
  153.             break;                          // else .. wait for next key
  154.         case LEFT:                          // left arrow
  155.             m = Left(m);                    // get entry to the left
  156.             k = 0;                          // clear keystroke
  157.             break;                          // ..then wait for next key
  158.         case RIGHT:                         // right arrow
  159.             m = Right(m);                   // get entry to the right
  160.             k = 0;                          // clear keystroke
  161.             break;                          // ..then wait for next key
  162.         case ESC:                           // escape key
  163.             CURSOR();                       // set cursor back to normal
  164.             return;                         // ..exit loop and return
  165.         default:                            // error case
  166.             if ((n = ValidateKey(k)) != 0)  // q. valid menu key?
  167.                 {
  168.                 m = n;                      // a. yes .. set up as current
  169.                 k = CR;                     // ..and force a <cr>
  170.                 }
  171.              else
  172.                 {
  173.                 printf(BELL);               // else .. ring bell
  174.                 k = 0;                      // finally, clear keystroke
  175.                 }
  176.         }
  177.     }
  178. }
  179. /* ******************************************************************** *
  180.  *
  181.  *  DisplayMenu -- write out a menu's entries
  182.  *
  183.  * ******************************************************************** */
  184. int     Menu::DisplayMenu(Menu *n,          // entry to highlight
  185.                           Window *w)        // window to display in
  186. {
  187. int  w_offset = 2,                          // offset in menu bar
  188.      s_offset;                              // offset of selected entry
  189. Menu *m = this;                             // work menu pointer
  190. w->GotoXY(1, 1);                            // start from the beginning
  191. for (;;)
  192.     {
  193.     w->Display("  ");                       // put some space out
  194.     if (m == n)                             // q. find entry?
  195.         {
  196.         w->DisplayReverse(m->item);         // a. yes .. highlight it
  197.         s_offset = w_offset;                // ..and save field offset
  198.         }
  199.      else
  200.         w->Display(m->item);                // else .. display normally
  201.     w_offset += strlen(m->item) + 2;        // get offset of next item
  202.     if ((m = m->next) == 0)                 // q. end of list?
  203.         break;                              // a. yes .. exit loop
  204.     }
  205. return(s_offset);                           // return with entry's offset
  206. }
  207. /* ******************************************************************** *
  208.  *
  209.  *  DisplaySub -- display a submenu
  210.  *
  211.  * ******************************************************************** */
  212. int     Menu::DisplaySub(int c, int r)      // upper left coordinates
  213. {
  214. int     k = 0,                              // keystroke
  215.         r_current;                          // current row
  216. Menu   *m = this,                           // current menu entry
  217.        *n;                                  // work menu pointer
  218. Window w(c, r, c + 3 + MaxWidth(),          // define menu window
  219.             r + 2 + Count(),                // ..to hold whole submenu
  220.             menu_cn, menu_cr);              // ..using default colors
  221. w.Open(single_line);                        // open submenu window
  222. for (;;)                                    // loop 'til exit requested
  223.     {
  224.     r_current = DisplaySubMenu(m, &w);      // display and highlight
  225.     if (NOT k)                              // q. need a new key?
  226.         while ((k = get_key(NO_ALT)) == 0)  // a. yes .. wait for a key
  227.             ;
  228.     switch (k)                              // handle user's keystroke
  229.         {
  230.         case CR:                            // carriage return
  231.             k = DoMenuAction(m, c,          // process menu entry
  232.                     r + r_current);
  233.             if (k != 0)                     // q. need to exit the menu?
  234.                 return(k);                  // a. yes .. rtn w/keystroke
  235.             break;                          // else .. wait for next key
  236.         case UP:                            // up arrow
  237.             m = Left(m);                    // get entry above this one
  238.             k = 0;                          // clear keystroke
  239.             break;                          // ..then wait for next key
  240.         case DOWN:                          // down arrow
  241.             m = Right(m);                   // get entry beneath
  242.             k = 0;                          // clear keystroke
  243.             break;                          // ..then wait for next key
  244.         case LEFT:                          // left arrow
  245.             return(LEFT);                   // ..then return w/left key
  246.         case RIGHT:                         // right arrow
  247.             return(RIGHT);                  // ..then return w/right key
  248.         case ESC:                           // escape key
  249.             return(0);                      // ..then return one level
  250.         default:                            // error case
  251.             if ((n = ValidateKey(k)) != 0)  // q. valid menu key?
  252.                 {
  253.                 m = n;                      // a. yes .. set up as current
  254.                 k = CR;                     // ..and force a <cr>
  255.                 }
  256.              else
  257.                 {
  258.                 printf(BELL);               // else .. ring bell
  259.                 k = 0;                      // finally, clear keystroke
  260.                 }
  261.         }
  262.     }
  263. }
  264. /* ******************************************************************** *
  265.  *
  266.  *  DisplaySubMenu -- write out a submenu's entries
  267.  *
  268.  * ******************************************************************** */
  269. int     Menu::DisplaySubMenu(Menu *n,       // entry to highlight
  270.                              Window *w)     // window to display in
  271. {
  272. int  w_row = 1,                             // work row in menu bar
  273.      s_row;                                 // row of selected entry
  274. Menu *m = this;                             // work menu pointer
  275. for (;;)                                    // loop 'til all done
  276.     {
  277.     w->AtSay(1, w_row, " ");                // put some space out
  278.     if (m == n)                             // q. find entry?
  279.         {
  280.         w->DisplayReverse(m->item);         // a. yes .. highlight it
  281.         s_row = w_row;                      // ..and save row number
  282.         }
  283.      else
  284.         w->Display(m->item);                // else .. display normally
  285.     w_row++;                                // next row number
  286.     if ((m = m->next) == 0)                 // q. end of list?
  287.         break;                              // a. yes .. exit loop
  288.     }
  289. return(s_row);                              // return with entry's row
  290. }
  291. /* ******************************************************************** *
  292.  *
  293.  *  DoMenuAction -- process menu entry
  294.  *
  295.  * ******************************************************************** */
  296. int     Menu::DoMenuAction(Menu *m,         // selected menu entry
  297.                            int c, int r)    // column and row
  298. {
  299. c += 2;                                     // new column number
  300. r++;                                        // ..and row number
  301. if (m->sub == 0)                            // q. submenu present?
  302.     {                                       // a. no .. continue
  303.     if (m->fnc != 0)                        // q. function available?
  304.         return((*(m->fnc))(c, r));          // a. yes .. call it
  305.      else
  306.         return(0);                          // else .. just return
  307.     }
  308.  else
  309.     return(m->sub->DisplaySub(c, r));       // else .. do submenu
  310. }
  311. /* ******************************************************************** *
  312.  *
  313.  *  Find -- find a menu entry by key
  314.  *
  315.  * ******************************************************************** */
  316. Menu *Menu::Find(char c)                    // key to search for
  317. {
  318. Menu *m = this;                             // work menu pointer
  319. c = toupper(c);                             // force uppercase search
  320. for (;;)                                    // loop thru the list
  321.     {
  322.     if (toupper(m->key) == c)               // q. find the entry?
  323.         return(m);                          // a. yes .. quit here
  324.     if ((m = m->next) == 0)                 // q. end of list?
  325.         break;                              // a. yes .. exit loop
  326.     }
  327. return(0);                                  // else return empty-handed
  328. }
  329. /* ******************************************************************** *
  330.  *
  331.  *  FindAlt -- find a menu entry by alt character (scan code)
  332.  *
  333.  * ******************************************************************** */
  334. Menu *Menu::FindAlt(char alt_c)             // scan code to search
  335. {
  336. Menu *m = this;                             // work menu pointer
  337. for (;;)                                    // loop thru the list
  338.     {
  339.     if (m->alt_key == alt_c)                // q. find the entry?
  340.         return(m);                          // a. yes .. quit here
  341.     if ((m = m->next) == 0)                 // q. end of list?
  342.         break;                              // a. yes .. exit loop
  343.     }
  344. return(0);                                  // else return empty-handed
  345. }
  346. /* ******************************************************************** *
  347.  *
  348.  *  Left -- find a menu entry's left
  349.  *
  350.  * ******************************************************************** */
  351. Menu *Menu::Left(Menu *m)                   // source menu entry
  352. {
  353. Menu *t = this,                             // target menu pointer
  354.      *last;                                 // last processed entry
  355. for (;;)                                    // loop thru the list
  356.     {
  357.     if (t->next == m)                       // q. find the entry?
  358.         return(t);                          // a. yes .. quit here
  359.     last = t;                               // save last one
  360.     if ((t = t->next) == 0)                 // q. end of list?
  361.         return(last);                       // a. yes .. exit w/last one
  362.     }
  363. }
  364. /* ******************************************************************** *
  365.  *
  366.  *  Right -- find a menu entry's right
  367.  *
  368.  * ******************************************************************** */
  369. Menu *Menu::Right(Menu *m)                  // source menu entry
  370. {
  371. return(m->next ? m->next : this);           // either next or 1st in list
  372. }
  373. /* ******************************************************************** *
  374.  *
  375.  *  MaxWidth -- find the widest menu label
  376.  *
  377.  * ******************************************************************** */
  378. int     Menu::MaxWidth(void)
  379. {
  380. int     x = 0,                              // max width
  381.         w;                                  // working width
  382. Menu   *m = this;                           // work pointer
  383. for (;;)                                    // loop thru the list
  384.     {
  385.     w = strlen(m->item);                    // get length of this entry
  386.     if (x < w)                              // q. find a larger one?
  387.         x = w;                              // a. yes .. save larger
  388.     if ((m = m->next) == 0)                 // q. end of list?
  389.         return(x);                          // a. yes .. exit loop
  390.     }
  391. }
  392. /* ******************************************************************** *
  393.  *
  394.  *  Count -- find the count of menu items
  395.  *
  396.  * ******************************************************************** */
  397. int     Menu::Count(void)
  398. {
  399. int     i;                                  // loop counter
  400. Menu   *m = this;                           // work pointer
  401. for (i = 0; m->next; i++, m = m->next)      // count number of entries
  402.     ;
  403. return(i);                                  // ..and return w/count
  404. }
  405. /* ******************************************************************** *
  406.  *
  407.  *  SetColors -- set global menu colors
  408.  *
  409.  * ******************************************************************** */
  410. void    Menu::SetColors(int cn,             // new normal color combo
  411.                         int cr)             // ..and reverse color combo
  412. {
  413. menu_cn = cn;                               // set up new global
  414. menu_cr = cr;                               // ..color scheme
  415. }
  416. /* ******************************************************************** *
  417.  *
  418.  *  ValidateKey -- validate key for a menu
  419.  *
  420.  * ******************************************************************** */
  421. Menu   *Menu::ValidateKey(int c)            // char to check
  422. {
  423. if (c == 0x100)                             // q. just alt key?
  424.     return(this);                           // a. yes .. use first entry
  425. if (c > 0x100)                              // q. alt key?
  426.     return(FindAlt(c));                     // a. yes .. check alt list
  427.  else
  428.     return(Find(c));                        // else .. check regular list
  429. }
  430. /* ******************************************************************** *
  431.  *
  432.  *  ~Menu -- object destructor
  433.  *
  434.  * ******************************************************************** */
  435. Menu::~Menu()
  436. {
  437. delete item;                                // de-allocate string memory
  438. }
  439. /* ******************************************************************** *
  440.  *
  441.  *  get_key() -- get a key (including function keys)
  442.  *
  443.  * ******************************************************************** */
  444. int     get_key(int alt_key)                // nonzero = allow alt_key
  445. {
  446. static
  447. int     k;                                  // local key variable
  448. if ((k = bioskey(1)) != 0)                  // q. key available?
  449.     {                                       // a. yes .. process it
  450.     if (k == -1)                            // q. control break?
  451.         {
  452.         k = 0;                              // a. yes .. clear key,
  453.         wait(1);                            // ..wait a tick, then return
  454.         }
  455.      else
  456.         {
  457.         k = bioskey(0);                     // else .. get waiting key
  458.         if (NOT (k & 0xff))                 // q. fnc or extended key?
  459.             k = 0x100 + (k >> 8);           // a. yes .. show special key
  460.          else
  461.             k &= 0xff;                      // else .. force regular key
  462.         }
  463.     }
  464.  else if (alt_key &&                        // q. allowing alt key?
  465.          (_bios_keybrd(_KEYBRD_SHIFTSTATUS) // ..and one pressed?
  466.             & 0x08))
  467.     k = 0x100;                              // a. yes .. special key
  468.  else
  469.     k = 0;                                  // else .. nothing available
  470. return(k);                                  // return w/key if available
  471. }
  472. /* ******************************************************************** *
  473.  *
  474.  *  get_scan() -- get scan code for a printable character
  475.  *
  476.  * ******************************************************************** */
  477. char    get_scan(unsigned char c)           // ASCII character to convert
  478. {
  479. static
  480. char    scan_codes[] =                      // scan codes for ! thru ~
  481.     {
  482.     0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d,
  483.     0x33, 0x0c, 0x34, 0x35, 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  484.     0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 0x03, 0x1e,
  485.     0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
  486.     0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
  487.     0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x07, 0x0c, 0x29, 0x1e, 0x30,
  488.     0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32,
  489.     0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d,
  490.     0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x29
  491.     };
  492. return((c >= '!' && c <= '~') ?             // if valid rtn scan code
  493.             scan_codes[c - '!'] : 0);       // ..else return a zero
  494. }
  495. /* ******************************************************************** *
  496.  *
  497.  *  NotYet -- null routine for incomplete menu entries
  498.  *
  499.  * ******************************************************************** */
  500. int     NotYet(int c, int r)                // column and row of window
  501. {
  502. Window  ny_win(c, r, c + 28, r + 3,         // define not yet window
  503.             menu_cn, menu_cr);              // ..using default colors
  504. ny_win.Open(single_line);                   // open window with a border
  505. ny_win.Display(" ** Not Yet Implemented **" //display the not yet message
  506.                "nr"
  507.                " Press any key to continue");
  508. while (NOT get_key(NO_ALT))                 // wait for a key
  509.     ;                                       // ..before closing down
  510. return(0);                                  // return to menu system
  511. }