home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / C / Libraries / stdwin / Ports / alfa / menu.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-16  |  10.2 KB  |  593 lines  |  [TEXT/????]

  1. /* TERMCAP STDWIN -- MENUS. */
  2.  
  3. #include "alfa.h"
  4.  
  5. static bool deflocal= FALSE;    /* Default menu state */
  6.  
  7. static struct menubar gmenus;    /* All global menus */
  8. static struct menubar lmenus;    /* All local menus */
  9.  
  10. static MENU *sysmenu;        /* Window selection commands */
  11. static MENU *curmenu;
  12.  
  13. static void
  14. addtobar(mbp, mp)
  15.     struct menubar *mbp;
  16.     MENU *mp;
  17. {
  18.     int i;
  19.     
  20.     for (i= 0; i < mbp->nmenus; ++i) {
  21.         if (mp == mbp->menulist[i])
  22.             return; /* Already attached */
  23.     }
  24.     L_APPEND(mbp->nmenus, mbp->menulist, MENU *, mp);
  25. }
  26.  
  27. static void
  28. delfrombar(mbp, mp)
  29.     struct menubar *mbp;
  30.     MENU *mp;
  31. {
  32.     int i;
  33.     
  34.     for (i= 0; i < mbp->nmenus; ++i) {
  35.         if (mp == mbp->menulist[i]) {
  36.             L_REMOVE(mbp->nmenus, mbp->menulist,
  37.                 MENU *, i);
  38.             break;
  39.         }
  40.     }
  41. }
  42.  
  43. _winitmenus()
  44. {
  45.     sysmenu= wmenucreate(0, "Windows");
  46.     wmenuadditem(sysmenu, "Previous Window", -1);
  47.     wmenuadditem(sysmenu, "Next Window", -1);
  48. #ifndef EM
  49.     /* Somehow, Euromath doesn't like this?!? */
  50.     wmenuadditem(sysmenu, "Close Window", -1);
  51.     wmenuadditem(sysmenu, "(left)", -1);
  52.     wmenuadditem(sysmenu, "(right)", -1);
  53.     wmenuadditem(sysmenu, "(up)", -1);
  54.     wmenuadditem(sysmenu, "(down)", -1);
  55.     wmenuadditem(sysmenu, "(cancel)", -1);
  56.     wmenuadditem(sysmenu, "(backspace)", -1);
  57.     wmenuadditem(sysmenu, "(tab)", -1);
  58.     wmenuadditem(sysmenu, "(return)", -1);
  59. #endif
  60.     /* Shortcuts are compiled in the key map! */
  61. }
  62.  
  63. MENU *
  64. wmenucreate(id, title)
  65.     int id;
  66.     char *title;
  67. {
  68.     MENU *mp= ALLOC(MENU);
  69.     
  70.     if (mp == NULL)
  71.         return NULL;
  72.     mp->id= id;
  73.     mp->title= strdup(title);
  74.     mp->local= deflocal;
  75.     mp->dirty= TRUE;
  76.     mp->left= mp->right= 0;
  77.     L_INIT(mp->nitems, mp->itemlist);
  78.     addtobar(mp->local ? &lmenus : &gmenus, mp);
  79.     if (!mp->local)
  80.         menubarchanged();
  81.     return mp;
  82. }
  83.  
  84. void
  85. wmenudelete(mp)
  86.     MENU *mp;
  87. {
  88.     int i;
  89.     
  90.     if (mp->local) {
  91.         for (i= 0; i < MAXWINDOWS; ++i) {
  92.             if (winlist[i].open)
  93.                 delfrombar(&winlist[i].mbar, mp);
  94.         }
  95.     }
  96.     delfrombar(mp->local ? &lmenus : &gmenus, mp);
  97.     for (i= 0; i < mp->nitems; ++i) {
  98.         FREE(mp->itemlist[i].text);
  99.         FREE(mp->itemlist[i].shortcut);
  100.     }
  101.     L_DEALLOC(mp->nitems, mp->itemlist);
  102.     FREE(mp);
  103.     menubarchanged();
  104. }
  105.  
  106. int
  107. wmenuadditem(mp, text, shortcut)
  108.     MENU *mp;
  109.     char *text;
  110.     int shortcut;
  111. {
  112.     struct item it;
  113.     
  114.     mp->dirty= TRUE;
  115.     it.text= strdup(text);
  116. #ifdef EM
  117. /* need to add the shortcut now, otherwise it will be taken from
  118.    the keymap whenever the menu is displayed, which might be after
  119.    opening another window and overwriting the keymap entry.
  120.    In the AddMenuEntry code I overwrite the shortcut anyway. */
  121. /* I don't understand this --Guido */
  122.     if(shortcut >= 32) {
  123.         it.shortcut=(char *)malloc(8);    
  124.         sprintf(it.shortcut,"ESC %c", shortcut);
  125.     } else 
  126. #endif
  127.     it.shortcut= NULL;
  128.     it.enabled= (text != NULL && *text != EOS);
  129.     it.checked= FALSE;
  130.     L_APPEND(mp->nitems, mp->itemlist, struct item, it);
  131.     if (shortcut >= 0)
  132.         wsetmetakey(mp->id, mp->nitems-1, shortcut);
  133.     return mp->nitems-1;
  134. }
  135.  
  136. void
  137. wmenusetitem(mp, item, text)
  138.     MENU *mp;
  139.     int item;
  140.     char *text;
  141. {
  142.     if (item < 0 || item >= mp->nitems)
  143.         return;
  144.     mp->dirty= TRUE;
  145.     FREE(mp->itemlist[item].text);
  146.     mp->itemlist[item].text= strdup(text);
  147.     mp->itemlist[item].enabled= (text != NULL && *text != EOS);
  148. }
  149.  
  150. void
  151. wmenuenable(mp, item, flag)
  152.     MENU *mp;
  153.     int item;
  154.     int flag;
  155. {
  156.     if (item < 0 || item >= mp->nitems)
  157.         return;
  158.     mp->itemlist[item].enabled= flag;
  159. }
  160.  
  161. void
  162. wmenucheck(mp, item, flag)
  163.     MENU *mp;
  164.     int item;
  165.     int flag;
  166. {
  167.     if (item < 0 || item >= mp->nitems)
  168.         return;
  169.     mp->itemlist[item].checked= flag;
  170. }
  171.  
  172. void
  173. wmenuattach(win, mp)
  174.     WINDOW *win;
  175.     MENU *mp;
  176. {
  177.     if (!mp->local)
  178.         return;
  179.     addtobar(&win->mbar, mp);
  180.     if (win == front)
  181.         menubarchanged();
  182. }
  183.  
  184. void
  185. wmenudetach(win, mp)
  186.     WINDOW *win;
  187.     MENU *mp;
  188. {
  189.     if (!mp->local)
  190.         return;
  191.     delfrombar(&win->mbar, mp);
  192.     if (win == front)
  193.         menubarchanged();
  194. }
  195.  
  196. void
  197. wmenusetdeflocal(local)
  198.     bool local;
  199. {
  200.     deflocal= local;
  201. }
  202.  
  203. /* Interface routines for the rest of the library. */
  204.  
  205. void
  206. initmenubar(mb)
  207.     struct menubar *mb;
  208. {
  209.     L_INIT(mb->nmenus, mb->menulist);
  210. }
  211.  
  212. void
  213. killmenubar(mb)
  214.     struct menubar *mb;
  215. {
  216.     L_DEALLOC(mb->nmenus, mb->menulist);
  217. }
  218.  
  219. void
  220. drawmenubar() /* This is part of the syswin draw procedure! */
  221. {
  222.     WINDOW *win= front;
  223.     char buf[256];
  224.     int k= 0;
  225.     int i;
  226.     
  227.     buf[0]= EOS;
  228.     for (i= 0; i < gmenus.nmenus; ++i)
  229.         k= bufappend(buf, k, gmenus.menulist[i]);
  230.     if (win != NULL) {
  231.         for (i= 0; i < win->mbar.nmenus; ++i)
  232.             k= bufappend(buf, k, win->mbar.menulist[i]);
  233.     }
  234.     wdrawtext(0, 0, buf, -1);
  235. }
  236.  
  237. static int
  238. bufappend(buf, pos, mp)
  239.     char *buf;
  240.     int pos;
  241.     MENU *mp;
  242. {
  243.     if (pos > 0) {
  244.         buf[pos++]= ' ';
  245.         buf[pos++]= ' ';
  246.     }
  247.     mp->left= pos;
  248.     strcpy(buf+pos, mp->title);
  249.     pos += strlen(buf+pos);
  250.     mp->right= pos;
  251.     return pos;
  252. }
  253.  
  254. /* TO DO:
  255.    - highlight current menu title, current menu item
  256.    - remember last menu and item
  257.    - Allow GOTO to select menus or menu items
  258.      (m-down on mbar opens the menu; m-up on item selects the item)
  259. */
  260.  
  261. static void menudraw(), menuitemdraw(), menucalcwidth();
  262. static bool handleevt(), handlecmd(), handlemenu();
  263. static int calcleft();
  264.  
  265. static leftblank;
  266.  
  267. static bool        curlocal;
  268. static struct menubar *    curmbar;
  269. static int        curimenu;
  270. static int        curitem;
  271. static int        lowest;
  272.  
  273. static bool
  274. firstmenu()
  275. {
  276.     curlocal= FALSE;
  277.     curmbar= &gmenus;
  278.     curimenu= 0;
  279.     
  280.     if (curmbar->nmenus == 0) {
  281.         curmbar= &lmenus;
  282.         curlocal= TRUE;
  283.         if (curmbar->nmenus == 0) {
  284.             wmessage("No menus defined");
  285.             return FALSE;
  286.         }
  287.     }
  288.     curmenu= curmbar->menulist[curimenu];
  289.     curitem= 0;
  290.     menudraw();
  291.     return TRUE;
  292. }
  293.  
  294. static void
  295. nextmenu()
  296. {
  297.     WINDOW *win=front; /* added mcv */
  298. /* the menus are now taken from the window's menubar, instead
  299.    of the menubar for *all* local menus */
  300.  
  301.     ++curimenu;
  302.     while (curimenu >= curmbar->nmenus) {
  303.         curlocal= !curlocal;
  304.         curmbar= curlocal ? 
  305.                  &win->mbar /* changed mcv, was: &lmenus*/ : 
  306.                  &gmenus;
  307.         curimenu= 0;
  308.     }
  309.     curmenu= curmbar->menulist[curimenu];
  310.     curitem= 0;
  311.     menudraw();
  312. }
  313.  
  314. static void
  315. prevmenu()
  316. {
  317.     WINDOW *win=front;  /* added mcv */
  318. /* the menus are now taken from the window's menubar, instead
  319.    of the menubar for *all* local menus */
  320.  
  321.     --curimenu;
  322.     while (curimenu < 0) {
  323.         curlocal= !curlocal;
  324.         curmbar= curlocal ? 
  325.                  &win->mbar /* changed mcv, was: &lmenus*/ : 
  326.                  &gmenus;
  327.         curimenu= curmbar->nmenus - 1;
  328.     }
  329.     curmenu= curmbar->menulist[curimenu];
  330.     curitem= 0;
  331.     menudraw();
  332. }
  333.  
  334. static void
  335. nextitem()
  336. {
  337.     ++curitem;
  338.     if (curitem >= curmenu->nitems)
  339.         curitem= 0;
  340.     trmsync(curitem+1, curmenu->left);
  341. }
  342.  
  343. static void
  344. previtem()
  345. {
  346.     --curitem;
  347.     if (curitem < 0)
  348.         curitem= curmenu->nitems - 1;
  349.     trmsync(curitem+1, curmenu->left);
  350. }
  351.  
  352. static void
  353. selectitem(ep)
  354.     EVENT *ep;
  355. {
  356.     ep->type= WE_NULL;
  357.     if (curitem >= curmenu->nitems || !curmenu->itemlist[curitem].enabled)
  358.         return;
  359.     ep->type= WE_MENU;
  360.     ep->u.m.id= curmenu->id;
  361.     ep->u.m.item= curitem;
  362. }
  363.  
  364. void
  365. menuselect(ep)
  366.     EVENT *ep;
  367. {
  368.     leftblank= columns;
  369.     lowest= 0;
  370.     wmessage((char *)NULL);
  371.     if (!firstmenu())
  372.         return;
  373.     for (;;) {
  374.         wsysevent(ep, 1);
  375.         if (handleevt(ep))
  376.             break;
  377.     }
  378. }
  379.  
  380. static bool
  381. handleevt(ep)
  382.     EVENT *ep;
  383. {
  384.     switch (ep->type) {
  385.     
  386.     case WE_MENU:
  387.         return handlemenu(ep);
  388.     
  389.     case WE_COMMAND:
  390.         return handlecmd(ep);
  391.     
  392.     default:
  393.         trmbell();
  394.         return FALSE;
  395.     
  396.     }
  397. }
  398.  
  399. static bool
  400. handlecmd(ep)
  401.     EVENT *ep;
  402. {
  403.     switch (ep->u.command) {
  404.     
  405.     default:
  406.         trmbell();
  407.         return FALSE;
  408.     
  409.     case WC_RETURN:
  410.         selectitem(ep);
  411.         if (curmenu == sysmenu)
  412.             wsyscommand(ep);
  413.         return TRUE;
  414.     
  415.     case WC_LEFT:
  416.         prevmenu();
  417.         break;
  418.     
  419.     case WC_RIGHT:
  420.         nextmenu();
  421.         break;
  422.     
  423.     case WC_UP:
  424.         previtem();
  425.         break;
  426.     
  427.     case WC_DOWN:
  428.         nextitem();
  429.         break;
  430.     
  431.     case WC_CANCEL:
  432.         ep->type= WE_NULL;
  433.         return TRUE;
  434.     
  435.     }
  436.     return FALSE;
  437. }
  438.  
  439. static bool
  440. handlemenu(ep)
  441.     EVENT *ep;
  442. {
  443.     if (ep->u.m.id != 0)
  444.         return TRUE;
  445.     switch (ep->u.m.item) {
  446.     
  447.     case SUSPEND_PROC:
  448.         _wsuspend();
  449.         menudraw();
  450.         break;
  451.     
  452.     case REDRAW_SCREEN:
  453.         _wredraw();
  454.         menudraw();
  455.         break;
  456.     
  457.     case MENU_CALL:
  458.         ep->type= WE_NULL;
  459.         return TRUE;
  460.  
  461.     default:
  462.         if (ep->u.m.item <= LAST_CMD) {
  463.             wsyscommand(ep);
  464.             if (ep->type == WE_COMMAND)
  465.                 return handlecmd(ep);
  466.             else
  467.                 return TRUE;
  468.         }
  469.         else {
  470.             trmbell();
  471.             return FALSE;
  472.         }
  473.     
  474.     }
  475.     return FALSE;
  476. }
  477.  
  478. static void
  479. menudraw()
  480. {
  481.     MENU *mp= curmenu;
  482.     int left;
  483.     int width;
  484.     int i;
  485.     
  486.     wupdate(syswin);
  487.     if (mp->dirty)
  488.         menucalcwidth(mp);
  489.     left= calcleft(mp);
  490.     width= mp->maxwidth;
  491.     if (left + width > columns)
  492.         width= columns - left;
  493.     for (i= 0; i < mp->nitems; ++i)
  494.         menuitemdraw(i+1, left, &mp->itemlist[i], width);
  495.     if (i+1 > lowest) {
  496.         lowest= i+1;
  497.         if (lowest < lines)
  498.             uptodate[lowest]= FALSE;
  499.     }
  500.     trmputdata(i+1, lowest, 0, "", (char *)0);
  501.     leftblank= left;
  502.     trmsync(curitem+1, mp->left);
  503. }
  504.  
  505. static int
  506. calcleft(mp)
  507.     MENU *mp;
  508. {
  509.     int left= columns - mp->maxwidth;
  510.     
  511.     if (left > mp->left)
  512.         left= mp->left;
  513.     if (left < 0)
  514.         left= 0;
  515.     if (left-3 < leftblank) {
  516.         leftblank= left-3;
  517.         if (leftblank < 4)
  518.             leftblank= 0;
  519.     }
  520.     return left;
  521. }
  522.  
  523. static void
  524. menuitemdraw(line, left, ip, width)
  525.     int line, left;
  526.     struct item *ip;
  527.     int width;
  528. {
  529.     char buf[256];
  530.     int margin= left-leftblank;
  531.     
  532.     buf[0]= EOS;
  533.     if (ip->text != NULL && *ip->text != EOS) {
  534.         int space;
  535.         char *p= buf;
  536.         for (space= margin; space-- > 0; )
  537.             *p++ = ' ';
  538.         if (ip->checked && margin >= 2)
  539.             p[-2]= '*';
  540.         strcpy(p, ip->text);
  541.         p += strlen(p);
  542.         if (!ip->enabled && margin >= 1 &&
  543.             ip->text != NULL && ip->text[0] != EOS) {
  544.             buf[margin-1]= '(';
  545.             *p++= ')';
  546.             *p= '\0';
  547.         }
  548.         if (ip->shortcut != NULL && *ip->shortcut != EOS) {
  549.             space= width - (p - buf - margin)
  550.                 - strlen(ip->shortcut);
  551.             if (space <= 0)
  552.                 space= 2;
  553.             while (--space >= 0)
  554.                 *p++ = ' ';
  555.             strcpy(p, ip->shortcut);
  556.         }
  557.     }
  558.     /* This was added because brackets and stars from disabled/marked
  559.        items on the first menu (after the sysmenu) weren't removed
  560.        from the screen.  I haven't tried to fix this in a more
  561.        efficient manner. */
  562.     trmputdata(line, line, 0, "", (char *)0);
  563.     trmputdata(line, line, leftblank, buf, (char *)0);
  564.     uptodate[line]= FALSE;
  565. }
  566.  
  567. static void
  568. menucalcwidth(mp)
  569.     MENU *mp;
  570. {
  571.     int i;
  572.     int width= 0;
  573.     
  574.     for (i= 0; i < mp->nitems; ++i) {
  575.         struct item *ip= &mp->itemlist[i];
  576.         char *text= ip->text;
  577.         if (text != NULL && *text != EOS) {
  578.             int w= strlen(text);
  579.             if (ip->shortcut == NULL) {
  580.                 char buf[256];
  581.                 getbindings(buf, mp->id, i);
  582.                 ip->shortcut= strdup(buf);
  583.             }
  584.             if (ip->shortcut != NULL && *ip->shortcut != EOS)
  585.                 w += 2 + strlen(ip->shortcut);
  586.             if (w > width)
  587.                 width= w;
  588.         }
  589.     }
  590.     mp->maxwidth= width;
  591.     mp->dirty= FALSE;
  592. }
  593.