/*
 * 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-file-read-only",		},
	{ "Save File",		"file-buffer",			},
	{ "Find File",		"find-file",			},
	{ "Write File",		"write-file"			},
	{ "Insert File",	"insert-file"			},
	{ "Set File Name",	"set-visited-file-name"		},
	{ "Save And Exit",	"save-buffers-kill-emacs"	},
	{ "Kill Emacs",		"kill-emacs",			}
};

/*
 * Commands for various editing functions
 */

static struct MenuBinding EditItems[] = {
	{ "Delete Char",		"delete-char"			},
	{ "Kill Line",			"kill-line"			},
	{ "Yank",			"yank"				},
	{ "Delete Blank Lines",		"delete-blank-lines"		},
	{ "Newline And Indent",		"newline-and-indent"		},
	{ "Transpose Characters",	"transpose-characters"		},
	{ "Quoted Insert",		"quoted-insert"			}
};

/*
 * Movement commands
 */

static struct MenuBinding MoveItems[] = {
	{ "Beginning Of Line",		"beginning-of-line"		},
#ifdef AS_DISTRIBUTED
	{ "Beg. Of  Paragraph",		"goto-bop"			},
#endif
	{ "Beginning Of Buffer",	"beginning-of-buffer"		},
	{ "End Of Line",		"end-of-line"			},
#ifdef AS_DISTRIBUTED
	{ "End Of Paragraph",		"goto-eop"			},
#endif
	{ "End Of Buffer",		"end-of-buffer"			},
	{ "Goto Line",			"goto-line"			},
	{ "Show Cursor Pos",		"what-cursor-position"		}
};

/*
 * Commands for searching and replacing
 */

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

/*
 * Commands that manipulate words
 */
static struct MenuBinding WordItems[] = {
#ifdef AS_DISTRIBUTED
	{ "Fill Paragraph",		"fill-paragraph"		},
	{ "Set Fill Column",		"set-fill-column"		},
#endif
	{ "Forward Word",		"forward-word"			},
	{ "Backward Word",		"backward-word"			},
	{ "Kill Word",			"kill-word"	 		},
	{ "Backward Kill Word",		"backward-kill-word" 		},
	{ "Capitalize Word",		"capitalize-word"		},
	{ "Downcase Word",		"downcase-word"			},
	{ "Upcase Word",		"upcase-word"			}
};

/*
 * Region management
 */

static struct MenuBinding RegionItems[] = {
	{ "Set Mark Command",		"set-mark-command"		},
	{ "Exch Point And Mark",	"exchange-point-and-mark"	},
	{ "Kill Region",		"kill-region"			},
	{ "Copy Region As Kill",	"copy-region-as-kill"		},
	{ "Downcase Region",		"downcase-region"		},
	{ "Upcase Region",		"upcase-region"			}
};

/*
 * Buffer management
 */

static struct MenuBinding BufferItems[] = {
#ifdef NOTIMPLEMENTED
	{ "Rename Buffer",		"rename-buffer"			},
#endif
	{ "Switch To Buffer",		"switch-to-buffer"		},
	{ "Kill Buffer",		"kill-buffer"			},
	{ "List Buffers",		"list-buffers"			}
};

/*
 * Commands for manipulating windows
 */

static struct MenuBinding WindowItems[] = {
	{ "Recenter",			"recenter"			},
	{ "Move To Window Line",	"move-to-window-line"		},
	{ "Split Window Vertically",	"split-window-vertically"	},
	{ "Delete Other Windows",	"delete-other-windows"		},
	{ "Other Window",		"other-window"			},
	{ "Back Window",		"back-window"			},
	{ "Down Window",		"down-window"			},
	{ "Up Window",			"up-window"			},
	{ "Enlarge Window",		"enlarge-window"		},
	{ "Shrink Window",		"shrink-window"			}
};

/*
 * Miscellaneous commands
 */

static struct MenuBinding MiscItems[] = {
	{ "Emacs Version",		"emacs-version"			},
	{ "Start Kbd Macro",		"start-kbd-macro"		},
	{ "End Kbd Macro",		"end-kbd-macro"			},
	{ "Call Kbd Macro",		"call-last-kbd-macro"		},
	{ "Execute Command",		"execute-extended-command"	},
	{ "Global Set Key",		"global-set-key"		},
	{ "Describe Bindings",		"describe-bindings"		},
	{ "Suspend Emacs",		"suspend-emacs"			}
};

/*
 * 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),	20,	&EditItems[0]	},
	{ "Move", 	NITEMS(MoveItems),	19,	&MoveItems[0]	},
	{ "Search",	NITEMS(SearchItems),	17,	&SearchItems[0] },
	{ "Word",	NITEMS(WordItems),	18,	&WordItems[0]	},
	{ "Region",	NITEMS(RegionItems),	19,	&RegionItems[0]	},
	{ "Buffer",	NITEMS(BufferItems),	16,	&BufferItems[0]	},
	{ "Window",	NITEMS(WindowItems),	23,	&WindowItems[0] },
	{ "Misc",	NITEMS(MiscItems),	17,	&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);
}
