// MPMorph - Amiga Morphing program
// Copyright (C) © 1993  Topicsave Limited

// This program 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 of the License, or
// any later version.

// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// mpaddock@cix.compulink.co.uk

// include precompiled headers if required
#ifndef MPMORPH_AMIGA_H
#include "MPMorph-amiga.h"
#endif
#ifndef MPMORPH_H
#include "MPMorph.h"
#endif

extern long __stack = 16000;

extern char TempFilename[256]="";	// file name buffer set up and used in various places
extern int MPHnum=0;						// Help Num for gui
extern struct Screen *myscreen = NULL;

/* Help call back for MPGui.library
 */
ULONG __saveds __asm HelpHook(register __a0 struct Hook *hook,
								  register __a2 char *name,
								  register __a1 APTR notused) {
	char buffer[256];
	struct AmigaGuideMsg *agm;

	if (handle) {
		while (agm = GetAmigaGuideMsg(handle)) {
			ReplyAmigaGuideMsg(agm);
		}
		sprintf(buffer,MyGetMsg(MSG_LINKS),name);
		SendAmigaGuideCmdA(handle,buffer,NULL);
		while (agm = GetAmigaGuideMsg(handle)) {
			ReplyAmigaGuideMsg(agm);
		}
	}
	return 1;
}

/* display short help message
 * at top of window
 * helpnum : number of help node
 */
void
ihelp(ULONG helpnum) {
	// only display if not zero, and there is a short message and the window is open
	// and not disabled
	if (helpnum && !Disabled) {
		if (ShortHelp[helpnum] != -1) {
			if (MPMorphWnd) {
				SetMessage(MyGetMsg(ShortHelp[helpnum]));
//				GT_SetGadgetAttrs(MPMorphGadgets[GDX_Help],MPMorphWnd,NULL,
//									GTTX_Justification, GTJ_CENTER,
//									GTTX_Clipped, TRUE,
//									GTTX_Text,MyGetMsg(ShortHelp[helpnum]), TAG_END );
			}
		}
	}
}

/* Display help using amigaguide (if available)
 * based on a number. Also displays short help message
 */
void
help(ULONG helpnum) {
	// display amigaguide if available
	if (handle) {
		SetAmigaGuideContext(handle,helpnum,NULL);
		SendAmigaGuideContext(handle,NULL);
	}
	// display short message
	ihelp(helpnum);
}

/* Standard CloseWindowSafely
 * removing messages on shared ports
 */
void
CloseWindowSafely(struct Window *win) {
	Forbid();
	StripIntuiMessages(win->UserPort,win);
	win->UserPort = NULL;
	ModifyIDCMP(win,0);
	Permit();
	CloseWindow(win);
}

/* Standard StripIntuiMessages	*/
void
StripIntuiMessages(struct MsgPort *mp,struct Window *win) {
	struct IntuiMessage *msg, *succ;
	msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
	while(succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ) {
		if(msg->IDCMPWindow == win) {
			Remove((struct Node *)msg);
			ReplyMsg((struct Message *)msg);
		}
		msg = succ;
	}
}

/* Display an error message
 * ErrorMessage	: The main text
 * Gadget			: Text for one gadget
 * extra				: more of the text
 * helpnum			: Number of a help node
 *
 * Uses reqtools.library if available
 */
void
Error(char *ErrorMessage,char *Gadget,char *extra,ULONG helpnum) {
	struct EasyStruct EasyStruct = {
		sizeof(struct EasyStruct),
		0,
		NULL,
		NULL,
		NULL
	};
	UBYTE *title;
	struct Window *req;
	UBYTE gad[32];
	UBYTE gad1[32];
	UBYTE buffer[512];
	ULONG ret = CALL_HANDLER;
	struct AmigaGuideMsg *agm;
	ULONG signals=0;
	struct rtHandlerInfo *rth;
	// Disable the windows and display the requester
	title = MyGetMsg(MSG_MPMERR);
	strcpy(gad,MyGetMsg(MSG_HELPOR));
	strcpy(gad1,MyGetMsg(MSG__HELPOR));
	DisableWindows(helpnum);
	if (GHelp) {
		help(helpnum);
	}
	if (EGS && Pic1_Open) {
		EGSError(ErrorMessage,Gadget,extra,helpnum,buffer,gad);
	}
	else {
		if (ReqToolsBase) {
			// Set up gadgets depending on if amigaguide is available
			if (!handle) {
				strcpy(gad1,MyGetMsg(MSG__));
			}
			strcat(gad1,Gadget);
			// This loops until OK is pressed, displaying help if Help is pressed (if present)
			while (ret) {
				ret = CALL_HANDLER;
				if (rtEZRequestTags(ErrorMessage,gad1,NULL,&extra,
											RT_ReqHandler,	&rth,
											RT_Window,		MPMorphWnd,
											RT_Underscore,	'_',
											RTEZ_ReqTitle,	title,
											TAG_END) == CALL_HANDLER) {
					while (ret == CALL_HANDLER) {
						if (!rth->DoNotWait) {
							signals = Wait(rth->WaitMask | ASig);
						}
						ret = rtReqHandlerA(rth,signals,NULL);
						if (ret == 1) {
							help(helpnum);
						}
						if (signals & ASig) {
						  	while (agm = GetAmigaGuideMsg(handle)) {
					 			ReplyAmigaGuideMsg(agm);
					 		}
					 	}
					}
				}
				else {
					ret = 0;
				}
			}
		}
		else {
			EasyStruct.es_TextFormat = ErrorMessage;
			EasyStruct.es_Title = title;
			// Set up gadgets depending on if amigaguide is available
			if (handle) {
				strcat(gad,Gadget);
			}
			else {
				strcpy(gad,Gadget);
			}
			EasyStruct.es_GadgetFormat = gad;
			req = BuildEasyRequest(MPMorphWnd,&EasyStruct,NULL,extra);
			// This loops until OK is pressed, displaying help if Help is pressed (if present)
			while (ret) {
				signals  = Wait((1L << req->UserPort->mp_SigBit) | ASig);
				if (signals & (1L << req->UserPort->mp_SigBit)) {
					ret = SysReqHandler(req,NULL,FALSE);
					if (ret == 1) {
						help(helpnum);
					}
				}
				if (signals & ASig) {
				  	while (agm = GetAmigaGuideMsg(handle)) {
				 		ReplyAmigaGuideMsg(agm);
				 	}
				}
			}
			FreeSysRequest(req);
		}
	}
	EnableWindows();
}

/* Draw all points
 * in both windows
 */
void
DrawAllPoints(void) {
	struct MyPoint *MyPoint;
	int i;
	// For each point
	for (MyPoint = (struct MyPoint *)PointList.lh_Head;
						  MyPoint->MyNode.mln_Succ;
						  MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
		// Draw point in image 1
		MyPoint->Drawn1 = FALSE;
		DrawPixels(&Pic1,MyPoint->x,MyPoint->y,NULL);
		// Same stuff for image 2
		MyPoint->Drawn2 = FALSE;
		DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,NULL);
		UpdatePens(MyPoint);
	}
	for (MyPoint = (struct MyPoint *)PointList.lh_Head;
						  MyPoint->MyNode.mln_Succ;
						  MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
		/* For each linked point draw a line
		 * to the other if the other is a "later" point
		 */
		for (i = 0;
			  i < MAX_LINKS;
			  i++) {
			if (MyPoint->p[i]) {
				if (EGS) {
					if (MyPoint->p[i] > MyPoint) {
						EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint->p[i]->x,MyPoint->p[i]->y,MyPoint->x,MyPoint->y);
						EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint->p[i]->x1,MyPoint->p[i]->y1,MyPoint->x1,MyPoint->y1);
					}
				}
				else {
					if (MyPoint->p[i] > MyPoint) {
						MyDraw(Pic1.Win->RPort,MyPoint->p[i]->x<<Zoom,MyPoint->p[i]->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
						MyDraw(Pic2.Win->RPort,MyPoint->p[i]->x1<<Zoom,MyPoint->p[i]->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
					}
				}
			}
		}
	}
}

/* Handle Raw Key in Information
 * Window - from GadToolsBox
 */
int
MPMorphRawKey(void) {
	if (!Disabled) {
		char *com=0;
		switch (MPMorphMsg.Code) {
		case 0x5f:
			help(MPHnum);
			break;
		case 0x50:
			Preview();
			break;
		case 0x51:
			com = User2;
			break;
		case 0x52:
			com = User3;
			break;
		case 0x53:
			com = User4;
			break;
		case 0x54:
			com = User5;
			break;
		case 0x55:
			com = User6;
			break;
		case 0x56:
			com = User7;
			break;
		case 0x57:
			com = User8;
			break;
		case 0x58:
			com = User9;
			break;
		}
		if (com) {
			SendRexxCommand(myhost,com,NULL);
		}
	}
	return 1;
}

/* Handle Vanilla Key in Information
 * Window - from GadToolsBox
 */
int
MPMorphVanillaKey(void) {
if (!Disabled) {
	int i;
	int j = -1;
	for (i=0; i< MPMorph_CNT; ++i) {
		if (MPMorphNGad[i].ng_GadgetText) {
			if (' ' != *(MPMorphNGad[i].ng_GadgetText-2)) {
				if (MPMorphMsg.Code == *(MPMorphNGad[i].ng_GadgetText-2)) {
					j = i;
				}
				else {
					if (MPMorphMsg.Code == *(MPMorphNGad[i].ng_GadgetText-1)) {
						j = i;
					}
				}
			}
		}
	}
	switch (j) {
	case GD_FileOne:
		/* O - if control window not open
		 * either activate string gadget
		 * or display file requester with shift
		 */
		if (!ControlWindow) {
			if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
				GetFileOneClicked();
			}
			else {
				ActivateGadget(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL);
			}
		}
		break;
	case GD_FileTwo:
		/* T - if control window not open
		 * either activate string gadget
		 * or display file requester with shift
		 */
		if (!ControlWindow) {
			if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
				GetFileTwoClicked();
			}
			else {
				ActivateGadget(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL);
			}
		}
		break;
	case GD_File241:
		/* 1 - either activate string gadget
		 * or display file requester with shift
		 */
		if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
			GetFile1Clicked();
		}
		else {
			ActivateGadget(MPMorphGadgets[GDX_File241],MPMorphWnd,NULL);
		}
		break;
	case GD_File242:
		/* 2 - either activate string gadget
		 * or display file requester with shift
		 */
		if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
			GetFile2Clicked();
		}
		else {
			ActivateGadget(MPMorphGadgets[GDX_File242],MPMorphWnd,NULL);
		}
		break;
	case GD_SinglePicture:
		// R - Cycle Single
		if (!ControlWindow) {
			if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
				if (!SinglePicture) {
					SinglePicture = 3;
				}
				else {
					--SinglePicture;
				}
			}
			else {
				if (SinglePicture == 3) {
					SinglePicture = 0;
				}
				else {
					++SinglePicture;
				}
			}
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_SinglePicture],MPMorphWnd,NULL,
									GTCY_Active,SinglePicture, TAG_END );
			Record(MyGetMsg(MSG_SETSINGLE),SinglePicture);
		}
		break;
	case GD_Frames:
		// F - activate string gadgtet
		if (!ControlWindow) {
			ActivateGadget(MPMorphGadgets[GDX_Frames],MPMorphWnd,NULL);
		}
		break;
	case GD_Start:
		// A - activate string gadgtet
		if (!ControlWindow) {
			ActivateGadget(MPMorphGadgets[GDX_Start],MPMorphWnd,NULL);
		}
		break;
	case GD_Name:
		/* N - either activate string gadget
		 * or display file requester with shift
		 */
		if (MPMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
			GetSaveNameClicked();
		}
		else {
			ActivateGadget(MPMorphGadgets[GDX_Name],MPMorphWnd,NULL);
		}
		break;
	case GD_EditPoints:
		/* P - either open Control and image windows
		 * or activate and bring control window to front
		 */
		MPMorphMenuEditPoints();
		break;
	case GD_Scale:
		ScaleClicked();
		break;
	case GD_SetSize:
		SetSizeClicked();
		break;
	default:
		// other key
		break;
	}
}
	return 1;
}

/* Open... menu item in Info window */
int
MPMorphMenuOpen(void) {
	// Just call MyOpen();
	MyOpen(NULL,FALSE,TRUE);
	return 1;
}

/* Save menu item in Info window */
int MPMorphMenuSave(void) {
	// Just call SaveAs(last saved name)
	DisableWindows(DI_WaitSave);
	SaveAs(savedfilename);
	EnableWindows();
  	return 1;
}

/* Save As... menu item in Info window */
int
MPMorphMenuSaveAs(void) {
	// Just call SaveAs(no name)
	DisableWindows(DI_WaitSave);
	SaveAs(NULL);
	EnableWindows();
	return 1;
}

/* Delete... menu item in Info window */
int
MPMorphMenuDelete(void) {
	BPTR cd;
	BOOL ok = TRUE;
	struct AnchorPath ap = {0};
	// Delete a project with Icon and all .nnn files
	DisableWindows(DI_Delete);
	if (GetAFile("",MyGetMsg(MSG_DELETEP),FRF_DOSAVEMODE,NULL,MyGetMsg(MSG_DELETE))) {
		// delete main file and icon
		DeleteFile(TempFilename);
		DeleteDiskObject(TempFilename);
		// delete "project.nnn" files
		strcat(TempFilename,MyGetMsg(MSG_090909));
		if (!MatchFirst(TempFilename,&ap)) {
			while (ok) {
				cd = CurrentDir(ap.ap_Current->an_Lock);
				DeleteFile(ap.ap_Info.fib_FileName);
				CurrentDir(cd);
				ok = !MatchNext(&ap);
			}
		}
		MatchEnd(&ap);
	}
	EnableWindows();
	return 1;
}

/* About menu item in Info window */
int
MPMorphMenuAbout(void) {
	// Just Call About()
	About();
	return 1;
}

/* Quit menu item in Info window */
int
MPMorphMenuQuit(void) {
	// Suggest save - quit if requested
  	if (!Saved) {
 		return !SaveRequester();
  	}
  	else {
  		return 0;
  	}
}

/* Edit Points... menu item in Info window */
int
MPMorphMenuEditPoints(void) {
	// Open window if not open
	Record(MyGetMsg(MSG_EDITPOINTS),NULL);
	if (!ControlWindow) {
		OpenPointsEdit();
	}
	// Otherwise activate and bring to front
	else {
		WindowToFront(ControlWindow);
		if (!EGS) {
			WindowToFront(Pic1.Win);
			WindowToFront(Pic2.Win);
		}
		ActivateWindow(ControlWindow);
	}
	return 1;
}

int
MPMorphMenuRecent1(void) {
	MyOpen(Recent1,FALSE,TRUE);
	return 1;
}

int
MPMorphMenuRecent2(void) {
	MyOpen(Recent2,FALSE,TRUE);
	return 1;
}

int
MPMorphMenuRecent3(void) {
	MyOpen(Recent3,FALSE,TRUE);
	return 1;
}

int
MPMorphMenuRecent4(void) {
	MyOpen(Recent4,FALSE,TRUE);
	return 1;
}

int
MPMorphMenuRecent5(void) {
	MyOpen(Recent5,FALSE,TRUE);
	return 1;
}

/* Window closed, acts like quit	*/
int MPMorphCloseWindow(void) {
	// Suggest save - quit if required
  	if (!Saved) {
 		return !SaveRequester();
  	}
  	else {
  		return 0;
  	}
}

static void
ResetNormPrefs(struct Menu *Menu,int pos) {
	ULONG OZoom = Zoom;
	// Restore any changes
	CreateIcons = ((ItemAddress(Menu,FULLMENUNUM(pos,MM_ICONS,NOSUB)))->Flags & CHECKED);
	CreateIconsP = ((ItemAddress(Menu,FULLMENUNUM(pos,MM_ICONSP,NOSUB)))->Flags & CHECKED);
	Zoom = ((ItemAddress(Menu,FULLMENUNUM(pos,MM_ZOOM,NOSUB)))->Flags & CHECKED);
	GHelp = ((ItemAddress(Menu,FULLMENUNUM(pos,MM_HELP,NOSUB)))->Flags & CHECKED);
	KeepSettings = ((ItemAddress(Menu,FULLMENUNUM(pos,MM_KEEPS,NOSUB)))->Flags & CHECKED);
	UpdateParams(OZoom);
}

static void
SettingsHelp(UWORD code) {
	ULONG HNum=0;		// Help node
	// Display help
	switch (code) {
	case FULLMENUNUM(M_M_SETTINGS,NOITEM,NOSUB):
	case FULLMENUNUM(M_M_SETTINGS,MM_C1,NOSUB):
	case FULLMENUNUM(M_M_SETTINGS,MM_C2,NOSUB):
	case FULLMENUNUM(M_M_SETTINGS,MM_C4,NOSUB):
	case FULLMENUNUM(M_SETTINGS,NOITEM,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_C1,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_C2,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_C4,NOSUB):
		HNum = H_IMS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_ICONS,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_ICONS,NOSUB):
		HNum = H_P_CI;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_ZOOM,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB):
		HNum = H_P_ZO;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_SCREEN,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_SCREEN,NOSUB):
		HNum = H_P_PS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_CUSTOM,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_CUSTOM,NOSUB):
		HNum = H_PCUSTM;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_SPREVIEW,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_SPREVIEW,NOSUB):
		HNum = H_P_Preview;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_ICONSP,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_ICONSP,NOSUB):
		HNum = H_P_CIP;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_KEEPS,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_KEEPS,NOSUB):
		HNum = H_P_KS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_LOADS,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_LOADS,NOSUB):
		HNum = H_P_LOADS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_SAVES,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_SAVES,NOSUB):
		HNum = H_P_SAVES;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_SAVESAS,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_SAVESAS,NOSUB):
		HNum = H_P_SAVESAS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_RESETD,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_RESETD,NOSUB):
		HNum = H_S_RD;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_LASTS,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_LASTS,NOSUB):
		HNum = H_S_LS;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_RESTORE,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_RESTORE,NOSUB):
		HNum = H_S_R;
		break;
	case FULLMENUNUM(M_M_SETTINGS,MM_HELP,NOSUB):
	case FULLMENUNUM(M_SETTINGS,MM_HELP,NOSUB):
		HNum = H_P_HE;
		break;
	}
	help(HNum);
}

/* Help pressed on a menu in the info window	*/
int
MPMorphMenuHelp(void) {
	ULONG HNum;		// Help node
	ResetNormPrefs(MPMorphMenus,M_M_SETTINGS);
	// Determine help number from menu position
	if (MENUNUM(MPMorphMsg.Code) == M_M_SETTINGS) {
		SettingsHelp(MPMorphMsg.Code);
		return 1;
	}
	switch (MPMorphMsg.Code) {
	case FULLMENUNUM(M_M_PROJECT,NOITEM,NOSUB):
	case FULLMENUNUM(M_M_PROJECT,M_MM_B1,NOSUB):
	case FULLMENUNUM(M_M_PROJECT,M_MM_B2,NOSUB):
	case FULLMENUNUM(M_M_PROJECT,M_MM_B3,NOSUB):
	case FULLMENUNUM(M_M_PROJECT,M_MM_B4,NOSUB):
		HNum = H_IMP;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_NEW,NOSUB):
		HNum = H_IMPN;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_OPEN,NOSUB):
		HNum = H_IMPO;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,NOSUB):
		HNum = H_IMPR;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_SAVE,NOSUB):
		HNum = H_IMPS;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_SAVEAS,NOSUB):
		HNum = H_IMPSA;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_DELETE,NOSUB):
		HNum = H_IMPD;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_ABOUT,NOSUB):
		HNum = H_IMPA;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_QUIT,NOSUB):
		HNum = H_IMPQ;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_EDITPOINTS,NOSUB):
		HNum = H_IMPE;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT1):
		HNum = H_IMPR1;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT2):
		HNum = H_IMPR2;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT3):
		HNum = H_IMPR3;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT4):
		HNum = H_IMPR4;
		break;
	case FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT5):
		HNum = H_IMPR5;
		break;
	case FULLMENUNUM(M_M_USER,NOITEM,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_D1,NOSUB):
		HNum = H_IMU;
		break;
	case FULLMENUNUM(M_M_USER,MM_PREVIEW,NOSUB):
		HNum = H_IMUP;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER2,NOSUB):
		HNum = H_IMU2;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER3,NOSUB):
		HNum = H_IMU3;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER4,NOSUB):
		HNum = H_IMU4;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER5,NOSUB):
		HNum = H_IMU5;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER6,NOSUB):
		HNum = H_IMU6;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER7,NOSUB):
		HNum = H_IMU7;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER8,NOSUB):
		HNum = H_IMU8;
		break;
	case FULLMENUNUM(M_M_USER,MM_USER9,NOSUB):
		HNum = H_IMU9;
		break;
	case FULLMENUNUM(M_M_USER,MM_MACRO,NOSUB):
		HNum = H_IMUM;
		break;
	case FULLMENUNUM(M_M_USER,MM_STARTLEARN,NOSUB):
		HNum = H_IMUStart;
		break;
	case FULLMENUNUM(M_M_USER,MM_STOPLEARN,NOSUB):
		HNum = H_IMUStop;
		break;
	case MENUNULL:
	default:
		HNum = H_IM;
		break;
	}
	// Display help
	help(HNum);
	return 1;
}

/* Display help on a control or image window menu
 * Code	: menu code
 * Note: this is a virtual clone of the code above (with 1 changed to M_SETTINGS)
 */
