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) = 0,       // ..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) = 0,       // ..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. return(0);                                  // MSC idiosynchracy
  264. }
  265. /* ******************************************************************** *
  266.  *
  267.  *  DisplaySubMenu -- write out a submenu's entries
  268.  *
  269.  * ******************************************************************** */
  270. int     Menu::DisplaySubMenu(Menu *n,       // entry to highlight
  271.                              Window *w)     // window to display in
  272. {
  273. int  w_row = 1,                             // work row in menu bar
  274.      s_row;                                 // row of selected entry
  275. Menu *m = this;                             // work menu pointer
  276. for (;;)                                    // loop 'til all done
  277.     {
  278.     w->AtSay(1, w_row, " ");                // put some space out
  279.     if (m == n)                             // q. find entry?
  280.         {
  281.         w->DisplayReverse(m->item);         // a. yes .. highlight it
  282.         s_row = w_row;                      // ..and save row number
  283.         }
  284.      else
  285.         w->Display(m->item);                // else .. display normally
  286.     w_row++;                                // next row number
  287.     if ((m = m->next) == 0)                 // q. end of list?
  288.         break;                              // a. yes .. exit loop
  289.     }
  290. return(s_row);                              // return with entry's row
  291. }
  292. /* ******************************************************************** *
  293.  *
  294.  *  DoMenuAction -- process menu entry
  295.  *
  296.  * ******************************************************************** */
  297. int     Menu::DoMenuAction(Menu *m,         // selected menu entry
  298.                            int c, int r)    // column and row
  299. {
  300. c += 2;                                     // new column number
  301. r++;                                        // ..and row number
  302. if (m->sub == 0)                            // q. submenu present?
  303.     {                                       // a. no .. continue
  304.     if (m->fnc != 0)                        // q. function available?
  305.         return((*(m->fnc))(c, r));          // a. yes .. call it
  306.      else
  307.         return(0);                          // else .. just return
  308.     }
  309.  else
  310.     return(m->sub->DisplaySub(c, r));       // else .. do submenu
  311. }
  312. /* ******************************************************************** *
  313.  *
  314.  *  Find -- find a menu entry by key
  315.  *
  316.  * ******************************************************************** */
  317. Menu *Menu::Find(char c)                    // key to search for
  318. {
  319. Menu *m = this;                             // work menu pointer
  320. c = toupper(c);                             // force uppercase search
  321. for (;;)                                    // loop thru the list
  322.     {
  323.     if (toupper(m->key) == c)               // q. find the entry?
  324.         return(m);                          // a. yes .. quit here
  325.     if ((m = m->next) == 0)                 // q. end of list?
  326.         break;                              // a. yes .. exit loop
  327.     }
  328. return(0);                                  // else return empty-handed
  329. }
  330. /* ******************************************************************** *
  331.  *
  332.  *  FindAlt -- find a menu entry by alt character (scan code)
  333.  *
  334.  * ******************************************************************** */
  335. Menu *Menu::FindAlt(char alt_c)             // scan code to search
  336. {
  337. Menu *m = this;                             // work menu pointer
  338. for (;;)                                    // loop thru the list
  339.     {
  340.     if (m->alt_key == alt_c)                // q. find the entry?
  341.         return(m);                          // a. yes .. quit here
  342.     if ((m = m->next) == 0)                 // q. end of list?
  343.         break;                              // a. yes .. exit loop
  344.     }
  345. return(0);                                  // else return empty-handed
  346. }
  347. /* ******************************************************************** *
  348.  *
  349.  *  Left -- find a menu entry's left
  350.  *
  351.  * ******************************************************************** */
  352. Menu *Menu::Left(Menu *m)                   // source menu entry
  353. {
  354. Menu *t = this,                             // target menu pointer
  355.      *last;                                 // last processed entry
  356. for (;;)                                    // loop thru the list
  357.     {
  358.     if (t->next == m)                       // q. find the entry?
  359.         return(t);                          // a. yes .. quit here
  360.     last = t;                               // save last one
  361.     if ((t = t->next) == 0)                 // q. end of list?
  362.         return(last);                       // a. yes .. exit w/last one
  363.     }
  364. }
  365. /* ******************************************************************** *
  366.  *
  367.  *  Right -- find a menu entry's right
  368.  *
  369.  * ******************************************************************** */
  370. Menu *Menu::Right(Menu *m)                  // source menu entry
  371. {
  372. return(m->next ? m->next : this);           // either next or 1st in list
  373. }
  374. /* ******************************************************************** *
  375.  *
  376.  *  MaxWidth -- find the widest menu label
  377.  *
  378.  * ******************************************************************** */
  379. int     Menu::MaxWidth(void)
  380. {
  381. int     x = 0,                              // max width
  382.         w;                                  // working width
  383. Menu   *m = this;                           // work pointer
  384. for (;;)                                    // loop thru the list
  385.     {
  386.     w = strlen(m->item);                    // get length of this entry
  387.     if (x < w)                              // q. find a larger one?
  388.         x = w;                              // a. yes .. save larger
  389.     if ((m = m->next) == 0)                 // q. end of list?
  390.         return(x);                          // a. yes .. exit loop
  391.     }
  392. }
  393. /* ******************************************************************** *
  394.  *
  395.  *  Count -- find the count of menu items
  396.  *
  397.  * ******************************************************************** */
  398. int     Menu::Count(void)
  399. {
  400. int     i;                                  // loop counter
  401. Menu   *m = this;                           // work pointer
  402. for (i = 0; m->next; i++, m = m->next)      // count number of entries
  403.     ;
  404. return(i);                                  // ..and return w/count
  405. }
  406. /* ******************************************************************** *
  407.  *
  408.  *  SetColors -- set global menu colors
  409.  *
  410.  * ******************************************************************** */
  411. void    Menu::SetColors(int cn,             // new normal color combo
  412.                         int cr)             // ..and reverse color combo
  413. {
  414. menu_cn = cn;                               // set up new global
  415. menu_cr = cr;                               // ..color scheme
  416. }
  417. /* ******************************************************************** *
  418.  *
  419.  *  ValidateKey -- validate key for a menu
  420.  *
  421.  * ******************************************************************** */
  422. Menu   *Menu::ValidateKey(int c)            // char to check
  423. {
  424. if (c == 0x100)                             // q. just alt key?
  425.     return(this);                           // a. yes .. use first entry
  426. if (c > 0x100)                              // q. alt key?
  427.     return(FindAlt(c));                     // a. yes .. check alt list
  428.  else
  429.     return(Find(c));                        // else .. check regular list
  430. }
  431. /* ******************************************************************** *
  432.  *
  433.  *  ~Menu -- object destructor
  434.  *
  435.  * ******************************************************************** */
  436. Menu::~Menu()
  437. {
  438. delete item;                                // de-allocate string memory
  439. }
  440. /* ******************************************************************** *
  441.  *
  442.  *  get_key() -- get a key (including function keys)
  443.  *
  444.  * ******************************************************************** */
  445. int     get_key(int alt_key)                // nonzero = allow alt_key
  446. {
  447. static
  448. int     k;                                  // local key variable
  449. if ((k = _bios_keybrd(1)) != 0)             // q. key available?
  450.     {                                       // a. yes .. process it
  451.     if (k == -1)                            // q. control break?
  452.         {
  453.         k = 0;                              // a. yes .. clear key,
  454.         wait(1);                            // ..wait a tick, then return
  455.         }
  456.      else
  457.         {
  458.         k = _bios_keybrd(0);                // else .. get waiting key
  459.         if (NOT (k & 0xff))                 // q. fnc or extended key?
  460.             k = 0x100 + (k >> 8);           // a. yes .. show special key
  461.          else
  462.             k &= 0xff;                      // else .. force regular key
  463.         }
  464.     }
  465.  else if (alt_key &&                        // q. allowing alt key?
  466.          (_bios_keybrd(_KEYBRD_SHIFTSTATUS) // ..and one pressed?
  467.             & 0x08))
  468.     k = 0x100;                              // a. yes .. special key
  469.  else
  470.     k = 0;                                  // else .. nothing available
  471. return(k);                                  // return w/key if available
  472. }
  473. /* ******************************************************************** *
  474.  *
  475.  *  get_scan() -- get scan code for a printable character
  476.  *
  477.  * ******************************************************************** */
  478. char    get_scan(unsigned char c)           // ASCII character to convert
  479. {
  480. static
  481. char    scan_codes[] =                      // scan codes for ! thru ~
  482.     {
  483.     0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d,
  484.     0x33, 0x0c, 0x34, 0x35, 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
  485.     0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 0x03, 0x1e,
  486.     0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26,
  487.     0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
  488.     0x2d, 0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x07, 0x0c, 0x29, 0x1e, 0x30,
  489.     0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32,
  490.     0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d,
  491.     0x15, 0x2c, 0x1a, 0x2b, 0x1b, 0x29
  492.     };
  493. return((c >= '!' && c <= '~') ?             // if valid rtn scan code
  494.             scan_codes[c - '!'] : 0);       // ..else return a zero
  495. }
  496. /* ******************************************************************** *
  497.  *
  498.  *  NotYet -- null routine for incomplete menu entries
  499.  *
  500.  * ******************************************************************** */
  501. int     NotYet(int c, int r)                // column and row of window
  502. {
  503. Window  ny_win(c, r, c + 28, r + 3,         // define not yet window
  504.             menu_cn, menu_cr);              // ..using default colors
  505. ny_win.Open(single_line);                   // open window with a border
  506. ny_win.Display(" ** Not Yet Implemented **" //display the not yet message
  507.                "nr"
  508.                " Press any key to continue");
  509. while (NOT get_key(NO_ALT))                 // wait for a key
  510.     ;                                       // ..before closing down
  511. return(0);                                  // return to menu system
  512. }