home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_100 / 198_02 / menu.c < prev    next >
C/C++ Source or Header  |  1990-01-23  |  12KB  |  520 lines

  1. /*    Menu:    Menu processor
  2.  */
  3.  
  4. #include    <stdio.h>
  5. #include    "estruct.h"
  6. #include    "edef.h"
  7.  
  8. #if    MENUS
  9.  
  10. /* screen area (taken from display.c, should be moved to a header file) */
  11.  
  12. typedef struct  VIDEOTAG {
  13.         int    v_flag;                 /* Flags */
  14. #if    COLOR
  15.     int    v_fcolor;        /* current forground color */
  16.     int    v_bcolor;        /* current background color */
  17.     int    v_rfcolor;        /* requested forground color */
  18.     int    v_rbcolor;        /* requested background color */
  19. #endif
  20.         char    v_text[1];              /* Screen data. */
  21. }       VIDEO;
  22.  
  23. #define VFCHG   0x0001                  /* Changed flag            */
  24. #define    VFEXT    0x0002            /* extended (beyond column 80)    */
  25. #define    VFREV    0x0004            /* reverse video status        */
  26. #define    VFREQ    0x0008            /* reverse video request    */
  27. #define    VFCOL    0x0010            /* color change requested    */
  28.  
  29. extern VIDEO   **vscreen;        /* Virtual screen. */
  30.  
  31. /* menu codes return by getmkey() */
  32.  
  33. #define    MENUMERR    0    /* unrecognized command */
  34. #define    MENUMUP        1    /* go up */
  35. #define    MENUMDOWN    2    /* go down */
  36. #define    MENUMLEFT    3    /* go left */
  37. #define    MENUMRIGHT    4    /* go right */
  38. #define    MENUMENTER    5    /* CR */
  39.  
  40. /* box drawing characters */
  41.  
  42. #if    IBMPC
  43. #define    BOXUR    218
  44. #define    BOXUL    191
  45. #define    BOXLR    192
  46. #define    BOXLL    217
  47. #define    BOXH    196
  48. #define    BOXV    179
  49. #else
  50. #define    BOXUR    '.'
  51. #define    BOXUL    '.'
  52. #define    BOXLR    '\''
  53. #define    BOXLL    '\''
  54. #define    BOXH    '-'
  55. #define    BOXV    '|'
  56. #endif
  57.  
  58. extern int fileread(), filesave(), filewrite(), insfile();
  59. extern int spawncli(), spawn(), quit();
  60. extern int forwsearch(), forwhunt(), nullproc(), sreplace();
  61.  
  62. extern int forwline(), backline(), forwchar(), backchar();
  63. extern int newline(), openline(), indent(), tab(), insspace();
  64. #if DECEDT
  65. extern int scupwind(), scdnwind();
  66. #endif
  67.  
  68. #define    FPNULL    0
  69.  
  70. typedef struct {
  71.     char *m_text;
  72.     int m_up;
  73.     int m_down;
  74.     int m_left;
  75.     int m_right;
  76.     int (*m_func)();
  77.     } MENUTABLE;
  78.  
  79. MENUTABLE menudata[] = {
  80. /* 0 */    { "", 0, 1, 0, 0, FPNULL },
  81. /* 1 */    { "File", 0, 2, 0, 9, FPNULL },            /* File option */
  82. /* 2 */        { "New", 1, 0, 0, 3, fileread },    /* create new file */
  83. /* 3 */        { "Open", 1, 0, 2, 4, fileread },    /* read old file */
  84. /* 4 */        { "Insert", 1, 0, 3, 5, insfile },    /* insert file */
  85. /* 5 */        { "Save", 1, 0, 4, 6, filesave },    /* save current file */
  86. /* 6 */        { "save As", 1, 0, 5, 7, filewrite },    /* write a file */
  87. /* 7 */        { "Dos", 1, 0, 6, 8, spawncli },    /* do a DOS command */
  88. /* 8 */        { "Exit", 1, 0, 7, 0, quit },        /* exit */
  89. /* 9 */    { "Edit", 0, 10, 1, 13, FPNULL },
  90. /* 10 */    { "Search", 9, 0, 0, 11, forwsearch },    /* search */
  91. /* 11 */    { "Last search", 9, 0, 10, 12, forwhunt }, /* hunt */
  92. /* 12 */    { "Replace", 9, 0, 11, 0, sreplace },    /* replace */
  93. /* 13 */ { "Compile", 0, 0, 9, 0, spawn }
  94.     };
  95.  
  96. int menutwid;    /* width of entries on top line */
  97.  
  98. int menulast;    /* last option on main menu */
  99.  
  100. menuinit()    /* create menu line */
  101. {
  102.     LINE *lalloc();
  103.     int i, j, num, wid, m, len;
  104.  
  105.     if (menuflag)    {
  106.         menulast = 1;
  107.  
  108.         if (menuline != NULL) free(menuline);
  109.         menuline = lalloc(term.t_ncol);
  110.         if (menuline == NULL)    {
  111.             mlwrite("[Can not create menu line]");
  112.             menuflag = 0;
  113.             return;
  114.         }
  115.         menuline->l_fp = NULL;
  116.         menuline->l_bp = NULL;
  117.         menuline->l_used = term.t_ncol;
  118.         num = menucount(0);
  119.         menutwid = llength(menuline) / num;
  120.         wid = menutwid - 1;
  121.         for (i = 0; i < llength(menuline); i++)
  122.             lputc(menuline, i, ' ');
  123.         j = 0;
  124.         for (m = 1; m != 0; m = menudata[m].m_right)    {
  125.             for (i = 0; menudata[m].m_text[i] && i < wid; i++)
  126.                 lputc(menuline, i+j, menudata[m].m_text[i]);
  127.             j += menutwid;
  128.         }
  129.     }
  130. }
  131.  
  132. /* find number of options beneath m */
  133.  
  134. int menucount(m)
  135. int m;
  136. {
  137.     int c;
  138.  
  139.     c = 0;
  140.     for(m = menudata[m].m_down; m != 0; m = menudata[m].m_right)
  141.         c++;
  142.     return(c);
  143. }
  144.  
  145. /* find length of longest string under m */
  146.  
  147. int menulen(m)
  148. int m;
  149. {
  150.     int i, len;
  151.  
  152.     len = 0;
  153.     for(m = menudata[m].m_down; m != 0; m = menudata[m].m_right) {
  154.         i = strlen( menudata[m].m_text );
  155.         if (i > len) len = i;
  156.     }
  157.     return(len);
  158. }
  159.  
  160. int menukey;        /* current key pressed */
  161.  
  162. getmkey()        /* read a menu movement command */
  163. {
  164.     int c, cmd;
  165.     int (*f)(), (*getbind())();
  166. #if    C86
  167.     int (*fbackline)(), (*fforwline)();
  168.     int (*fbackchar)(), (*fforwchar)(), (*findent)(), (*ftab)();
  169.     int (*finsspace)(), (*fnewline)(), (*fopenline)();
  170. #if DECEDT
  171.     int (*fscupwind)(), (*fscdnwind)();
  172.  
  173.     fscupwind = scupwind;
  174.     fscdnwind = scdnwind;
  175. #endif
  176.  
  177.     fbackline = backline;
  178.         fforwline = forwline;
  179.     fbackchar = backchar;
  180.     fforwchar = forwchar;
  181.     findent   = indent;
  182.     ftab      = tab;
  183.     finsspace = insspace;
  184.     fnewline  = newline;
  185.     fopenline = openline;
  186. #else
  187. #if DECEDT
  188. #define    fscupwind scupwind
  189. #define fscdnwind scdnwind
  190. #endif
  191. #define    fbackline backline
  192. #define    fforwline forwline
  193. #define fbackchar backchar
  194. #define fforwchar forwchar
  195. #define findent   indent
  196. #define ftab      tab
  197. #define finsspace insspace
  198. #define fnewline  newline
  199. #define    fopenline openline
  200. #endif
  201.  
  202.     TTflush();
  203.  
  204.     c = getcmd();
  205.     menukey = c & 0x7F;
  206.     if (menukey >= 'a' && menukey <= 'z') menukey += 'A' - 'a';
  207.  
  208.     f = getbind(c);
  209.  
  210.     if (f == fbackline) cmd = MENUMUP;
  211.     else if (f == fforwline) cmd = MENUMDOWN;
  212. #if DECEDT
  213.     else if (f == fscupwind) cmd = MENUMUP;
  214.     else if (f == fscdnwind) cmd = MENUMDOWN;
  215. #endif
  216.     else if (f == fbackchar) cmd = MENUMLEFT;
  217.     else if (f == fforwchar || f == findent || f == ftab ||
  218.          f == finsspace) cmd = MENUMRIGHT;
  219.     else if (f == fnewline || f == fopenline) cmd = MENUMENTER;
  220.     else if (c == ' ') cmd = MENUMRIGHT;
  221.     else if (c == '\n') cmd = MENUMENTER;
  222.     else cmd = MENUMERR;
  223.  
  224.     return(cmd);
  225. }
  226.  
  227. int menumatch(m)    /* check if menukey is in menu item m */
  228. int m;
  229. {
  230.     char *cp;
  231.  
  232.     if (menukey >= 'A' && menukey <= 'Z')
  233.         for(cp = menudata[m].m_text; *cp != '\0'; cp++)
  234.             if (*cp == menukey) return(1);
  235.     return(0);
  236. }
  237.  
  238. menudo(r, c, m)        /* execute a menu enter command */
  239. int r, c, m;
  240. {
  241.     int status;
  242.  
  243.     status = HOOK;
  244.     if (menudata[m].m_down != 0)
  245.         status = menupull(r, c, m);
  246.     if (menudata[m].m_func != FPNULL)
  247.         status = (*menudata[m].m_func)(FALSE, 1);
  248.     return(status);
  249. }
  250.  
  251. menuput(row, col, len, normal)        /* display a string */
  252. int row, col, len, normal;
  253. {
  254.     char *str;
  255.  
  256.     str = &(vscreen[row]->v_text[col]);
  257.  
  258.     if (row > 0) normal = 1 - normal;
  259.  
  260.     TTrev(normal);
  261.  
  262.     movecursor(row, col);
  263.     if (normal)    {
  264. #if    COLOR
  265.         TTforg(gbcolor);
  266.         TTbacg(gfcolor);
  267. #endif
  268. #if    IBMPC
  269.         menuwrite(row, col, str, len, gbcolor, gfcolor);
  270. #endif
  271.     }
  272.     else    {
  273. #if    COLOR
  274.         TTforg(gfcolor);
  275.         TTbacg(gbcolor);
  276. #endif
  277. #if    IBMPC
  278.         menuwrite(row, col, str, len, gfcolor, gbcolor);
  279. #endif
  280.     }
  281.  
  282.     ttcol += len;
  283.  
  284. #if    IBMPC
  285. #else
  286.     while(len-- > 0) TTputc(*str++);
  287.  
  288.     TTrev(0);
  289. #endif
  290. }
  291.  
  292. int menupull(row, col, men)    /* pull down a menu */
  293. int row, col, men;
  294. {
  295.     int nrows, ncols;
  296.     int c, r, m, curmrow, status, tmprow, tmpm;
  297.     char *save, *sp, *tp;
  298.     register VIDEO *vp;
  299.  
  300.     /* initialize */
  301.  
  302.     ++row;
  303.     nrows = menucount(men) + 2;
  304.     if (nrows > term.t_nrow) nrows = term.t_nrow;
  305.     if (row + nrows > term.t_nrow) row = term.t_nrow - nrows;
  306.  
  307.     ncols = menulen(men) + 2;
  308.     if (ncols > term.t_ncol) ncols = term.t_ncol;
  309.     if (col + ncols > term.t_ncol) col = term.t_ncol - ncols;
  310.  
  311.     save = malloc(nrows * ncols);
  312.     status = HOOK;
  313.  
  314.     if (save == NULL) {
  315.         mlwrite("[No memory to pull down menu]");
  316.         return(status);
  317.     }
  318.  
  319.     /* pull down the menu */
  320.  
  321.     m = menudata[men].m_down;
  322.     sp = save;
  323.     for(r = row; r < row + nrows; r++) {
  324.         /* save old line */
  325.         tp = &(vscreen[r]->v_text[col]);
  326.         for(c = 0; c < ncols; c++) *sp++ = *tp++;
  327.  
  328.         /* create new line */
  329.         tp = &(vscreen[r]->v_text[col]);
  330.         if (r == row) {
  331.             *tp++ = BOXUR;
  332.             for(c = 0; c < ncols-2; c++) *tp++ = BOXH;
  333.             *tp = BOXUL;
  334.         }
  335.         else if (r == row + nrows - 1) {
  336.             *tp++ = BOXLR;
  337.             for(c = 0; c < ncols-2; c++) *tp++ = BOXH;
  338.             *tp = BOXLL;
  339.         }
  340.         else    {
  341.             *tp++ = BOXV;
  342.             for(c = 0; c < ncols-2 && menudata[m].m_text[c]; c++)
  343.                 *tp++ = menudata[m].m_text[c];
  344.             for(; c < ncols-2; c++)
  345.                 *tp++ = ' ';
  346.             *tp = BOXV;
  347.             m = menudata[m].m_right;
  348.         }
  349.  
  350.         /* display new line */
  351.         menuput(r, col, ncols, 1);
  352.     }
  353.  
  354.     /* process keys */
  355.  
  356.     m = menudata[men].m_down;
  357.     curmrow = row + 1;
  358.     menuput(curmrow, col, ncols, 0);
  359.  
  360.     do {
  361.         movecursor(curmrow, col);
  362.         c = getmkey();
  363.         if (c == MENUMLEFT)
  364.             m = 0;
  365.         else if (c == MENUMRIGHT || c == MENUMENTER)
  366.             status = menudo(row+nrows-1, col, m);
  367.         else if (c == MENUMUP) {
  368.             if (menudata[m].m_left != 0) {
  369.                 menuput(curmrow, col, ncols, 1);
  370.                 m = menudata[m].m_left; --curmrow;
  371.                 menuput(curmrow, col, ncols, 0);
  372.             }
  373.         }
  374.         else if (c == MENUMDOWN) {
  375.             if (menudata[m].m_right != 0 &&
  376.                 curmrow < row + nrows - 2) {
  377.                 menuput(curmrow, col, ncols, 1);
  378.                 m = menudata[m].m_right; curmrow++;
  379.                 menuput(curmrow, col, ncols, 0);
  380.             }
  381.         }
  382.         else    {
  383.             tmprow = row + 1;
  384.             tmpm = menudata[men].m_down;
  385.             while (tmpm != 0 && (!menumatch(tmpm)) &&
  386.               tmprow < row + nrows - 2) {
  387.                 tmpm = menudata[tmpm].m_right;
  388.                 ++tmprow;
  389.             }
  390.             if (tmpm != 0)    {
  391.                 menuput(curmrow, col, ncols, 1);
  392.                 m = tmpm;
  393.                 curmrow = tmprow;
  394.                 menuput(curmrow, col, ncols, 0);
  395.                 status = menudo(curmrow, col, m);
  396.             }
  397.             else
  398.                 TTbeep();
  399.         }
  400.     } while (m != 0 && status == HOOK);
  401.  
  402.     /* restore the screen */
  403.  
  404.     sp = save;
  405.     for(r = row; r < row + nrows; r++) {
  406.         movecursor(r, col);
  407.         if (vscreen[r]->v_flag & VFREQ) TTrev(1); else TTrev(0);
  408. #if    COLOR
  409.         TTforg(vscreen[r]->v_rfcolor);
  410.         TTbacg(vscreen[r]->v_rbcolor);
  411. #endif
  412. #if    IBMPC
  413.         menuwrite(r, col, sp, ncols,
  414.             vscreen[r]->v_rfcolor, vscreen[r]->v_rbcolor);
  415. #endif
  416.         tp = &(vscreen[r]->v_text[col]);
  417.         for(c = 0; c < ncols; c++) {
  418. #if    IBMPC
  419. #else
  420.             TTputc(*sp);
  421. #endif
  422.             *tp++ = *sp++;
  423.         }
  424.         ttcol += ncols;
  425.     }
  426.  
  427.     free(save);
  428.  
  429.     /* return */
  430.     return(status);
  431. }
  432.  
  433. menutput(col, m, normal)        /* display a string on top line */
  434. int col, m, normal;
  435. {
  436.     int len;
  437.  
  438.     len = strlen(menudata[m].m_text);
  439.     if (len >= menutwid) len = menutwid - 1;
  440.     menuput(0, col, len, normal);
  441. }
  442.  
  443. int menu(f, n)            /* actual menu command */
  444. {
  445.     int i, m, c, curmcol, wid, status, tmpcol, tmpm;
  446.  
  447.     if (!menuflag) return(TRUE);
  448.  
  449.     status = HOOK;
  450.     m = 1;
  451.     curmcol = 0;
  452.  
  453.     if (f == TRUE)
  454.         while (--n > 0 && menudata[m].m_right != 0) {
  455.             m = menudata[m].m_right;
  456.             curmcol += menutwid;
  457.         }
  458.     else
  459.         while (m != menulast && menudata[m].m_right != 0) {
  460.             m = menudata[m].m_right;
  461.             curmcol += menutwid;
  462.         }
  463.  
  464.     menutput(curmcol, m, 0);
  465.  
  466.     do {
  467.         movecursor(0, curmcol);
  468.         c = getmkey();
  469.         if (c == MENUMLEFT) {
  470.             menutput(curmcol, m, 1);
  471.             if (menudata[m].m_left != 0)
  472.                 {m = menudata[m].m_left; curmcol -= menutwid;}
  473.             else
  474.                 while(menudata[m].m_right != 0) {
  475.                     m = menudata[m].m_right;
  476.                     curmcol += menutwid;
  477.                 }
  478.             menutput(curmcol, m, 0);
  479.         }
  480.         else if (c == MENUMRIGHT) {
  481.             menutput(curmcol, m, 1);
  482.             if (menudata[m].m_right != 0)
  483.                 {m = menudata[m].m_right; curmcol += menutwid;}
  484.             else
  485.                 {m = 1; curmcol = 0;}
  486.             menutput(curmcol, m, 0);
  487.         }
  488.         else if (c == MENUMUP)
  489.             status = TRUE;
  490.         else if (c == MENUMDOWN || c == MENUMENTER)
  491.             status = menudo(0, curmcol, m);
  492.         else    {
  493.             tmpcol = 0;
  494.             tmpm = menudata[0].m_down;
  495.             while (tmpm != 0 && !menumatch(tmpm))    {
  496.                 tmpm = menudata[tmpm].m_right;
  497.                 tmpcol += menutwid;
  498.             }
  499.             if (tmpm != 0)    {
  500.                 menutput(curmcol, m, 1);
  501.                 m = tmpm;
  502.                 curmcol = tmpcol;
  503.                 status = menudo(0, curmcol, m);
  504.                 menutput(curmcol, m, 0);
  505.             }
  506.             else
  507.                 TTbeep();
  508.         }
  509.     } while (status == HOOK);
  510.  
  511.     menutput(curmcol, m, 1);
  512.  
  513.     menulast = m;
  514.  
  515.     return(status);
  516. }
  517.  
  518. #endif
  519.  
  520.