home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / jade-3.0.lha / Jade / src / amiga_menus.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-19  |  7.9 KB  |  357 lines

  1. /* amiga_menus.c -- Pull-down menu handling for AmigaDOS
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4. This file is part of Jade.
  5.  
  6. Jade is free software; you can redistribute it and/or modify it
  7. under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2, or (at your option)
  9. any later version.
  10.  
  11. Jade is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with Jade; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #define INTUI_V36_NAMES_ONLY
  24. #include <clib/intuition_protos.h>
  25. #include <clib/gadtools_protos.h>
  26. #include <string.h>
  27. #include <ctype.h>
  28.  
  29. #define MAX_MENUS 500
  30. #define NMSIZE (MAX_MENUS * sizeof(struct NewMenu))
  31.  
  32. _PR void clearmenu(struct Window *);
  33. _PR void setmenu(struct Window *);
  34. _PR VALUE evalmenu(WORD, WORD);
  35.  
  36. _PR void ami_mark_menus(void);
  37. _PR void ami_menus_init(void);
  38. _PR void ami_menus_kill(void);
  39.  
  40. static struct Menu *Menu;
  41. static struct NewMenu *NewMenu;
  42. static APTR VisInfo;
  43.  
  44. #ifdef AMIGA_NEED_VARARGS_STUBS
  45. struct Menu *
  46. CreateMenus(struct NewMenu *newMenu, Tag firstTag, ...)
  47. {
  48.     return(CreateMenusA(newMenu, (struct TagItem *)&firstTag));
  49. }
  50. APTR
  51. GetVisualInfo(struct Screen *screen, Tag firstTag, ...)
  52. {
  53.     return(GetVisualInfoA(screen, (struct TagItem *)&firstTag));
  54. }
  55. BOOL
  56. LayoutMenus(struct Menu *menu, APTR vi, Tag firstTag, ...)
  57. {
  58.     return(LayoutMenusA(menu, vi, (struct TagItem *)&firstTag));
  59. }
  60. #endif /* AMIGA_NEEDS_VARARGS_STUBS */
  61.  
  62. void
  63. clearmenu(struct Window *wd)
  64. {
  65.     ClearMenuStrip(wd);
  66.     wd->Flags |= WFLG_RMBTRAP;
  67. }
  68.  
  69. static void
  70. clearallmenus(void)
  71. {
  72.     VW *thisvw;
  73.     for(thisvw = ViewChain; thisvw; thisvw = thisvw->vw_Next)
  74.     clearmenu(thisvw->vw_Window);
  75. }
  76.  
  77. void
  78. setmenu(struct Window *wd)
  79. {
  80.     if(Menu)
  81.     {
  82.     SetMenuStrip(wd, Menu);
  83.     wd->Flags &= ~WFLG_RMBTRAP;
  84.     }
  85. }
  86.  
  87. static void
  88. setallmenus(void)
  89. {
  90.     VW *thisvw;
  91.     for(thisvw = ViewChain; thisvw; thisvw = thisvw->vw_Next)
  92.     setmenu(thisvw->vw_Window);
  93. }
  94.  
  95. _PR VALUE cmd_set_menu_enabled(VALUE stat, VALUE vw);
  96. DEFUN("set-menu-enabled", cmd_set_menu_enabled, subr_set_menu_enabled, (VALUE stat, VALUE vw), V_Subr2, DOC_set_menu_enabled) /*
  97. ::doc:set_menu_enabled::
  98. (menu-status ENABLED-P [WINDOW]) <AMIGA-ONLY>
  99. If ENABLED-P is non-nil the menu will be active in WINDOW, if WINDOW is not
  100. specified, menus will be enabled in *all* windows. When a menu is not enabled
  101. in a window right mouse button events will be detectable.
  102.  
  103. Note that for a menu to be displayed the `set-menu' command must be used first
  104. to create a menu strip.
  105. ::end:: */
  106. {
  107.     if(NILP(vw))
  108.     {
  109.     if(!NILP(stat))
  110.         setallmenus();
  111.     else
  112.         clearallmenus();
  113.     }
  114.     else
  115.     {
  116.     if(!NILP(stat))
  117.         setmenu(VWIN(vw)->vw_Window);
  118.     else
  119.         clearmenu(VWIN(vw)->vw_Window);
  120.     }
  121.     return(sym_t);
  122. }
  123.  
  124. _PR VALUE cmd_menu_enabled_p(VALUE vw);
  125. DEFUN("menu-enabled-p", cmd_menu_enabled_p, subr_menu_enabled_p, (VALUE vw), V_Subr1, DOC_menu_enabled_p) /*
  126. ::doc:menu_enabled_p::
  127. (menu-enabled-p [WINDOW]) <AMIGA-ONLY>
  128. Returns t if a menu is being displayed in WINDOW (or the current window).
  129. ::end:: */
  130. {
  131.     if(!WINDOWP(vw))
  132.     vw = CurrVW;
  133.     return(VWIN(vw)->vw_Window->MenuStrip ? sym_t : sym_nil);
  134. }
  135.  
  136. _PR VALUE cmd_set_menu(VALUE args);
  137. DEFUN("set-menu", cmd_set_menu, subr_set_menu, (VALUE args), V_SubrN, DOC_set_menu) /*
  138. ::doc:set_menu::
  139. (set-menu MENUS...) <AMIGA-ONLY>
  140. Creates a new menustrip, each window then has these menus.
  141.  
  142. Each MENU defines a single menu block, it has this format,
  143.  
  144.     (MENU-NAME MENU-ITEM...)
  145.  
  146. MENU-NAME is the name of the block, each MENU-ITEM defines a single menuitem,
  147. they are either nil (empty menu item) or look like,
  148.  
  149.     (ITEM-NAME [SHORTCUT] FORMS...)
  150.  
  151. ITEM-NAME is the item name, SHORTCUT is an optional keyboard shortcut (a one
  152. character long string) and FORMS are the forms which get evaluated when the
  153. menu is picked.
  154.  
  155. The shortcuts may be upper or lower case. Menu shortcuts are only
  156. considered to be case-significant when two shortcuts of the same letter (but
  157. different case) are defined.
  158. ::end:: */
  159. {
  160.     if(!CONSP(args))
  161.     {
  162.     signalargerror(args, 0);
  163.     return(NULL);
  164.     }
  165.     struct NewMenu *nm = mycalloc(NMSIZE);
  166.     if(nm)
  167.     {
  168.     struct NewMenu *cur = nm;
  169.     ami_menus_kill();
  170.     while(CONSP(args) && CONSP(VCAR(args)))
  171.     {
  172.         VALUE menu = VCAR(args);
  173.         cur->nm_Type = NM_TITLE;
  174.         cur->nm_Label = VSTR(STRINGP(VCAR(menu)) ? VCAR(menu) : NullString);
  175.         cur++;
  176.         menu = VCDR(menu);
  177.         while(CONSP(menu))
  178.         {
  179.         VALUE item = VCAR(menu);
  180.         cur->nm_Type = NM_ITEM;
  181.         if(CONSP(item) && STRINGP(VCAR(item)))
  182.         {
  183.             cur->nm_Label = VSTR(VCAR(item));
  184.             item = VCDR(item);
  185.             if(CONSP(item) && STRINGP(VCAR(item)))
  186.             {
  187.             cur->nm_CommKey = VSTR(VCAR(item));
  188.             item = VCDR(item);
  189.             }
  190.             cur->nm_UserData = item;
  191.         }
  192.         else
  193.             cur->nm_Label = NM_BARLABEL;
  194.         cur++;
  195.         menu = VCDR(menu);
  196.         }
  197.         args = VCDR(args);
  198.     }
  199.     cur->nm_Type = NM_END;
  200.     cur++;
  201.     NewMenu = mymalloc((cur - nm) * sizeof(struct NewMenu));
  202.     if(NewMenu)
  203.     {
  204.         memcpy(NewMenu, nm, (cur - nm) * sizeof(struct NewMenu));
  205.         myfree(nm);
  206.     }
  207.     else
  208.         NewMenu = nm;
  209.  
  210.     Menu = CreateMenus(NewMenu, TAG_END);
  211.     if(Menu)
  212.     {
  213.         VisInfo = GetVisualInfo(CurrVW->vw_Window->WScreen, TAG_END);
  214.         if(VisInfo)
  215.         {
  216.         if(LayoutMenus(Menu, VisInfo,
  217. #if AMIGA_INCLUDE_VER >= 39
  218.                    GTMN_NewLookMenus, TRUE,
  219. #endif
  220.                    TAG_END))
  221.         {
  222.             setallmenus();
  223.             return(sym_t);
  224.         }
  225.         else
  226.             cmd_signal(sym_error, LIST_1(MKSTR("Can't layout menus")));
  227.         FreeVisualInfo(VisInfo);
  228.         VisInfo = NULL;
  229.         }
  230.         else
  231.         cmd_signal(sym_error, LIST_1(MKSTR("Can't get visual info")));
  232.         FreeMenus(Menu);
  233.         Menu = NULL;
  234.     }
  235.     else
  236.         cmd_signal(sym_error, LIST_1(MKSTR("Can't create menus")));
  237.     myfree(NewMenu);
  238.     NewMenu = NULL;
  239.     }
  240.     return(NULL);
  241. }
  242.  
  243. /*
  244.  * This routine is used so we can make command key shortcuts case
  245.  * sensitive - is there an easier way than this???
  246.  */
  247. static struct MenuItem *
  248. findcommmenu(u_char commKey)
  249. {
  250.     struct Menu *menu;
  251.     for(menu = Menu; menu; menu = menu->NextMenu)
  252.     {
  253.     struct MenuItem *mi;
  254.     for(mi = menu->FirstItem; mi; mi = mi->NextItem)
  255.     {
  256.         struct MenuItem *si;
  257.         for(si = mi->SubItem; si; si = si->NextItem)
  258.         {
  259.         if(si->Command == commKey)
  260.             return(si);
  261.         }
  262.         if(mi->Command == commKey)
  263.         return(mi);
  264.     }
  265.     }
  266.     return(FALSE);
  267. }
  268.  
  269. /*
  270.  * called from IDCMP event loop
  271.  */
  272. VALUE
  273. evalmenu(WORD code, WORD qual)
  274. {
  275.     VALUE res = sym_nil;
  276.     if(Menu)
  277.     {
  278.     struct MenuItem *mi;
  279.     while(mi = ItemAddress(Menu, code))
  280.     {
  281.         VALUE forms;
  282.         if(mi->Command && (qual & IEQUALIFIER_RCOMMAND))
  283.         {
  284.         struct MenuItem *actual;
  285.         if(qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
  286.         {
  287.             if(actual = findcommmenu(toupper(mi->Command)))
  288.             mi = actual;
  289.         }
  290.         else
  291.         {
  292.             if(actual = findcommmenu(tolower(mi->Command)))
  293.             mi = actual;
  294.         }
  295.         code = MENUNULL;
  296.         }
  297.         else
  298.         code = mi->NextSelect;
  299.         forms = GTMENUITEM_USERDATA(mi);
  300.         if(forms)
  301.         res = cmd_progn(forms);
  302.         refreshworld();
  303.         cursor(CurrVW, CURS_ON);
  304.     }
  305.     }
  306.     return(res);
  307. }
  308.  
  309. void
  310. ami_mark_menus(void)
  311. {
  312.     if(NewMenu)
  313.     {
  314.     struct NewMenu *nm = NewMenu;
  315.     while(nm->nm_Type != NM_END)
  316.     {
  317.         if(nm->nm_Label != NM_BARLABEL)
  318.         {
  319.         MARKVAL(STRING_HDR(nm->nm_Label));
  320.         if(nm->nm_CommKey)
  321.             MARKVAL(STRING_HDR(nm->nm_CommKey));
  322.         MARKVAL(nm->nm_UserData);
  323.         }
  324.         nm++;
  325.     }
  326.     }
  327. }
  328.  
  329. void
  330. ami_menus_init(void)
  331. {
  332.     ADD_SUBR(subr_set_menu_enabled);
  333.     ADD_SUBR(subr_menu_enabled_p);
  334.     ADD_SUBR(subr_set_menu);
  335. }
  336.  
  337. void
  338. ami_menus_kill(void)
  339. {
  340.     if(Menu)
  341.     {
  342.     clearallmenus();
  343.     FreeMenus(Menu);
  344.     Menu = NULL;
  345.     }
  346.     if(VisInfo)
  347.     {
  348.     FreeVisualInfo(VisInfo);
  349.     VisInfo = NULL;
  350.     }
  351.     if(NewMenu)
  352.     {
  353.     myfree(NewMenu);
  354.     NewMenu = NULL;
  355.     }
  356. }
  357.