
/*
 * MENUS.C
 * (c) 1992-3 J.Harper
 */

#include "jed.h"
#include "jed_protos.h"

#define MAX_MENUS 300
#define NMSIZE (MAX_MENUS * sizeof(struct NewMenu))

Prototype   VALUE *		cmd_menu	(LONG, VALUE *);
Prototype   VALUE *		cmd_setmenu	(LONG, VALUE *);
Local	    BOOL		makemenu	(STRPTR);
Prototype   VOID		killmenu	(VOID);
Prototype   VOID		clearmenu	(struct Window *);
Local	    VOID		clearallmenus	(VOID);
Prototype   VOID		setmenu		(struct Window *);
Local	    VOID		setallmenus	(VOID);
Prototype   VOID		evalmenu	(WORD, WORD);
Local	    struct MenuItem *	findcommmenu	(UBYTE);
Local	    STRPTR		getstring	(STRPTR *);

Local struct Menu *Menu;
Local STRPTR MenuDef;
Local APTR VisInfo;

/*
 * (menu 1)
 * (menu 0)
 */
VALUE *
cmd_menu(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_NUMBER))
    {
	BOOL rc = FALSE;
	if(ARG1.val_Value.Number)
	{
	    setmenu(CurrVW->vw_Window);
	    rc = TRUE;
	}
	else
	{
	    clearmenu(CurrVW->vw_Window);
	    rc = TRUE;
	}
	setnumres(rc);
    }
    return(&RES);
}

/*
 * (setmenu `fileName')
 */
VALUE *
cmd_setmenu(LONG argc, VALUE *argv)
{
    if(TPLATE1(VTF_STRING))
    {
	setnumres(makemenu(ARG1.val_Value.String));
    }
    return(&RES);
}

Local BOOL
makemenu(STRPTR file)
{
    killmenu();
    if(MenuDef = squirrelfile(file))
    {
	STRPTR def = MenuDef;
	struct NewMenu *nm;

	if(!(nm = (struct NewMenu *)AllocMem(NMSIZE, MEMF_CLEAR)))
	{
	    settitle(NoMemMsg);
	    freestring(MenuDef);
	    MenuDef = NULL;
	    return(FALSE);
	}
	else
	{
	    struct NewMenu *cnm = nm;
	    UBYTE keyword[20];
	    BOOL exitflag = FALSE;

	    def = stpblk(def);
	    while((!exitflag) && (*def))
	    {
		cpyalnum(keyword, def);
		def = stpblk(stpalnum(def));

		if(!(stricmp(keyword, "MENU")))
		{
		    cnm->nm_Type = NM_TITLE;
		    cnm->nm_Label = getstring(&def);
		    cnm++;
		}
		else if(!(stricmp(keyword, "ITEM")))
		{
		    STRPTR temp;

		    cnm->nm_Type = NM_ITEM;
		    cnm->nm_Label = getstring(&def);
		    temp = getstring(&def);
		    if(*temp == NULL)
			cnm->nm_CommKey = NULL;
		    else
			cnm->nm_CommKey = temp;
		    cnm->nm_UserData = getstring(&def);
		    cnm++;
		}
		else if(!(stricmp(keyword, "SUB")))
		{
		    STRPTR temp;

		    cnm->nm_Type = NM_SUB;
		    cnm->nm_Label = getstring(&def);
		    temp = getstring(&def);
		    if(*temp == NULL)
			cnm->nm_CommKey = NULL;
		    else
			cnm->nm_CommKey = temp;
		    cnm->nm_UserData = getstring(&def);
		    cnm++;
		}
		else if(!(stricmp(keyword, "BAR")))
		{
		    cnm->nm_Type = NM_ITEM;
		    cnm->nm_Label = NM_BARLABEL;
		    cnm++;
		}
		else if(!(stricmp(keyword, "SBAR")))
		{
		    cnm->nm_Type = NM_SUB;
		    cnm->nm_Label = NM_BARLABEL;
		    cnm++;
		}
		else if(!(stricmp(keyword, "END")))
		{
		    cnm->nm_Type = NM_END;
		    exitflag = TRUE;
		}
		else
		{
		    settitlefmt("error: unknown menu type %s", (LONG)keyword);
		    FreeMem(nm, NMSIZE);
		    freestring(MenuDef);
		    MenuDef = NULL;
		    return(FALSE);
		}
		def = stpblk(def);
	    }
	}
	if(!(Menu = CreateMenus(nm, TAG_END)))
	    settitle("createmenus error: either out of mem or an illegal menu");
	else
	{
	    if(VisInfo = GetVisualInfo(CurrVW->vw_Window->WScreen, TAG_END))
	    {
		if(LayoutMenus(Menu, VisInfo, TAG_END))
		    setallmenus();
		else
		{
		    FreeVisualInfo(VisInfo);
		    VisInfo = NULL;
		    FreeMenus(Menu);
		    Menu = NULL;
		    freestring(MenuDef);
		    MenuDef = NULL;
		}
	    }
	    else
	    {
		FreeMenus(Menu);
		Menu = NULL;
		freestring(MenuDef);
		MenuDef = NULL;
	    }
	}
	FreeMem(nm, NMSIZE);
    }
    else
	settitle("error: can't open menu definition file");
    return((BOOL)Menu);
}

