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