home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1988 / 10 / menu.c < prev   
C/C++ Source or Header  |  1988-10-31  |  18KB  |  758 lines

  1. _C PROGRAMMING_
  2. by
  3. Al Stevens
  4.  
  5. Listing 1.
  6.  
  7.  
  8. /* ----------- menu.h ---------- */
  9.  
  10. typedef struct w_menu {
  11.     char *mname;            /* menu bar selection names                     */
  12.     char *mhlpmsg;          /* menu bar prompting messages                  */
  13.     char **mselcs;          /* the pop-down menu selections                 */
  14.     char **mshelp;          /* help mnemonics for the pop-down selections   */
  15.     char *mskeys;           /* key strokes that accompany the selections    */
  16.     int (**func)(int,int);  /* the functions to execute for the selections  */
  17.     int lastvsel;           /* most recent vertical selection               */
  18. } MENU;
  19.  
  20. void menu_select(MENU *, int);
  21. char *display_menubar(MENU *);
  22. void restore_menubar(char *);
  23.  
  24. Listing 2.
  25.  
  26. /* ------------ menu.c ------------ */
  27.  
  28. #include <stdio.h>
  29. #include <conio.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <ctype.h>
  33. #include "window.h"
  34. #include "menu.h"
  35.  
  36. #define ON 1
  37. #define OFF 0
  38.  
  39. static int getvmn(void);
  40. static void haccent(int);
  41. static void dimension(char **,int *,int *);
  42. static void light(int);
  43. static int vlook(int,int);
  44.  
  45. int hsel = 1;        /* horizontal selection */
  46. MENU *mn;            /* active menu          */
  47.  
  48. /* ------------- display & process a menu ----------- */
  49. void menu_select(MENU *mnn, int sel)
  50. {
  51.     int hs, sx, sy, vsel, holdhsel, frtn = FALSE;
  52.     char *mb;
  53.  
  54.     if (sel)
  55.         hsel = sel;
  56.     mn = mnn;
  57.     sx = wherex();
  58.     sy = wherey();
  59.     mb = display_menubar(mn);
  60.     light(ON);
  61.     while (!frtn && ((vsel = getvmn()) != 0))    {
  62.         light(OFF);
  63.         holdhsel = hsel;
  64.         hs = hsel;
  65.         hsel = 1;
  66.         frtn = (*(mn+hs-1)->func [vsel-1]) ?
  67.                (*(mn+hs-1)->func [vsel-1])(hs,vsel) : FALSE;
  68.         hsel = holdhsel;
  69.         mn = mnn;
  70.         light(ON);
  71.     }
  72.     light(OFF);
  73.     gotoxy(sx, sy);
  74.     restore_menubar(mb);
  75. }
  76.  
  77. /* --- display the menu bar with no selections chosen ---- */
  78. char *display_menubar(MENU *mn)
  79. {
  80.     int i = 0;
  81.     char *mb;
  82.  
  83.     if ((mb = malloc(160)) != NULL)
  84.         gettext(1,1,80,1,mb);
  85.     window(1,1,80,25);
  86.     gotoxy(1,1);
  87.     textcolor(MENUFG);
  88.     textbackground(MENUBG);
  89.     cprintf("    ");
  90.     while ((mn+i)->mname)
  91.         cprintf(" %-10.10s ", (mn+i++)->mname);
  92.     while (i++ < 6)
  93.         cprintf("            ");
  94.     cprintf("    ");
  95.     hidecursor();
  96.     return mb;
  97. }
  98.  
  99. /* ------------ restore the menu bar line --------------- */
  100. void restore_menubar(char *mb)
  101. {
  102.     if (mb)    {
  103.         puttext(1,1,80,1,mb);
  104.         free(mb);
  105.     }
  106. }
  107.  
  108. /* ---------pop down a vertical menu --------- */
  109. static int getvmn()
  110. {
  111.     int ht, wd, vx, sel;
  112.  
  113.     while (TRUE)    {
  114.         dimension((mn+hsel-1)->mselcs, &ht, &wd);
  115.         if (!(mn+hsel-1)->lastvsel)
  116.             (mn+hsel-1)->lastvsel = 1;
  117.         if (ht > 0)    {
  118.             vx = 5+(hsel-1)*12;
  119.             establish_window(vx, 2, vx+wd+1, ht+3,
  120.                 MENUFG, MENUBG,TRUE);
  121.             text_window((mn+hsel-1)->mselcs, 1);
  122.             sel = select_window((mn+hsel-1)->lastvsel,
  123.                 SELECTFG, SELECTBG, vlook);
  124.             delete_window();
  125.             if (sel == FWD || sel == BS)
  126.                 haccent(sel);
  127.             else
  128.                 return ((mn+hsel-1)->lastvsel = sel);
  129.         }
  130.         else    {
  131.             if ((sel = getkey()) == *(mn+hsel-1)->mskeys)
  132.                 return 1;
  133.             switch (sel)    {
  134.                 case FWD:
  135.                 case BS:    haccent(sel);
  136.                             break;
  137.                 case '\r':    return 1;
  138.                 case ESC:    return 0;
  139.                 default:    putch(BELL);
  140.                             break;
  141.             }
  142.         }
  143.     }
  144. }
  145.  
  146. /* ---- if vertical menu user types FWD, BS,
  147.                or a menu key, return it ---- */
  148. static int vlook(ch, sel)
  149. {
  150.     char *cs, *ks;
  151.  
  152.     if (ch == FWD || ch == BS)    {
  153.         (mn+hsel-1)->lastvsel = sel;
  154.         return ch;
  155.     }
  156.     ks = (mn+hsel-1)->mskeys;
  157.     if ((cs = memchr(ks, tolower(ch), strlen(ks))) == NULL)
  158.         return ERROR;
  159.     return ((mn+hsel-1)->lastvsel = cs-ks+1);
  160. }
  161.  
  162. /* ----- manage the horizontal menu selection accent ----- */
  163. static void haccent(int sel)
  164. {
  165.     switch (sel)    {
  166.         case FWD:
  167.             light(OFF);
  168.             if ((mn+hsel)->mname)
  169.                 hsel++;
  170.             else
  171.                 hsel = 1;
  172.             light(ON);
  173.             break;
  174.         case BS:
  175.             light(OFF);
  176.             if (hsel == 1)
  177.                 while ((mn+hsel)->mname)
  178.                     hsel++;
  179.             else
  180.                 --hsel;
  181.             light(ON);
  182.             break;
  183.         default:
  184.             break;
  185.     }
  186. }
  187.  
  188. /* ---------- compute a menu's height & width --------- */
  189. static void dimension(char *sl[], int *ht, int *wd)
  190. {
  191.     *ht = *wd = 0;
  192.  
  193.     while (sl && sl [*ht])    {
  194.         *wd = max(*wd, (unsigned) strlen(sl [*ht]));
  195.         (*ht)++;
  196.     }
  197. }
  198.  
  199. /* --------- accent a horizontal menu selection ---------- */
  200. static void light(int onoff)
  201. {
  202.     extern struct wn wkw;
  203.     extern char spaces[];
  204.     int ln;
  205.  
  206.     window(1,1,80,25);
  207.      textcolor(onoff ? SELECTFG : MENUFG);
  208.      textbackground(onoff ? SELECTBG : MENUBG);
  209.      gotoxy((hsel-1)*12+6, 1);
  210.     cprintf((mn+hsel-1)->mname);
  211.     textcolor(TEXTFG);
  212.     textbackground(TEXTBG);
  213.     if ((mn+hsel-1)->mhlpmsg)    {
  214.         if (onoff)    {
  215.             ln = strlen((mn+hsel-1)->mhlpmsg);
  216.             gotoxy((80-ln)/2,25);
  217.             cprintf((mn+hsel-1)->mhlpmsg);
  218.         }
  219.         else    {
  220.             gotoxy(1,25);
  221.             cprintf(spaces);
  222.         }
  223.     }
  224.     current_window();
  225.     hidecursor();
  226. }
  227.  
  228.  
  229. Listing 3.
  230.  
  231.  
  232. /* --------- testmenu.c ------------ */
  233. #include <stdio.h>
  234. #include <string.h>
  235. #include "window.h"
  236. #include "menu.h"
  237.  
  238. /* ---------- menu tables --------- */
  239. static char *fselcs[] = {
  240.     "Load",
  241.     "Save",
  242.     "New",
  243.     "Quit   [Esc]",
  244.     NULL
  245. };
  246.  
  247. static char *eselcs[] = {
  248.     "Move       [F3]",
  249.     "Copy       [F4]",
  250.     "Delete     [F8]",
  251.     "Find       [F7]",
  252.     NULL
  253. };
  254.  
  255. static char *oselcs[] = {
  256.     "Auto Paragraph Reformat       ",
  257.     "Insert  [Ins]                 ",
  258.     NULL
  259. };
  260.  
  261. static int quit(int,int);
  262. static int reform(int, int);
  263. static int insert(int, int);
  264. static void set_toggles(void);
  265.  
  266. static char forced[] = {F3,F4,F8,F7};
  267.  
  268. static char options[] = {'a', INS};
  269.  
  270. static int (*ffuncs[])()={NULL,NULL,NULL,quit};
  271. static int (*efuncs[])()={NULL,NULL,NULL,NULL};
  272. static int (*ofuncs[])()={reform,insert};
  273.  
  274. static char filehelp[] =
  275.    "Load a file, Save current buffer, Type a new file, Quit";
  276. static char edithelp[] =
  277.    "Move, Copy, Delete blocks, Find a string";
  278. static char optnhelp[] = 
  279.    "Toggle editor options";
  280.  
  281. MENU emn [] = {
  282.     {"File",    filehelp, fselcs, NULL,   "",      ffuncs, 0},
  283.     {"Edit",    edithelp, eselcs, NULL,   forced,  efuncs, 0},
  284.     {"Options", optnhelp, oselcs, NULL,   options, ofuncs, 0},
  285.     {NULL}
  286. };
  287.  
  288. void main()
  289. {
  290.     set_toggles();
  291.     clear_screen();
  292.     menu_select(emn, 1);
  293.     clear_screen();
  294. }
  295.  
  296. /* ---- illustrates toggled menu mode selectors -------- */
  297. int reforming, inserting;  /* these are mode variables */
  298.  
  299. static int reform(hs,vs)
  300. {
  301.     reforming ^= TRUE;
  302.     set_toggles();
  303.     return FALSE;
  304. }
  305.  
  306. static int insert(hs,vs)
  307. {
  308.     inserting ^= TRUE;
  309.     set_toggles();
  310.     return FALSE;
  311. }
  312.  
  313. static void set_toggles()
  314. {
  315.     strcpy(&oselcs[0][24], reforming ? "(on) " : "(off)");
  316.     strcpy(&oselcs[1][24], inserting ? "(on) " : "(off)");
  317. }
  318.  
  319. /* ---- when TRUE is returned, the menu system exits ----- */
  320. static int quit(hs,vs)
  321. {
  322.     return TRUE;
  323. }
  324.  
  325.  
  326. Listing 4.
  327.  
  328.  
  329. /* --------- entry.h ---------- */
  330.  
  331. typedef struct field {      /* data entry field description*/
  332.     int frow;               /* field row                   */
  333.     int fcol;               /* field column position       */
  334.     int fx;                 /* running column              */
  335.     char *fbuff;            /* field buffer                */
  336.     char *fmask;            /* field data entry mask       */
  337.     char *fhelp;            /* field help window mnemonic  */
  338. } FIELD;
  339.  
  340. void field_tally(void);
  341. int data_entry(FIELD *, int, int);
  342. void clear_template(void);
  343. void insert_line(void);
  344.  
  345. #define INSERTING TRUE      /* initial Insert mode */
  346.  
  347.  
  348.  
  349. Listing 5.
  350.  
  351. /* --------- entry.c ---------- */
  352.  
  353. #include <stdio.h>
  354. #include <ctype.h>
  355. #include <stdlib.h>
  356. #include <string.h>
  357. #include <conio.h>
  358. #include <dos.h>
  359. #include "window.h"
  360. #include "entry.h"
  361.  
  362. #define FIELDCHAR '_'
  363. int inserting = INSERTING;      /* insert mode, TRUE/FALSE */
  364.  
  365. extern struct wn wkw;
  366.  
  367. /* -------- local prototypes -------- */
  368. static void addfield(FIELD *);
  369. static void disp_field(FIELD *, char *, char *);
  370. static int read_field(int);
  371. static void data_value(FIELD *);
  372. static int endstroke(int);
  373. static void home_cursor(void);
  374. static int backspace(void);
  375. static void end_cursor(void);
  376. static void forward(void);
  377. static int fore_word(void);
  378. static int back_word(void);
  379. static void delete_char(void);
  380. static void delete_word(void);
  381.  
  382. static FIELD *fhead;
  383. static FIELD *ftail;
  384. FIELD *fld;
  385.  
  386. /* -------- display a data field ------ */
  387. static void disp_field(FIELD *fldv, char *bf, char *msk)
  388. {
  389.     char cl[80], *cp = cl;
  390.  
  391.     while (*msk)    {
  392.         *cp++ = (*msk != FIELDCHAR ? *msk : *bf++);
  393.         msk++;
  394.     }
  395.     *cp = '\0';
  396.     writeline(fldv->fx + fldv->fcol - 1,
  397.                fldv->frow, cl);
  398. }
  399.  
  400. /* ------- display the data value in a field ------ */
  401. static void data_value(FIELD *fldv)
  402. {
  403.     gotoxy(fldv->fcol, fldv->frow);
  404.     fldv->fx = 1;
  405.     disp_field(fldv, fldv->fbuff, fldv->fmask);
  406. }
  407.  
  408. /* ------ display all the fields in a window ------- */
  409. void field_tally()
  410. {
  411.     FIELD *fldt;
  412.  
  413.     fldt = fhead;
  414.     while (fldt != ftail)    {
  415.         data_value(fldt);
  416.         fldt++;
  417.     }
  418. }
  419.  
  420. /* ------- clear a template to all blanks ------ */
  421. void clear_template()
  422. {
  423.     FIELD *fldc;
  424.     char *bf, *msk;
  425.  
  426.     fldc = fhead;
  427.     while (fldc != ftail)    {
  428.         bf = fldc->fbuff;
  429.         msk = fldc->fmask;
  430.         while (*msk)    {
  431.             if (*msk == FIELDCHAR)
  432.                 *bf++ = ' ';
  433.             msk++;
  434.         }
  435.         fldc++;
  436.     }
  437.     *bf = '\0';
  438.     field_tally();
  439. }
  440.  
  441. char *mask, *buff;
  442.  
  443. /* ------- read a field from the keyboard ------------- */
  444. static int read_field(c)
  445. {
  446.     int done = FALSE, first = TRUE;
  447.  
  448.     home_cursor();
  449.     while (TRUE)    {
  450.         gotoxy(fld->fx+fld->fcol-1, fld->frow);
  451.         if (!c || !first)
  452.             c = getkey();
  453.         first = FALSE;
  454.         switch (c)    {
  455.             case CTRL_D:
  456.                 delete_word();
  457.                 break;
  458.             case CTRL_FWD:
  459.                 done = !fore_word();
  460.                 break;
  461.             case CTRL_BS:
  462.                 done = !back_word();
  463.                 break;
  464.             case HOME:
  465.                 fld->fx = 1;
  466.                 home_cursor();
  467.                 break;
  468.             case END:
  469.                 end_cursor();
  470.                 break;
  471.             case FWD:
  472.                 forward();
  473.                 break;
  474.             case BS:
  475.                 backspace();
  476.                 break;
  477.             case '\b':
  478.                 if (!backspace())
  479.                     break;
  480.                 gotoxy(fld->fx+fld->fcol-1, fld->frow);
  481.             case DEL:
  482.                 delete_char();
  483.                 disp_field(fld, buff, mask);
  484.                 break;
  485.             case INS:
  486.                 inserting ^= TRUE;
  487.                 insert_line();
  488.                 break;
  489.             default:
  490.                 if (endstroke(c))    {
  491.                     done = TRUE;
  492.                     break;
  493.                 }
  494.                 if (inserting)    {
  495.                     memmove(buff+1, buff, strlen(buff)-1);
  496.                     disp_field(fld, buff, mask);
  497.                     gotoxy(fld->fcol+fld->fx-1, fld->frow);
  498.                 }
  499.                 *buff = (char) c;
  500.                 putch(c);
  501.                 forward();
  502.                 if (!*mask)
  503.                     c = FWD;
  504.                 break;
  505.         }
  506.         if (done || !*mask)
  507.             break;
  508.     }
  509.     wkw.wx = fld->fx+1;
  510.     return c;
  511. }
  512.  
  513. /* -------- home the cursor in the field -------- */
  514. static void home_cursor()
  515. {
  516.     buff = fld->fbuff+fld->fx-1;
  517.     mask = fld->fmask+fld->fx-1;
  518.     while (*mask != FIELDCHAR)    {
  519.         fld->fx++;
  520.         mask++;
  521.     }
  522. }
  523.  
  524. /* ------- move the cursor to the end of the field ------ */
  525. static void end_cursor()
  526. {
  527.     fld->fx += strlen(mask)-1;
  528.     buff += strlen(buff)-1;
  529.     mask += strlen(mask)-1;
  530.     while (*buff == ' ')
  531.         if (!backspace())
  532.             break;
  533.     forward();
  534. }
  535.  
  536. /* ------ move the cursor forward one character -------- */
  537. static void forward()
  538. {
  539.     do    {
  540.         fld->fx++;
  541.         mask++;
  542.     } while (*mask && *mask != FIELDCHAR);
  543.     buff++;
  544. }
  545.  
  546. /* ------- move back one character ------------ */
  547. static int backspace()
  548. {
  549.     if (buff != fld->fbuff)    {
  550.         --buff;
  551.         do    {
  552.             --mask;
  553.             --(fld->fx);
  554.         } while (*mask != FIELDCHAR);
  555.         return TRUE;
  556.     }
  557.     return FALSE;
  558. }
  559.  
  560. /* ------- move forward one word ------- */
  561. static int fore_word()
  562. {
  563.     int ct = 2, test = *buff == ' ';
  564.  
  565.     while (ct--)    {
  566.         while ((*buff == ' ') == test && *mask)
  567.             forward();
  568.         if (!*mask)
  569.             return FALSE;
  570.         if (test)
  571.             break;
  572.         test = !test;
  573.     }
  574.     return TRUE;
  575. }
  576.  
  577. /* ------- move backward one word ------- */
  578. static int back_word()
  579. {
  580.     int test;
  581.  
  582.     if (buff == fld->fbuff)
  583.         return FALSE;
  584.     if (*(buff-1) == ' ')
  585.         backspace();
  586.     test = *buff == ' ';
  587.     while ((*buff == ' ') == test && buff != fld->fbuff)
  588.         backspace();
  589.     if (test)
  590.         while (*buff != ' ' && buff != fld->fbuff)
  591.             backspace();
  592.     if (*buff == ' ')
  593.         forward();
  594.     return TRUE;
  595. }
  596.  
  597. /* --------- delete a character ----------- */
  598. static void delete_char()
  599. {
  600.     memmove(buff, buff+1, strlen(buff));
  601.     *(buff+strlen(buff)) = ' ';
  602. }
  603.  
  604. /* ----------- delete a word ---------- */
  605. static void delete_word()
  606. {
  607.     int test = *buff == ' ';
  608.     int ln = strlen(buff);
  609.  
  610.     while ((*buff == ' ') == test && ln--)
  611.         delete_char();
  612.     if (!test)
  613.         delete_char();
  614.     disp_field(fld, buff, mask);
  615. }
  616.  
  617. /* ---------- test c for an ending keystroke ----------- */
  618. static int endstroke(int c)
  619. {
  620.     switch (c)    {
  621.         case '\r':
  622.         case '\n':
  623.         case '\t':
  624.         case ESC:
  625.         case F1:
  626.         case F2:
  627.         case F3:
  628.         case F4:
  629.         case F5:
  630.         case F6:
  631.         case F7:
  632.         case F8:
  633.         case F9:
  634.         case F10:
  635.         case PGUP:
  636.         case PGDN:
  637.         case HOME:
  638.         case END:
  639.         case CTRL_FWD:
  640.         case CTRL_BS:
  641.         case CTRL_HOME:
  642.         case CTRL_END:
  643.         case UP:
  644.         case DN:
  645.             return TRUE;
  646.         default:
  647.             return FALSE;
  648.     }
  649. }
  650.  
  651. /* ----- Process data entry for a screen template. ---- */
  652. int data_entry(FIELD *fldin, int init, int firstfld)
  653. {
  654.     int exitcode = 0, done = FALSE;
  655.  
  656.     insert_line();
  657.     fhead = ftail = fld = fldin;
  658.     while (ftail->frow)
  659.         ftail++;
  660.     while (firstfld-- && fld != ftail)
  661.         fld++;
  662.     --fld;
  663.     if (init)
  664.         clear_template();
  665.     field_tally();
  666.     /* ---- collect data from keyboard into screen ---- */
  667.     while (done == FALSE)    {
  668.         gotoxy(fld->fcol, fld->frow);
  669.         textcolor(FIELDFG);
  670.         textbackground(FIELDBG);
  671.         data_value(fld);
  672.         gotoxy(fld->fcol, fld->frow);
  673.         fld->fx = 1;
  674.         exitcode = read_field(0);
  675.         textcolor(ENTRYFG);
  676.         textbackground(ENTRYBG);
  677.         data_value(fld);
  678.         switch (exitcode)    {
  679.             case DN:
  680.             case '\r':
  681.             case '\t':
  682.             case CTRL_FWD:
  683.             case FWD:    done = (ftail == fhead+1);
  684.                         fld++;
  685.                         if (fld == ftail)
  686.                             fld = fhead;
  687.                         break;
  688.             case CTRL_BS:
  689.             case UP:    if (fld == fhead)
  690.                             fld = ftail;
  691.                         --fld;
  692.                         break;
  693.             case CTRL_HOME:
  694.                         fld = fhead;
  695.                         break;
  696.             case CTRL_END:
  697.                         fld = ftail-1;
  698.                         break;
  699.             default:    done = endstroke(exitcode);
  700.                         break;
  701.         }
  702.     }
  703.     fld = NULL;
  704.     return (exitcode);
  705. }
  706.  
  707. /* ---------- set insert/exchange cursor shape ----------- */
  708. void insert_line()
  709. {
  710.     set_cursor_type(inserting ? 0x0106 : 0x0607);
  711. }
  712.  
  713.  
  714. Listing 6.
  715.  
  716. /* ----------- testentr.c --------- */
  717. #include <stdio.h>
  718. #include <conio.h>
  719. #include <string.h>
  720. #include "window.h"
  721. #include "entry.h"
  722.  
  723. struct config {
  724.     char name[36];
  725.     char acctno[21];
  726.     char password[11];
  727.     char phone[15];
  728. } cfg;
  729.  
  730. static char mask[] = "___________________________________";
  731. static char phmask[] = "(___) ___-____ ext.____";
  732.  
  733. FIELD pers_template[] = {
  734.     {3, 14, 1, cfg.name,    mask,    NULL},
  735.     {4, 14, 1, cfg.acctno,  mask+15, NULL},
  736.     {5, 14, 1, cfg.password,mask+25, NULL},
  737.     {6, 14, 1, cfg.phone,   phmask,  NULL},
  738.     {0}
  739. };
  740.  
  741. void main()
  742. {
  743.     establish_window(15,5,65,12,ENTRYFG,ENTRYBG,TRUE);
  744.     window_title(" Personal Data ");
  745.     gotoxy(3,3);
  746.     cputs("Name:");
  747.     gotoxy(3,4);
  748.     cputs("Account #:");
  749.     gotoxy(3,5);
  750.     cputs("Password:");
  751.     gotoxy(3,6);
  752.     cputs("Phone:");
  753.     data_entry(pers_template, TRUE, 1);
  754.     delete_window();
  755.     return FALSE;
  756. }
  757.  
  758.