📄 menu.cpp
字号:
// ******************************************************************** //
// //
// 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 = '\0'); // ..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 = '\0'); // ..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
*
* ******************************************************************** */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -