/*
 * Name:	MicroEmacs
 * 		Commodore Amiga Intuition menus
 * Version:	31
 * Last edit:	20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 * Created:	20-Apr-86 ...!ihnp4!seismo!ut-sally!ut-ngp!mic
 */

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/text.h>
#include <libraries/diskfont.h>
#include <intuition/intuition.h>
#undef	TRUE
#undef	FALSE
#include "def.h"	/* Also includes "sysdef.h" and "ttydef.h" */

/*
 * When ttgetc() sees a menu selection event, it stuffs
 * the sequence <CSI>M~ into the input buffer, and
 * caches the menu number and item number for later.
 * This sequence is translated into the internal key code
 * KMENU, similar to KHELP and the other function keys.
 *
 * The menu item names are chosen to be relatively close
 * to the extended function names, so a user can usually
 * figure out the key binding of a menu item by searching
 * through the "display-bindings" buffer for something
 * that's close.
 */

/*
 * Commands for managing files
 */

static struct MenuBinding FileItems[] = {
	{ "Read File",		"file-read",		},
	{ "Save File",		"file-save",		},
	{ "Visit File",		"file-visit",		},
	{ "Write File",		"file-write"		},
	{ "Insert File",	"file-insert"		},
	{ "Set File Name",	"set-file-name"		},
	{ "Quit",		"quit",			}
};

/*
 * Commands for various editing functions
 */

static struct MenuBinding EditItems[] = {
	{ "Forward Del Char",	"forw-del-char"		},
	{ "Kill Line",		"kill-line"		},
	{ "Yank",		"yank"			},
	{ "Delete Blank Lines",	"del-blank-lines"	},
	{ "NL And Indent",	"ins-nl-and-indent"	},
	{ "Twiddle",		"twiddle"		},
	{ "Quote Character",	"quote"			}
};

/*
 * Movement commands
 */

static struct MenuBinding MoveItems[] = {
	{ "Beg. Of  Line",	"goto-bol"		},
	{ "Beg. Of  Paragraph",	"goto-bop"		},
	{ "Beg. Of  Buffer",	"goto-bob"		},
	{ "End Of   Line",	"goto-eol"		},
	{ "End Of   Paragraph",	"goto-eop"		},
	{ "End Of   Buffer",	"goto-eob"		},
	{ "Goto Line",		"goto-line"		},
	{ "Show Cursor Pos",	"display-position"	}
};

/*
 * Commands for searching and replacing
 */

static struct MenuBinding SearchItems[] = {
	{ "Search Again",	"search-again"	},
	{ "Forward  I-Search",	"forw-i-search"	},
	{ "Backward I-Search",	"back-i-search"	},
	{ "Forward  Search",	"forw-search"	},
	{ "Backward Search",	"back-search"	},
	{ "Query Replace",	"query-replace"	},
};

/*
 * Commands that manipulate words
 */
static struct MenuBinding WordItems[] = {
	{ "Forward  Word",	"forw-word"		},
	{ "Backward Word",	"back-word"		},
	{ "Forward Del Word",	"forw-del-word" 	},
	{ "Backward Del Word",	"back-del-word" 	},
	{ "Capitalize Word",	"cap-word"		},
	{ "Lowercase  Word",	"lower-word"		},
	{ "Uppercase  Word",	"upper-word"		},
	{ "Fill Paragraph",	"fill-paragraph"	},
	{ "Set Fill Column",	"set-fill-column"	}
};

/*
 * Region management
 */

static struct MenuBinding RegionItems[] = {
	{ "Set Mark",		"set-mark"		},
	{ "Swap Dot And Mark",	"swap-dot-and-mark"	},
	{ "Kill Region",	"kill-region"		},
	{ "Copy Region",	"copy-region"		},
	{ "Lowercase Region",	"lower-region"		},
	{ "Uppercase Region",	"upper-region"		}
};

/*
 * Buffer management
 */

static struct MenuBinding BufferItems[] = {
	{ "Use Buffer",		"use-buffer" 		},
	{ "Kill Buffer",	"kill-buffer"		},
	{ "Display Buffers",	"display-buffers"	},
	{ "Rename Buffer",	"rename-buffer"		}
};

/*
 * Commands for manipulating windows
 */

static struct MenuBinding WindowItems[] = {
	{ "Refresh Screen",	"refresh"		},
	{ "Reposition Window",	"reposition-window"	},
	{ "Split Window",	"split-window"		},
	{ "One Window",		"only-window"		},
	{ "Next Window",	"forw-window"		},
	{ "Previous Window",	"back-window"		},
	{ "Move Window Down",	"down-window"		},
	{ "Move Window Up",	"up-window"		},
	{ "Enlarge Window",	"enlarge-window"	},
	{ "Shrink Window",	"shrink-window"		}
};