void
DoMenuHelp(USHORT Code) {
	ULONG HNum;		// Help node
	UWORD MyMode=0;
	/* Update everything which could have been set
	 * using the menu
	 */
	ResetNormPrefs(MyMenu,M_SETTINGS);
	if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITONE)))->Flags & CHECKED) {
		MyMode = EDIT1;
	}
	else {
		if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITTWO)))->Flags & CHECKED) {
			MyMode = EDIT2;
		}
		else {
			if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITREL)))->Flags & CHECKED) {
				MyMode = EDITREL;
			}
			else {
				if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_ADD)))->Flags & CHECKED) {
					MyMode = ADD;
				}
				else {
					if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_DELETE)))->Flags & CHECKED) {
						MyMode = DELETE;
					}
					else {
						if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_LINK)))->Flags & CHECKED) {
							MyMode = LINK1;
						}
						else {
							if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_UNLINK)))->Flags & CHECKED) {
								MyMode = UNLINK1;
							}
							else {
								if ((ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_NONE)))->Flags & CHECKED) {
									MyMode = NONE;
								}
							}
						}
					}
				}
			}
		}
	}
	MySetMode(MyMode);
	// Determine help node
	if (MENUNUM(Code) == M_SETTINGS) {
		SettingsHelp(Code);
		return;
	}
	switch (Code) {
	case FULLMENUNUM(M_PROJECT,NOITEM,NOSUB):
	case FULLMENUNUM(M_PROJECT,MM_B1,NOSUB):
	case FULLMENUNUM(M_PROJECT,MM_B2,NOSUB):
	case FULLMENUNUM(M_PROJECT,MM_B3,NOSUB):
	case FULLMENUNUM(M_PROJECT,MM_B4,NOSUB):
		HNum = H_CMP;
		break;
	case FULLMENUNUM(M_PROJECT,MM_NEW,NOSUB):
		HNum = H_CMPN;
		break;
	case FULLMENUNUM(M_PROJECT,MM_OPEN,NOSUB):
		HNum = H_CMPO;
		break;
	case FULLMENUNUM(M_PROJECT,MM_SAVE,NOSUB):
		HNum = H_CMPS;
		break;
	case FULLMENUNUM(M_PROJECT,MM_SAVEAS,NOSUB):
		HNum = H_CMPSA;
		break;
	case FULLMENUNUM(M_PROJECT,MM_ABOUT,NOSUB):
		HNum = H_CMPA;
		break;
	case FULLMENUNUM(M_PROJECT,MM_EXITPOINTS,NOSUB):
		HNum = H_CMPE;
		break;
	case FULLMENUNUM(M_PROJECT,MM_QUIT,NOSUB):
		HNum = H_CMPQ;
		break;
	case FULLMENUNUM(M_EDIT,NOITEM,NOSUB):
		HNum = H_CME;
		break;
	case FULLMENUNUM(M_EDIT,MM_GRID,NOSUB):
		HNum = H_CMEG;
		break;
	case FULLMENUNUM(M_EDIT,MM_TRIANGULATE,NOSUB):
		HNum = H_CMET;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,NOSUB):
		HNum = H_CMEF;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,MI_FIRST):
		HNum = H_CMEFF;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,MI_PREV):
		HNum = H_CMEFP;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,MI_GOTO):
		HNum = H_CMEFG;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,MI_NEXT):
		HNum = H_CMEFN;
		break;
	case FULLMENUNUM(M_EDIT,MM_FRAME,MI_LAST):
		HNum = H_CMEFL;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,NOSUB):
		HNum = H_CMSM;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITONE):
		HNum = H_EOne;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITTWO):
		HNum = H_ETwo;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITREL):
		HNum = H_ERel;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_ADD):
		HNum = H_EAdd;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_DELETE):
		HNum = H_EDel;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_LINK):
		HNum = H_ELnk;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_UNLINK):
		HNum = H_EUnl;
		break;
	case FULLMENUNUM(M_EDIT,MM_MODE,MI_NONE):
		HNum = H_EMov;
		break;
	case FULLMENUNUM(M_USER,NOITEM,NOSUB):
	case FULLMENUNUM(M_USER,MM_D1,NOSUB):
		HNum = H_IMU;
		break;
	case FULLMENUNUM(M_USER,MM_PREVIEW,NOSUB):
		HNum = H_IMUP;
		break;
	case FULLMENUNUM(M_USER,MM_USER2,NOSUB):
		HNum = H_IMU2;
		break;
	case FULLMENUNUM(M_USER,MM_USER3,NOSUB):
		HNum = H_IMU3;
		break;
	case FULLMENUNUM(M_USER,MM_USER4,NOSUB):
		HNum = H_IMU4;
		break;
	case FULLMENUNUM(M_USER,MM_USER5,NOSUB):
		HNum = H_IMU5;
		break;
	case FULLMENUNUM(M_USER,MM_USER6,NOSUB):
		HNum = H_IMU6;
		break;
	case FULLMENUNUM(M_USER,MM_USER7,NOSUB):
		HNum = H_IMU7;
		break;
	case FULLMENUNUM(M_USER,MM_USER8,NOSUB):
		HNum = H_IMU8;
		break;
	case FULLMENUNUM(M_USER,MM_USER9,NOSUB):
		HNum = H_IMU9;
		break;
	case FULLMENUNUM(M_USER,MM_MACRO,NOSUB):
		HNum = H_IMUM;
		break;
	case FULLMENUNUM(M_USER,MM_STARTLEARN,NOSUB):
		HNum = H_IMUStart;
		break;
	case FULLMENUNUM(M_USER,MM_STOPLEARN,NOSUB):
		HNum = H_IMUStop;
		break;
	case MENUNULL:
	default:
		HNum = H_CM;
		break;
	}
	help(HNum);
}

/* String gadget clicked */
int
File241Clicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_24File1);
		ActivateGadget(MPMorphGadgets[GDX_File241],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETFILE241),(ULONG)GetString(MPMorphGadgets[GDX_File241]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int
File242Clicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_24File2);
		ActivateGadget(MPMorphGadgets[GDX_File242],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETFILE242),(ULONG)GetString(MPMorphGadgets[GDX_File242]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int
FramesClicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_Frames);
		ActivateGadget(MPMorphGadgets[GDX_Frames],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETFRAMES),(ULONG)GetNumber(MPMorphGadgets[GDX_Frames]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int
FileOneClicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_FileOne);
		ActivateGadget(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETFILE1),(ULONG)GetString(MPMorphGadgets[GDX_FileOne]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int FileTwoClicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_FileTwo);
		ActivateGadget(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETFILE2),(ULONG)GetString(MPMorphGadgets[GDX_FileTwo]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* CheckBox clicked */
int
SinglePictureClicked(void) {
	// Toggle BOOL
	SinglePicture = MPMorphMsg.Code;
	Record(MyGetMsg(MSG_SETSINGLE),SinglePicture);
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int
NameClicked(void) {
	// Only read when required	- display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_Name);
		ActivateGadget(MPMorphGadgets[GDX_Name],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETOUTPUT),(ULONG)GetString(MPMorphGadgets[GDX_Name]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* String gadget clicked */
int
StartClicked(void) {
	// Read when required - display help if help pressed
	if (MPMorphMsg.Code == 0x5F) {
		help(H_Start);
		ActivateGadget(MPMorphGadgets[GDX_Start],MPMorphWnd,NULL);
	}
	Record(MyGetMsg(MSG_SETSTART),(ULONG)GetNumber(MPMorphGadgets[GDX_Start]));
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	return 1;
}

/* Edit Points gadget clicked */
int
EditPointsClicked(void) {
	// Open window if not open
	MPMorphMenuEditPoints();
	return 1;
}

/* Set Si_ze gadget clicked */
int
SetSizeClicked(void) {
	struct MPGuiHandle *MPGuiHandle;
	char *res,*s;
	int x,y;
	char *params[3];
	char param1[6];
	char param2[6];
	struct Hook Hook = {
		0
	};
	
	DisableWindows(DI_SetSize);
	sprintf(param1,MyGetMsg(MSG_LD),Width);
	sprintf(param2,MyGetMsg(MSG_LD),Height);
	params[0] = param1;
	params[1] = param2;
	params[2] = NULL;
	Hook.h_Entry = (HOOKFUNC)HelpHook;

	if (MPGuiHandle = AllocMPGuiHandle(MPG_RELMOUSE,TRUE,
												MPG_PUBSCREENNAME,(ULONG)PubScreenName,
												MPG_HELP,(ULONG)&Hook,
												MPG_CHELP,GHelp,
												MPG_PARAMS,(ULONG)params,
												TAG_END)) {
		res = SyncMPGuiRequest(MyGetMsg(MSG_SIZEGUI),MPGuiHandle);
		if (res) {
			if (res == (char *)-1) {
				Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MPGuiError(MPGuiHandle),HE_MPG);
			}
			else {
				s = res;
				x = atoi(s);
				while (*s && (*s != ' ')) {
					s++;
				}
				y = atoi(s);
				ReallySetSize(x,y);
			}
		}
	}
	else {
		Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MyGetMsg(MSG_OUTOFMEM),HE_MPG);
	}
	EnableWindows();
	return 1;
}

BOOL
ReallySetSize(int x,int y) {
	struct MyPoint *MyPoint,*MyPoint1 = NULL;
	if ((x>0) && (y>0)) {
		if (!Width || !Height) {
			Width = x;
			Height = y;
		}
		else {
		  	if (!Saved) {
				if (!SaveRequester()) {
					return FALSE;
				}
			}
			Record(MyGetMsg(MSG_SETSIZE),(ULONG)x,(ULONG)y);
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
			if (Pic1_Open) {
				DrawAllPoints();
			}
			// For each point
			for (MyPoint = (struct MyPoint *)PointList.lh_Head;
								  MyPoint->MyNode.mln_Succ;
								  MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
				if (MyPoint1) {
					DeletePoint(MyPoint1);
					MyPoint1 = NULL;
				}
				if ((MyPoint->x > (x-1)) ||
					 (MyPoint->x1 > (x-1)) ||
					 (MyPoint->y > (y-1)) ||
					 (MyPoint->y1 > (y-1))) {
					MyPoint1 = MyPoint;	// Delete next time round to prevent looking at freed memory
				}
			}
			if (MyPoint1) {
				DeletePoint(MyPoint1);
			}
			Width = x;
			Height = y;
			if (Pic1_Open) {
		      xfact = (float)(Width-1) / (Pic1.MPi->Width-1);
				yfact = (float)(Height-1) / (Pic1.MPi->Height-1);
				DrawAllPoints();
			}
		}
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_Width],MPMorphWnd,NULL,
								GTNM_Number,Width, TAG_END );
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_Height],MPMorphWnd,NULL,
								GTNM_Number,Height, TAG_END );
	}
	return TRUE;
}

/* _Scale gadget clicked */
int
ScaleClicked(void) {
	struct MPGuiHandle *MPGuiHandle;
	char *res,*s;
	int x,y;
	char *params[3];
	char param1[6];
	char param2[6];
	struct Hook Hook = {
		0
	};
	
	DisableWindows(DI_Scale);
	sprintf(param1,MyGetMsg(MSG_LD),Width);
	sprintf(param2,MyGetMsg(MSG_LD),Height);
	params[0] = param1;
	params[1] = param2;
	params[2] = NULL;
	Hook.h_Entry = (HOOKFUNC)HelpHook;

	if (MPGuiHandle = AllocMPGuiHandle(MPG_RELMOUSE,TRUE,
												MPG_PUBSCREENNAME,(ULONG)PubScreenName,
												MPG_HELP,(ULONG)&Hook,
												MPG_CHELP,GHelp,
												MPG_PARAMS,(ULONG)params,
												TAG_END)) {
		res = SyncMPGuiRequest(MyGetMsg(MSG_SCALEGUI),MPGuiHandle);
		if (res) {
			if (res == (char *)-1) {
				Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MPGuiError(MPGuiHandle),HE_MPG);
			}
			else {
				s = res;
				x = atoi(s);
				while (*s && (*s != ' ')) {
					s++;
				}
				y = atoi(s);
				ReallyScale(x,y);
			}
		}
	}
	else {
		Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MyGetMsg(MSG_OUTOFMEM),HE_MPG);
	}
	EnableWindows();
	return 1;
}

BOOL
ReallyScale(int x,int y) {
	float xf,yf;
	struct MyPoint *MyPoint;
	if ((x>0) && (y>0)) {
		if (!Width || !Height) {
			Width = x;
			Height = y;
		}
		else {
		  	if (!Saved) {
				if (!SaveRequester()) {
					return FALSE;
				}
			}
			Record(MyGetMsg(MSG_SETSCALE),(ULONG)x,(ULONG)y);
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
			xf = (float)(x-1)/(float)(Width-1);
			yf = (float)(y-1)/(float)(Height-1);
			if (Pic1_Open) {
				DrawAllPoints();
			}
			// For each point
			for (MyPoint = (struct MyPoint *)PointList.lh_Head;
								  MyPoint->MyNode.mln_Succ;
								  MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
				MyPoint->x *= xf;
				MyPoint->x1 *= xf;
				MyPoint->y *= yf;
				MyPoint->y1 *= yf;
			}
			Width = x;
			Height = y;
			if (Pic1_Open) {
		      xfact = (float)(Width-1) / (Pic1.MPi->Width-1);
				yfact = (float)(Height-1) / (Pic1.MPi->Height-1);
				DrawAllPoints();
			}
		}
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_Width],MPMorphWnd,NULL,
								GTNM_Number,Width, TAG_END );
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_Height],MPMorphWnd,NULL,
								GTNM_Number,Height, TAG_END );
	}
	return TRUE;
}

/* Open the Control and Image Windows	*/
void
OpenPointsEdit(void) {
	char buffer[257];
	BOOL ok=TRUE;
	// Open Control window, Pic1 and Pic2
	if ((SinglePicture == 2) || (SinglePicture == 3)) {	// Anim so need frame number
		ok = GetFrameNumber();
	}
	if (ok) {
		if (ControlWindow = OpenControlWindow()) {			// note multiple calls to DisableWindows()
			DisableWindows(DI_Image1);								// are safe, required to disable just opened window
			Pic1_Open = openAPicture(GetString(MPMorphGadgets[GDX_FileOne]),&Pic1,TRUE);
			if (Pic1_Open) {
				DisableWindows(DI_Image2);
		  		Pic2_Open = openAPicture(GetString(MPMorphGadgets[GDX_FileTwo]),&Pic2,TRUE);
				if (Pic2_Open) {
	 				// validate image sizes	??? following is done in openAPicture - should not be here as well
			 	  	if ((Pic1.MPi->Width != Pic2.MPi->Width) ||
		  	 			 (Pic1.MPi->Height != Pic2.MPi->Height)) {
		 				DisableWindows(DI_Scale2);
						if (!RescaleMPImage(Pic2.MPi,Pic1.MPi->Width,Pic1.MPi->Height)) {
				  	 		Error(MyGetMsg(MSG_MPIMAGESCALE),MyGetMsg(MSG_OK),MPImageErrorMessage(),HE_MPIScale);
							CloseAPicture(&Pic2);
		  					Pic2_Open = FALSE;
							CloseAPicture(&Pic1);
		  					Pic1_Open = FALSE;
		  				}
			  	  	}
			  	  	if (Pic2_Open) {
		 				DisableWindows(DI_Draw);
			  	  		// if we have changed from non anim to anim then we may still have
			  	  		// points in memory - so draw, otherwise try and load points file
						if ((!(((struct MyPoint *)PointList.lh_Head)->MyNode.mln_Succ)) &&
							((SinglePicture == 2) || (SinglePicture == 3))) {
							strcpy(TempFilename,savedfilename);
							strcat(TempFilename,MyGetMsg(MSG_03LD));
							sprintf(buffer,TempFilename,FrameNumber);
							MyOpen(buffer,TRUE,FALSE);
						}
						else {
							DrawAllPoints();
						}
			  	  		// disable some menus, generally set up and activate things
						SetMyPointer();
						EnableWindows();
						OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_NEW,NOSUB));
						OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_OPEN,NOSUB));
						ActivateWindow(ControlWindow);
						return;
					}
				}
				// Tidy up and close down cleanly
				else {
					CloseAPicture(&Pic1);
	  				Pic1_Open = FALSE;
				}
			}
			CloseControlWindow();
		}
		EnableWindows();
	}
}

/* Display ASL requesters	*/
int
GetFile1Clicked(void) {
	if (GetAFile(GetString(MPMorphGadgets[GDX_File241]),MyGetMsg(MSG_GET241),0,NULL,MyGetMsg(MSG_SELECT))) {
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_File241],MPMorphWnd,NULL,
								GTST_String, TempFilename, TAG_END );
		Saved = FALSE;
		CurrentTime(&USecs,&Um);
		Record(MyGetMsg(MSG_SETFILE241),(ULONG)TempFilename);
	}
	return 1;
}

/* Display ASL requesters	*/
int
GetFile2Clicked(void) {
	if (GetAFile(GetString(MPMorphGadgets[GDX_File242]),MyGetMsg(MSG_GET242),0,NULL,MyGetMsg(MSG_SELECT))) {
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_File242],MPMorphWnd,NULL,
								GTST_String, TempFilename, TAG_END );
		Saved = FALSE;
		CurrentTime(&USecs,&Um);
		Record(MyGetMsg(MSG_SETFILE242),(ULONG)TempFilename);
	}
	return 1;
}

/* Display ASL requesters	*/
int
GetFileOneClicked(void) {
	if (!ControlWindow) {
		if (GetAFile(GetString(MPMorphGadgets[GDX_FileOne]),MyGetMsg(MSG_PIC1),0,NULL,MyGetMsg(MSG_SELECT))) {
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL,
									GTST_String, TempFilename, TAG_END );
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
			Record(MyGetMsg(MSG_SETFILE1),(ULONG)TempFilename);
		}
	}
	return 1;
}

/* Display ASL requesters	*/
int
GetFileTwoClicked(void) {
	if (!ControlWindow) {
		if (GetAFile(GetString(MPMorphGadgets[GDX_FileTwo]),MyGetMsg(MSG_PIC2),0,NULL,MyGetMsg(MSG_SELECT))) {
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL,
									GTST_String, TempFilename, TAG_END );
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
			Record(MyGetMsg(MSG_SETFILE2),(ULONG)TempFilename);
		}
	}
	return 1;
}

/* Display ASL requesters	*/
int
GetSaveNameClicked(void) {
	if (GetAFile(GetString(MPMorphGadgets[GDX_Name]),MyGetMsg(MSG_MFILEN),0,NULL,MyGetMsg(MSG_SELECT))) {
		GT_SetGadgetAttrs(MPMorphGadgets[GDX_Name],MPMorphWnd,NULL,
								GTST_String, TempFilename, TAG_END );
		Saved = FALSE;
		CurrentTime(&USecs,&Um);
		Record(MyGetMsg(MSG_SETOUTPUT),(ULONG)TempFilename);
	}
	return 1;
}

/* Displays requester to add a grid of points */
void
AddGrid(void) {
	struct MPGuiHandle *MPGuiHandle;
	char *res,*s;
	int x,y;
	struct Hook Hook = {
		0
	};
	
	DisableWindows(DI_Grid);
	Hook.h_Entry = (HOOKFUNC)HelpHook;

	if (MPGuiHandle = AllocMPGuiHandle(MPG_RELMOUSE,TRUE,
												MPG_PUBSCREENNAME,(ULONG)PubScreenName,
												MPG_HELP,(ULONG)&Hook,
												MPG_CHELP,GHelp,
												TAG_END)) {
		res = SyncMPGuiRequest(MyGetMsg(MSG_GRIDGUI),MPGuiHandle);
		if (res) {
			if (res == (char *)-1) {
				Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MPGuiError(MPGuiHandle),HE_MPG);
			}
			else {
				s = res;
				x = atoi(s);
				while (*s && (*s != ' ')) {
					s++;
				}
				y = atoi(s);
				ReallyAddGrid(x,y);
			}
		}
	}
	else {
		Error(MyGetMsg(MSG_MPG),MyGetMsg(MSG_OK),MyGetMsg(MSG_OUTOFMEM),HE_MPG);
	}
	EnableWindows();
}

/* Actually add the grid of points	*/
BOOL
ReallyAddGrid(int xgrid, int ygrid) {
	UWORD x;			// X coord
	UWORD y;			// Y coord
	BOOL ok = TRUE;// Is it working?
	struct MyPoint **MyPointp;	// Point Pointer
	struct MyPoint *MyPoint;	// Point

	if (xgrid && ygrid) {
	  	if (!Saved) {
			if (!SaveRequester()) {
				return FALSE;
			}
		}
		Saved = FALSE;
		CurrentTime(&USecs,&Um);
		Record(MyGetMsg(MSG_SETADDGRID),(ULONG)xgrid,(ULONG)ygrid);
		/* Allocate Pointer to points memory
		 * We need an array but cannot allocate all points
		 * as one block of memory as a single point can be deleted
		 */
		if (MyPointp = AllocMem(sizeof(struct MyPoint *)*((xgrid+1)*(ygrid+1)),MEMF_CLEAR)) {
			// Create and draw all points
			for (x = 0;
					ok && (x <= xgrid);
					++x) {
				for (y = 0;
						ok  && (y <= ygrid);
						++y) {
					if (MyPoint = MyPointp[x*(xgrid+1)+y] = AllocMem(sizeof(struct MyPoint),MEMF_CLEAR)) {
						MyPoint->x = (x * (Width-1))/xgrid;
						MyPoint->y = (y * (Height-1))/ygrid;
						MyPoint->x1 = MyPoint->x;
						MyPoint->y1 = MyPoint->y;
						AddTail(&PointList,(struct Node *)MyPoint);
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
					}
					else {
						ok = FALSE;
					}
				}
			}
			if (ok) {
				// Link all points - link top left to bottom right
				for (x = 0;
						x <= xgrid;
						++x) {
					for (y = 0;
							y <= ygrid;
							++y) {
						if (x < xgrid) {
							LinkPoints(MyPointp[x*(xgrid+1)+y],MyPointp[(x+1)*(xgrid+1)+y]);
						}
						if (y < ygrid) {
							LinkPoints(MyPointp[x*(xgrid+1)+y],MyPointp[x*(xgrid+1)+y+1]);
						}
					}
				}
			}
			// Free the Points pointers
			FreeMem(MyPointp,sizeof(struct MyPoint *)*((xgrid+1)*(ygrid+1)));
		}
		else {
			ok = FALSE;
		}
	}
	else {
		Error(MyGetMsg(MSG_BOTHGT0),MyGetMsg(MSG_OK),NULL,HE_Grid0);
		return FALSE;
	}
	if (!ok) {
		Error(MyGetMsg(MSG_OUTMP),MyGetMsg(MSG_OK),NULL,HE_MPoints);
		return FALSE;
	}
	return TRUE;
}


/* If project not saved then
 * display requester and then
 * save if required
 * Returns:	TRUE keep going
 */
BOOL
SaveRequester(void) {
	struct EasyStruct EasyStruct = {
		sizeof(struct EasyStruct),
		0,
		NULL,
		NULL,
		NULL
	};
	UBYTE *title = MyGetMsg(MSG_MPM);
	UBYTE *body;
	UBYTE *gadget;
	struct Window *req;
	LONG gad = -1;
	ULONG ret = 2;
	ULONG signals=0;
	struct rtHandlerInfo *rth;
	struct AmigaGuideMsg *agm;
	BOOL ret1=FALSE;
	char *other = &(savedfilename[0]);
	// Disable the windows and display the requester - using reqtools if available
	DisableWindows(DI_Unsaved);
	if (GHelp) {
		help(H_Unsaved);
	}
	body = MyGetMsg(MSG_UNSAVED);
	if (ReqToolsBase) {
		// set up gadgets depending on availability of amigaguide
		if (handle) {
			gadget = MyGetMsg(MSG__SHAC);
		}
		else {
			gadget = MyGetMsg(MSG__SAC);
		}
		// Loop until Save,Abandon or Cancel pressed
		while (((ret == 2) && handle) || (gad == -1)) {
			ret = CALL_HANDLER;
			if (rtEZRequestTags(body,gadget,NULL,&other,
										RT_ReqHandler, &rth,
										RT_Window, MPMorphWnd,
										RT_Underscore, '_',
										RTEZ_ReqTitle, title,
										TAG_END) == CALL_HANDLER) {
				while (ret == CALL_HANDLER) {
					if (!rth->DoNotWait) {
						signals = Wait(rth->WaitMask | ASig);
					}
					ret = rtReqHandlerA(rth,signals,NULL);
					if ((ret == 2) && handle) {
						help(H_Unsaved);
					}
					if (signals & ASig) {
					  	while (agm = GetAmigaGuideMsg(handle)) {
				 			ReplyAmigaGuideMsg(agm);
				 		}
				 	}
				}
			}
			else {
				ret = 0;
			}
			gad = ret;
		}
	}
	else {
		EasyStruct.es_TextFormat = body;
		EasyStruct.es_Title = title;
		// set up gadgets depending on availability of amigaguide
		if (handle) {
			EasyStruct.es_GadgetFormat = MyGetMsg(MSG_SHAC);
		}
		else {
			EasyStruct.es_GadgetFormat = MyGetMsg(MSG_SAC);
		}
		req = BuildEasyRequest(MPMorphWnd,&EasyStruct,NULL,savedfilename);
		// Loop until Save,Abandon or Cancel pressed
		while ((((gad = SysReqHandler(req,NULL,TRUE)) == 2) && handle) ||
				 (gad == -1)) {
			if (handle) {
				help(H_Unsaved);
			}
		}
		FreeSysRequest(req);
	}
	switch(gad) {
	case 1:
		if (*savedfilename) {
			ret1 = SaveAs(savedfilename);
		}
		else {
			ret1 = SaveAs(NULL);
		}
		break;
	case 2:
	case 3:				// 2 if no help, 3 otherwise
		ret1 = TRUE;
		break;
	case 0:
		ret1 = FALSE;
		break;
	}
	EnableWindows();
	return ret1;
}

/* Link two points
 * Drawing in the windows if open
 * Does not link already linked points
 */
void
LinkPoints(struct MyPoint* MyPoint,struct MyPoint *MyPoint1) {
	int i,j=0,j1=0;
	BOOL Ok = TRUE;
	// Link in first free position
	if ((MyPoint->NumLinks < MAX_LINKS) &&
		 (MyPoint1->NumLinks < MAX_LINKS)) {
		for (i = 0;
			  i < MAX_LINKS;
			  i++) {
			if (MyPoint->p[i] == MyPoint1) {
				Ok = FALSE;
			}
			if ((!MyPoint->p[i]) && (!j)) {
				j = i;
			}
		}
		for (i = 0;
			  (i < MAX_LINKS) && !j1;
			  i++) {
			if ((!MyPoint1->p[i]) && (!j1)) {
				j1 = i;
			}
		}
		if (Ok) {
			MyPoint->NumLinks++;
			MyPoint1->NumLinks++;
			MyPoint->p[j] = MyPoint1;
			MyPoint1->p[j1] = MyPoint;
			// If windows open then draw points and lines
			if (EGS) {
				if (Pic1_Open) {
					EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint1->x,MyPoint1->y,MyPoint->x,MyPoint->y);
				}
				if (Pic2_Open) {
					EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint1->x1,MyPoint1->y1,MyPoint->x1,MyPoint->y1);
				}
			}
			else {
				if (Pic1_Open) {
					MyDraw(Pic1.Win->RPort,MyPoint1->x<<Zoom,MyPoint1->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
				}
				if (Pic2_Open) {
					MyDraw(Pic2.Win->RPort,MyPoint1->x1<<Zoom,MyPoint1->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
				}
			}
		}
	}
}

/* Unlink two points
 * Drawing on the screen if required
 */
void
UnlinkPoints(struct MyPoint* MyPoint,struct MyPoint *MyPoint1,BOOL MYDraw) {
	int i;
	// Erase lines if required
	if (MYDraw) {
		if (EGS) {
			EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint1->x,MyPoint1->y,MyPoint->x,MyPoint->y);
			EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint1->x1,MyPoint1->y1,MyPoint->x1,MyPoint->y1);
		}
		else {
			MyDraw(Pic1.Win->RPort,MyPoint1->x<<Zoom,MyPoint1->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
			MyDraw(Pic2.Win->RPort,MyPoint1->x1<<Zoom,MyPoint1->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
		}
	}
	// Unlink each way
	for (i = 0;
		  i < MAX_LINKS;
		  i++) {
		if (MyPoint->p[i] == MyPoint1) {
			MyPoint->p[i] = NULL;
			MyPoint->NumLinks--;
		}
	}
	for (i = 0;
		  i < MAX_LINKS;
		  i++) {
		if (MyPoint1->p[i] == MyPoint) {
			MyPoint1->p[i] = NULL;
			MyPoint1->NumLinks--;
		}
	}
}

/* Unlink all points
 * Erasing lines if images are open
 */
void
UnlinkAllPoints(BOOL Draw) {
	int i;
	struct MyPoint *MyPoint;
	/* Loop round looking at the first point every time
	 * since DeletePoint removes it from the list
	 */
	for (MyPoint = (struct MyPoint *)PointList.lh_Head;
			MyPoint->MyNode.mln_Succ;
			MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
		for (i = 0;
			  i < MAX_LINKS;
			  i++) {
			if (MyPoint->p[i]) {
				UnlinkPoints(MyPoint,MyPoint->p[i],Draw);
			}
		}
	}
}

/* Find a point in an image given
 * x and y coordinates
 * Returns	: NULL if none closeby
 */
struct MyPoint *
FindPoint(struct Picture *pic,WORD x,WORD y) {
	struct MyPoint *MyPoint;			// Point to look at
	LONG diff = 36;						// Must be closer than sqrt(36) pixels
	LONG diff1;								// sqr(distance apart) for current point
	struct MyPoint *RetPoint = NULL;	// Point being returned
	// adjust coords for zoom and scroll
	x+=(pic->Left>>Zoom);
	x *= xfact;
	y+=(pic->Top>>Zoom);
	y *= yfact;
	// Step thru all points and find closest
	for (MyPoint = (struct MyPoint *)PointList.lh_Head;
			MyPoint->MyNode.mln_Succ;
			MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
		if (pic == &Pic1) {
			diff1 = ((MyPoint->x-x)*(MyPoint->x-x)+
						(MyPoint->y-y)*(MyPoint->y-y));
		}
		else {
			diff1 = ((MyPoint->x1-x)*(MyPoint->x1-x)+
						(MyPoint->y1-y)*(MyPoint->y1-y));
		}
  		if (diff1<diff) {
  			diff = diff1;
  			RetPoint = MyPoint;
  		}
	}
	return RetPoint;
}

/* Delete a point
 * removing all links
 */
void
DeletePoint(struct MyPoint *MyPoint){
	int i;
	// Unlink any links
	for (i = 0;
		  i < MAX_LINKS;
		  i++) {
		if (MyPoint->p[i]) {
			UnlinkPoints(MyPoint,MyPoint->p[i],FALSE);
		}
	}
	// remove from list and free memory
	Remove((struct Node *)MyPoint);
	FreeMem(MyPoint,sizeof(struct MyPoint));
}

/* Similar to Draw() but always draws top left to bottom right
 * to prevent stray pixels if erasing by drawing in the other direction
 */
void
MyDraw(struct RastPort *rp, LONG x, LONG y, LONG oldx, LONG oldy) {
	if ((oldx < x) || ((oldx == x) && (oldy < y))) {
		Move(rp,(LONG)((oldx + 0.5)/xfact),(LONG)((oldy + 0.5)/yfact));
		Draw(rp,(LONG)((x + 0.5)/xfact),(LONG)((y + 0.5)/yfact));
	}
	else {
		Move(rp,(LONG)((x + 0.5)/xfact),(LONG)((y + 0.5)/yfact));
		Draw(rp,(LONG)((oldx + 0.5)/xfact),(LONG)((oldy + 0.5)/yfact));
	}
}

/* Shows ASL file requester for a file
 * name	: current file name
 * Prompt: Title
 * flags	: e.g. for save flag
 * Returns: TRUE if file selected, name is TempFileName
 */
BOOL
GetAFile(char *name,char *Prompt,ULONG flags, UBYTE *Pattern,char *positive) {
	char pat[80];

	if (Pattern) {
		ParsePatternNoCase(Pattern,pat,79);
	}
	// Split of directory name
	strncpy(TempFilename,name,PathPart(name) - name);
	TempFilename[PathPart(name) - name] = 0;
	// Show requesters
	if (	AslRequestTags((APTR) filereq,
							ASLFR_TitleText,(Tag) Prompt,
							ASLFR_Flags1,flags,
							ASLFR_InitialDrawer, (Tag) TempFilename,
							ASLFR_InitialFile,(Tag) FilePart(name),
							ASLFR_Window, MPMorphWnd,
							Pattern ? ASLFR_AcceptPattern : TAG_IGNORE, (Tag)pat,
							ASLFR_RejectIcons, TRUE,
							ASLFR_PositiveText, positive,
							TAG_DONE)) {
		// rejoin name
		strncpy(TempFilename,filereq->fr_Drawer,256);
		AddPart(TempFilename,filereq->fr_File,256);
		return TRUE;
	}
	else {
		return FALSE;
	}
}

/* New selected on the Info window */
int
MPMorphMenuNew(void) {
	// Suggest save if unsaved
	if (!Saved) {
		if (!SaveRequester()) {
			return 1;
		}
		DisableWindows(DI_New);
	}
	Record(MyGetMsg(MSG_SETCLEAR),NULL);
	// Reset everything
	Saved = TRUE;
	savedfilename[0]=0;
	DeleteAllPoints();
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL,
							GTST_String, "", TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL,
							GTST_String, "", TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_File241],MPMorphWnd,NULL,
							GTST_String, "", TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_File242],MPMorphWnd,NULL,
							GTST_String, "", TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Name],MPMorphWnd,NULL,
							GTST_String, "", TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Frames],MPMorphWnd,NULL,
							GTIN_Number,1, TAG_END );
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Start],MPMorphWnd,NULL,
							GTIN_Number,1, TAG_END );
	SinglePicture = 0;
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_SinglePicture],MPMorphWnd,NULL,
							GTCY_Active,SinglePicture, TAG_END );
	Width = 0;
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Width],MPMorphWnd,NULL,
							GTNM_Number,Width, TAG_END );
	Height = 0;
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Height],MPMorphWnd,NULL,
							GTNM_Number,Height, TAG_END );
	MaxWidth = 0;
	MaxHeight = 0;
	EnableWindows();
	return 1;
}

/* Limit the coordinates of a point to the image size */
void
LimitPoints(LONG *x,LONG *y,struct Picture *pic) {
	if (*x < 0)
		*x = 0;
	if (*x > Width-1)
		*x = Width-1;
	if (*y < 0)
		*y = 0;
	if (*y > Height-1)
		*y = Height-1;
}

static BOOL realfirstcall = TRUE;	// Is this really the first call
												// not sure I understand this!
												// but some parameters (e.g. Public screen) must
												// only be set on the very first call
// Initialise all settings values from parameters etc.
void
InitParams(BOOL firstcall) {
	ULONG OZoom = Zoom;
	if (realfirstcall) {
		PubScreenName 	= MyArgString(MyGetMsg(MSG_PSCREEN),NULL,!firstcall);
		if (!*PubScreenName) {
			PubScreenName = NULL;
		}
		strcpy(PreviewScript,MyArgString(MyGetMsg(MSG_PREVIEW),PreviewScript,!firstcall));
		strcpy(Recent1,MyArgString(MyGetMsg(MSG_RECENT1),Recent1,!firstcall));
		strcpy(Recent2,MyArgString(MyGetMsg(MSG_RECENT2),Recent2,!firstcall));
		strcpy(Recent3,MyArgString(MyGetMsg(MSG_RECENT3),Recent3,!firstcall));
		strcpy(Recent4,MyArgString(MyGetMsg(MSG_RECENT4),Recent4,!firstcall));
		strcpy(Recent5,MyArgString(MyGetMsg(MSG_RECENT5),Recent5,!firstcall));
		strcpy(User2,MyArgString(MyGetMsg(MSG_USER2),User2,!firstcall));
		strcpy(User3,MyArgString(MyGetMsg(MSG_USER3),User3,!firstcall));
		strcpy(User4,MyArgString(MyGetMsg(MSG_USER4),User4,!firstcall));
		strcpy(User5,MyArgString(MyGetMsg(MSG_USER5),User5,!firstcall));
		strcpy(User6,MyArgString(MyGetMsg(MSG_USER6),User6,!firstcall));
		strcpy(User7,MyArgString(MyGetMsg(MSG_USER7),User7,!firstcall));
		strcpy(User8,MyArgString(MyGetMsg(MSG_USER8),User8,!firstcall));
		strcpy(User9,MyArgString(MyGetMsg(MSG_USER9),User9,!firstcall));
	}
	if (realfirstcall || !ControlWindow) {
		ZoomAllowed 	= !MatchToolValue(MyArgString(MyGetMsg(MSG_ZOOM),ZoomAllowed?MyGetMsg(MSG_NO):MyGetMsg(MSG_OFF),!firstcall),MyGetMsg(MSG_OFF));
	}
	realfirstcall = FALSE;
	strcpy(ScreenName,MyArgString(MyGetMsg(MSG_PSCREEN),ScreenName,!firstcall));
	strcpy(CustomName,MyArgString(MyGetMsg(MSG_CMODE),CustomName,!firstcall));
	CustomDepth = MyArgInt(MyGetMsg(MSG_CDEPTH),CustomDepth,!firstcall);
	CreateIcons 	= MatchToolValue(MyArgString(MyGetMsg(MSG_CICONS),CreateIcons?MyGetMsg(MSG_YES):MyGetMsg(MSG_NO),!firstcall),MyGetMsg(MSG_YES));
	CreateIconsP 	= MatchToolValue(MyArgString(MyGetMsg(MSG_CICONSP),CreateIconsP?MyGetMsg(MSG_YES):MyGetMsg(MSG_NO),!firstcall),MyGetMsg(MSG_YES));
	KeepSettings   = MatchToolValue(MyArgString(MyGetMsg(MSG_KEEPS),KeepSettings?MyGetMsg(MSG_YES):MyGetMsg(MSG_NO),!firstcall),MyGetMsg(MSG_YES));
	if (ZoomAllowed) {
		Zoom = (MatchToolValue(MyArgString(MyGetMsg(MSG_ZOOM),Zoom?MyGetMsg(MSG_YES):MyGetMsg(MSG_NO),!firstcall),MyGetMsg(MSG_YES)) ? 1 : 0);	// Note: not a BOOL
	}
	else {
		Zoom = FALSE;
	}
	GHelp = MatchToolValue(MyArgString(MyGetMsg(MSG_HELP),GHelp?MyGetMsg(MSG_YES):MyGetMsg(MSG_NO),!firstcall),MyGetMsg(MSG_YES));
	// Update with the new parameters
	UpdateParams(OZoom);
}

// Update to new settings - OZoom is old zoom mode
void
UpdateParams(ULONG OZoom) {
	// remove all the menus
	RemoveMenus();
	// change all the menu items
	if (ZoomAllowed && (Zoom != OZoom)) {
		// If windows are open and changing zoom then update the zoom
		if (ControlWindow) {
			DisableWindows(DI_Zoom);
			if (OZoom) {
				UnZoom();
			}
			else {
				ReZoom();
			}
			EnableWindows();
		}
		SwitchMenuItem(MM_ZOOM,Zoom,FALSE);
	}
	SwitchMenuItem(MM_ICONSP,CreateIconsP,FALSE);
	SwitchMenuItem(MM_KEEPS,KeepSettings,FALSE);
	SwitchMenuItem(MM_HELP,GHelp,FALSE);
	// Add the menus back
	AddMenus();
	// and disable/enable items
	if (ZoomAllowed) {
		if (MPMorphWnd) {
			OnMenu(MPMorphWnd,FULLMENUNUM(M_M_SETTINGS,MM_ZOOM,NOSUB));
		}
		if (ControlWindow) {
			OnMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB));
		}
	}
	else {
		if (MPMorphWnd) {
			OffMenu(MPMorphWnd,FULLMENUNUM(M_M_SETTINGS,MM_ZOOM,NOSUB));
		}
		if (ControlWindow) {
			OffMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB));
		}
	}
}

/* Preview render
 * Basically calls ARexx script with parameters - filename
 */
int
Preview(void) {
	DisableWindows(DI_Preview);		// disable all windows
	SendRexxCommand(myhost,PreviewScript,NULL);
	EnableWindows();						// and re-enable windows
	return 1;
}

static UBYTE newcol[24][3] = {
	0,255,0,		//   0
	255,0,0,		//   1
	0,0,255,		//   2
	255,255,0,	//   3
	0,255,255,	//   4
	255,0,255,	//   5
	0,136,0,		//   6
	136,0,0,		//   7
	0,0,136,		//   8
	136,136,0,	//   9
	0,136,136,	//  10
	136,0,136,	//  11
	0,68,0,		//  12
	68,0,0,		//  13
	0,0,68,		//  14
	68,68,0,		//  15
	0,68,68,		//  16
	68,0,68,		//  17
	0,204,0,		//  18
	204,0,0,		//  19
	0,0,204,		//  20
	204,204,0,	//  21
	0,204,204,	//  22
	204,0,204,	//  23
};

static UBYTE curcol[256][3];

static BOOL used[256];	// table of in use palette entry
								// we use the rest for grey scale

static BOOL Bit12;

// Check a colour is not already almost in the pallete
static void
CheckCol(ULONG *color32) {
	int i;
	int j;
	BOOL changed = TRUE;
	ULONG t;
	int diff,temp;
	for (j = 0;
		  (j < 256) && changed;
		  ++j) {
		changed = FALSE;
		if (!Bit12) {
			t = (*color32)>>24;
		}
		else {
			t = (*color32)>>28;
		}
		for (i = 0;
			  (i < 256) && !changed;
			  ++i) {
			if (used[i]) {
				temp = (int)t-(int)curcol[i][0];
				diff = temp*temp;
				temp = (int)t-(int)curcol[i][1];
				diff += temp*temp;
				temp = (int)t-(int)curcol[i][2];
				diff += temp*temp;
				if (diff < 3) {
					changed = TRUE;
					if (Bit12) {
						*color32 += 0x10000000;
					}
					else {
						*color32 += 0x01000000;
					}
				}
			}
		}
	}
}

/* Opens a custom screen
 * Public Screen name is ScreenName
 * Mode name is CustomName
 * Depth is CustomDepth
 * Most other stuff is cloned from the WorkBench
 *
 * This whole thing needs redoing a bit
 */
BOOL
OpenCustomScreen(void) {
	struct Screen *Screen;
	struct NameInfo buff;
	ULONG id = (ULONG)INVALID_ID;
	ULONG myid = (ULONG)INVALID_ID;
	UWORD numcols;
	UWORD i,j;
	ULONG diff;
	ULONG Color32;
	BOOL usedri = TRUE;
	struct DrawInfo *dri;
	struct DrawInfo *mydri;
	BOOL retflag = TRUE;
	char *emsg="";
	char *e1=NULL;
	ULONG err=0;
	UWORD d2;
	struct DisplayInfo di;
	ULONG rgb[3];

	// check we have a name and a mode and depth
	if (ScreenName && *ScreenName && CustomName && *CustomName && (CustomDepth > 0)) {
		// check public screen not already open
		if (!(Screen = LockPubScreen(ScreenName))) {
			// try and find modeid
			id = NextDisplayInfo(id);
			while ((id != INVALID_ID) && (myid == INVALID_ID)) {
				if (GetDisplayInfoData(NULL,(UBYTE *)&buff,sizeof(struct NameInfo),DTAG_NAME,id)) {
					if (!Stricmp(buff.Name,CustomName)) {
						myid = id;
					}
				}
				id = NextDisplayInfo(id);
			}
			if (myid != INVALID_ID) {
				// Get info from the workbench
				if (Screen = LockPubScreen(MyGetMsg(MSG_WORKBENCH))) {
					if (dri = GetScreenDrawInfo(Screen)) {
						for (i = 0;
							  i < dri->dri_NumPens;
							  ++i) {
							if (dri->dri_Pens[i] < 256) {
								if (!(dri->dri_Pens[i] < (1<<CustomDepth))) {
									usedri = FALSE;
								}
							}
						}
						// open sort of cloned screen
						if (myscreen = OpenScreenTags(NULL,
									SA_LikeWorkbench, usedri?TRUE:FALSE,
									SA_SharePens, TRUE,
									SA_Depth, CustomDepth,
									SA_Overscan, OSCAN_TEXT,
									SA_SysFont, 1,
									SA_DisplayID, myid,
									SA_Type, PUBLICSCREEN,
									SA_PubName, ScreenName,
									SA_Title, ScreenName,
									SA_FullPalette, TRUE,
									SA_Interleaved, TRUE,
									TAG_END)) {
							// set unused palette entries to grey scale
							// with as good inversion as we can get.
							Bit12 = FALSE;
							if (GetDisplayInfoData(NULL,(UBYTE *)&di,sizeof(di),DTAG_DISP,myscreen->ViewPort.ColorMap->VPModeID)) {
								if (di.RedBits < 5) {
									Bit12 = TRUE;
								}
							}
							if (mydri = GetScreenDrawInfo(myscreen)) {
								for (i = 0;
									  i < 256;
									  ++i) {
									used[i] = FALSE;
								}
								numcols = 1<<CustomDepth;
								for (i = 0;
									  i < mydri->dri_NumPens;
									  ++i) {
									if (mydri->dri_Pens[i] < 256) {
										if (!used[mydri->dri_Pens[i]]) {
											used[mydri->dri_Pens[i]] = TRUE;
											--numcols;
										}
									}
								}
								// Remove pointer colours from palette
								if (CustomDepth > 4) {
									if (!used[17]) {
										used[17] = TRUE;
										--numcols;
									}
									if (!used[18]) {
										used[18] = TRUE;
										--numcols;
									}
									if (!used[19]) {
										used[19] = TRUE;
										--numcols;
									}
								}
								for (i = 0;
									  i < (1<<CustomDepth);
									  ++i) {
									if (used[i]) {
										GetRGB32(myscreen->ViewPort.ColorMap,i,1,rgb);
										if (Bit12) {
											curcol[i][0] = rgb[0]>>28;
											curcol[i][1] = rgb[1]>>28;
											curcol[i][2] = rgb[2]>>28;
										}
										else {
											curcol[i][0] = rgb[0]>>24;
											curcol[i][1] = rgb[1]>>24;
											curcol[i][2] = rgb[2]>>24;
										}
									}
								}
								d2 = (1<<CustomDepth)/2;
								// If 16 or greater colours set some colours
								if (CustomDepth > 3) {
									if (numcols) {
										j = 0;
										for (i = 0;
											  (i < d2) && (j < 24);
											  ++i) {
											if (!used[i]) {
												SetRGB32(&(myscreen->ViewPort),i,newcol[j][0]<<24,newcol[j][1]<<24,newcol[j][2]<<24);
												++j;
												--numcols;
												used[i] = TRUE;
											}
										}
									}
								}
								if (numcols) {
									diff = (0xFFFFFFFF / (numcols + 1));
									diff = (diff>>24)<<24;
									Color32 = 0;
									if (!diff) {
										if (Bit12) {
											diff = 0x10000000;
										}
										else {
											diff = 0x01000000;
										}
									}
									CheckCol(&Color32);
									for (i = 0;
										  (i < d2);
										  ++i) {
										if (!used[i]) {
											ObtainPen(myscreen->ViewPort.ColorMap,i,Color32,Color32,Color32,PEN_EXCLUSIVE);
//											SetRGB32(&(myscreen->ViewPort),i,Color32,Color32,Color32);
											Color32 += diff;
											CheckCol(&Color32);
										}
										if (!used[i + d2]) {
											ObtainPen(myscreen->ViewPort.ColorMap,i+d2,Color32,Color32,Color32,PEN_EXCLUSIVE);
//											SetRGB32(&(myscreen->ViewPort),i+d2,Color32,Color32,Color32);
											Color32 += diff;
											CheckCol(&Color32);
										}
									}
								}
								// Free everything, set screen to public and return
								FreeScreenDrawInfo(myscreen,mydri);
							}
							PubScreenStatus(myscreen,NULL);
							FreeScreenDrawInfo(Screen,dri);
							UnlockPubScreen(NULL,Screen);
							OpenedScreen = TRUE;
							return TRUE;
						}
						// Free everything and display error
						else {
							retflag = FALSE;
							emsg = MyGetMsg(MSG_EOPSCR);
							err = HE_OScreen;
						}
						FreeScreenDrawInfo(Screen,dri);
					}
					else {
						retflag = FALSE;
						emsg = MyGetMsg(MSG_UNDRI);
						err = HE_DrawI;
					}
					UnlockPubScreen(NULL,Screen);
				}
				else {
					retflag = FALSE;
					emsg = MyGetMsg(MSG_LOCKWB);
					err = HE_LockW;
				}
			}
			else {
				retflag = FALSE;
				emsg = MyGetMsg(MSG_INVMODE);
				e1 = CustomName;
				err = HE_ScreenMode;
			}
		}
		else {
			UnlockPubScreen(NULL,Screen);
		}
	}
	if (!retflag) {
		Error(emsg,MyGetMsg(MSG_QUIT),e1,err);
	}
	return retflag;
}

