home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Fresh Fish 8
/
FreshFishVol8-CD1.bin
/
new
/
util
/
edit
/
jade
/
src
/
amiga_menus.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-01
|
8KB
|
373 lines
/* 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>
#ifdef NEED_MEMORY_H
# include <memory.h>
#endif
#define MAX_MENUS 500
#define NMSIZE (MAX_MENUS * sizeof(struct NewMenu))
_PR void ami_clear_menu(struct Window *);
_PR void ami_set_menu(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_strip;
static struct NewMenu *new_menu;
static APTR vis_info;
#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
ami_clear_menu(struct Window *wd)
{
ClearMenuStrip(wd);
wd->Flags |= WFLG_RMBTRAP;
}
static void
clear_all_menus(void)
{
VW *thisvw;
for(thisvw = view_chain; thisvw; thisvw = thisvw->vw_Next)
{
if(thisvw->vw_Window)
ami_clear_menu(thisvw->vw_Window);
}
}
void
ami_set_menu(struct Window *wd)
{
if(menu_strip)
{
SetMenuStrip(wd, menu_strip);
wd->Flags &= ~WFLG_RMBTRAP;
}
}
static void
set_all_menus(void)
{
VW *thisvw;
for(thisvw = view_chain; thisvw; thisvw = thisvw->vw_Next)
{
if(thisvw->vw_Window)
ami_set_menu(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::
set-menu-enabled 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))
set_all_menus();
else
clear_all_menus();
}
else
{
if(!NILP(stat))
ami_set_menu(VWIN(vw)->vw_Window);
else
ami_clear_menu(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 = curr_vw;
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] COMMAND)
ITEM-NAME is the item name, SHORTCUT is an optional keyboard shortcut (a one
character long string) and COMMAND is the command to be called when the
menu is selected (see the function `call-command').
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))
{
signal_arg_error(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) : null_string);
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);
}
if(CONSP(item))
cur->nm_UserData = VCAR(item);
}
else
cur->nm_Label = NM_BARLABEL;
cur++;
menu = VCDR(menu);
}
args = VCDR(args);
}
cur->nm_Type = NM_END;
cur++;
new_menu = mymalloc((cur - nm) * sizeof(struct NewMenu));
if(new_menu)
{
memcpy(new_menu, nm, (cur - nm) * sizeof(struct NewMenu));
myfree(nm);
}
else
new_menu = nm;
menu_strip = CreateMenus(new_menu, TAG_END);
if(menu_strip)
{
vis_info = GetVisualInfo(curr_vw->vw_Window->WScreen, TAG_END);
if(vis_info)
{
if(LayoutMenus(menu_strip, vis_info,
#if AMIGA_INCLUDE_VER >= 39
GTMN_NewLookMenus, TRUE,
#endif
TAG_END))
{
set_all_menus();
return(sym_t);
}
else
cmd_signal(sym_error, LIST_1(MKSTR("Can't layout menus")));
FreeVisualInfo(vis_info);
vis_info = NULL;
}
else
cmd_signal(sym_error, LIST_1(MKSTR("Can't get visual info")));
FreeMenus(menu_strip);
menu_strip = NULL;
}
else
cmd_signal(sym_error, LIST_1(MKSTR("Can't create menus")));
myfree(new_menu);
new_menu = 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_strip; 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_strip)
{
struct MenuItem *mi;
while(mi = ItemAddress(menu_strip, code))
{
VALUE command;
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;
command = GTMENUITEM_USERDATA(mi);
if(command)
res = cmd_call_command(command, sym_nil);
refresh_world();
cursor(curr_vw, CURS_ON);
}
}
return(res);
}
void
ami_mark_menus(void)
{
if(new_menu)
{
struct NewMenu *nm = new_menu;
while(nm->nm_Type != NM_END)
{
if(nm->nm_Label != NM_BARLABEL)
{
MARKVAL(VAL(STRING_HDR(nm->nm_Label)));
if(nm->nm_CommKey)
MARKVAL(VAL(STRING_HDR(nm->nm_CommKey)));
MARKVAL(VAL(nm->nm_UserData));
}
nm++;
}
}
}
void
ami_menus_init(void)
{
ADD_SUBR(subr_set_menu_enabled);
ADD_SUBR(subr_menu_en