VOID
killmenu(VOID)
{
    if(Menu)
    {
	clearallmenus();
	FreeMenus(Menu);
	Menu = NULL;
    }
    if(MenuDef)
    {
	freestring(MenuDef);
	MenuDef = NULL;
    }
    if(VisInfo)
    {
	FreeVisualInfo(VisInfo);
	VisInfo = NULL;
    }
}

VOID
clearmenu(struct Window *wd)
{
    ClearMenuStrip(wd);
}

Local VOID
clearallmenus(VOID)
{
    TX *thistx = (TX *)TXList.mlh_Head;
    VW *thisvw;

    for(thistx = (TX *)TXList.mlh_Head; thistx->tx_Node.mln_Succ; thistx = (TX *)thistx->tx_Node.mln_Succ)
    {
	for(thisvw = (VW *)thistx->tx_Views; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
	{
	    ClearMenuStrip(thisvw->vw_Window);
	}
    }
}

VOID
setmenu(struct Window *wd)
{
    if(Menu)
	SetMenuStrip(wd, Menu);
}

Local VOID
setallmenus(VOID)
{
    TX *thistx = (TX *)TXList.mlh_Head;
    VW *thisvw;

    for(thistx = (TX *)TXList.mlh_Head; thistx->tx_Node.mln_Succ; thistx = (TX *)thistx->tx_Node.mln_Succ)
    {
	for(thisvw = (VW *)thistx->tx_Views; thisvw->vw_Node.mln_Succ; thisvw = (VW *)thisvw->vw_Node.mln_Succ)
	{
	    SetMenuStrip(thisvw->vw_Window, Menu);
	}
    }
}

/*
 * called from IDCMP event loop
 */
VOID
evalmenu(WORD code, WORD qual)
{
    if(Menu)
    {
	struct MenuItem *mi;
	while(mi = ItemAddress(Menu, code))
	{
	    VALUE result;
	    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;
	    cursor(OFF);
	    execstr(GTMENUITEM_USERDATA(mi), &result, FALSE, 0, NULL);
	    cursor(ON);
	    releasevalue(&result);
	}
    }
}

/*
 * This routine is used so we can make command key shortcuts case
 * sensitive - is there an easier way than this???
 */
Local struct MenuItem *
findcommmenu(UBYTE 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);
}

/*
 * Get a string enclosed in "...", zero terminate it and return it.
 * string is not copied, input is advanced past the zero.
 */
STRPTR
getstring(STRPTR *text_pt)
{
    STRPTR text;
    STRPTR rtn;
    UBYTE c;

    text = *text_pt;

    while((c = *text++) != '\"')
    {
	if(!c)
	{
	    *text_pt = text-1;
	    settitle("premature EOF: quoted string expected");
	    return(FALSE);
	}
    }
    rtn = text;
    while((c = *text++) != '\"')
    {
	if(!c)
	{
	    *text_pt = text-1;
	    settitle("premature EOF: no string termination quote");
	    return(FALSE);
	}
    }
    *(text-1) = '\0';
    *text_pt = text;
    return(rtn);
}