/* Attempt to close the public screen
 *
 * Now does it sort of properly
 *
 * Has to reopen AmigaGuide if required
 */
void
CloseCustomScreen(void) {
	while (!CloseScreen(myscreen)) {
		// Open backdrop window to force requesters to screen
		MPMorphWnd = OpenWindowTags(NULL,
			WA_Width,			1,
			WA_Height,			1,
			WA_IDCMP,			0,
			WA_Flags,			WFLG_BACKDROP |
									WFLG_BORDERLESS |
									WFLG_NOCAREREFRESH,
			WA_PubScreen,		myscreen,
			TAG_END );
		if (AmigaGuideBase) {
			if (handle = OpenAmigaGuideAsync(&nag,
			  					AGA_HelpGroup, HelpGroup,
  								TAG_END)) {
				ASig = AmigaGuideSignal(handle);
			}
		}
		Error(MyGetMsg(MSG_TRYCLOSE),MyGetMsg(MSG_RETRY),"",HE_CScreen);
		if (handle) {
			CloseAmigaGuide(handle);
			handle = NULL;
			ASig = NULL;
		}
		if (MPMorphWnd) {
			CloseWindow(MPMorphWnd);
			MPMorphWnd = NULL;
		}
	}
}

/* Unlinks all points and triangulates */
BOOL
Triangulate(void) {
	BOOL ret=TRUE;
	// Open window and wait till close selected then close it
  	if (!Saved) {
		if (!SaveRequester()) {
			return FALSE;
		}
	}
	Record(MyGetMsg(MSG_SETTRIANG),NULL);
	DisableWindows(DI_Triangulate);
	UnlinkAllPoints(TRUE);
	if (!GenerateTriangles()) {
		Error(MyGetMsg(MSG_FAILURET),MyGetMsg(MSG_OK),NULL,HE_GENT);
		ret = FALSE;
	}
	Saved = FALSE;
	CurrentTime(&USecs,&Um);
	EnableWindows();
	return ret;
}

/* nsort() was written by Dave Watson and uses the algorithm described in -
 *    Watson, D.F., 1981, Computing the n-dimensional Delaunay tessellation with 
 *          application to Voronoi polytopes: The Computer J., 24(2), p. 167-172. 
 */

#define SQ(x)				(x) * (x)
#define BIGNUM				1E37
#define EPSILON         0.00001
#define XTSIZE				75                  /* temporary storage size factor*/
#define XRANGE          10.0                /* factor (>=1) for radius of control points */
#define FILENAMELEN     32
#define AND             &&
#define OR              ||
#define EQ              ==
#define NE              !=

BOOL
GenerateTriangles(void) {
	BOOL ok = FALSE;
	BOOL flag = TRUE;
   double xx, bgs, **mxy, **wrk, **pts, **ccr;
   int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11, ii[3], 
       dm, nts, tsz, *id, **tmp, **a3s;
   struct MyPoint *MyPoint,**MyPoints,*MyPoint1,*MyPoint2,*MyPoint3;
	ULONG PointCount;

	PointCount = 0;
	for (MyPoint = (struct MyPoint *)PointList.lh_Head;
			MyPoint->MyNode.mln_Succ;
			MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
		PointCount++;
	}
if ((PointCount>2) && (MyPoints = (struct MyPoint **)AllocVec((sizeof (struct MyPoint *))*PointCount,MEMF_CLEAR))) {
   if (mxy = DoubleMatrix(2, 2)) {
	   for (i0=0; i0<2; i0++) {
	  		mxy[0][i0] = - (mxy[1][i0] = BIGNUM);
	   }
	   if (wrk = DoubleMatrix(2, 3)) {
		   for (i0=0; i0<2; i0++) {
		   	for (i1=0; i1<3; i1++) {
		   		wrk[i0][i1] = -XRANGE;
		   	}
		   }
		   for (i0=0; i0<2; i0++) {
		   	wrk[i0][i0] = XRANGE * (3 * 2 - 1);
		   }
			if (pts = DoubleMatrix(PointCount + 3, 2)) {
				for (i0=0, MyPoint = (struct MyPoint *)PointList.lh_Head;
						i0<PointCount;
						MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ, i0++) {
					MyPoints[i0] = MyPoint;
					pts[i0][0] = (MyPoint->x + MyPoint->x1)>>1;
					pts[i0][1] = (MyPoint->y + MyPoint->y1)>>1;
					for (i1=0; i1<2; i1++) {
						if (mxy[0][i1] < pts[i0][i1]) {
							mxy[0][i1] = pts[i0][i1];
						}
						if (mxy[1][i1] > pts[i0][i1]) {
							mxy[1][i1] = pts[i0][i1];
						}
					}
				}
				for (bgs=0, i0=0; i0<2; i0++) {
					mxy[0][i0] -= mxy[1][i0];
			      if (bgs < mxy[0][i0]) {
			      	bgs = mxy[0][i0];
			      }
			   }
				bgs *= EPSILON;
			   for (i0=0; i0<PointCount; i0++) {
			   	for (i1=0; i1<2; i1++) {
						pts[i0][i1] += bgs * (0.5 - (double)rand() / 0x7fffffff);
					}
				}
				for (i0=0; i0<3; i0++) {
					for (i1=0; i1<2; i1++) {
						pts[PointCount+i0][i1] = mxy[1][i1] + wrk[i1][i0] * mxy[0][i1];
					}
				}
			   for (i1=1, i0=2; i0<3; i0++) {
			   	i1 *= i0;
			   }
			   tsz = XTSIZE * i1;
			   if (tmp = IntMatrix(tsz + 1, 2)) {
				   i1 *= (PointCount + i1);
				   if (id = IntVect(i1)) {
					   for (i0=0; i0<i1; i0++) {
					   	id[i0] = i0;
					   }
						if (a3s = IntMatrix(i1,3)) {
						  	if (ccr = DoubleMatrix(i1,3)) {
							  	for (a3s[0][0]=PointCount, i0=1; i0<3; i0++) {
							  		a3s[0][i0] = a3s[0][i0-1] + 1;
							  	}
								for (ccr[0][2]=BIGNUM, i0=0; i0<2; i0++) {
									ccr[0][i0] = 0;
								}
							   nts = i4 = 1;
							   dm = 2 - 1;
							   SetMax(PointCount - 1);
							   for (i0=0; i0<PointCount; i0++) {
							   	SetCurr(i0);
							      i1 = i7 = -1;
							      i9 = 0;
							      for (i11=0; i11<nts; i11++) {
							         i1++;
							         while (a3s[i1][0] < 0) { 
							         	i1++;
							         }
							         xx = ccr[i1][2];
							         for (i2=0; i2<2; i2++) {
							            xx -= SQ(pts[i0][i2] - ccr[i1][i2]);
										   if (xx<0) {
										   	goto Corner3;
										   }
							         }
							         i9--;
										i4--;
										id[i4] = i1;
										for (i2=0; i2<3; i2++) {
										   ii[0] = 0;
							            if (ii[0] EQ i2) {
							            	ii[0]++;
							            }
							            for (i3=1; i3<2; i3++) {
							               ii[i3] = ii[i3-1] + 1;
							               if (ii[i3] EQ i2) {
							               	ii[i3]++;
							               }
							            }
							            if (i7>dm) {
											   i8 = i7;
												for (i3=0; i3<=i8; i3++) {
												   for (i5=0; i5<2; i5++) {
												   	if (a3s[i1][ii[i5]] NE tmp[i3][i5]) {
												   		goto Corner1;
												   	}
												   }
													for (i6=0; i6<2; i6++) {
														tmp[i3][i6] = tmp[i8][i6];
													}
													i7--;
													goto Corner2;
Corner1:;
												}
											}
											if (++i7 > tsz) {
												goto returnfail;
											}
											for (i3=0; i3<2; i3++) {
												tmp[i7][i3] = a3s[i1][ii[i3]];
											}
Corner2:;
										}
								      a3s[i1][0] = -1;
Corner3:;
								   }
								   for (i1=0; i1<=i7; i1++) {
								      for (i2=0; i2<2; i2++) {
								   		for (wrk[i2][2]=0, i3=0; i3<2; i3++) {
								            wrk[i2][i3] = pts[tmp[i1][i2]][i3] - pts[i0][i3];
										   	wrk[i2][2] += wrk[i2][i3] * (pts[tmp[i1][i2]][i3] + pts[i0][i3]) / 2;
											}
										}
										xx = wrk[0][0] * wrk[1][1] - wrk[1][0] * wrk[0][1];
										ccr[id[i4]][0] = (wrk[0][2] * wrk[1][1] - wrk[1][2] * wrk[0][1]) / xx;
										ccr[id[i4]][1] = (wrk[0][0] * wrk[1][2] - wrk[1][0] * wrk[0][2]) / xx;
								      for (ccr[id[i4]][2]=0, i2=0; i2<2; i2++) {
								        	ccr[id[i4]][2] += SQ(pts[i0][i2] - ccr[id[i4]][i2]);
										   a3s[id[i4]][i2] = tmp[i1][i2];
								      }
										a3s[id[i4]][2] = i0;
										i4++;
								      i9++;
								   }
								   nts += i9;
								}
								i0 = -1;
								for (i11=0; flag && (i11<nts); i11++) {
									i0++;
								   while (a3s[i0][0] < 0) {
								   	i0++;
								   }
								   if (a3s[i0][0] < PointCount) {
										for (i1=0; i1<2; i1++) for (i2=0; i2<2; i2++)  {
								      	wrk[i1][i2] = pts[a3s[i0][i1]][i2] - pts[a3s[i0][2]][i2];
								      }
								      xx = wrk[0][0] * wrk[1][1] - wrk[0][1] * wrk[1][0];
								      if (fabs(xx) > EPSILON) {
								      	MyPoint1 = MyPoints[a3s[i0][0]];
								      	MyPoint2 = MyPoints[a3s[i0][1]];
								      	MyPoint3 = MyPoints[a3s[i0][2]];
							      		LinkPoints(MyPoint1,MyPoint2);
							      		LinkPoints(MyPoint2,MyPoint3);
							      		LinkPoints(MyPoint3,MyPoint1);
								      	// Could set flag
								      }
								   }
								}
							   ok = flag;
returnfail:
								FreeMatrixd(ccr);
							}
							FreeMatrixi(a3s);
						}
						MyFreeVecti(id);
					}
				   FreeMatrixi(tmp);
				}
				FreeMatrixd(pts);
			}
			FreeMatrixd(wrk);
		}
		FreeMatrixd(mxy);
	}
	FreeVec(MyPoints);
}
else {
	ok = FALSE;
}
return ok;
}
	
