home *** CD-ROM | disk | FTP | other *** search
- /* amiga_menus.c -- Pull-down menu handling for AmigaDOS
- Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
-
- This file is part of Jade.
-
- Jade is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Jade is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Jade; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "jade.h"
- #include "jade_protos.h"
-
- #define INTUI_V36_NAMES_ONLY
- #include <clib/intuition_protos.h>
- #include <clib/gadtools_protos.h>
- #include <string.h>
- #include <ctype.h>
-
- #define MAX_MENUS 500
- #define NMSIZE (MAX_MENUS * sizeof(struct NewMenu))
-
- _PR void clearmenu(struct Window *);
- _PR void setmenu(struct Window *);
- _PR VALUE evalmenu(WORD, WORD);
-
- _PR void ami_mark_menus(void);
- _PR void ami_menus_init(void);
- _PR void ami_menus_kill(void);
-
- static struct Menu *Menu;
- static struct NewMenu *NewMenu;
- static APTR VisInfo;
-
- #ifdef AMIGA_NEED_VARARGS_STUBS
- struct Menu *
- CreateMenus(struct NewMenu *newMenu, Tag firstTag, ...)
- {
- return(CreateMenusA(newMenu, (struct TagItem *)&firstTag));
- }
- APTR
- GetVisualInfo(struct Screen *screen, Tag firstTag, ...)
- {
- return(GetVisualInfoA(screen, (struct TagItem *)&firstTag));
- }
- BOOL
- LayoutMenus(struct Menu *menu, APTR vi, Tag firstTag, ...)
- {
- return(LayoutMenusA(menu, vi, (struct TagItem *)&firstTag));
- }
- #endif /* AMIGA_NEEDS_VARARGS_STUBS */
-
- void
- clearmenu(struct Window *wd)
- {
- ClearMenuStrip(wd);
- wd->Flags |= WFLG_RMBTRAP;
- }
-
- static void
- clearallmenus(void)
- {
- VW *thisvw;
- for(thisvw = ViewChain; thisvw; thisvw = thisvw->vw_Next)
- clearmenu(thisvw->vw_Window);
- }
-
- void
- setmenu(struct Window *wd)
- {
- if(Menu)
- {
- SetMenuStrip(wd, Menu);
- wd->Flags &= ~WFLG_RMBTRAP;
- }
- }
-
- static void
- setallmenus(void)
- {
- VW *thisvw;
- for(thisvw = ViewChain; thisvw; thisvw = thisvw->vw_Next)
- setmenu(thisvw->vw_Window);
- }
-
- _PR VALUE cmd_set_menu_enabled(VALUE stat, VALUE vw);
- DEFUN("set-menu-enabled", cmd_set_menu_enabled, subr_set_menu_enabled, (VALUE stat, VALUE vw), V_Subr2, DOC_set_menu_enabled) /*
- ::doc:set_menu_enabled::
- (menu-status ENABLED-P [WINDOW]) <AMIGA-ONLY>
- If ENABLED-P is non-nil the menu will be active in WINDOW, if WINDOW is not
- specified, menus will be enabled in *all* windows. When a menu is not enabled
- in a window right mouse button events will be detectable.
-
- Note that for a menu to be displayed the `set-menu' command must be used first
- to create a menu strip.
- ::end:: */
- {
- if(NILP(vw))
- {
- if(!NILP(stat))
- setallmenus();
- else
- clearallmenus();
- }
- else
- {
- if(!NILP(stat))
- setmenu(VWIN(vw)->vw_Window);
- else
- clearmenu(VWIN(vw)->vw_Window);
- }
- return(sym_t);
- }
-
- _PR VALUE cmd_menu_enabled_p(VALUE vw);
- DEFUN("menu-enabled-p", cmd_menu_enabled_p, subr_menu_enabled_p, (VALUE vw), V_Subr1, DOC_menu_enabled_p) /*
- ::doc:menu_enabled_p::
- (menu-enabled-p [WINDOW]) <AMIGA-ONLY>
- Returns t if a menu is being displayed in WINDOW (or the current window).
- ::end:: */
- {
- if(!WINDOWP(vw))
- vw = CurrVW;
- return(VWIN(vw)->vw_Window->MenuStrip ? sym_t : sym_nil);
- }
-
- _PR VALUE cmd_set_menu(VALUE args);
- DEFUN("set-menu", cmd_set_menu, subr_set_menu, (VALUE args), V_SubrN, DOC_set_menu) /*
- ::doc:set_menu::
- (set-menu MENUS...) <AMIGA-ONLY>
- Creates a new menustrip, each window then has these menus.
-
- Each MENU defines a single menu block, it has this format,
-
- (MENU-NAME MENU-ITEM...)
-
- MENU-NAME is the name of the block, each MENU-ITEM defines a single menuitem,
- they are either nil (empty menu item) or look like,
-
- (ITEM-NAME [SHORTCUT] FORMS...)
-
- ITEM-NAME is the item name, SHORTCUT is an optional keyboard shortcut (a one
- character long string) and FORMS are the forms which get evaluated when the
- menu is picked.
-
- The shortcuts may be upper or lower case. Menu shortcuts are only
- considered to be case-significant when two shortcuts of the same letter (but
- different case) are defined.
- ::end:: */
- {
- if(!CONSP(args))
- {
- signalargerror(args, 0);
- return(NULL);
- }
- struct NewMenu *nm = mycalloc(NMSIZE);
- if(nm)
- {
- struct NewMenu *cur = nm;
- ami_menus_kill();
- while(CONSP(args) && CONSP(VCAR(args)))
- {
- VALUE menu = VCAR(args);
- cur->nm_Type = NM_TITLE;
- cur->nm_Label = VSTR(STRINGP(VCAR(menu)) ? VCAR(menu) : NullString);
- cur++;
- menu = VCDR(menu);
- while(CONSP(menu))
- {
- VALUE item = VCAR(menu);
- cur->nm_Type = NM_ITEM;
- if(CONSP(item) && STRINGP(VCAR(item)))
- {
- cur->nm_Label = VSTR(VCAR(item));
- item = VCDR(item);
- if(CONSP(item) && STRINGP(VCAR(item)))
- {
- cur->nm_CommKey = VSTR(VCAR(item));
- item = VCDR(item);
- }
- cur->nm_UserData = item;
- }
- else
- cur->nm_Label = NM_BARLABEL;
- cur++;
- menu = VCDR(menu);
- }
- args = VCDR(args);
- }
- cur->nm_Type = NM_END;
- cur++;
- NewMenu = mymalloc((cur - nm) * sizeof(struct NewMenu));
- if(NewMenu)
- {
- memcpy(NewMenu, nm, (cur - nm) * sizeof(struct NewMenu));
- myfree(nm);
- }
- else
- NewMenu = nm;
-
- Menu = CreateMenus(NewMenu, TAG_END);
- if(Menu)
- {
- VisInfo = GetVisualInfo(CurrVW->vw_Window->WScreen, TAG_END);
- if(VisInfo)
- {
- if(LayoutMenus(Menu, VisInfo,
- #if AMIGA_INCLUDE_VER >= 39
- GTMN_NewLookMenus, TRUE,
- #endif
- TAG_END))
- {
- setallmenus();
- return(sym_t);
- }
- else
- cmd_signal(sym_error, LIST_1(MKSTR("Can't layout menus")));
- FreeVisualInfo(VisInfo);
- VisInfo = NULL;
- }
- else
- cmd_signal(sym_error, LIST_1(MKSTR("Can't get visual info")));
- FreeMenus(Menu);
- Menu = NULL;
- }
- else
- cmd_signal(sym_error, LIST_1(MKSTR("Can't create menus")));
- myfree(NewMenu);
- NewMenu = NULL;
- }
- return(NULL);
- }
-
- /*
- * This routine is used so we can make command key shortcuts case
- * sensitive - is there an easier way than this???
- */
- static struct MenuItem *
- findcommmenu(u_char commKey)
- {
- struct Menu *menu;
- for(menu = Menu; menu; menu = menu->NextMenu)
- {
- struct MenuItem *mi;
- for(mi = menu->FirstItem; mi; mi = mi->NextItem)
- {
- struct MenuItem *si;
- for(si = mi->SubItem; si; si = si->NextItem)
- {
- if(si->Command == commKey)
- return(si);
- }
- if(mi->Command == commKey)
- return(mi);
- }
- }
- return(FALSE);
- }
-
- /*
- * called from IDCMP event loop
- */
- VALUE
- evalmenu(WORD code, WORD qual)
- {
- VALUE res = sym_nil;
- if(Menu)
- {
- struct MenuItem *mi;
- while(mi = ItemAddress(Menu, code))
- {
- VALUE forms;
- if(mi->Command && (qual & IEQUALIFIER_RCOMMAND))
- {
- struct MenuItem *actual;
- if(qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
- {
- if(actual = findcommmenu(toupper(mi->Command)))
- mi = actual;
- }
- else
- {
- if(actual = findcommmenu(tolower(mi->Command)))
- mi = actual;
- }
- code = MENUNULL;
- }
- else
- code = mi->NextSelect;
- forms = GTMENUITEM_USERDATA(mi);
- if(forms)
- res = cmd_progn(forms);
- refreshworld();
- cursor(CurrVW, CURS_ON);
- }
- }
- return(res);
- }
-
- void
- ami_mark_menus(void)
- {
- if(NewMenu)
- {
- struct NewMenu *nm = NewMenu;
- while(nm->nm_Type != NM_END)
- {
- if(nm->nm_Label != NM_BARLABEL)
- {
- MARKVAL(STRING_HDR(nm->nm_Label));
- if(nm->nm_CommKey)
- MARKVAL(STRING_HDR(nm->nm_CommKey));
- MARKVAL(nm->nm_UserData);
- }
- nm++;
- }
- }
- }
-
- void
- ami_menus_init(void)
- {
- ADD_SUBR(subr_set_menu_enabled);
- ADD_SUBR(subr_menu_enabled_p);
- ADD_SUBR(subr_set_menu);
- }
-
- void
- ami_menus_kill(void)
- {
- if(Menu)
- {
- clearallmenus();
- FreeMenus(Menu);
- Menu = NULL;
- }
- if(VisInfo)
- {
- FreeVisualInfo(VisInfo);
- VisInfo = NULL;
- }
- if(NewMenu)
- {
- myfree(NewMenu);
- NewMenu = NULL;
- }
- }
-