/*
 * Dynamic Intuition menu functions
 * from the author of PDTerm
 */

#include "exec/types.h"
#include "exec/memory.h"
#include "graphics/text.h"
#include "intuition/intuition.h"
#define	MEMFLAGS (LONG) (MEMF_PUBLIC | MEMF_CHIP | MEMF_CLEAR)

extern	char	*AllocMem();
extern	LONG	FreeMem();

/*
 * Create an instance of an Intuitext structure
 * containing text, positioned at (left,top)
 */

struct IntuiText *NewIText(text, left, top)
char *text;
int left, top;
{
	struct IntuiText *newtext = NULL;

	newtext = (struct IntuiText *)
		AllocMem((LONG) sizeof(*newtext), MEMFLAGS);
	newtext->IText = (UBYTE *)text;
	newtext->FrontPen = 0;
	newtext->BackPen = 1;
	newtext->DrawMode = JAM2;
	newtext->LeftEdge = left;
	newtext->TopEdge = top;
	newtext->ITextFont = NULL;
	newtext->NextText = NULL;

	return(newtext);
}

/*
 * Add an Intuitext structure to the end of
 * list of them, returning a pointer to the
 * new Intuitext.
 */

struct IntuiText *AddIText(IText, text)
struct IntuiText *IText;
char *text;
{
	struct IntuiText *newtext = NULL;

	newtext = (struct IntuiText *)
		AllocMem((LONG) sizeof(*newtext), MEMFLAGS);
                
	newtext->IText = (UBYTE *)text;
	newtext->FrontPen = IText->FrontPen;
	newtext->BackPen  = IText->BackPen;
	newtext->DrawMode = IText->DrawMode;
	newtext->LeftEdge = IText->LeftEdge;
	newtext->TopEdge  = IText->TopEdge + 11;
	newtext->ITextFont = IText->ITextFont;
	newtext->NextText = NULL;
	IText->NextText   = newtext;

	return(newtext);
}

/*
 * Dispose of a lise of IntuiText structures
 */

DisposeIText(IText)
struct IntuiText *IText;
{
	struct IntuiText *cur, *next;

	cur = IText;
	for(next = cur->NextText; cur != NULL; next = next->NextText) {
		FreeMem(cur,(LONG) sizeof(*cur));
		cur = next;
	}
}


/*
 * Dynamic menu constructor functions
 */

#define InterMenuWidth 15

/*
 * Create a new menu structure.
 */

struct Menu *NewMenu(menuname, width, height)
char *menuname;
int width, height;
{
	struct Menu *menu = NULL;

	menu = (struct Menu *)
		AllocMem((LONG) sizeof(*menu), MEMFLAGS);

	menu->NextMenu = NULL;
	menu->LeftEdge = 0;
	menu->TopEdge = 0;
	menu->Width = width;
	menu->Height = height;
	menu->Flags = MENUENABLED;
	menu->MenuName = menuname;
	menu->FirstItem = NULL;

	return(menu);
}

/*
 * Create a new menu and add it to
 * the end of the list of menus.
 */
struct Menu *AddMenu(menus, MenuName, width, height)
struct Menu *menus;
char *MenuName;
int width, height;
{
	struct Menu *newmenu;

	newmenu = NewMenu(MenuName, width, height);
	newmenu->LeftEdge = menus->LeftEdge + menus->Width + InterMenuWidth;
	menus->NextMenu = newmenu;
	return(newmenu);
}

/*
 * Create a new menu item
 */

struct MenuItem *NewMenuItem(name, width, height)
char *name;
int width, height;
{
	struct MenuItem *newitem = NULL;
	struct IntuiText *NewIText(), *newtext = NULL;

	newitem = (struct MenuItem *)
		AllocMem((LONG) sizeof(*newitem), MEMFLAGS);

	newtext = New. The
 * value is from the ITS EMACS manual. The
 * hard update is done because the top line in
 * the window is zapped.
 */
backpage(f, n, k)
register int	n;
{
	register LINE	*lp;

	if (f == FALSE) {
		n = curwp->w_ntrows - 2;	/* Default scroll.	*/
		if (n <= 0)			/* Don't blow up if the	*/
			n = 1;			/* window is tiny.	*/
	} else if (n < 0)
		return (forwpage(f, -n, KRANDOM));
#if	CVMVAS
	else					/* Convert from pages	*/
		n *= curwp->w_ntrows;		/* to lines.		*/
#endif
	lp = curwp->w_linep;
	while (n-- && lback(lp)!=curbp->b_linep)
		lp = lback(lp);
	curwp->w_linep = lp;
	curwp->w_dotp  = lp;
	curwp->w_doto  = 0;
	curwp->w_flag |= WFHARD;
	return (TRUE);
}

/*
 * Set the mark in the current window
 * to the value of dot. A message is written to
 * the echo line unless we are running in a keyboard
 * macro, when it would be silly.
 */
setmark(f, n, k)
{
	isetmark();
	if (kbdmop == NULL)
		eprintf("[Mark set]");
	return (TRUE);
}

/* 
 * So other commands can set the mark easily.  (daveb)
 */
isetmark()
{
	curwp->w_markp = curwp->w_dotp;
	curwp->w_marko = curwp->w_doto;
}


/*
 * Swap the values of "dot" and "mark" in
 * the current window. This is pretty easy, because
 * all of the hard work gets done by the standard routine
 * that moves the mark about. The only possible
 * error is "no mark".
 */
swapmark(f, n, k)
{
	register LINE	*odotp;
	register int	odoto;

	if (curwp->w_markp == NULL) {
		eprintf("No mark in this window");
		return (FALSE);
	}
	odotp = curwp->w_dotp;
	odoto = curwp->w_doto;
	curwp->w_dotp  = curwp->w_markp;
	curwp->w_doto  = curwp->w_marko;
	curwp->w_markp = odotp;
	curwp->w_marko = odoto;
	curwp->w_flag |= WFMOVE;
	return (TRUE);
}

/*
 * Go to a specific line, mostly for
 * looking up errors in C programs, which give the
 * error a line number. If an argument is present, then
 * it is the line number, else prompt for a line number
 * to use.
 */
gotoline(f, n, k)
register int	n;
{
	register LINE	*clp;
	register int	s;
	char		buf[32];

	if (f == FALSE) {
		if ((s=ereply("Goto line: ", buf, sizeof(buf))) != TRUE)
			return (s);
		n = atoi(buf);
	}
	if (n <= 0) {
		eprintf("Bad line");
		