/*
 * Miscellaneous commands
 */

static struct MenuBinding MiscItems[] = {
	{ "About MicroEMACS",	"display-version"	},
	{ "Start Macro",	"start-macro"		},
	{ "End Macro",		"end-macro"		},
	{ "Execute Macro",	"execute-macro"		},
	{ "Extended Command",	"extended-command"	},
	{ "Bind Key",		"bind-to-key"		},
	{ "Display Bindings",	"display-bindings"	},
	{ "CLI Subprocess",	"spawn-cli"		}
};

/*
 * The following table contains the titles, number of
 * items, and pointers to, the individual menus.
 *
 * The MenuWidth field is the number of characters
 * in the longest item name.
 */

static struct MenuInfo EMInfo[] = {
	{ "File",	NITEMS(FileItems),	13,	&FileItems[0]	},
	{ "Edit",	NITEMS(EditItems),	18,	&EditItems[0]	},
	{ "Move", 	NITEMS(MoveItems),	18,	&MoveItems[0]	},
	{ "Search",	NITEMS(SearchItems),	17,	&SearchItems[0] },
	{ "Word",	NITEMS(WordItems),	17,	&WordItems[0]	},
	{ "Region",	NITEMS(RegionItems),	17,	&RegionItems[0]	},
	{ "Buffer",	NITEMS(BufferItems),	15,	&BufferItems[0]	},
	{ "Window",	NITEMS(WindowItems),	17,	&WindowItems[0] },
	{ "Misc",	NITEMS(MiscItems),	16,	&MiscItems[0]	}
};

/*
 * Initialize the MicroEmacs menus.
 *
 * Returns a pointer to the first menu header in
 * the menu list back to the caller.
 *
 * Makes the assumption that the font for
 * the window being used is 8 pixels wide --
 * a safe bet with the version 1.1 ROM Kernel.
 */

struct Menu *InitEmacsMenu()
{
	struct Menu *EMMenu, *NewMenu(), *AddMenu();
	struct MenuItem *AddNewMenuItem(), *AddItem(), *AddNewSubItem();

	register struct Menu *cm;
	register struct MenuInfo *cinf, *lastinfo;/* current menu info	*/

	lastinfo = &EMInfo[NITEMS(EMInfo)];	/* sentinel for loop	*/

	for (cinf = EMInfo; cinf < lastinfo; cinf++) {
		if (cinf == EMInfo)		/* create menu header	*/
			EMMenu = cm = NewMenu(cinf->Name,
				strlen(cinf->Name) * 8 + 6, 10);
		else
			cm = AddMenu(cm,
				cinf->Name,strlen(cinf->Name) * 8 + 6, 10);
		MakeMenu(cinf,cm,cinf->MenuWidth * 8 + 2, 10);
	}
	return EMMenu;
}

/*
 * Put menu items in a menu.  Width and
 * height control the respective
 * sizes of the menu items.
 */

static	MakeMenu(cinf,cm,width,height)
struct MenuInfo *cinf;
struct Menu *cm;
int width, height;
{
	struct Menu *NewMenu(), *AddMenu();
	struct MenuItem *AddNewMenuItem(), *AddItem(), *AddNewSubItem();

	register struct MenuBinding *cb, *lastbinding;
	register struct MenuItem *ci;

	lastbinding = &cinf->Items[cinf->NumItems];
	for (cb = cinf->Items; cb < lastbinding; cb++) {
		if (cb == cinf->Items)
			ci = AddNewMenuItem(cm, cb->Command, width, height);
		else
			ci = AddItem(ci, cb->Command);
	}
}

/*
 * Menu command.   Get the name of the command to
 * perform from the menu binding table, then
 * run the command if it is found and has the
 * right type. Print an error if there is anything
 * wrong.
 */
extern ttmenu();			/* Defined in "ttyio.c" 	*/
					/* Returns last menu selection	*/
amigamenu(f, n, k)
{
	register SYMBOL	*sp, *symlookup();
	char		*xname;
	int MenuNum, ItemNum, SubItem;

	ttmenu(&MenuNum,&ItemNum,&SubItem);

	/* check for spurious numbers */
	if ((MenuNum < 0) || (MenuNum >= NITEMS(EMInfo)))
		return (FALSE);
	if ((ItemNum < 0) || (ItemNum >= EMInfo[MenuNum].NumItems))
		return (FALSE);	

	xname = EMInfo[MenuNum].Items[ItemNum].Binding;

	if ((sp=symlookup(xname)) != NULL)
		return ((*sp->s_funcp)(f, n, KRANDOM));
	eprintf("Unknown menu command");
	return (ABORT);
}