int
*IntVect(int ncols) {  
	return (int *) AllocVec(ncols * sizeof(int),0);
}

void
MyFreeVecti(int *vectptr) {
	if (vectptr) {
		FreeVec(vectptr);
	}
}

int
**IntMatrix(int nrows, int ncols) {
   int i0;
   int **matptr;
   if (nrows<2) nrows = 2;
   if (ncols<2) ncols = 2;
   if ((matptr = (int **) AllocVec(nrows * sizeof(int *),0)) EQ NULL) {
   	return NULL;
   }
   if ((matptr[0] = (int *) AllocVec(nrows * ncols * sizeof(int),0)) EQ NULL) {
   	FreeVec(matptr);
   	return NULL;
   }
   for (i0=1; i0<nrows; i0++) {
   	matptr[i0] = matptr[0] + i0 * ncols;
   }
   return matptr;
}

void
FreeMatrixi(int **matptr) {  
	if (matptr) {
		if (matptr[0]) {
			FreeVec(matptr[0]);
		}
		FreeVec(matptr);
	}
}

double
**DoubleMatrix(int nrows, int ncols) {
   int i0;
   double **matptr;
   if (nrows<2) nrows = 2;
   if (ncols<2) ncols = 2;
   if ((matptr = (double **) AllocVec(nrows * sizeof(double *),0)) EQ NULL) {
   	return NULL;
   }
   if ((matptr[0] = (double *) AllocVec(nrows * ncols * sizeof(double),0)) EQ NULL) {
   	FreeVec(matptr);
   	return NULL;
   }
   for (i0=1; i0<nrows; i0++) {
	   matptr[i0] = matptr[0] + i0 * ncols;
	}
   return matptr;
}

void
FreeMatrixd(double **matptr) {
	if (matptr) {
		if (matptr[0]) {
		   FreeVec(matptr[0]);
		}
		FreeVec(matptr);
	}
}

static char MTitle[60];

void UserMenu(ULONG Selection) {
	char* com = NULL;
	switch (Selection) {
	case FULLMENUNUM(M_USER,MM_PREVIEW,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_PREVIEW,NOSUB):
		Preview();
		break;
	case FULLMENUNUM(M_USER,MM_USER2,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER2,NOSUB):
		com = User2;
		break;
	case FULLMENUNUM(M_USER,MM_USER3,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER3,NOSUB):
		com = User3;
		break;
	case FULLMENUNUM(M_USER,MM_USER4,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER4,NOSUB):
		com = User4;
		break;
	case FULLMENUNUM(M_USER,MM_USER5,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER5,NOSUB):
		com = User5;
		break;
	case FULLMENUNUM(M_USER,MM_USER6,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER6,NOSUB):
		com = User6;
		break;
	case FULLMENUNUM(M_USER,MM_USER7,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER7,NOSUB):
		com = User7;
		break;
	case FULLMENUNUM(M_USER,MM_USER8,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER8,NOSUB):
		com = User8;
		break;
	case FULLMENUNUM(M_USER,MM_USER9,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_USER9,NOSUB):
		com = User9;
		break;
	case FULLMENUNUM(M_USER,MM_MACRO,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_MACRO,NOSUB):
		DisableWindows(DI_Macro);
		if (GetAFile("",MyGetMsg(MSG_SELECTSCRIPT),0,MyGetMsg(MSG_HQDMPM),MyGetMsg(MSG_EXECUTE))) {
			EnableWindows();
			com = TempFilename;
		}
		else {
			EnableWindows();
		}
		break;
	case FULLMENUNUM(M_USER,MM_STARTLEARN,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_STARTLEARN,NOSUB):
		DisableWindows(DI_Learn);
		if (GetAFile("",MyGetMsg(MSG_SELECTRECORD),FRF_DOSAVEMODE,NULL,MyGetMsg(MSG_RECORD))) {
			if (strlen(TempFilename) < 5) {
				strcat(TempFilename,MyGetMsg(MSG_DMPM));
			}
			else {
				if (Stricmp(&TempFilename[strlen(TempFilename) - 4],MyGetMsg(MSG_DMPM))) {
					strcat(TempFilename,MyGetMsg(MSG_DMPM));
				}
			}
			if (RecordBPTR = Open(TempFilename,MODE_NEWFILE)) {
				struct DateTime DateTime = {0};
				char dbuf[LEN_DATSTRING];
				char tbuf[LEN_DATSTRING];
				strcpy(dbuf,MyGetMsg(MSG_UDATE));
				strcpy(tbuf,MyGetMsg(MSG_UTIME));
				DateStamp(&(DateTime.dat_Stamp));
				DateTime.dat_Format = FORMAT_DOS;
				DateTime.dat_StrDate = dbuf;
				DateTime.dat_StrTime = tbuf;
				DateToStr(&DateTime);
				Record(MyGetMsg(MSG_REXXHEAD),(ULONG)&Version[6],(ULONG)TempFilename,(ULONG)dbuf,(ULONG)tbuf);
				strcpy(RecordFName,TempFilename);
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_USER,MM_STARTLEARN,NOSUB));
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_USER,MM_STOPLEARN,NOSUB));
	   	   MPMorphNewMenu[M_NM_STOPLEARNING].nm_Flags &= ~NM_ITEMDISABLED;
	      	MPMorphNewMenu[M_NM_STARTLEARNING].nm_Flags |= NM_ITEMDISABLED;
				if (ControlWindow) {
					OffMenu(ControlWindow,FULLMENUNUM(M_USER,MM_STARTLEARN,NOSUB));
					OnMenu(ControlWindow,FULLMENUNUM(M_USER,MM_STOPLEARN,NOSUB));
				}
				else {
		   	   MyNewMenu[NM_STOPLEARNING].nm_Flags &= ~NM_ITEMDISABLED;
		      	MyNewMenu[NM_STARTLEARNING].nm_Flags |= NM_ITEMDISABLED;
				}
			}
			else {
				Error(MyGetMsg(MSG_EOPF),MyGetMsg(MSG_OK),TempFilename,HE_Open);
			}
			sprintf(MTitle,MyGetMsg(MSG_TITLE_L),&Version[6]);
			SetWindowTitles(MPMorphWnd,MTitle,(UBYTE *)-1);
		}
		EnableWindows();
		break;
	case FULLMENUNUM(M_USER,MM_STOPLEARN,NOSUB):
	case FULLMENUNUM(M_M_USER,MM_STOPLEARN,NOSUB):
		if (!Close(RecordBPTR)) {
			Error(MyGetMsg(MSG_ECLOF),MyGetMsg(MSG_OK),RecordFName,HE_Close);
		}
		RecordBPTR = NULL;
		OnMenu(MPMorphWnd,FULLMENUNUM(M_M_USER,MM_STARTLEARN,NOSUB));
		OffMenu(MPMorphWnd,FULLMENUNUM(M_M_USER,MM_STOPLEARN,NOSUB));
		MPMorphNewMenu[M_NM_STARTLEARNING].nm_Flags &= ~NM_ITEMDISABLED;
		MPMorphNewMenu[M_NM_STOPLEARNING].nm_Flags |= NM_ITEMDISABLED;
		if (ControlWindow) {
			OnMenu(ControlWindow,FULLMENUNUM(M_USER,MM_STARTLEARN,NOSUB));
			OffMenu(ControlWindow,FULLMENUNUM(M_USER,MM_STOPLEARN,NOSUB));
		}
		else {
	      MyNewMenu[NM_STARTLEARNING].nm_Flags &= ~NM_ITEMDISABLED;
	      MyNewMenu[NM_STOPLEARNING].nm_Flags |= NM_ITEMDISABLED;
	   }
		SetWindowTitles(MPMorphWnd,&Version[6],(UBYTE *)-1);
		break;
	}
	if (com) {
		SendRexxCommand(myhost,com,NULL);
	}
	return;
}

extern void Record(char *Main,ULONG first,...) {
	if (RecordBPTR) {
		VFPrintf(RecordBPTR,Main,&first);
	}
}

static int PCurr = 0;
static int PMax = 1;

extern void SetMax(int max) {
	if (PCurr > 0) {
		SetDrMd(MPMorphWnd->RPort,COMPLEMENT);
		RectFill(MPMorphWnd->RPort,HelpLeft+1,HelpTop,HelpLeft + HelpWidth * PCurr / PMax, HelpTop + HelpHeight);
	}
	if (max < 1) {
		PMax = 1;
		PCurr = 0;
	}
	else {
		PMax = max;
		PCurr = 0;
	}
}

extern void SetCurr(int curr) {
	if (!(curr > PMax) && !(curr < 0)) {
		int OldCurr;
		int NewCurr;
		OldCurr = HelpWidth * PCurr / PMax;
		NewCurr = HelpWidth * curr / PMax;
		if (NewCurr > OldCurr) {
			SetDrMd(MPMorphWnd->RPort,COMPLEMENT);
			RectFill(MPMorphWnd->RPort,HelpLeft + OldCurr + 1, HelpTop, HelpLeft + NewCurr, HelpTop + HelpHeight);
		}
		else {
			if (NewCurr < OldCurr) {
				SetDrMd(MPMorphWnd->RPort,COMPLEMENT);
				RectFill(MPMorphWnd->RPort,HelpLeft + NewCurr + 1, HelpTop, HelpLeft + OldCurr, HelpTop + HelpHeight);
			}
		}
		PCurr = curr;
	}
}

extern void SetMessage(char *message) {
	SetCurr(0);
//	if (PCurr) {
//		SetDrMd(MPMorphWnd->RPort,COMPLEMENT);
//		RectFill(MPMorphWnd->RPort,HelpLeft+1,HelpTop,HelpLeft + HelpWidth * PCurr / PMax, HelpTop + HelpHeight);
//	}	
	GT_SetGadgetAttrs(MPMorphGadgets[GDX_Help],MPMorphWnd,NULL,
					GTTX_Text,message, TAG_END );
//	if (PCurr) {
//		SetDrMd(MPMorphWnd->RPort,COMPLEMENT);
//		RectFill(MPMorphWnd->RPort,HelpLeft+1,HelpTop,HelpLeft + HelpWidth * PCurr / PMax, HelpTop + HelpHeight);
//	}	
}
