// 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.

// mark@topic.demon.co.uk

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

/* Define all the Library bases	*/
struct IntuitionBase *IntuitionBase;
struct Library	*GfxBase,
					*LayersBase,
					*InputBase,
					*IFFParseBase,
					*GadToolsBase,
					*AslBase,
					*UtilityBase,
					*DiskfontBase,
					*AmigaGuideBase,
					*IconBase,
					*WorkbenchBase,
					*ReqToolsBase,
					*LocaleBase;
extern struct RxsLib *RexxSysBase;

struct Catalog *Catalog = NULL;

struct Library *EGSIntuiBase = NULL;
struct Library *EGSGfxBase = NULL;
struct Library *EGSBase = NULL;
struct Library *EGSRequestBase = NULL;

struct Library *MPImageBase = NULL;

struct Library *MPGuiBase = NULL;

/* Table of system gadget sizes
 * See MPMorph.h for definitions
 */
extern struct gadgetsizing gs[] = {
	{SYSISIZE_LOWRES,13,11,16,11,13,11,16,11,13,11,15,18,18, 7, 9},
	{SYSISIZE_MEDRES,18,10,16,10,18,11,16,10,18,11,20,24,24,10,13}
};

extern UWORD 						Mode 			= NONE;
extern struct List				PointList 	= {0};
extern struct Picture	 		Pic1			= {0},
										Pic2			= {0};
extern BOOL 						Pic1_Open	= FALSE;
extern BOOL 						Pic2_Open	= FALSE;
extern struct FileRequester 	*filereq		= NULL;
extern BOOL 						Saved 		= TRUE;
char 									savedfilename[256]	= "";
extern LONG							Width			= 0,
										Height		= 0;
extern LONG							SinglePicture			= 0;
extern BOOL 						Zoom			= FALSE;
extern BOOL 						ZoomAllowed	= TRUE;
extern char 						**ArgArray				= NULL;
extern char 						**ArgArraySettings	= NULL;
extern AMIGAGUIDECONTEXT 		handle 		= NULL;
extern BOOL							CreateIcons = TRUE;
extern BOOL							CreateIconsP = TRUE;	/* TRUE if to write prefs Icons	*/
extern BOOL							KeepSettings = TRUE; /* TRUE to save settings on quit */
char									PreviewScript[128] = "";
char									ScreenName[128] = "";
char									CustomName[128] = "";
extern ULONG						CustomDepth = 4;
extern BOOL							OpenedScreen = FALSE;/* Did we open the screen			*/
extern ULONG						ASig			= 0;
extern int							changedboxcount	= 0;	// Used to redraw points after resizing BOTH windows
extern UWORD						n=0;							// Holds screen resolution
extern LONG 						MaxWidth		= 0;	// Max x of points
extern LONG							MaxHeight	= 0;	// Max y of points
extern BOOL							GHelp			= FALSE;	// Gadget Help?
extern struct NewAmigaGuide	nag 	= {NULL};		// .guide stuff
extern BOOL							EGS = FALSE;		// Use EGS picture window
extern ULONG						HelpGroup=0;		// Help Group for GadgetHelp
extern float						xfact	= 0.0;			//	X Scale to get from image size to point size
extern float						yfact	= 0.0;			// Y Scale
extern int							RexxQuitFlag = 1;	// Quit from ARexx
extern BOOL							Disabled = FALSE;
extern char							Recent1[256] = "";	// Recently opened files
extern char							Recent2[256] = "";
extern char							Recent3[256] = "";
extern char							Recent4[256] = "";
extern char							Recent5[256] = "";
extern char							User2[128] = "";
extern char							User3[128] = "";
extern char							User4[128] = "";
extern char							User5[128] = "";
extern char							User6[128] = "";
extern char							User7[128] = "";
extern char							User8[128] = "";
extern char							User9[128] = "";
extern struct MsgPort			*AMsgPortp = NULL;// Message port for AppWindows
extern struct AppWindow			*AppWindow = NULL;
extern struct MsgPort			*WMsgPortp = NULL;			// Message port for Picture Windows
extern ULONG 						USecs=0,Um=0;			// Time of last update

LONG 									Start;				// Start frame

BPTR									RecordBPTR = NULL;
extern char 						RecordFName[257] = "";

extern LONG FrameNumber = 0;					// Current frame number
extern BOOL ARexxLock = FALSE;

extern struct RexxHost *myhost = NULL;

/* Mapping for Boopsi gadgets	*/
struct TagItem MapToIdcmp[] = {
	{PGA_Top,ICSPECIAL_CODE},
	{GA_ID,ICSPECIAL_CODE},
	{TAG_END,}
};

/* Version string for CLI version */
extern const char Version[30] = "";

/* Display About requester
 * using reqtools.library if available
 */
void
About(void) {
	UBYTE *body;
	UBYTE *title = MyGetMsg(MSG_VTITLE);
	UBYTE *gad;
	struct EasyStruct EasyStruct = {
	  	sizeof(struct EasyStruct),
		0,
		NULL,
		NULL,
		NULL
	};
	DisableWindows(DI_About);
	if (GHelp) {
		help(H_ABOUT);
	}
	body = MyGetMsg(MSG_ABOUT);
	gad = MyGetMsg(MSG_OK);
	if (ReqToolsBase) {
		ULONG tags[] = {RT_Window,		0,
							RTEZ_ReqTitle, 0,
							RTEZ_Flags,		EZREQF_CENTERTEXT,
							RT_Underscore,	'_',
							TAG_END };
		tags[1] = (ULONG)MPMorphWnd;
		tags[3] = (ULONG)title,
		rtEZRequest(body,MyGetMsg(MSG__OK),NULL,
						(struct TagItem *)tags,
						myhost?myhost->portname:"");

	}
	else {
		EasyStruct.es_Title = title;
		EasyStruct.es_TextFormat = body;
		EasyStruct.es_GadgetFormat = gad;
		EasyRequest(MPMorphWnd,&EasyStruct,NULL,
						myhost?myhost->portname:"");
	}
	EnableWindows();
}

extern struct Hook ProgressHook = {
	0
};

ULONG __saveds __asm ProgressH(register __a0 struct Hook *hook,
								  register __a2 APTR *object,
								  register __a1 APTR *message) {
	switch ((int)object) {
	case (int)MPIP_MAX:
		SetMax((int)message);
		break;
	case (int)MPIP_CURR:
		SetCurr((int)message);
		break;
	case (int)MPIP_MESSAGE:
		SetMessage((UBYTE *)message);
		break;
	default:
		break;
	}
	return 1;
}


/* The main procedure	*/
int
main(int argc,char **argv) {
 BOOL 				OkFlag		= FALSE;		// Still running ok
 struct IOStdReq	InputIO;						// Input device to check Shift key
 struct Message 	*Message;					// To discard messages from ports
 struct WBStartup *argmsg;						// Workbench stuff
 struct WBArg 		*wb_arg;						// Workbench arguments
 struct Window		*oldWindowPtr;				// Retain old pointer for system requesters
 struct Process	*process;					// This process for system requesters
 char 				*e				= NULL;		// Main error message string
 char 				*e1			= NULL;		// Variable part of error message
 char 				*filename;					// General file name
 LONG					hnum			= 0;			// Help to display on an error message
 BPTR					progdir;

 /* Copy strings */
 if (LocaleBase = OpenLibrary("locale.library",0)) {
  Catalog = OpenCatalog(NULL,
  								"mpmorph.catalog",
  								TAG_END);
 }
 else {
  printf("Error opening locale.library!");
  return 20;
 }
 strcpy(PreviewScript,MyGetMsg(MSG_DEFPRE));
 strcpy(User2,MyGetMsg(MSG_DEFU2));
 strcpy(User3,MyGetMsg(MSG_DEFU3));
 strcpy(User4,MyGetMsg(MSG_DEFU4));
 strcpy(Version,MyGetMsg(MSG_VERSION));
 /* Assign MPMorph to progdir */
 if (progdir = Lock("progdir:",ACCESS_READ)) {
  AssignLock("MPMorph",progdir);
 }
 /* Initalise list of points	*/
 NewList(&PointList);
 // try and open optional libraries
 ReqToolsBase = OpenLibrary("reqtools.library",38);
 if (UtilityBase = OpenLibrary("utility.library",39L)) {
  // Get Help Group
  HelpGroup = GetUniqueID();
  CloseLibrary(UtilityBase);
 }
 /* If we can open amigaguide.library
  * then set up the help stuff
  */
 if (AmigaGuideBase = OpenLibrary ("amigaguide.library", 34L)) {
  nag.nag_BaseName		= MyGetMsg(MSG_MPM);
  nag.nag_Name				= MyGetMsg(MSG_MPMGUIDE);
  nag.nag_ClientPort		= MyGetMsg(MSG_MPM_HELP);
  nag.nag_Context			= context;
  nag.nag_Flags			= HTF_NOACTIVATE;
  nag.nag_PubScreen		= NULL;
  if (handle = OpenAmigaGuideAsync(&nag, 
  					AGA_HelpGroup, HelpGroup,
  					TAG_END)) {
   ASig = AmigaGuideSignal(handle);
  }
 }
 /* Open all the libraries/devices/message ports/file requesters etc.	*/
 if (IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39L)) {
  if (RexxSysBase = (struct RxsLib *)OpenLibrary("rexxsyslib.library",0L)) {
   if (IconBase = OpenLibrary("icon.library",37L)) {
    if (IFFParseBase = OpenLibrary("iffparse.library",37L)) {
     if (!OpenDevice("input.device",NULL,(struct IORequest *)&InputIO,NULL)) {
      InputBase = (struct Library *)InputIO.io_Device;
      if (GfxBase = OpenLibrary("graphics.library",39L)) {
       if (LayersBase = OpenLibrary("layers.library",37L)) {
        if (GadToolsBase = OpenLibrary("gadtools.library",37L)) {
         if (AslBase = OpenLibrary("asl.library",37L)) {
          if (UtilityBase = OpenLibrary("utility.library",39L)) {
           if (DiskfontBase = OpenLibrary("diskfont.library",36L)) {
            if (WorkbenchBase = OpenLibrary("workbench.library",36L)) {
             if (MPImageBase = OpenLibrary("MPImage.library",6L)) {
              ProgressHook.h_Entry = (HOOKFUNC)ProgressH;
              MPProgressHook(&ProgressHook);
              if (MPGuiBase = OpenLibrary("MPGui.library",0L)) {
               if (WMsgPortp = CreateMsgPort()) {
                if (AMsgPortp = CreateMsgPort()) {
                 /* Read all the parameters/tooltypes/settings file	*/
                 MyArgArrayInit(argc,argv,MyGetMsg(MSG_DOTPREFS),MyGetMsg(MSG_ENVDIR));
                 InitParams(TRUE);
                 if (MatchToolValue(MyArgString(MyGetMsg(MSG_REQTOOLS),MyGetMsg(MSG_YES),FALSE),MyGetMsg(MSG_NO))) {
                  if (ReqToolsBase) {
                   CloseLibrary(ReqToolsBase);
                   ReqToolsBase = NULL;
                  }
                 }
                 if (MatchToolValue(MyArgString(MyGetMsg(MSG_EGS),MyGetMsg(MSG_NO),FALSE),MyGetMsg(MSG_YES))) {
                  if ((EGSBase = OpenLibrary("egs.library",0)) &&
                      (EGSGfxBase = OpenLibrary("egsgfx.library", 0)) &&
                      (EGSIntuiBase = OpenLibrary("egsintui.library", 0)) &&
                      (EGSRequestBase = OpenLibrary("egsrequest.library", 0))) {
                   EGS = TRUE;
                   ZoomAllowed = FALSE;
                  }
                 }
                 if (filereq = (struct FileRequester *)AllocAslRequest(ASL_FileRequest,NULL)) {
                  /* Open custom screen if required				*/
                  if (OpenCustomScreen()) {
                   if (PubScreenName && *PubScreenName) {
                    /* Since the screen now exists reopen amigaguide on it! */
                    if (handle) {
                     CloseAmigaGuide(handle);
                     handle = NULL;
                    }
                    if (AmigaGuideBase) {
                     nag.nag_PubScreen		= PubScreenName;
                     if (handle = OpenAmigaGuideAsync(&nag,
                     						AGA_HelpGroup, HelpGroup,
						  		  					TAG_END)) {
                      ASig = AmigaGuideSignal(handle);
                     }
                    }
                   }
                   /* Update the Info window menus and open	*/
                   if (!SetupScreen()) {
                    SetMPImageScreen(PubScreenName,0); //MPIF_PROGRESS);
                    if (!OpenMPMorphWindow()) {
                     /* Set up system requester redirection	*/
                     process = (struct Process *)FindTask(NULL);
                     oldWindowPtr = process->pr_WindowPtr;
                     process->pr_WindowPtr = MPMorphWnd;
                     /* Activate the window and disable		*/
                     ActivateWindow(MPMorphWnd);
                     DisableWindows(DI_LoadBrush);
                     /* Load brushes if possible					*/
                     LoadBrushes();
                     /* No filename as yet							*/
   		            *savedfilename = 0;
   		            if (argc) {
 	                   if (filename = ArgString(ArgArray,MyGetMsg(MSG_FILES),NULL)) {
                       MyOpen(filename,FALSE,TRUE);				// From the CLI and FILES parameter supplied
                      }
                     }
                     else {
                	    argmsg = (struct WBStartup *)argv;
   				  	    if (argmsg->sm_NumArgs > 1) {
 	                    wb_arg = argmsg->sm_ArgList;
    	                 wb_arg++;
         	           if (wb_arg->wa_Lock) {
    	      	         NameFromLock(wb_arg->wa_Lock,savedfilename,256);
    	      	        }
          	           if (AddPart(savedfilename,wb_arg->wa_Name,256)) {
            	         MyOpen(savedfilename,FALSE,TRUE);		// From the WB and project supplied
             	        }
                	    }
                     }
                     /* Enable the windows and do the main stuff	*/
                     EnableWindows();
                     myhost = SetupARexxHost(MyArgString(MyGetMsg(MSG_PORTNAME),MyGetMsg(MSG_MPMCAPS),FALSE),NULL);
                     doMsgLoop();
                     if (myhost) {
                      DisableWindows(DI_RexxScr);
                      CloseDownARexxHost(myhost);
                     }
                     if (KeepSettings) {
                      SaveSettings(MyGetMsg(MSG_ENVP));	// save settings for next run
                     }
                     /* Close everything down in reverse order
                      * Setting up error message if required
                      */
                     if (Pic1_Open) {
                      CloseAPicture(&Pic1);
                      Pic1_Open = FALSE;
                     }
                     if (Pic2_Open) {
                      CloseAPicture(&Pic2);
                      Pic2_Open = FALSE;
                     }
                     DeleteAllPoints();
                     if (ControlWindow) {
                      CloseControlWindow();
                     }
                     process->pr_WindowPtr = oldWindowPtr;
                     OkFlag = TRUE;
                     Record(MyGetMsg(MSG_SETQUIT),NULL);
                     if (RecordBPTR) {
							 if (!Close(RecordBPTR)) {
							  Error(MyGetMsg(MSG_ECLOF),MyGetMsg(MSG_OK),RecordFName,HE_Close);
							 }
							 RecordBPTR = NULL;
                     }
                    }
                    CloseMPMorphWindow();
                    if (!OkFlag && !e) {
                     e = MyGetMsg(MSG_FAILURE);					// e and e1 to save memory as e is reused
                     e1 = MyGetMsg(MSG_OMPMW);
                     hnum = HE_OMorph;
                    }
                   }
                   CloseDownScreen();
                   if (Add_o) DisposeObject(Add_o);
                   if (Del_o) DisposeObject(Del_o);
                   if (L1_o) DisposeObject(L1_o);
                   if (L2_o) DisposeObject(L2_o);
                   if (Mov_o) DisposeObject(Mov_o);
                   if (One_o) DisposeObject(One_o);
                   if (Rel_o) DisposeObject(Rel_o);
                   if (Two_o) DisposeObject(Two_o);
                   if (U1_o) DisposeObject(U1_o);
                   if (U2_o) DisposeObject(U2_o);
                   if (!OkFlag && !e) {
                    e = MyGetMsg(MSG_FAILURE);
                    e1 = MyGetMsg(MSG_SUSCR);
                    hnum = HE_Screen;
                   }
                  }
                  else {
                   // Displayed error message elsewhere
                   OkFlag = TRUE;
                  }
                  FreeAslRequest(filereq);
                 }
                 MyArgArrayDone();
                 if (!OkFlag && !e) {
                  e = MyGetMsg(MSG_UNABLE);
                  e1 = MyGetMsg(MSG_FILER);
                  hnum = HE_FileReq;
                 }
                 Forbid();
                 while (Message = GetMsg(AMsgPortp)) {
                  ReplyMsg(Message);
                 }
                 DeleteMsgPort(AMsgPortp);
                 Permit();
                }
                if (!OkFlag && !e) {
                 e = MyGetMsg(MSG_UNABLE);
                 e1 = MyGetMsg(MSG_AWMP);
                 hnum = HE_APort;
                }
                Forbid();
                while (Message = GetMsg(WMsgPortp)) {
                 ReplyMsg(Message);
                }
                DeleteMsgPort(WMsgPortp);
                Permit();
               }
               if (!OkFlag && !e) {
                e = MyGetMsg(MSG_UNABLE);
                e1 = MyGetMsg(MSG_CWMP);
                hnum = HE_WPort;
               }
               CloseLibrary(MPGuiBase);
              }
              if (!OkFlag && !e) {
               e = MyGetMsg(MSG_CANNOTOP);
               e1= MyGetMsg(MSG_MPGLV);
               hnum = HE_Library;
	 	 	     }
              CloseLibrary(MPImageBase);
             }
             if (!OkFlag && !e) {
              e = MyGetMsg(MSG_CANNOTOP);
              e1= MyGetMsg(MSG_MPILV);
              hnum = HE_Library;
 	 	 	    }
             CloseLibrary(WorkbenchBase);
            }
            if (!OkFlag && !e) {
             e = MyGetMsg(MSG_CANNOTOP);
             e1= MyGetMsg(MSG_WBLV);
             hnum = HE_Library;
 	 	 	   }
            CloseLibrary(DiskfontBase);
           }
           if (!OkFlag && !e) {
            e = MyGetMsg(MSG_CANNOTOP);
            e1= MyGetMsg(MSG_DFLV);
            hnum = HE_Library;
	 	 	  }
           CloseLibrary(UtilityBase);
          }
          if (!OkFlag && !e) {
           e = MyGetMsg(MSG_CANNOTOP);
           e1 = MyGetMsg(MSG_ULV);
           hnum = HE_Library;
          }
          CloseLibrary(AslBase);
         }
         if (!OkFlag && !e) {
          e = MyGetMsg(MSG_CANNOTOP);
          e1 = MyGetMsg(MSG_ASLV);
          hnum = HE_Library;
         }
         CloseLibrary(GadToolsBase);
        }
        if (!OkFlag && !e) {
         e = MyGetMsg(MSG_CANNOTOP);
         e1 = MyGetMsg(MSG_GTLV);
         hnum = HE_Library;
        }
        CloseLibrary(LayersBase);
       }
       if (!OkFlag && !e) {
        e = MyGetMsg(MSG_CANNOTOP);
        e1 = MyGetMsg(MSG_LLV);
        hnum = HE_Library;
       }
       CloseLibrary(GfxBase);
      }
      if (!OkFlag && !e) {
       e = MyGetMsg(MSG_CANNOTOP);
       e1 = MyGetMsg(MSG_GFXLV);
       hnum = HE_Library;
      }
      CloseDevice(&InputIO);
     }
     if (!OkFlag && !e) {
      e = MyGetMsg(MSG_CANNOTOP);
      e1 = MyGetMsg(MSG_IPLV);
      hnum = HE_IDevice;
     }
     CloseLibrary(IFFParseBase);
    }
    if (!OkFlag && !e) {
     e = MyGetMsg(MSG_CANNOTOP);
     e1 = MyGetMsg(MSG_IFFPLV);
     hnum = HE_Library;
    }
 	 CloseLibrary(IconBase);
   }
   if (!OkFlag && !e) {
    e = MyGetMsg(MSG_CANNOTOP);
    e1 = MyGetMsg(MSG_ICONLV);
    hnum = HE_Library;
   }
   CloseLibrary((struct Library *)RexxSysBase);
  }
  if (!OkFlag && !e) {
   e = MyGetMsg(MSG_CANNOTOP);
   e1 = MyGetMsg(MSG_REXXLV);
   hnum = HE_Library;
  }
  if (!OkFlag) {
   Error(e,MyGetMsg(MSG_QUIT),e1,hnum);			// Display error message if it failed
  }
  /* Close AmigaGuide (so we can close the screen)
   * It will be reopened if required
   */
  if (handle) {
   CloseAmigaGuide(handle);
   handle = NULL;
   ASig = NULL;
  }
  if (OpenedScreen) {
   CloseCustomScreen();
  }
 }
 if (EGSRequestBase) {
  CloseLibrary(EGSRequestBase);
 }
 if (EGSIntuiBase) {
  CloseLibrary(EGSIntuiBase);
 }
 if (EGSGfxBase) {
  CloseLibrary(EGSGfxBase);
 }
 if (EGSBase) {
  CloseLibrary(EGSBase);
 }
 if (AmigaGuideBase) {
  CloseLibrary(AmigaGuideBase);
 }
 if (ReqToolsBase) {
  CloseLibrary(ReqToolsBase);
 }
 if (IntuitionBase) {
  CloseLibrary((struct Library *)IntuitionBase);
 }
 if (LocaleBase) {
  CloseCatalog(Catalog);
  CloseLibrary(LocaleBase);
 }
 return 0;
}

/* Open and image in a window
 * returns	: TRUE or FALSE for sucess failure
 * filename	: Name of file, can be NULL in which case ASL file requester is displayed
 * pic		: pointer to a structure to hold all the stuff
 * GUI		: TRUE or FALSE to display error message on failure
 */
BOOL
openAPicture(char *filename,struct Picture *pic,BOOL GUI) {
 char dirname[257];	// full filename from ASL requester or FrameNumber
 char *ifilename	= NULL;	// filename to use
 char *e 			= NULL;	// first part of error message
 char *e1 			= NULL;	// 2nd part of error message
 LONG hnum			= 0;		// Help number for error
 /* Set file name from input supplied
  * or by using ASL file requester
  */
 if (filename) {
  if ((SinglePicture == 2) || (SinglePicture == 3)) {
   sprintf(dirname,filename,FrameNumber);		// Add in frame number
   ifilename = dirname;
  }
  else {
   ifilename = filename;
  }
 }
 else {
  if (AslRequestTags((APTR) filereq,
  						ASLFR_TitleText,(Tag) MyGetMsg(MSG_PICKIFF),
  						ASLFR_RejectIcons, TRUE,
  						TAG_DONE)) {
   strncpy(dirname,filereq->fr_Drawer,256);
   if (AddPart(dirname,filereq->fr_File,256)) {
    ifilename=dirname;
   }
  }
 }
 /* If we now have a file name then find the screen (passed in PUBSCREEN=)
  * determine its resolution and get some data
  */
 if (ifilename) {
  if (pic->Screen = LockPubScreen(PubScreenName)) {
   if (pic->DRI = GetScreenDrawInfo(pic->Screen)) {
    /* Load the image using
     * and do some validation and set some gadgets
     */
    if (!(pic->MPi = LoadMPImage(filename,pic->Screen,MPIF_CLONEBITMAP | (EGS ? MPIF_EGS : 0)))) {
     e = MyGetMsg(MSG_MPIMAGELOAD);
     e1 = MPImageErrorMessage();
     hnum = HE_MPILoad;
    }
    else {
     if (pic == &Pic1) {
      if (Width == 0) {
       Width = Pic1.MPi->Width;
       GT_SetGadgetAttrs(MPMorphGadgets[GDX_Width],MPMorphWnd,NULL,
							GTNM_Number,Width,
							TAG_END );
      }
      if (Height == 0) {
       Height = Pic1.MPi->Height;
       GT_SetGadgetAttrs(MPMorphGadgets[GDX_Height],MPMorphWnd,NULL,
							GTNM_Number,Height,
							TAG_END );
      }
      xfact = (float)(Width-1) / (Pic1.MPi->Width-1);
		yfact = (float)(Height-1) / (Pic1.MPi->Height-1);
     }
     else {
      if ((Pic1.MPi->Width != Pic2.MPi->Width) ||
          (Pic1.MPi->Height != Pic2.MPi->Height)) {
       if (!RescaleMPImage(Pic2.MPi,Pic1.MPi->Width,Pic1.MPi->Height)) {
	     e = MyGetMsg(MSG_MPIMAGESCALE);
		  e1 = MPImageErrorMessage();
   	  hnum = HE_MPIScale;
   	 }
      }
     }
     /* If Zoom is allowed then we always display the Zoom bitmap
      * This is either 2x the normal bit map or just use the top left corner
      */
     if (!e) {
      if (ZoomAllowed) {
       if (!(pic->BitMap = AllocBitMap(pic->MPi->Width<<1,pic->MPi->Height<<1,pic->Screen->BitMap.Depth,0,pic->MPi->BitMap))) {
        e = MyGetMsg(MSG_UNALLOC);
        e1 = MyGetMsg(MSG_ZOOMR);
        hnum = HE_ZRaster;
       }
		 else {
	     pic->BitScaleArgs.bsa_SrcX 			= 0;
	     pic->BitScaleArgs.bsa_SrcY 			= 0;
		  pic->BitScaleArgs.bsa_SrcWidth		= pic->MPi->Width;
		  pic->BitScaleArgs.bsa_SrcHeight 	= pic->MPi->Height;
		  pic->BitScaleArgs.bsa_DestX 		= 0;
		  pic->BitScaleArgs.bsa_DestY 		= 0;
		  pic->BitScaleArgs.bsa_DestWidth 	= pic->MPi->Width<<1;
		  pic->BitScaleArgs.bsa_DestHeight	= pic->MPi->Height<<1;
		  pic->BitScaleArgs.bsa_XSrcFactor	= 1;
		  pic->BitScaleArgs.bsa_XDestFactor	= 2;
		  pic->BitScaleArgs.bsa_YSrcFactor 	= 1;
		  pic->BitScaleArgs.bsa_YDestFactor	= 2;
		  pic->BitScaleArgs.bsa_SrcBitMap 	= pic->MPi->BitMap;
		  pic->BitScaleArgs.bsa_DestBitMap	= pic->BitMap;
		  pic->BitScaleArgs.bsa_Flags 		= 0;
		  /* Either scale image 2x or straight copy	*/
 		  if (Zoom) {
 		   BitMapScale(&(pic->BitScaleArgs));
 		  }
		  else {
		   BltBitMap(pic->MPi->BitMap,0,0,
		    			  pic->BitMap,0,0,
		     			  pic->MPi->Width,pic->MPi->Height,
		     			  0xC0,0xff,NULL);
		  }
		 }
		}
     }
	 }
    if (!e) {
     pic->Left = 0;	//	Need to do this as Pic structures can be closed and reopened
     pic->Top = 0;
     if (EGS) {
     	if (EGSOpenAPicture(pic,ifilename,&e,&e1,&hnum)) {
       return TRUE;
      }
     }
     else {
      /* Allocate all gadgets and images	*/
      if (pic->BotGad = (struct Gadget *)NewObject(NULL,"propgclass",
        PGA_Freedom,		FREEHORIZ,
        PGA_NewLook,		TRUE,
        PGA_Borderless,	(pic->Screen->BitMap.Depth>1)?TRUE:FALSE,
        PGA_Top,			pic->Left,
        PGA_Visible,		pic->MPi->Width<<Zoom,
        PGA_Total,		pic->MPi->Width<<Zoom,
        ICA_TARGET,		ICTARGET_IDCMP,
        GA_Left,			pic->Screen->WBorLeft - 1,
        GA_Height,		SIZEIMAGE_H(n) - 4,
        GA_RelBottom,	-SIZEIMAGE_H(n) + 3,
        GA_RelWidth,		-(SIZEIMAGE_W(n)+LEFTIMAGE_W(n)+RIGHTIMAGE_W(n)+pic->Screen->WBorLeft+1),
        GA_ID,				LEFT_RIGHT_GADGET,
        GA_GZZGadget,	TRUE,
        GA_Immediate,	TRUE,
        GA_RelVerify,	TRUE,
        GA_BottomBorder,TRUE,
        GA_GadgetHelp,	TRUE,
        ICA_MAP,			MapToIdcmp,
        GA_UserData,		pic,
        TAG_END)) {
       if (pic->SideGad = (struct Gadget *)NewObject(NULL,"propgclass",
         PGA_Freedom,	FREEVERT,
         PGA_NewLook,	TRUE,
         PGA_Borderless,(pic->Screen->BitMap.Depth>1)?TRUE:FALSE,
         PGA_Top,			pic->Top,
         PGA_Visible,	pic->MPi->Height<<Zoom,
         PGA_Total,		pic->MPi->Height<<Zoom,
         ICA_TARGET,		ICTARGET_IDCMP,
         GA_Top,			pic->Screen->WBorTop + pic->Screen->Font->ta_YSize + 2,
         GA_Width,		VSCROLL_W(n),
         GA_RelRight,	-VSCROLL_L(n),
         GA_RelHeight,	-(pic->Screen->WBorTop+pic->Screen->Font->ta_YSize+3+UPIMAGE_H(n)+DOWNIMAGE_H(n)+SIZEIMAGE_H(n)),
         GA_ID,			UP_DOWN_GADGET,
         GA_GZZGadget,	TRUE,
         GA_Immediate,	TRUE,
         GA_RelVerify,	TRUE,
         GA_RightBorder,TRUE,
         GA_Previous,	pic->BotGad,
         GA_GadgetHelp,	TRUE,
         ICA_MAP,			MapToIdcmp,
         GA_UserData,	pic,
         TAG_END)) {
        if (pic->Limage = (struct Image *)NewObject(NULL,"sysiclass",
          SYSIA_DrawInfo,	pic->DRI,
          SYSIA_Which,		LEFTIMAGE,
          SYSIA_Size,		SYSISIZE(n),
          TAG_END)) {
         if (pic->Rimage = (struct Image *)NewObject(NULL,"sysiclass",
           SYSIA_DrawInfo,	pic->DRI,
           SYSIA_Which,		RIGHTIMAGE,
           SYSIA_Size,		SYSISIZE(n),
           TAG_END)) {
          if (pic->Dimage = (struct Image *)NewObject(NULL,"sysiclass",
            SYSIA_DrawInfo,	pic->DRI,
            SYSIA_Which,		DOWNIMAGE,
            SYSIA_Size,			SYSISIZE(n),
            TAG_END)) {
           if (pic->Uimage = (struct Image *)NewObject(NULL,"sysiclass",
             SYSIA_DrawInfo,	pic->DRI,
             SYSIA_Which,		UPIMAGE,
             SYSIA_Size,		SYSISIZE(n),
             TAG_END)) {
            if (pic->Lgad = (struct Gadget *)NewObject(NULL,"buttongclass",
              ICA_TARGET,			ICTARGET_IDCMP,
              GA_RelRight,			-(SIZEIMAGE_W(n)+RIGHTIMAGE_W(n)+LEFTIMAGE_W(n)-1),
              GA_RelBottom,		-SIZEIMAGE_H(n)+1,
              GA_Height,			LEFTIMAGE_H(n),
              GA_Width,				LEFTIMAGE_W(n),
              GA_ID,					LEFT_GADGET,
              GA_GZZGadget,		TRUE,
              GA_Immediate,		TRUE,
              GA_RelVerify,		TRUE,
              GA_BottomBorder,	TRUE,
              GA_Previous,			pic->SideGad,
              ICA_MAP,				MapToIdcmp,
              GA_Image,				pic->Limage,
              GA_UserData,			pic,
		        GA_GadgetHelp,		TRUE,
              TAG_END)) {
             if (pic->Rgad = (struct Gadget *)NewObject(NULL,"buttongclass",
               ICA_TARGET,			ICTARGET_IDCMP,
               GA_RelRight,		-(SIZEIMAGE_W(n)+RIGHTIMAGE_W(n)-1),
               GA_RelBottom,		-SIZEIMAGE_H(n)+1,
               GA_Height,			LEFTIMAGE_H(n),
               GA_Width,			LEFTIMAGE_W(n),
               GA_ID,				RIGHT_GADGET,
               GA_GZZGadget,		TRUE,
               GA_Immediate,		TRUE,
               GA_RelVerify,		TRUE,
               GA_BottomBorder,	TRUE,
               GA_Previous,		pic->Lgad,
               ICA_MAP,				MapToIdcmp,
               GA_Image,			pic->Rimage,
               GA_UserData,		pic,
					GA_GadgetHelp,		TRUE,
               TAG_END)) {
              if(pic->Ugad = (struct Gadget *)NewObject(NULL,"buttongclass",
                ICA_TARGET,		ICTARGET_IDCMP,
                GA_RelRight,		-SIZEIMAGE_W(n)+1,
                GA_RelBottom,		-(SIZEIMAGE_H(n)+UPIMAGE_H(n)+DOWNIMAGE_H(n)-1),
                GA_Height,			UPIMAGE_H(n),
                GA_Width,			UPIMAGE_W(n),
                GA_ID,				UP_GADGET,
                GA_GZZGadget,		TRUE,
                GA_Immediate,		TRUE,
                GA_RelVerify,		TRUE,
                GA_RightBorder,	TRUE,
                GA_Previous,		pic->Rgad,
                ICA_MAP,			MapToIdcmp,
                GA_Image,			pic->Uimage,
                GA_UserData,		pic,
					 GA_GadgetHelp,	TRUE,
                TAG_END)) {
               if (pic->Dgad = (struct Gadget *)NewObject(NULL,"buttongclass",
                 ICA_TARGET,		ICTARGET_IDCMP,
                 GA_RelRight,		-SIZEIMAGE_W(n)+1,
                 GA_RelBottom,	-(SIZEIMAGE_H(n)+DOWNIMAGE_H(n)-1),
                 GA_Height,		DOWNIMAGE_H(n),
                 GA_Width,			DOWNIMAGE_W(n),
                 GA_ID,				DOWN_GADGET,
                 GA_GZZGadget,	TRUE,
                 GA_Immediate,	TRUE,
                 GA_RelVerify,	TRUE,
                 GA_RightBorder,	TRUE,
                 GA_Previous,		pic->Ugad,
                 ICA_MAP,			MapToIdcmp,
                 GA_Image,			pic->Dimage,
                 GA_UserData,		pic,
					  GA_GadgetHelp,	TRUE,
                 TAG_END)) {
                /* Set up size of shrunk window	*/
                pic->Zoom.Left 		= 0;
                pic->Zoom.Top 		= pic->Screen->Font->ta_YSize+1;
                pic->Zoom.Width 	= max(ZOOMIMAGE_W(n)+DEPTHIMAGE_W(n)+CLOSEIMAGE_W(n)+1,
                  							pic->Screen->WBorLeft+SIZEIMAGE_W(n)+LEFTIMAGE_W(n)+RIGHTIMAGE_W(n)+7);
                pic->Zoom.Height 	= pic->Screen->WBorTop+pic->Screen->Font->ta_YSize+
                	 						  SIZEIMAGE_H(n)+UPIMAGE_H(n)+DOWNIMAGE_H(n)+8;
                /* Copy filename for title and open the window */
                if (pic->filename 	= AllocVec(strlen(ifilename)+1+20,MEMF_CLEAR)) {	// Extra for other frames
                 strcpy(pic->filename,ifilename);
                 if (pic->Win = OpenWindowTags(NULL,
                   WA_Width,			(pic->MPi->Width<<Zoom)+
                   				 		 pic->Screen->WBorLeft+SIZEIMAGE_W(n),
                   WA_Height,			(pic->MPi->Height<<Zoom)+
                 							 pic->Screen->WBorTop+pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n),
                   WA_AutoAdjust,	TRUE,
                   WA_MaxWidth,		(pic->MPi->Width<<Zoom)+
                   						 pic->Screen->WBorLeft+SIZEIMAGE_W(n),
                   WA_MaxHeight,		(pic->MPi->Height<<Zoom)+
                    						 pic->Screen->WBorTop + pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n),
                   WA_MinWidth,		pic->Zoom.Width,
                   WA_MinHeight,		pic->Zoom.Height,
                   WA_IDCMP,			0,
                   WA_Flags,			WFLG_SIZEGADGET | WFLG_SIZEBRIGHT | WFLG_SIZEBBOTTOM |
                   	 					WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
                     					WFLG_SUPER_BITMAP + WFLG_GIMMEZEROZERO | WFLG_NOCAREREFRESH,
                   WA_Gadgets,		pic->BotGad,
                   WA_Title,			FilePart(pic->filename),
                   WA_ScreenTitle,	pic->filename,
                   WA_PubScreen,		pic->Screen,
                   WA_SuperBitMap,	(ZoomAllowed ? pic->BitMap : pic->MPi->BitMap),
                   /* Open image 1 to the right of the control window
                    * Image 2 to the bottom right of the 1st image
                    */
                   WA_Left, 			((pic == &Pic1) ?
                   					    ControlWindow->Width :
                    						 ControlWindow->Width+Pic1.Win->Width),
                   WA_Top, 			((pic == &Pic1) ?
                    						 ControlWindow->TopEdge :
                    						 Pic1.Win->Height+Pic1.Win->TopEdge),
				 		 WA_MenuHelp,		TRUE,
				 	    WA_NewLookMenus,	TRUE,
						 Check ? WA_Checkmark: TAG_IGNORE,	Check,
						 Amiga ? WA_AmigaKey : TAG_IGNORE,	Amiga,
				 	    WA_HelpGroup,		HelpGroup,
                   TAG_DONE)) {
                  pic->AppWindow = AddAppWindow(0,(ULONG)pic,pic->Win,AMsgPortp,
                  										TAG_END);
                  // Enable gadget Help
                  HelpControl(pic->Win,HC_GADGETHELP);
                  /* Set user data to determine window
                   * and use shared message port
                   */
                  pic->Win->UserData  = (BYTE *)pic;
                  pic->Win->UserPort	= WMsgPortp;
                  ModifyIDCMP(pic->Win,MYIDCMP_VERIFY);
                  pic->Win->Flags |= WFLG_REPORTMOUSE;
						/* Set mode to draw and erase points easily	*/
						SetDrMd(pic->Win->RPort,COMPLEMENT);
						/* Set the (shared with Control Window) menu
						 * and do some size calculations
						 */
						if (SetMenuStrip(pic->Win,MyMenu)) {
                   doNewSize(pic);
                   return (TRUE);							// It all worked !!!
                  }
                  /* Set relevant error message	*/
                  if (!e) {
                   e = MyGetMsg(MSG_UNABLE);
                   e1 = MyGetMsg(MSG_SETMENU);
                   hnum = HE_Menu;
                  }
                 }
                 if (!e) {
                  e = MyGetMsg(MSG_UNABLE);
                  e1 = MyGetMsg(MSG_OPENW);
                  hnum = HE_OWindow;
                 }
                }
                if (!e) {
                 e = MyGetMsg(MSG_UNABLE);
                 e1 = MyGetMsg(MSG_ALLOCFIL);
                 hnum = HE_MemFile;
                }
               }
               if (!e) {
                e = MyGetMsg(MSG_UNALLOC);
                e1 = MyGetMsg(MSG_DOWNG);
                hnum = HE_AllocGadget;
               }
              }
              if (!e) {
               e = MyGetMsg(MSG_UNALLOC);
               e1 = MyGetMsg(MSG_UPG);
               hnum = HE_AllocGadget;
              }
             }
             if (!e) {
              e = MyGetMsg(MSG_UNALLOC);
              e1 = MyGetMsg(MSG_RIGHTG);
              hnum = HE_AllocGadget;
             }
            }
            if (!e) {
             e = MyGetMsg(MSG_UNALLOC);
             e1 = MyGetMsg(MSG_LEFTG);
             hnum = HE_AllocGadget;
            }
           }
           if (!e) {
            e = MyGetMsg(MSG_UNALLOC);
            e1 = MyGetMsg(MSG_UPI);
            hnum = HE_AllocImage;
           }
          }
          if (!e) {
           e = MyGetMsg(MSG_UNALLOC);
           e1 = MyGetMsg(MSG_DOWNI);
           hnum = HE_AllocImage;
          }
         }
         if (!e) {
          e = MyGetMsg(MSG_UNALLOC);
          e1 = MyGetMsg(MSG_RIGHTI);
          hnum = HE_AllocImage;
         }
        }
        if (!e) {
         e = MyGetMsg(MSG_UNALLOC);
         e1 = MyGetMsg(MSG_LEFTI);
         hnum = HE_AllocImage;
        }
       }
       if (!e) {
        e = MyGetMsg(MSG_UNALLOC);
        e1 = MyGetMsg(MSG_VGAD);
        hnum = HE_AllocGadget;
       }
      }
      if (!e) {
       e = MyGetMsg(MSG_UNALLOC);
       e1 = MyGetMsg(MSG_HGAD);
       hnum = HE_AllocGadget;
      }
     }
    }
   }
   if (!e) {
    e = MyGetMsg(MSG_UNABLE);
    e1 = MyGetMsg(MSG_GEMPDI);
    hnum = HE_GetDRI;
   }
  }
  if (!e) {
   e = MyGetMsg(MSG_LOCKPUBS);
   e1 = PubScreenName;
   hnum = HE_LockScreen;
  }
  /* Clear everything down
   * and display an error message if requested
   */
  CloseAPicture(pic);
  if (GUI) {
   Error(e,MyGetMsg(MSG_OK),e1,hnum);
  }
 }
 return(FALSE);
}

/* Close a (partially open)
 * picture, clearing everything
 * down in reverse order
 */
void
CloseAPicture(struct Picture *pic) {
	if (pic) {
		if (EGS) {
			EGSCloseAPicture(pic);
		}
		if (pic->AppWindow) {
			RemoveAppWindow(pic->AppWindow);
			pic->AppWindow = NULL;
		}
		if (pic->Win) {
			ClearMenuStrip(pic->Win);
			CloseWindowSafely(pic->Win);
			pic->Win = NULL;
		}
		if (pic->filename) {
			FreeVec(pic->filename);
			pic->filename = NULL;
		}
		if (pic->Dgad) {
			DisposeObject(pic->Dgad);
			pic->Dgad = NULL;
		}
		if (pic->Ugad) {
			DisposeObject(pic->Ugad);
			pic->Ugad = NULL;
		}
		if (pic->Rgad) {
			DisposeObject(pic->Rgad);
			pic->Rgad = NULL;
		}
		if (pic->Lgad) {
			DisposeObject(pic->Lgad);
			pic->Lgad = NULL;
		}
		if (pic->Uimage) {
			DisposeObject(pic->Uimage);
			pic->Uimage = NULL;
		}
		if (pic->Dimage) {
			DisposeObject(pic->Dimage);
			pic->Dimage = NULL;
		}
		if (pic->Rimage) {
			DisposeObject(pic->Rimage);
			pic->Rimage = NULL;
		}
		if (pic->Limage) {
			DisposeObject(pic->Limage);
			pic->Limage = NULL;
		}
		if (pic->SideGad) {
			DisposeObject(pic->SideGad);
			pic->SideGad = NULL;
		}
		if (pic->BotGad) {
			DisposeObject(pic->BotGad);
			pic->BotGad = NULL;
		}
		if (pic->BitMap) {
			FreeBitMap(pic->BitMap);
		}
		if (pic->MPi) {
			if (pic->MPi->BitMap) {
				FreeBitMap(pic->MPi->BitMap);
				pic->MPi->BitMap = NULL;
			}
			FreeMPImage(pic->MPi);
			pic->MPi = NULL;
		}
		if (pic->Screen) {
			if (pic->DRI) {
				FreeScreenDrawInfo(pic->Screen,pic->DRI);
				pic->DRI = NULL;
			}
			UnlockPubScreen(NULL,pic->Screen);
			pic->Screen = NULL;
		}
	}
}

/* After opening or resizing a window
 * this does various gadget recalculations
 */
void
doNewSize(struct Picture *pic) {
	ULONG tmp;
	/* If window made wider then may need to scroll image
	 * right to prevent gap on the right
	 */
	tmp = pic->Win->RPort->Layer->Scroll_X + pic->Win->GZZWidth;
	if (tmp >= (pic->MPi->Width<<Zoom)) {
		ScrollLayer(0,pic->Win->RPort->Layer,(pic->MPi->Width<<Zoom)-tmp,0);
		pic->Left += (pic->MPi->Width<<Zoom)-tmp;
	}
	/* Update sideways gadget and recalculate movement */
	SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
						PGA_Visible, pic->Win->GZZWidth,
						PGA_Top, pic->Left, TAG_END);
	pic->ALeft = pic->Win->GZZWidth/10;
	pic->MLeft = (pic->MPi->Width<<Zoom) - pic->Win->GZZWidth;
	/* If window made taller then may need to scroll image
	 * down to prevent gap at the bottom
	 */
	tmp = pic->Win->RPort->Layer->Scroll_Y + pic->Win->GZZHeight;
	if (tmp >= (pic->MPi->Height<<Zoom)) {
		ScrollLayer(0,pic->Win->RPort->Layer,0,(pic->MPi->Height<<Zoom)-tmp);
		pic->Top += (pic->MPi->Height<<Zoom)-tmp;
	}
	/* Update vertical gadget and recalculate movement */
	SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
						PGA_Visible, pic->Win->GZZHeight,
						PGA_Top, pic->Top, TAG_END);
	pic->ATop = pic->Win->GZZHeight/10;
	pic->MTop = (pic->MPi->Height<<Zoom) - pic->Win->GZZHeight;
}

/* Scroll the image when required */
void
checkGadget(struct Picture *pic) {
	WORD dX;
	WORD dY;
	if (!EGS) {
		dY = pic->Top-pic->XTop;
		dX = pic->Left-pic->XLeft;
		if (dX || dY) {
			ScrollLayer(0,pic->Win->RPort->Layer,dX,dY);
		}
	}
}

static struct MyPoint TPoint = {0};

static struct MyOff {
	BYTE x;
	BYTE y;
} Off[] = {-2,-2, -1,-2,  0,-2, +1,-2, +2,-2,
			  -2,-1, -2, 0, -2,+1, -2,+2, +2,-1,
			  +2, 0, +2,+1, -1,+2,  0,+2, +1,+2,
			  +2,+2, -1,-1,  0,-1, +1,-1, -1, 0,
			   0, 0, +1, 0, -1,+1,  0,+1, +1,+1
};

void
UpdatePens(struct MyPoint *MyPoint) {
	if (!EGS) {
		int i;
		for (i=0; i<16; ++i) {
			MyPoint->Pen1[i] = TPoint.Pen1[i];
			MyPoint->Pen2[i] = TPoint.Pen2[i];
		}
		MyPoint->Drawn1 = TRUE;
		TPoint.Drawn1 = FALSE;
		MyPoint->Drawn2 = TRUE;
		TPoint.Drawn2 = FALSE;
	}
}

/* Draw a point and linked lines if required
 * if MyPoint is not supplied the just draw the point
 */
void
DrawPixels(struct Picture *pic,SHORT x,SHORT y,struct MyPoint *MyPoint) {
	SHORT zx,zy;
	struct MyPoint *MyPoint1;
	UBYTE *Pen;
	int i;
	if (EGS) {
		EGSDrawPixels(pic,x,y,MyPoint);
	}
	else {
		/* Scale coordinates if zoomed
		 * and draw 3x3 point
		 */

		zx = ((x << Zoom) + (xfact/2))/xfact;
		zy = ((y << Zoom) + (yfact/2))/yfact;

		if (MyPoint) {
			MyPoint1 = MyPoint;
		}
		else {
			MyPoint1 = &TPoint;
		}
		if (pic == &Pic1) {
			Pen = &(MyPoint1->Pen1[0]);
		}
		else {
			Pen = &(MyPoint1->Pen2[0]);
		}
		/* Draw linked lines in the correct window if MyPoint supplied
		 * Note: MyDraw is like Draw only it always draws top left to bottom right
		 * 		to prevent problems when erasing lines in the other direction
		 */
		if (((pic == &Pic1) && (MyPoint1->Drawn1)) ||
			 ((pic == &Pic2) && (MyPoint1->Drawn2))) {
			if (MyPoint) {
				SetDrMd(pic->Win->RPort,COMPLEMENT);
				for (i = 0;
					  i < MAX_LINKS;
					  i++) {
					if (MyPoint->p[i]) {
						if (pic == &Pic2) {
							MyDraw(pic->Win->RPort,MyPoint->p[i]->x1<<Zoom,MyPoint->p[i]->y1<<Zoom,x<<Zoom,y<<Zoom);
						}
						else {
							MyDraw(pic->Win->RPort,MyPoint->p[i]->x<<Zoom,MyPoint->p[i]->y<<Zoom,x<<Zoom,y<<Zoom);
						}
					}	
				}
			}
			SetDrMd(pic->Win->RPort,JAM1);
			for (i=0; i<16; ++i) {
				SetAPen(pic->Win->RPort,Pen[i]);
				WritePixel(pic->Win->RPort,zx+Off[i].x,zy+Off[i].y);
			}
			SetDrMd(pic->Win->RPort,COMPLEMENT);
		}
		else {
			for (i=0; i<16; ++i) {
				Pen[i] = ReadPixel(pic->Win->RPort,zx+Off[i].x,zy+Off[i].y);
			}
			SetDrMd(pic->Win->RPort,JAM1);
			SetAPen(pic->Win->RPort,pic->DRI->dri_Pens[SHINEPEN]);
			for (i=0; i<9; ++i) {
				WritePixel(pic->Win->RPort,zx+Off[i].x,zy+Off[i].y);
			}
			SetAPen(pic->Win->RPort,pic->DRI->dri_Pens[SHADOWPEN]);
			for (i=9; i<16; ++i) {
				WritePixel(pic->Win->RPort,zx+Off[i].x,zy+Off[i].y);
			}
			SetDrMd(pic->Win->RPort,COMPLEMENT);
		}
		for (i=16; i<25; ++i) {
			WritePixel(pic->Win->RPort,zx+Off[i].x,zy+Off[i].y);
		}
		/* Draw linked lines in the correct window if MyPoint supplied
		 * Note: MyDraw is like Draw only it always draws top left to bottom right
		 * 		to prevent problems when erasing lines in the other direction
		 */
		if (pic == &Pic2) {
			if (!MyPoint1->Drawn2) {
				if (MyPoint) {
					for (i = 0;
						  i < MAX_LINKS;
						  i++) {
						if (MyPoint->p[i]) {
							MyDraw(pic->Win->RPort,MyPoint->p[i]->x1<<Zoom,MyPoint->p[i]->y1<<Zoom,x<<Zoom,y<<Zoom);
						}
					}	
				}
			}
			MyPoint1->Drawn2 = !MyPoint1->Drawn2;
		}
		if (pic == &Pic1) {
			if (!MyPoint1->Drawn1) {
				if (MyPoint) {
					for (i = 0;
						  i < MAX_LINKS;
						  i++) {
						if (MyPoint->p[i]) {
							MyDraw(pic->Win->RPort,MyPoint->p[i]->x<<Zoom,MyPoint->p[i]->y<<Zoom,x<<Zoom,y<<Zoom);
						}
					}
				}
			}
			MyPoint1->Drawn1 = !MyPoint1->Drawn1;
		}
	}
}	

/* Delete all points
 * Erasing them if images are open
 */
void
DeleteAllPoints(void) {
	struct MyPoint *MyPoint;
	/* Loop round looking at the first point every time
	 * since DeletePoint removes it from the list
	 */
	while ((MyPoint = (struct MyPoint *)PointList.lh_Head)->MyNode.mln_Succ) {
		if (Pic1_Open) {
			DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
		}
		if (Pic2_Open) {
			DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
		}
		DeletePoint(MyPoint);
	}
}

static void
UpdateRecents(char *ifilename) {
	if (Stricmp(Recent1,ifilename)) {
		if (Stricmp(Recent2,ifilename)) {
			if (Stricmp(Recent3,ifilename)) {
				if (Stricmp(Recent4,ifilename)) {
					strcpy(Recent5,Recent4);
					strcpy(Recent4,Recent3);
					strcpy(Recent3,Recent2);
					strcpy(Recent2,Recent1);
					strcpy(Recent1,ifilename);
				}
				else {
					strcpy(Recent4,Recent3);
					strcpy(Recent3,Recent2);
					strcpy(Recent2,Recent1);
					strcpy(Recent1,ifilename);
				}
			}
			else {
				strcpy(Recent3,Recent2);
				strcpy(Recent2,Recent1);
				strcpy(Recent1,ifilename);
			}
		}
		else {
			strcpy(Recent2,Recent1);
			strcpy(Recent1,ifilename);
		}
	}
	ClearMenuStrip( MPMorphWnd );
	FreeMenus( MPMorphMenus );
	UpdateMenuDefs();
	MPMorphNewMenu[M_NM_RECENT1].nm_Label = FilePart(Recent1);
	MPMorphNewMenu[M_NM_RECENT2].nm_Label = FilePart(Recent2);
	MPMorphNewMenu[M_NM_RECENT3].nm_Label = FilePart(Recent3);
	MPMorphNewMenu[M_NM_RECENT4].nm_Label = FilePart(Recent4);
	MPMorphNewMenu[M_NM_RECENT5].nm_Label = FilePart(Recent5);
	MPMorphMenus = CreateMenus( MPMorphNewMenu,
										GTMN_FullMenu,TRUE,
										TAG_DONE );
	LayoutMenus( MPMorphMenus, VisualInfo, 
					GTMN_NewLookMenus,TRUE,
					Amiga ? GTMN_AmigaKey : TAG_IGNORE, Amiga,
					Check ? GTMN_Checkmark : TAG_IGNORE, Check,
					TAG_DONE );
	SetMenuStrip( MPMorphWnd, MPMorphMenus );
}

/* Open a project
 * Suggests you save first if not already saved
 * Returns		: TRUE or FALSE for how well it went
 * filename		: file name to open - if NULL then display ASL file requeseter
 * JustPoints	: If TRUE then only the points are used
 * Gui         : Display error messages
 */
BOOL
MyOpen(char *filename,BOOL JustPoints,BOOL Gui) {
	LONG PointCount	= 0;		// Number of points read
	LONG i;							// General loop counter
	char *ifilename	= NULL;	// File name to use
	BOOL ok				= TRUE;	// Is it all working?
	BPTR fh;							// File handle
	char buffer[257];				// Buffer to read records
	LONG w=0,h=0;					// Width and Height
	LONG x,x1,y,y1;				// Coordinates in image 1 and 2
	LONG p1,p2;						// Index to linked points
	LONG Frames=0;					// Number of frames
	struct MyPoint *MyPoint,	// Points to create and link
						*MyPoint1;
	BOOL JP = FALSE;				// Set if 2.0 points file
	BOOL notEOF = TRUE;
	/* If current project not saved then suggest it is saved	*/
	if (!Saved) {
		if (!SaveRequester()) {
			return FALSE;
		}
	}
	Saved = TRUE;
	DisableWindows(DI_WaitOpen);
	/* Get filename, from parameter or ASL requester, save name for saving later */
	if (filename) {
		strcpy(TempFilename,filename);
		ifilename = TempFilename;
	}
	else {
		if (GetAFile(*savedfilename?savedfilename:"",
						 (Tag) JustPoints ? MyGetMsg(MSG_LOADPO): MyGetMsg(MSG_LOADPR),
						 0, NULL,MyGetMsg(MSG_OPEN))) {
			ifilename=TempFilename;
		}
  	}
  	/* If we have a filename then delete current points and set the window title	*/
	if (ifilename) {
		if (fh=Open(ifilename,MODE_OLDFILE)) {
			if (JustPoints) {
				Record(MyGetMsg(MSG_RECOPENP),(ULONG)ifilename);
			}
			else {
				Record(MyGetMsg(MSG_RECOPEN),(ULONG)ifilename);
			}
			UpdateRecents(ifilename);
			DeleteAllPoints();
			if (!JustPoints) {
				Width = 0;
				Height = 0;
				OpenNewArgs(ifilename);		// Load new parameters
				InitParams(FALSE);
				strncpy(savedfilename,ifilename,256);
				SetWindowTitles(MPMorphWnd,(UBYTE *)-1,savedfilename);
			}
			// Get header
			FGets(fh,buffer,256);
			if (JustPoints && (JP = !strcmp(buffer,MyGetMsg(MSG_TSM20)))) {
//				DeleteAllPoints();
			}	// We always delete them above!!!!
			else {
				if (strcmp(buffer,MyGetMsg(MSG_TSM12))) {
					Error(MyGetMsg(MSG_VERS10),MyGetMsg(MSG_OK),NULL,HE_OldFormat);
				}
				else {
					// Name of first image
					FGets(fh,buffer,256);
				}
			}
			if (!JustPoints) {
				if (strlen(buffer)) {
					buffer[strlen(buffer)-1]=0;
				}
				GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL,
										GTST_String, buffer, TAG_END );
			}
			// Name of second image
			if (!JP) {
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL,
											GTST_String, buffer, TAG_END );
				}
				// 24 bit name of first image
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					GT_SetGadgetAttrs(MPMorphGadgets[GDX_File241],MPMorphWnd,NULL,
											GTST_String, buffer, TAG_END );
				}
				// 24 bit name of second image
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					GT_SetGadgetAttrs(MPMorphGadgets[GDX_File242],MPMorphWnd,NULL,
											GTST_String, buffer, TAG_END );
				}
				// Name of animation
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (strlen(buffer)) {
						buffer[strlen(buffer)-1]=0;
					}
					GT_SetGadgetAttrs(MPMorphGadgets[GDX_Name],MPMorphWnd,NULL,
											GTST_String, buffer, TAG_END );
				}
				// General stuff
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (ok && (sscanf(buffer,MyGetMsg(MSG_WHFSS),&w,&h,&Frames,&SinglePicture,&Start) != 5)) {
						Error(MyGetMsg(MSG_INVLINE),MyGetMsg(MSG_OK),buffer,HE_FileFormat);
						ok = FALSE;
					}
					else {
						GT_SetGadgetAttrs(MPMorphGadgets[GDX_Frames],MPMorphWnd,NULL,
												GTIN_Number,Frames, TAG_END );
						GT_SetGadgetAttrs(MPMorphGadgets[GDX_Start],MPMorphWnd,NULL,
													GTIN_Number,Start, TAG_END );
						GT_SetGadgetAttrs(MPMorphGadgets[GDX_SinglePicture],MPMorphWnd,NULL,
												GTCY_Active,SinglePicture, TAG_END );
					}
				}
			}
			if (ok) {
				MaxWidth 	= 0;
				MaxHeight 	= 0;
				// Read and validate point
				while (ok &&
					FGets(fh,buffer,256) &&
					(sscanf(buffer,MyGetMsg(MSG_XYX1Y1),&x,&y,&x1,&y1) == 4)) {
					// Create point and add to list
					if (MyPoint = AllocMem(sizeof(struct MyPoint),MEMF_CLEAR)) {
						MyPoint->x = x;
						MyPoint->y = y;
						MyPoint->x1 = x1;
						MyPoint->y1 = y1;
						MaxWidth = max(x,MaxWidth);
						MaxWidth = max(x1,MaxWidth);
						MaxHeight = max(y,MaxHeight);
						MaxHeight = max(y1,MaxHeight);
						AddTail(&PointList,(struct Node *)MyPoint);
						++PointCount;
						if (ControlWindow) {
							// If the windows are open then actually draw the points
							DrawPixels(&Pic1,x,y,MyPoint);
							DrawPixels(&Pic2,x1,y1,MyPoint);
						}
					}
					else {
						Error(MyGetMsg(MSG_OOMPO),MyGetMsg(MSG_OK),NULL,HE_MemPoints);
						ok=FALSE;
					}
				}
				Width = max(Width,max(w,MaxWidth));
				Height = max(Height,max(h,MaxHeight));
				if (Pic1_Open) {
					xfact = (float)(Width-1) / (Pic1.MPi->Width-1);
					yfact = (float)(Height-1) / (Pic1.MPi->Height-1);
				}
				GT_SetGadgetAttrs(MPMorphGadgets[GDX_Width],MPMorphWnd,NULL,
										GTNM_Number,Width, TAG_END );
				GT_SetGadgetAttrs(MPMorphGadgets[GDX_Height],MPMorphWnd,NULL,
										GTNM_Number,Height, TAG_END );
				// Read all the links
				while (ok && notEOF &&
					(sscanf(buffer,MyGetMsg(MSG_P1P2),&p1,&p2) == 2)) {
					if ((p1>PointCount) || (p2>PointCount)) {
						Error(MyGetMsg(MSG_INVPOLI),MyGetMsg(MSG_OK),buffer,HE_InvLink);
						ok = FALSE;
					}
					else {
						// Link two points based on indexes to linked lists
						i = 0;
						MyPoint = (struct MyPoint *)PointList.lh_Head;
						while (i < p1) {
							MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ;
							++i;
						}
						i = 0;
						MyPoint1 = (struct MyPoint *)PointList.lh_Head;
						while (i < p2) {
							MyPoint1 = (struct MyPoint *)MyPoint1->MyNode.mln_Succ;
							++i;
						}
						LinkPoints(MyPoint,MyPoint1);
					}
					if (!FGets(fh,buffer,256)) {
						notEOF = FALSE;
					}
				}
			}
			// Close file and return cleanly
			if (!Close(fh)) {
				if (ok) {
					Error(MyGetMsg(MSG_ECLOF),MyGetMsg(MSG_OK),ifilename,HE_Close);
					ok = FALSE;
				}
			}
		}
		else {
			if (Gui) {
				Error(MyGetMsg(MSG_EOPF),MyGetMsg(MSG_OK),ifilename,HE_Open);
			}
			ok = FALSE;
		}
	}
	if (ok && !JustPoints) {
		Saved = TRUE;
	}
	else {
		if (ok && JustPoints) {
			Saved = FALSE;
			CurrentTime(&USecs,&Um);
		}
	}
	EnableWindows();
	CurrentTime(&USecs,&Um);
	return ok;
}

BOOL ISaveAs(char *filename,BOOL errors) {
	BPTR fh;							// File handle
	char buffer[257];				// buffer to write records
	BOOL ok;							// How well is it going
	struct MyPoint *MyPoint,	// Points to write
						*MyPoint1;
	LONG i,							// Loop counters
		  j,
		  k;
	if (fh=Open(filename,MODE_NEWFILE)) {
		FPuts(fh,MyGetMsg(MSG_TSM12));
		FPuts(fh,GetString(MPMorphGadgets[GDX_FileOne]));
		FPuts(fh,MyGetMsg(MSG_SN));
		FPuts(fh,GetString(MPMorphGadgets[GDX_FileTwo]));
		FPuts(fh,MyGetMsg(MSG_SN));
		FPuts(fh,GetString(MPMorphGadgets[GDX_File241]));
		FPuts(fh,MyGetMsg(MSG_SN));
		if ((SinglePicture == 0) || (SinglePicture == 2)) {
			FPuts(fh,GetString(MPMorphGadgets[GDX_File242]));
		}
		FPuts(fh,MyGetMsg(MSG_SN));
		FPuts(fh,GetString(MPMorphGadgets[GDX_Name]));
		FPuts(fh,MyGetMsg(MSG_SN));
		sprintf(buffer,MyGetMsg(MSG_WHFSSN),
				  Width,Height,GetNumber(MPMorphGadgets[GDX_Frames]),SinglePicture,GetNumber(MPMorphGadgets[GDX_Start]));
		ok = !FPuts(fh,buffer);
		if ((SinglePicture == 2) || (SinglePicture == 3)) {
			if (ControlWindow) {
				if (!Close(fh)) {
					if (ok) {
						if (errors) {
							Error(MyGetMsg(MSG_ECLOF),MyGetMsg(MSG_OK),filename,HE_Close);
						}
						ok = FALSE;
					}
				}
				strcpy(buffer,filename);
				strcat(buffer,MyGetMsg(MSG_03LD));
				sprintf(TempFilename,buffer,FrameNumber);
				filename = TempFilename;
				if (fh=Open(filename,MODE_NEWFILE)) {
					FPuts(fh,MyGetMsg(MSG_TSM20));
				}
				else {
					if (errors) {
						Error(MyGetMsg(MSG_EOPF),MyGetMsg(MSG_OK),filename,HE_Open);
					}
					ok = FALSE;
				}
			}
		}
		// Write out all the points
		for (MyPoint = (struct MyPoint *)PointList.lh_Head;
				MyPoint->MyNode.mln_Succ && ok;
				MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
			sprintf(buffer,MyGetMsg(MSG_XYX1Y1N),MyPoint->x,MyPoint->y,MyPoint->x1,MyPoint->y1);
			ok = !FPuts(fh,buffer);
		}
		// Write out all the links
		i = 0;
		for (MyPoint = (struct MyPoint *)PointList.lh_Head;
				MyPoint->MyNode.mln_Succ && ok;
				MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
			j = 0;
			for (MyPoint1= (struct MyPoint *)PointList.lh_Head;
					MyPoint1->MyNode.mln_Succ;
					MyPoint1 = (struct MyPoint *)MyPoint1->MyNode.mln_Succ) {
				// Only write each link once
				if (j>i) {
					for (k = 0;
						  k < MAX_LINKS;
						  k++) {
						if (MyPoint->p[k] == MyPoint1) {
							sprintf(buffer,MyGetMsg(MSG_P1P2N),i,j);
							ok = !FPuts(fh,buffer);
						}
					}
				}
				++j;
			}
			++i;
		}
		if (!ok && errors) {
			Error(MyGetMsg(MSG_EWRR),MyGetMsg(MSG_OK),filename,HE_Write);
		}
		// Close file and clean up
		if (!Close(fh)) {
			if (ok) {
				if (errors) {
					Error(MyGetMsg(MSG_ECLOF),MyGetMsg(MSG_OK),filename,HE_Close);
				}
				ok = FALSE;
			}
		}
	}
	else {
		if (errors) {
			Error(MyGetMsg(MSG_EOPF),MyGetMsg(MSG_OK),filename,HE_Open);
		}
		ok = FALSE;
	}
	return ok;
}

/* Saves a project
 * Returns		: TRUE or FALSE for how well it went
 * filename		: file name to open - if NULL then display ASL file requeseter
 */
BOOL
SaveAs(char *filename) {
	char *ifilename	= NULL;	// File name to use
	struct DiskObject *MyDiskObject;	// The Icon
	BOOL ok;							// How well is it going

	/* Set up the file name from the parameter or using and ASL requester	*/
	if (filename && *filename) {
		ifilename = filename;
		strncpy(savedfilename,filename,256);
	}
	else {
		if (GetAFile(*savedfilename?savedfilename:"",MyGetMsg(MSG_SAVEP),FRF_DOSAVEMODE,NULL,MyGetMsg(MSG_SAVE))) {
			ifilename=TempFilename;
			strncpy(savedfilename,TempFilename,256);
		}
  	}
  	/* If we have a file name then set the window title
  	 * and write out the fixed information
  	 */
	if (ifilename) {
		Record(MyGetMsg(MSG_RECSAVE),(ULONG)ifilename);
		UpdateRecents(ifilename);
		SetWindowTitles(MPMorphWnd,(UBYTE *)-1,savedfilename);
		ok = ISaveAs(ifilename,TRUE);
		// Write Icon if required and none already exists
		if (ok) {
			if (CreateIcons) {
				if (MyDiskObject = GetDiskObject(savedfilename)) {
					FreeDiskObject(MyDiskObject);
				}
				else {
					if ((MyDiskObject = GetDiskObject(MyGetMsg(MSG_MDEFPTS))) ||
					    (MyDiskObject = GetDiskObject(MyGetMsg(MSG_SDEFPTS))) ||
						 (MyDiskObject = GetDefDiskObject(WBPROJECT))) {
						PutDiskObject(savedfilename,MyDiskObject);
						FreeDiskObject(MyDiskObject);
					}
				}
			}
			Saved = TRUE;
		}
	}
	else {
		ok = FALSE;
	}
	return ok;
}

/* Set editing mode
 * This sets the window title, pointer, gadgets, menus etc.
 */
void
MySetMode(UWORD NewMode) {
	UWORD 			oldpos;				// Pointer to unlink gadgets
	UWORD 			menupos=0;			// menu pointer
	struct Gadget 	*Gadget1	= NULL;	// Gadget to update
	ULONG				HNum=0;
	// Determine "current" menu and gadget
	switch(Mode) {
	case EDIT1:
		Gadget1 = &OneGadget;
		menupos = MI_EDITONE;
		break;
	case EDIT2:
		Gadget1 = &TwoGadget;
		menupos = MI_EDITTWO;
		break;
	case EDITREL:
	 	Gadget1 = &RelGadget;
		menupos = MI_EDITREL;
	 	break;
	case ADD:
		Gadget1 = &MyAddGadget;
		menupos = MI_ADD;
		break;
	case DELETE:
		Gadget1 = &DelGadget;
		menupos = MI_DELETE;
		break;
	case LINK1:
	case LINK2:
	case LINK2A:
		Gadget1 = &LinkGadget;
		menupos = MI_LINK;
		break;
	case UNLINK1:
	case UNLINK2:
	case UNLINK2A:
		Gadget1 = &UnlinkGadget;
		menupos = MI_UNLINK;
		break;
	case NONE:
		Gadget1 = &NoneGadget;
		menupos = MI_NONE;
		break;
	}
	// Unselect old gadget
	oldpos = RemoveGList(ControlWindow,Gadget1,1);
	Gadget1->Flags &= ~GFLG_SELECTED;
	AddGList(ControlWindow,Gadget1,oldpos,1,NULL);
	RefreshGList(Gadget1,ControlWindow,NULL,1);
	/* Remove menus and
	 * Unselect old menu item
	 * Actually unselects all (why?)
	 */
	if (!EGS) {
		if (Pic1_Open) {
			ClearMenuStrip(Pic1.Win);
		}
		if (Pic2_Open) {
			ClearMenuStrip(Pic2.Win);
		}
	}
	ClearMenuStrip(ControlWindow);
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITONE)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITTWO)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITREL)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_ADD)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_DELETE)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_LINK)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_UNLINK)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,MI_NONE)))->Flags &= ~CHECKED;
	// Determine "new" title, gadget and menu
	switch (NewMode) {
	case EDIT1:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_1),(UBYTE *)-1);
		Gadget1 = &OneGadget;
		menupos = MI_EDITONE;
		HNum = H_EOne;
		break;
	case EDIT2:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_2),(UBYTE *)-1);
		Gadget1 = &TwoGadget;
		menupos = MI_EDITTWO;
		HNum = H_ETwo;
		break;
	case EDITREL:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_REL),(UBYTE *)-1);
	 	Gadget1 = &RelGadget;
		menupos = MI_EDITREL;
		HNum = H_ERel;
		break;
	case ADD:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_ADD),(UBYTE *)-1);
	  	Gadget1 = &MyAddGadget;
		menupos = MI_ADD;
		HNum = H_EAdd;
		break;
	case DELETE:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_DEL),(UBYTE *)-1);
	  	Gadget1 = &DelGadget;
		menupos = MI_DELETE;
		HNum = H_EDel;
		break;
	case LINK1:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_L1),(UBYTE *)-1);
	  	Gadget1 = &LinkGadget;
		menupos = MI_LINK;
		HNum = H_ELnk;
		break;
	case UNLINK1:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_U1),(UBYTE *)-1);
	  	Gadget1 = &UnlinkGadget;
		menupos = MI_UNLINK;
		HNum = H_EUnl;
		break;
	case NONE:
		SetWindowTitles(ControlWindow,MyGetMsg(MSG_MOV),(UBYTE *)-1);
	 	Gadget1 = &NoneGadget;
		menupos = MI_NONE;
		HNum = H_EMov;
		break;
	}
	// Select new gadget
	oldpos = RemoveGList(ControlWindow,Gadget1,1);
	Gadget1->Flags |= GFLG_SELECTED;
	AddGList(ControlWindow,Gadget1,oldpos,1,NULL);
	RefreshGList(Gadget1,ControlWindow,NULL,1);
	// Select new menu item and readd menus
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,menupos)))->Flags |= CHECKED;
	ResetMenuStrip(ControlWindow,MyMenu);
	if (!EGS) {
		if (Pic1_Open) {
			ResetMenuStrip(Pic1.Win,MyMenu);
		}
		if (Pic2_Open) {
			ResetMenuStrip(Pic2.Win,MyMenu);
		}
	}
	// Set mode and set the pointer
	Mode = NewMode;
	SetMyPointer();
	// Display (short) help
	if (GHelp) {
		help(HNum);
	}
	else {
		ihelp(HNum);
	}
}

static BOOL 				SelDown = FALSE;	// Set if left button currently pressed
static UWORD 				OldLeft,		// Old position of image
								OldTop;
static UWORD 				OldLeft1,	// Old position of other image
								OldTop1;
static struct MyPoint 	*MyPoint,	// Points to add, link etc.
								*MyPoint1;
static LONG 				OldX,			// Old coordinates
								OldY;
static LONG 				OldX1,		// Old coordinates in other window
								OldY1;
static LONG 				CurX,			// Current coordinates
								CurY;
static LONG 				CurX1,		// Current coordinates in other window
								CurY1;
static struct Picture	*pic1;		// The other image

/* The main program
 * this loops until the program is quited
 */
void
doMsgLoop(void) {
	struct IntuiMessage 	*msg;			// Message from the Control window
	struct Picture 		*pic;			// Main image pointer
	int 						flag 	= 1;	// 1 = keep going, 0 = quit, 2 = Close control and image windows
	UWORD 					Shift;		// Set if either Shift key pressed
	ULONG 					Signals;		// Signals set after Wait()
	UWORD 					Selection;	// Menu selection
	struct AmigaGuideMsg *agm;			// message from amigaguide
	ULONG HNum;								// The Help node to use
	struct AppMessage		*AppMessage;//	An APP window message;
	/* Loop until we quit	*/
	while (flag==1) {
		// Wait on open windows etc.
		Signals = Wait((ASig) |
							(1L << MPMorphWnd->UserPort->mp_SigBit) |
							(1L << WMsgPortp->mp_SigBit) |
							(ControlWindow ? (1L << ControlWindow->UserPort->mp_SigBit) : 0) |
							(myhost ? (1L<<myhost->port->mp_SigBit) : 0) |
							(1L << AMsgPortp->mp_SigBit)|
							SIGBREAKF_CTRL_C);
		// AppWindow
		if (Signals & SIGBREAKF_CTRL_C) {
		  	if (!Saved) {
 				flag = !SaveRequester();
		  	}
		  	else {
		  		flag = 0;
		  	}
		}
		if (Signals & (1L << AMsgPortp->mp_SigBit)) {
			while (AppMessage = (struct AppMessage *)GetMsg(AMsgPortp)) {
				switch (AppMessage->am_Type) {
				case AMTYPE_APPWINDOW:
					TempFilename[0]=0;
					if (AppMessage->am_NumArgs) {
						if (AppMessage->am_ArgList->wa_Lock && *(AppMessage->am_ArgList->wa_Name)) {
  	      	         NameFromLock(AppMessage->am_ArgList->wa_Lock,TempFilename,256);
						}
						AddPart(TempFilename,AppMessage->am_ArgList->wa_Name,256);
					}
					if (*TempFilename) {
						if (AppMessage->am_UserData == (ULONG)&Pic1) {
							if (Pic1_Open) {
								DrawAllPoints();
								if (ReopenAPicture(TempFilename,&Pic1)) {
									GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL,
										GTST_String, TempFilename, TAG_END );
									DrawAllPoints();
									Saved = FALSE;
									CurrentTime(&USecs,&Um);
								}
								else {
									if (!ReopenAPicture(GetString(MPMorphGadgets[GDX_FileOne]),&Pic1)) {
										flag = 3;
									}
									else {
										DrawAllPoints();
									}
								}
							}
						}
						else {
							if (AppMessage->am_UserData == (ULONG)&Pic2) {
								DrawAllPoints();
								if (Pic2_Open) {
									if (ReopenAPicture(TempFilename,&Pic2)) {
										GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL,
											GTST_String, TempFilename, TAG_END );
										DrawAllPoints();
										Saved = FALSE;
										CurrentTime(&USecs,&Um);
									}
									else {
										if (!ReopenAPicture(GetString(MPMorphGadgets[GDX_FileTwo]),&Pic2)) {
											flag = 3;
										}
										else {
											DrawAllPoints();
										}
									}
								}
							}
							else {
								if (AppMessage->am_UserData == (ULONG)MPMorphWnd) {
									if (!ControlWindow) {
										MyOpen(TempFilename,FALSE,TRUE);
									}
								}
							}
						}
					}
					break;
				default:
					break;
				}
				ReplyMsg((struct Message *)AppMessage);
			}
		}
		// ARexx command
		if (myhost && 
			 (Signals & (1L<<myhost->port->mp_SigBit))) {
			RexxQuitFlag = 1;
			ARexxDispatch(myhost);
			flag = RexxQuitFlag;
		}
		// Something for the Information window
		if (Signals & (1L << MPMorphWnd->UserPort->mp_SigBit)) {
			flag = HandleMPMorphIDCMP();
		}
		/* Something for amigaguide
		 * Note: all we do is reply the message(s)
		 */
		if (Signals & ASig) {
			if (handle) {
				while (agm = GetAmigaGuideMsg(handle)) {
					switch (agm->agm_Type) {
					case ToolCmdReplyID:
						break;
					case ToolStatusID:
						break;
					default:
						break;
					}
					ReplyAmigaGuideMsg(agm);
				}
			}
		}
		// Something for the Control window
		if (ControlWindow &&
			(Signals & (1L << ControlWindow->UserPort->mp_SigBit))) {
			// Loop on all messages
		 	while (msg = (struct IntuiMessage *)GetMsg(ControlWindow->UserPort)) {
		 		switch (msg->Class) {
		 		// gadget help
		 		case IDCMP_GADGETHELP:
	 				if ((msg->IAddress == NULL) ||
	 					 (msg->IAddress == ControlWindow)) {
						switch(Mode) {
						case EDIT1:
							HNum = H_EOne;
							break;
						case EDIT2:
							HNum = H_ETwo;
							break;
						case EDITREL:
							HNum = H_ERel;
						 	break;
						case ADD:
							HNum = H_EAdd;
							break;
						case DELETE:
							HNum = H_EDel;
							break;
						case LINK1:
						case LINK2:
						case LINK2A:
							HNum = H_ELnk;
							break;
						case UNLINK1:
						case UNLINK2:
						case UNLINK2A:
							HNum = H_EUnl;
							break;
						case NONE:
							HNum = H_EMov;
							break;
						default:
							HNum = H_CWindow;
							break;
						}
					}
 					else {
 						if (((struct Gadget *)msg->IAddress)->GadgetType & GTYP_SYSGADGET) {
	 						switch (((struct Gadget *)msg->IAddress)->GadgetType & GTYP_SYSTYPEMASK) {
	 						case GTYP_WDRAGGING:
	 							HNum = H_CDrag;
 								break;
 							case GTYP_WUPFRONT:
 								HNum = H_CDepth;
 								break;
 							case GTYP_CLOSE:
 								HNum = H_CClose;
 								break;
	 						default:
								HNum = H_CWindow;
								break;
		 					}
		 				}
 						else {
	 						switch (((struct Gadget *)msg->IAddress)->GadgetID) {
 							case ONEGADGET:
 								HNum = H_EOne;
 								break;
 							case TWOGADGET:
 								HNum = H_ETwo;
 								break;
 							case RELGADGET:
	 							HNum = H_ERel;
	 							break;
 							case DELGADGET:
 								HNum = H_EDel;
 								break;
 							case UNLINKGADGET:
 								HNum = H_EUnl;
 								break;
 							case LINKGADGET:
	 							HNum = H_ELnk;
	 							break;
 							case NONEGADGET:
 								HNum = H_EMov;
 								break;
 							case ADDGADGET:
 								HNum = H_EAdd;
 								break;
 							case STGADGET:
 								HNum = HC_First;
 								break;
 							case PREVGADGET:
 								HNum = HC_Previous;
 								break;
 							case GOTOGADGET:
 								HNum = HC_Goto;
 								break;
 							case NEXTGADGET:
 								HNum = HC_Next;
 								break;
 							case LASTGADGET:
 								HNum = HC_Last;
 								break;
 							default:
 								HNum = H_CWindow;
 								break;
 							}
 						}
	 				}
	 				MPHnum = HNum;
 					if (GHelp && HNum) {
		 				help(HNum);
		 			}
		 			else {
		 				ihelp(HNum);
		 			}
		 			break;
		 		case IDCMP_VANILLAKEY:
		 			if (!Disabled) {
		 				Vanilla(msg->Code);
		 			}
		 			break;
		 		case IDCMP_RAWKEY:
		 			if (!Disabled) {
		 				char *com = NULL;
			 			switch (msg->Code) {
			 			case 0x5F:
		 					/* Everything has been set up by Gadget Help */
							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;
			 			default:
			 				// any other key
			 				break;
		 				}
						if (com) {
							SendRexxCommand(myhost,com,NULL);
						}
		 			}
		 			break;
		 		case IDCMP_MENUHELP:
			 		// Show help on the Control and image windows menus
		 			if (!Disabled) {
			 			DoMenuHelp(msg->Code);
			 		}
		 			break;
		 		case IDCMP_GADGETDOWN:
		 			if (!Disabled) {
				 		// Gadget down so set mode to the gadget pressed
			 			switch (((struct Gadget *)(msg->IAddress))->GadgetID) {
						case ONEGADGET:
							MySetMode(EDIT1);
 							break;
 						case TWOGADGET:
	 						MySetMode(EDIT2);
  							break;
 						case RELGADGET:
  							MySetMode(EDITREL);
  							break;
 						case ADDGADGET:
	 						MySetMode(ADD);
  							break;
 						case DELGADGET:
 							MySetMode(DELETE);
  							break;
  						case LINKGADGET:
  							MySetMode(LINK1);
	  						break;
 						case UNLINKGADGET:
 							MySetMode(UNLINK1);
  							break;
  						case NONEGADGET:
  							MySetMode(NONE);
	  						break;
		  				default:
		  					// unkown gadget ?
	  						break;
		 				}
		 			}
		 			break;
		 		case IDCMP_GADGETUP:
		 			if (!Disabled) {
				 		// Gadget up so change frame
				 		switch (((struct Gadget *)(msg->IAddress))->GadgetID) {
						case STGADGET:
							flag = FirstFrame();
 							break;
 						case PREVGADGET:
 							flag = PrevFrame();
 							break;
 						case GOTOGADGET:
 							flag = GotoFrame();
 							break;
 						case NEXTGADGET:
 							flag = NextFrame();
 							break;
	 					case LASTGADGET:
 							flag = LastFrame();
 							break;
						default:
							break;
						}
					}
					break;
		 		case IDCMP_CLOSEWINDOW:
		 			if (!Disabled) {
				 		// Close window - set flag to close image windows as well
						flag = 2;
					}
		 			break;
		 		case IDCMP_MENUPICK:
			 		// Loop around menu selections
					Selection = msg->Code;
					while ((Selection != MENUNULL) && (flag==1)) {
						flag = DoMenu(NULL,Selection);
						Selection = ((struct MenuItem *)ItemAddress(MyMenu,(LONG)Selection))->NextSelect;
					}
		 			break;
		 		default:
			 		// unknown message
		 			break;
		 		}
				ReplyMsg((struct Message *)msg);
		 	}
	  	}
	  	// Something from one of the image windows
		if (Signals & (1L << WMsgPortp->mp_SigBit)) {
			if (EGS) {
				EGSMsgLoop(&flag);
			}
		 	else {
		  		// Loop round messages
		  		while (msg = (struct IntuiMessage *)GetMsg(WMsgPortp)) {
					// determine which image it relates to
					pic = (struct Picture *)(msg->IDCMPWindow->UserData);
					switch (msg->Class) {
					case IDCMP_GADGETHELP:
 						if ((msg->IAddress == NULL) || (msg->IAddress == pic->Win)) {
							switch(Mode) {
							case EDIT1:
								HNum = H_EOne;
								break;
							case EDIT2:
								HNum = H_ETwo;
								break;
							case EDITREL:
								HNum = H_ERel;
							 	break;
							case ADD:
								HNum = H_EAdd;
								break;
							case DELETE:
								HNum = H_EDel;
								break;
							case LINK1:
							case LINK2:
							case LINK2A:
								HNum = H_ELnk;
								break;
							case UNLINK1:
							case UNLINK2:
							case UNLINK2A:
								HNum = H_EUnl;
								break;
							case NONE:
								HNum = H_EMov;
								break;
							default:
								HNum = H_EWindow;
								break;
							}
						}
						else {
	 						if (((struct Gadget *)msg->IAddress)->GadgetType & GTYP_SYSGADGET) {
		 						switch (((struct Gadget *)msg->IAddress)->GadgetType & GTYP_SYSTYPEMASK) {
								case GTYP_SIZING:
		 							HNum = H_ESize;
 									break;
 								case GTYP_WDRAGGING:
 									HNum = H_EDrag;
		 							break;
 								case GTYP_WUPFRONT:
 									HNum = H_EDepth;
 									break;
		 						case GTYP_WDOWNBACK:
 									HNum = H_EZoom;
 									break;
 								case GTYP_CLOSE:
		 							HNum = H_EClose;
 									break;
 								default:
	 								HNum = H_EWindow;
 									break;
 								}
 							}
 							else {
								switch (((struct Gadget *)msg->IAddress)->GadgetID) {
	 							case LEFT_RIGHT_GADGET:
	 								HNum = H_Horiz;
									break;
								case UP_DOWN_GADGET:
									HNum = H_Vert;
									break;
	 							case UP_GADGET:
									HNum = H_Up;
									break;
								case DOWN_GADGET:
	 								HNum = H_Down;
 									break;
 								case LEFT_GADGET:
 									HNum = H_Left;
 									break;
	 							case RIGHT_GADGET:
 									HNum = H_Right;
 									break;
 								default:
	 								HNum = H_EWindow;
 									break;
 								}
		 					}
 						}
		 				MPHnum = HNum;
	 					if (GHelp && HNum) {
			 				help(HNum);
	 					}
			 			else {
			 				ihelp(HNum);
		 				}
						break;
					case IDCMP_NEWSIZE:
						// Image resized so resize the gadgets etc.
						pic->JustSeconds = 0;	// Note No break !!!!!!!
					case IDCMP_CHANGEWINDOW:
						/* reset window size after change in Zoom
						 * Changing from 2x to normal size may require the windows
						 * to be made smaller - this can be delayed by intuition.
						 * The window limits can only be reset when the window has
						 * been actually resized.
						 */
						if (ZoomAllowed && !Zoom) {
							if (changedboxcount < 3) {
								if (WindowLimits(pic->Win,0,0,pic->MPi->Width+pic->Screen->WBorLeft+SIZEIMAGE_W(n),
													  pic->MPi->Height+pic->Screen->WBorTop + pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n))) {
									if (pic == &Pic1) {
										changedboxcount |= 1;
									}
									else {
										if (pic == &Pic2) {
											changedboxcount |= 2;
										}
									}
									if (changedboxcount == 3) {
									/* Once both windows have been resized then we
									 * can redraw all the points
									 */
										DrawAllPoints();
									}
								}
								else {
									/* User must have resized in the meantime
									 * so have another go
									 */
									ChangeWindowBox(pic->Win,pic->Win->LeftEdge,pic->Win->TopEdge,
														 min(pic->Win->Width,pic->MPi->Width+pic->Screen->WBorLeft+SIZEIMAGE_W(n)),
														 min(pic->Win->Height,pic->MPi->Height+pic->Screen->WBorTop + pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n)));
								}
							}
						}
						// Reset gadgets etc. for new size
						doNewSize(pic);
						break;
				 	case IDCMP_VANILLAKEY:
				 		if (!Disabled) {
					 		Vanilla(msg->Code);
					 	}
						break;
	  				case IDCMP_RAWKEY:
	  					if (!Disabled) {
	  						char *com=0;
		  					switch (msg->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;
				  				default:
	  							// some other key
	  							break;
	  						}
							if (com) {
								SendRexxCommand(myhost,com,NULL);
							}
			  			}
	  					break;
			  		case IDCMP_MENUHELP:
			 			if (!Disabled) {
		  					// Display help on Control and Image window menus
		  					DoMenuHelp(msg->Code);
		  				}
			  			break;
					case IDCMP_ACTIVEWINDOW:
						/* Window became active
						 * Store time so that we can ignore the first click
						 * (for which we may next recieve a message)
						 */
						pic->JustSeconds = msg->Seconds;
						break;
					case IDCMP_INACTIVEWINDOW:
						/* Window just became inactive
						 */
						break;
					case IDCMP_MENUVERIFY:
						/* Somebody wants to display a menu
						 * If it is somebody else then just let them
						 * otherwise if the left mouse button is down then
						 * do not display the menu as we are going to use
						 * the right button up/down message to cancel the current action
						 */
						switch (msg->Code) {
						case MENUWAITING:
							break;
						case MENUHOT:
							pic->JustSeconds = 0;
							if (SelDown) {
								msg->Code = MENUCANCEL;
							}
							break;
						default:
							break;
						}
						break;
			  		case IDCMP_MENUPICK:
	  					// Menu item selected, use any further clicks and loop round menu selections
						pic->JustSeconds = 0;
						Selection = msg->Code;
						while ((Selection != MENUNULL) && flag) {
							flag = DoMenu(pic,Selection);
							Selection = ((struct MenuItem *)ItemAddress(MyMenu,(LONG)Selection))->NextSelect;
				 		}
						break;
			 		case IDCMP_CLOSEWINDOW:
	 					/* Close the window with Control and other image windows
	 					 * and change the palette back to original if required
			 			 */
			 			if (!Disabled) {
							flag = 2;
						}
	  					break;
					case IDCMP_MOUSEBUTTONS:
			 			if (!Disabled) {
							MouseButtons(pic,msg->Code,msg->Seconds);
						}
						break;
					case IDCMP_MOUSEMOVE:
			 			if (!Disabled) {
							MouseMove(pic);
						}
						break;
					case IDCMP_GADGETDOWN:
			 			if (!Disabled) {
							// Gadget down, save the current gadget id
							pic->JustSeconds = 0;
							pic->currentg = ((struct Gadget *)(msg->IAddress))->GadgetID;
						}
						break;
					case IDCMP_GADGETUP:
						// Gadget up, no current gadget id
						pic->JustSeconds = 0;
						pic->currentg = NO_GADGET;
						break;
					case IDCMP_IDCMPUPDATE:
						// Gadget update message
						pic->JustSeconds = 0;
						/* If an arrow then check the mouse button
						 * is down (prevents image scrolling long
						 * after button is released)
						 */
						if ((pic->currentg == LEFT_RIGHT_GADGET) ||
							 (pic->currentg == UP_DOWN_GADGET) ||
							 (PeekQualifier() & IEQUALIFIER_LEFTBUTTON)) {
							pic->XLeft=pic->Left;
							pic->XTop=pic->Top;
							Shift = PeekQualifier() & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT);
							switch(pic->currentg) {
							case LEFT_RIGHT_GADGET:
								// Horizontal gadget - get position
								pic->Left = msg->Code;
								break;
							case UP_DOWN_GADGET:
								// Vertical gadget - get position
								pic->Top = msg->Code;
								break;
							case UP_GADGET:
								// Up gadget, check shift key
								if (pic->Top) {
									if (Shift) {
										--(pic->Top);
									}
									else {
										if (pic->Top > pic->ATop) {
											pic->Top -= pic->ATop;
										}
										else {
											pic->Top = 0;
										}
									}
									SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
														PGA_Top, pic->Top, TAG_END);
								}
								break;
							case LEFT_GADGET:
								// Left gadget, check shift key
								if (pic->Left) {
									if (Shift) {
										--(pic->Left);
									}
									else {
										if (pic->Left > pic->ALeft) {
											pic->Left -= pic->ALeft;
										}
										else {
											pic->Left = 0;
										}
									}
									SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
														PGA_Top, pic->Left, TAG_END);
								}
								break;
							case DOWN_GADGET:
								// Down gadget, check shift key
								if (Shift) {
									++(pic->Top);
								}
								else {
									pic->Top += pic->ATop;
								}
								if (pic->Top > pic->MTop) {
									pic->Top = pic->MTop;
								}
								SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
													PGA_Top, pic->Top, TAG_END);
								break;
							case RIGHT_GADGET:
								// Right gadget, check shift key
								if (Shift) {
									++(pic->Left);
								}
								else {
									pic->Left += pic->ALeft;
								}
								if (pic->Left > pic->MLeft) {
									pic->Left = pic->MLeft;
								}
								SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
													PGA_Top, pic->Left, TAG_END);
								break;
							}
							// Update image scroll
							checkGadget(pic);
						}
						break;
					}
					ReplyMsg((struct Message *)msg);
				}
			}
		}
		/* If a window was closed etc.
		 * then turn on some menus and close the windows
		 * etc.
		 */
		if ((flag == 2) || (flag == 3)) {
			if ((flag == 2) &&
					 ((SinglePicture == 2) || (SinglePicture == 3))) {
				if (!Saved) {
					flag = SaveRequester();
				}
				DeleteAllPoints();
			}
			if (flag) {
				if (2 == flag) {
					Record(MyGetMsg(MSG_RECEXITP),NULL);
				}
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_NEW,NOSUB));
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_OPEN,NOSUB));
				if (Pic1_Open) {
					CloseAPicture(&Pic1);
					Pic1_Open = FALSE;
				}
				if (Pic2_Open) {
					CloseAPicture(&Pic2);
					Pic2_Open = FALSE;
				}
				if (EGS) {
					E_ActivateAmigaScreen();
					ScreenToFront(Scr);
				}
				CloseControlWindow();
			}
			// Below just updates the correct gadgets
			EnableWindows();
			flag = 1;
		}
	}
}

struct E_EMouseImg32 EMouseImg = {32,32,1,1};
struct E_EMouse EGS_Pointer = {0x00000000, 0xFF000000, 0xFFFFFF00,
										 EMSF_HALF32,
										 EMSV_01,NULL,&EMouseImg,NULL};

/* SetPointer
 * based on the current mode
 */
void
SetMyPointer(void) {
	UWORD *Pointer=0;	// Pointer image
	APTR o=0;
	// Set pointer based on mode
	switch (Mode) {
	case EDIT1:
		Pointer = One;
		o = One_o;
 		break;
	case EDIT2:
		Pointer = Two;
		o = Two_o;
		break;
	case EDITREL:
		Pointer = Rel;
		o = Rel_o;
		break;
	case ADD:
		Pointer = Add;
		o = Add_o;
		break;
	case DELETE:
		Pointer = Del;
		o = Del_o;
		break;
	case LINK1:
		Pointer = L1;
		o = L1_o;
		break;
	case UNLINK1:
		Pointer = U1;
		o = U1_o;
		break;
	case NONE:
		Pointer = Mov;
		o = Mov_o;
		break;
	case UNLINK2:
		Pointer = U2;
		o = U2_o;
		break;
	case LINK2:
		Pointer = L2;
		o = L2_o;
		break;
	}
	if (EGS) {
		EGSSetMyPointer(Pointer,&EMouseImg);
	}
	// Set the window pointers
	if (Pic1_Open) {
		if (!EGS) {
			if (o) {
				SetWindowPointer(Pic1.Win,
									WA_Pointer, o,
									TAG_END);
			}
			else {
				SetPointer(Pic1.Win, Pointer, 16, 16, -1, 0);
			}
		}
		else {
			EI_ClearPointer(Pic1.EGS_Win);
			EI_SetPointer(Pic1.EGS_Win,&EGS_Pointer);
		}
	}
	if (Pic2_Open) {
		if (!EGS) {
			if (o) {
				SetWindowPointer(Pic2.Win,
									WA_Pointer, o,
									TAG_END);
			}
			else {
				SetPointer(Pic2.Win, Pointer, 16, 16, -1, 0);
			}
		}
		else {
			EI_ClearPointer(Pic2.EGS_Win);
			EI_SetPointer(Pic2.EGS_Win,&EGS_Pointer);
		}
	}
	if (ControlWindow) {
		if (o) {
			SetWindowPointer(ControlWindow,
								WA_Pointer, o,
								TAG_END);
		}
		else {
			SetPointer(ControlWindow, Pointer, 16, 16, -1, 0);
		}
	}
}

/* Do the Control and image window menus
 * Returns	: 1 = OK, 0 = quit, 2=exit points
 * pic		: Picture structure if an image window
 * Selection: Menu item
 */
int
DoMenu(struct Picture *pic,UWORD Selection) {
	int flag = 1;			// Return value
	// Large switch statements for menu items
  	switch (MENUNUM(Selection)) {
  	case M_PROJECT:
		switch(ITEMNUM(Selection)) {
		case MM_NEW:
			/* New Points
			 * Suggest Save if not saved
			 * then delete all point
			 */
			DisableWindows(DI_New);
			if (!Saved) {
				if (SaveRequester()) {
					Saved = TRUE;
				}
			}
			if (Saved) {
				Record(MyGetMsg(MSG_RECNEWP),NULL);
				DeleteAllPoints();
				MaxWidth = 0;
				MaxHeight = 0;
				Saved = FALSE;
				CurrentTime(&USecs,&Um);
			}
			EnableWindows();
			break;
		case MM_OPEN:
			// Open Points - just call MyOpen() with JustPoints=TRUE
			DisableWindows(DI_WaitOpen);
			MyOpen(NULL,TRUE,TRUE);
			EnableWindows();
			break;
		case MM_SAVE:
			// Save - just call SaveAs() with last filename
			DisableWindows(DI_WaitSave);
			SaveAs(savedfilename);
			EnableWindows();
			break;
		case MM_SAVEAS:
			// Save - just call SaveAs() with no filename
			DisableWindows(DI_WaitSave);
			SaveAs(NULL);
			EnableWindows();
			break;
	  	case MM_ABOUT:
	  		// About - display requester
			DisableWindows(DI_About);
			About();
			EnableWindows();
			break;
		case MM_EXITPOINTS:
			// Exit Points - Close Image and control windows
			flag = 2;
			break;
		case MM_QUIT:
			// Quit - Suggest save first
			if (!Saved) {
		  		flag = !SaveRequester();
		  	}
		  	else {
		  		flag = 0;
		  	}
			break;
	 	default:
	 		// Some other item
	  		break;
		}
		break;
	case M_EDIT:
		switch(ITEMNUM(Selection)) {
		case MM_GRID:
			// Add Grid... - Add a grid of points
			AddGrid();
			break;
		case MM_TRIANGULATE:
			Triangulate();
			break;
		case MM_FRAME:
			// Frame sub menu
			switch (SUBNUM(Selection)) {
			case MI_FIRST:
				flag = FirstFrame();
				break;
			case MI_PREV:
				flag = PrevFrame();
				break;
			case MI_GOTO:
				flag = GotoFrame();
				break;
			case MI_NEXT:
				flag = NextFrame();
				break;
			case MI_LAST:
				flag = LastFrame();
				break;
			default:
				break;
			}
			break;
		case MM_MODE:
			switch (SUBNUM(Selection)) {
			// Edit Mode ???? - set the relevant mode
  			case MI_EDITONE:
  				MySetMode(EDIT1);
  				break;
 			case MI_EDITTWO:
  				MySetMode(EDIT2);
	  			break;
			case MI_EDITREL:
				MySetMode(EDITREL);
	  			break;
			case MI_ADD:
				MySetMode(ADD);
	  			break;
			case MI_DELETE:
				MySetMode(DELETE);
	  			break;
			case MI_LINK:
				MySetMode(LINK1);
	  			break;
			case MI_UNLINK:
				MySetMode(UNLINK1);
	  			break;
			case MI_NONE:
				MySetMode(NONE);
				break;
			default:
				break;
			}
			break;
		default:
			// Some other item
			break;
		}
		break;
	case M_SETTINGS:
		HandleSettings(Selection,pic);
		break;
	case M_USER:
		UserMenu(Selection);
		break; 
	default:
		// something else ??
		break;
	}
	// return 0,1 or 2
	return flag;
}

static struct Requester RequestW;
static BOOL DW = FALSE;
static struct Requester RequestC;
static BOOL DC = FALSE;
static struct Requester Request1;
static BOOL D1 = FALSE;
static struct Requester Request2;
static BOOL D2 = FALSE;

/* Disable all windows,
 * menus, pointers,
 * gadgets etc.
 *
 * Note: This must be able to be called multiple times without EnableWindows()
 *
 * No longer disables gadgets
 */
void
DisableWindows(ULONG dnum) {
	if (dnum < 1000) {
		ihelp(dnum);
	}
	else {
		if (disabled[dnum-1000] != -1) {
			if (Scr) {		// Need to check as MPMorphWnd is also used for backdrop temp window
				if (MPMorphWnd) {
					SetMessage(MyGetMsg(disabled[dnum-1000]));
				}
			}
		}
	}
	if (ControlWindow) {
		if (!DC) {
			DC = TRUE;
			InitRequester(&RequestC);
			Request(&RequestC,ControlWindow);
			// Wait pointer
			SetWindowPointer(ControlWindow, WA_BusyPointer, TRUE,
								  WA_PointerDelay, TRUE,
								  TAG_END);
		}
	}
	if (Pic1_Open) {
	 if (!EGS) {
	 	if (!D1) {
			D1 = TRUE;
			InitRequester(&Request1);
			Request(&Request1,Pic1.Win);
		}
		// Turn verify off
		ModifyIDCMP(Pic1.Win,MYIDCMP_NOVERIFY);
		Pic1.Win->Flags |= WFLG_REPORTMOUSE;
		// Wait pointer
		SetWindowPointer(Pic1.Win, WA_BusyPointer, TRUE,
							  WA_PointerDelay, TRUE,
							  TAG_END);
	 }
	 else {
	  EI_ClearPointer(Pic1.EGS_Win);
	  EI_SetPointer(Pic1.EGS_Win,EI_GetPrefPointer(EIM_SLEEP_MOUSE));
	 }
	}
	if (Pic2_Open) {
	 if (!EGS) {
	 	if (!D2) {
	 		D2 = TRUE;
			InitRequester(&Request2);
			Request(&Request2,Pic2.Win);
		}
		// Turn verify off
		ModifyIDCMP(Pic2.Win,MYIDCMP_NOVERIFY);
		Pic2.Win->Flags |= WFLG_REPORTMOUSE;
		// Wait pointer
		SetWindowPointer(Pic2.Win, WA_BusyPointer, TRUE,
							  WA_PointerDelay, TRUE,
							  TAG_END);
	 }
	 else {
	  EI_ClearPointer(Pic2.EGS_Win);
	  EI_SetPointer(Pic2.EGS_Win,EI_GetPrefPointer(EIM_SLEEP_MOUSE));
	 }
	}
	/* Disable gadgets in the Info window
	 * Do not disable the GetFile gadgets
	 * as it causes enforcer hits
	 */
	if (Scr) {
		if (MPMorphWnd) {
			if (!DW) {
				DW = TRUE;
				InitRequester(&RequestW);
				Request(&RequestW,MPMorphWnd);
			}
			// Wait pointer
			SetWindowPointer(MPMorphWnd, WA_BusyPointer, TRUE,
								  WA_PointerDelay, TRUE,
								  TAG_END);
		}
	}
	Disabled = TRUE;
}

/* Enable all windows,
 * menus, pointers,
 * gadgets etc.
 */
void
EnableWindows(void) {
	LONG Frames=0,Start=0;
	if (Scr) {
		if (MPMorphWnd) {
			Frames = GetNumber(MPMorphGadgets[GDX_Frames]);
			Start = GetNumber(MPMorphGadgets[GDX_Start]);
			if (!*Recent1 || ControlWindow) {
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT1));
			}
			else {
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT1));
			}
			if (!*Recent2 || ControlWindow) {
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT2));
			}
			else {
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT2));
			}
			if (!*Recent3 || ControlWindow) {
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT3));
			}
			else {
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT3));
			}
			if (!*Recent4 || ControlWindow) {
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT4));
			}
			else {
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT4));
			}
			if (!*Recent5 || ControlWindow) {
				OffMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT5));
			}
			else {
				OnMenu(MPMorphWnd,FULLMENUNUM(M_M_PROJECT,M_MM_RECENT,M_MI_RECENT5));
			}
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileOne],MPMorphWnd,NULL,
						GA_Disabled,ControlWindow?TRUE:FALSE, TAG_END );
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_FileTwo],MPMorphWnd,NULL,
						GA_Disabled,ControlWindow?TRUE:FALSE, TAG_END );
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_GetFileOne],MPMorphWnd,NULL,
						GA_Disabled,ControlWindow?TRUE:FALSE, TAG_END );
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_GetFileTwo],MPMorphWnd,NULL,
						GA_Disabled,ControlWindow?TRUE:FALSE, TAG_END );
			GT_SetGadgetAttrs(MPMorphGadgets[GDX_SinglePicture],MPMorphWnd,NULL,
						GA_Disabled,ControlWindow?TRUE:FALSE, TAG_END );
		}
	}
	if (ControlWindow) {
		if (DC && !ARexxLock) {
			EndRequest(&RequestC,ControlWindow);
			DC = FALSE;
		}
		if ((SinglePicture == 2) || (SinglePicture == 3)) {
			if (FrameNumber > Start) {
				OnGadget(&stGadget,ControlWindow,NULL);
				OnGadget(&prevGadget,ControlWindow,NULL);
				OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_FIRST));
				OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_PREV));
			}
			else {
				OffGadget(&stGadget,ControlWindow,NULL);
				OffGadget(&prevGadget,ControlWindow,NULL);
				OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_FIRST));
				OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_PREV));
			}
			if (FrameNumber < (Start+Frames-1)) {
				OnGadget(&nextGadget,ControlWindow,NULL);
				OnGadget(&lastGadget,ControlWindow,NULL);
				OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_NEXT));
				OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_LAST));
			}
			else {
				OffGadget(&nextGadget,ControlWindow,NULL);
				OffGadget(&lastGadget,ControlWindow,NULL);
				OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_NEXT));
				OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_LAST));
			}
			if (Frames > 1) {
				OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_GOTO));
				OnGadget(&gotoGadget,ControlWindow,NULL);
			}
			else {
				OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,MI_GOTO));
				OffGadget(&gotoGadget,ControlWindow,NULL);
			}
		}
		else {
			OffGadget(&stGadget,ControlWindow,NULL);
			OffGadget(&prevGadget,ControlWindow,NULL);
			OffGadget(&gotoGadget,ControlWindow,NULL);
			OffGadget(&nextGadget,ControlWindow,NULL);
			OffGadget(&lastGadget,ControlWindow,NULL);
			OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,NOSUB));
		}
	}
	if (Pic1_Open) {
	 if (!EGS) {
		if (D1 && !ARexxLock) {
			D1 = FALSE;
			EndRequest(&Request1,Pic1.Win);
		}
		// verify, menus and gadgets on
		ModifyIDCMP(Pic1.Win,MYIDCMP_VERIFY);
		Pic1.Win->Flags |= WFLG_REPORTMOUSE;
	 }
	 else {
	  EI_ClearPointer(Pic1.EGS_Win);
	 }
	}
	if (Pic2_Open) {
	 if (!EGS) {
		if (D2 && !ARexxLock) {
			D2 = FALSE;
			EndRequest(&Request2,Pic2.Win);
		}
		// verify, menus and gadgets on
		ModifyIDCMP(Pic2.Win,MYIDCMP_VERIFY);
		Pic2.Win->Flags |= WFLG_REPORTMOUSE;
	 }
	 else {
	  EI_ClearPointer(Pic2.EGS_Win);
	 }
	}
	if (Scr) {
		if (MPMorphWnd) {
			if (DW && !ARexxLock) {
				DW = FALSE;
				EndRequest(&RequestW,MPMorphWnd);
			}
			// Set pointer for Control and both image windows
			SetMyPointer();
			/* Turn relevant gadgets back on
			 * Do not enable GetFile gadgets as it causes enforcer hits
			 */
			// Pointer back on
			SetWindowPointer(MPMorphWnd,
								  TAG_END);
		}
		if (MPMorphWnd) {
			SetMessage(MyGetMsg(MSG_READY));
		}
	}
	Disabled = FALSE;
}

static void
SetMyGadgets(struct Picture *np,LONG nx,LONG ny) {
	if ((((ny<<Zoom) + (yfact/2))/yfact) < np->Top) {
		np->Top = ((ny<<Zoom) + (yfact/2))/yfact;
		SetGadgetAttrs(np->SideGad, np->Win, NULL,
							PGA_Top, np->Top, TAG_END);
	}
	if ((((nx<<Zoom) + (xfact/2))/xfact) < np->Left) {
		np->Left = ((nx<<Zoom) + (xfact/2))/xfact;
		SetGadgetAttrs(np->BotGad, np->Win, NULL,
							PGA_Top, np->Left, TAG_END);
	}
	if ((((ny<<Zoom) + (yfact/2))/yfact) > (np->Win->GZZHeight+np->Top)) {
		np->Top = ((((ny<<Zoom) + (yfact/2))/yfact) - np->Win->GZZHeight);
		SetGadgetAttrs(np->SideGad, np->Win, NULL,
							PGA_Top, np->Top, TAG_END);
	}
	if ((((nx<<Zoom) + (xfact/2))/xfact) > (np->Win->GZZWidth+np->Left)) {
		np->Left = ((((nx<<Zoom) + (xfact/2))/xfact) - np->Win->GZZWidth);
		SetGadgetAttrs(np->BotGad, np->Win, NULL,
							PGA_Top, np->Left, TAG_END);
	}
	checkGadget(np);
}

void
Vanilla(ULONG code) {
	switch (code) {
	// Edit Mode ???? - set the relevant mode
	case '1':
		MySetMode(EDIT1);
		break;
	case '2':
		MySetMode(EDIT2);
		break;
	case '3':
		MySetMode(EDITREL);
		break;
	case '4':
		MySetMode(ADD);
		break;
	case '5':
		MySetMode(DELETE);
		break;
	case '6':
		MySetMode(LINK1);
		break;
	case '7':
		MySetMode(UNLINK1);
		break;
	case '8':
		MySetMode(NONE);
		break;
	default:
		break;
	}
}

void
MouseButtons(struct Picture *pic,ULONG code,ULONG seconds) {
	int k;
	/* Somebody pressed a button
	 * If the second is the same as the activate window
	 * message then ignore this click
	 */
	if (EGS && pic->JustSeconds && (pic->JustSeconds == seconds)) {
		pic->JustSeconds = 0;
	}
	else {
		/* otherwise process the mouse click/release */
		pic->JustSeconds = 0;
		switch (code) {
		case SELECTDOWN:
			/* Left button pressed
			 * remember the currentimage positions
			 * in case Cancelled
			 */
			SelDown = TRUE;
			if (!EGS) {
				OldLeft = pic->Left;
				OldTop = pic->Top;
				if (pic == &Pic1) {
					OldLeft1 = Pic2.Left;
					OldTop1 = Pic2.Top;
				}
				else {
					OldLeft1 = Pic1.Left;
					OldTop1 = Pic1.Top;
				}
			}
			if (Pic1_Open && Pic2_Open) {
				// both windows open so action current mode
				switch(Mode) {
				case EDIT1:
					/* moving points in one window
					 * Find point near click
					 * erase and draw in new position
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						if (pic == &Pic2) {
							DrawPixels(pic,MyPoint->x1,MyPoint->y1,MyPoint);
						}
						else {
							DrawPixels(pic,MyPoint->x,MyPoint->y,MyPoint);
						}
						CurX=EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
						CurY=EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
						CurX *= xfact;
						CurY *= yfact;
						LimitPoints(&CurX,&CurY,pic);
						DrawPixels(pic,CurX,CurY,MyPoint);
					}
					else {
						SelDown = FALSE;
					}
					break;
				case EDIT2:
					/* moving points in both windows
					 * Find point near click
					 * erase and draw in new positions
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
						CurX=EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
						CurY=EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
						CurX *= xfact;
						CurY *= yfact;
						LimitPoints(&CurX,&CurY,pic);
						DrawPixels(pic,CurX,CurY,MyPoint);
						if (pic == &Pic1) {
							DrawPixels(&Pic2,CurX,CurY,MyPoint);
						}
						else {
							DrawPixels(&Pic1,CurX,CurY,MyPoint);
						}	
					}
					else {
						SelDown = FALSE;
					}
					break;
				case EDITREL:
					/* moving points relatively in both windows
					 * Find point near click
					 * erase and draw in new positions
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
						CurX=EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
						CurY=EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
						CurX *= xfact;
						CurY *= yfact;
						LimitPoints(&CurX,&CurY,pic);
						if (pic == &Pic1) {
							CurX1 = CurX - MyPoint->x + MyPoint->x1;
							CurY1 = CurY - MyPoint->y + MyPoint->y1;
						}
						else {
							CurX1 = CurX - MyPoint->x1 + MyPoint->x;
							CurY1 = CurY - MyPoint->y1 + MyPoint->y;
						}
						LimitPoints(&CurX1,&CurY1,pic);
						DrawPixels(pic,CurX,CurY,MyPoint);
						if (pic == &Pic1) {
							DrawPixels(&Pic2,CurX1,CurY1,MyPoint);
						}
						else {
							DrawPixels(&Pic1,CurX1,CurY1,MyPoint);
						}	
					}
					else {
						SelDown = FALSE;
					}
					break;
				case ADD:
					/* Adding point to both windows
					 * Draw in both windows
					 */
					CurX=EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
					CurY=EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
					CurX *= xfact;
					CurY *= yfact;
					LimitPoints(&CurX,&CurY,pic);
					DrawPixels(pic,CurX,CurY,NULL);
					if (pic == &Pic1) {
						DrawPixels(&Pic2,CurX,CurY,NULL);
					}
					else {
						DrawPixels(&Pic1,CurX,CurY,NULL);
					}	
					break;
				case DELETE:
					/* Deleting point from both windows
					 * Erase in both windows - if found
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
					}
					else {
						SelDown = FALSE;
					}
					break;
				case LINK1:
					/* Linking two points
					 * Selecting first point
					 * If we can find it then check its not already linked to
					 * 4 points then set up the new mode - finding 2nd point
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						if (MyPoint->NumLinks == MAX_LINKS) {
									SelDown = FALSE;
							Error(MyGetMsg(MSG_4POINTS),MyGetMsg(MSG_OK),NULL,HE_4points);
						}
						else {
							SetWindowTitles(ControlWindow,MyGetMsg(MSG_L2),(UBYTE *)-1);
							Mode = LINK2;
							MyPoint1 = MyPoint;
							SetMyPointer();
						}
					}
					else {
						SelDown = FALSE;
					}
					break;
				case UNLINK1:
					/* Unlinking two points
					 * Selecting first point
					 * If we can find it then check its already linked
					 * then set up the new mode - finding 2nd point
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						if (MyPoint->NumLinks) {
							SetWindowTitles(ControlWindow,MyGetMsg(MSG_U2),(UBYTE *)-1);
							Mode = UNLINK2;
							MyPoint1 = MyPoint;
							SetMyPointer();
						}
						else {
							SelDown = FALSE;
//							Error(MyGetMsg(MSG_NOTLINK),MyGetMsg(MSG_OK),NULL,HE_NotLinked);
						}
					}
					else {
						SelDown = FALSE;
					}
					break;
				case LINK2:
					/* Linking two points
					 * Selecting 2nd point
					 * If we can find it then do some validation
					 * then set up the new mode
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						if (MyPoint == MyPoint1) {
							SelDown = FALSE;
//							Error(MyGetMsg(MSG_LINKSE),MyGetMsg(MSG_OK),NULL,HE_LinkSelf);
						}
						else {
							if (MyPoint1->NumLinks == MAX_LINKS) {
								SelDown = FALSE;
								Error(MyGetMsg(MSG_4POINTS),MyGetMsg(MSG_OK),NULL,HE_4points);
							}
							else {
								for (k = 0;
									  k < MAX_LINKS;
									  k++) {
									if (MyPoint->p[k] == MyPoint1) {
  										SelDown = FALSE;
//										Error(MyGetMsg(MSG_READYLI),MyGetMsg(MSG_OK),NULL,HE_Linked);
									}
								}
								if (SelDown) {
									Record(MyGetMsg(MSG_RECLINK),(ULONG)MyPoint->x,(ULONG)MyPoint->y,(ULONG)MyPoint1->x,(ULONG)MyPoint1->y);
									LinkPoints(MyPoint,MyPoint1);
									Mode = LINK2A;
								}
							}
						}
					}
					break;
				case UNLINK2:
					/* Unlinking two points
					 * Selecting 2nd point
					 * If we can find it then do some validation
					 * then set up the new mode
					 */
					if (MyPoint = FindPoint(pic,EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom) >> Zoom,EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
						if (MyPoint == MyPoint1) {
							SelDown = FALSE;
//							Error(MyGetMsg(MSG_UNLSE),MyGetMsg(MSG_OK),NULL,HE_UnlinkSelf);
						}
						else {
							for (k = 0;
								  k < MAX_LINKS;
								  k++) {
								if (MyPoint->p[k] == MyPoint1) {
									SelDown = FALSE;
								}
							}
							if (!SelDown) {
								SelDown = TRUE;
								Record(MyGetMsg(MSG_RECUNLINK),(ULONG)MyPoint->x,(ULONG)MyPoint->y,(ULONG)MyPoint1->x,(ULONG)MyPoint1->y);
								UnlinkPoints(MyPoint,MyPoint1,TRUE);
								Mode = UNLINK2A;
							}
							else {
//								Error(MyGetMsg(MSG_NOTLINK),MyGetMsg(MSG_OK),NULL,HE_NotLinked);
								SelDown = FALSE;
							}
						}
					}
					break;
				default:
					// Some other mode?
					break;
				}
				/* If we are adding a point, or moving a point
				 * then we may need to scroll the other window
				 * to get the point in view
				 * So update the gadgets and check the values set up
				 */
				if ((Mode == ADD) || 
					 ((MyPoint) && ((Mode == EDIT2) || (Mode == EDITREL)))) {
					if (pic == &Pic1) {
						pic1 = &Pic2;
					}
					else {
						pic1 = &Pic1;
					}
					if (Mode != EDITREL) {
						// if not edit rel then both points are in the same position
						CurX1 = CurX;
						CurY1 = CurY;
					}
					pic1->XLeft=pic1->Left;
					pic1->XTop=pic1->Top;
					if (!EGS) {
						SetMyGadgets(pic1,CurX1,CurY1);
					}
				}
			}
			break;
		case SELECTUP:
			/* Left mouse button up
			 * If we are currently doing something then
			 * this actually confirms we really want
			 * to do it, Saved is set to FALSE following any change
			 */
			if (SelDown) {
				SelDown = FALSE;
				switch(Mode) {
				case ADD:
					// Adding a point, Create and add to list
					if (MyPoint = AllocMem(sizeof(struct MyPoint),MEMF_CLEAR)) {
						MyPoint->x = CurX;
						MyPoint->y = CurY;
						MyPoint->x1 = CurX;
						MyPoint->y1 = CurY;
						UpdatePens(MyPoint);
						MaxWidth = max(CurX,MaxWidth);
						MaxHeight = max(CurY,MaxHeight);
						AddTail(&PointList,(struct Node *)MyPoint);
						Record(MyGetMsg(MSG_RECADDP),(ULONG)MyPoint->x,(ULONG)MyPoint->y,(ULONG)MyPoint->x1,(ULONG)MyPoint->y1);
						Saved = FALSE;
						CurrentTime(&USecs,&Um);
					}
					else {
						Error(MyGetMsg(MSG_MEMPO),MyGetMsg(MSG_OK),NULL,HE_MemNewPoint);
					}
					break;
				case EDIT1:
					// Editing one window, update actual point
					Record(MyGetMsg(MSG_RECMOVEP),(ULONG)MyPoint->x,(ULONG)MyPoint->y,
							(ULONG)CurX,(ULONG)CurY,(ULONG)MyPoint->x1,(ULONG)MyPoint->y1);
					if (pic == &Pic2) {
						MyPoint->x1 = CurX;
						MyPoint->y1 = CurY;
					}
					else {
						MyPoint->x = CurX;
						MyPoint->y = CurY;
					}
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					break;
				case EDIT2:
					// Editing two windows, update actual point
					Record(MyGetMsg(MSG_RECMOVEP),(ULONG)MyPoint->x,(ULONG)MyPoint->y,
							(ULONG)CurX,(ULONG)CurY,(ULONG)CurX,(ULONG)CurY);
					MyPoint->x = CurX;
					MyPoint->y = CurY;
					MyPoint->x1 = CurX;
					MyPoint->y1 = CurY;
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					break;
				case EDITREL:
					// Editing relative, update actual point
					if (pic == &Pic1) {
						CurX1 = CurX - MyPoint->x + MyPoint->x1;
						CurY1 = CurY - MyPoint->y + MyPoint->y1;
						LimitPoints(&CurX1,&CurY1,&Pic2);
						Record(MyGetMsg(MSG_RECMOVEP),(ULONG)MyPoint->x,(ULONG)MyPoint->y,
								(ULONG)CurX,(ULONG)CurY,(ULONG)CurX1,(ULONG)CurY1);
						MyPoint->x = CurX;
						MyPoint->y = CurY;
					}
					else {
						CurX1 = CurX - MyPoint->x1 + MyPoint->x;
						CurY1 = CurY - MyPoint->y1 + MyPoint->y;
						LimitPoints(&CurX1,&CurY1,&Pic1);
						Record(MyGetMsg(MSG_RECMOVEP),(ULONG)MyPoint->x,(ULONG)MyPoint->y,
								(ULONG)CurX1,(ULONG)CurY1,(ULONG)CurX,(ULONG)CurY);
						MyPoint->x1 = CurX;
						MyPoint->y1 = CurY;
					}
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					if (pic == &Pic1) {
						MyPoint->x1 = CurX1;
						MyPoint->y1 = CurY1;
					}
					else {
						MyPoint->x = CurX1;
						MyPoint->y = CurY1;
					}
					break;
				case DELETE:
					// Deleting, delete actual point
					if (MyPoint) {
						Record(MyGetMsg(MSG_RECDELP),(ULONG)MyPoint->x,(ULONG)MyPoint->y);
						DeletePoint(MyPoint);
					}
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					break;
				case LINK2A:
					// Linking, reset window title and pointer
					SetWindowTitles(ControlWindow,MyGetMsg(MSG_L1),(UBYTE *)-1);
					Mode = LINK1;
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					SetMyPointer();
					break;
				case UNLINK2A:
					// Unlinking, reset window title and pointer
					SetWindowTitles(ControlWindow,MyGetMsg(MSG_U1),(UBYTE *)-1);
					Mode = UNLINK1;
					Saved = FALSE;
					CurrentTime(&USecs,&Um);
					SetMyPointer();
					break;
				default:
					break;
				}
			}
			break;
		case MENUDOWN:
		case MENUUP:
			/* Menu button pressed
			 * Cancel any current action
			 */
			if (SelDown) {
				SelDown = FALSE;
				switch (Mode) {
				case ADD:
					/* Adding,
					 * erase points
					 */
					DrawPixels(&Pic1,CurX,CurY,NULL);
					DrawPixels(&Pic2,CurX,CurY,NULL);
					break;
				case EDIT1:
					/* Editing in one window,
					 * erase current postion and redraw in original
					 */
					DrawPixels(pic,CurX,CurY,MyPoint);
					if (pic == &Pic2) {
						DrawPixels(pic,MyPoint->x1,MyPoint->y1,MyPoint);
					}
					else {
						DrawPixels(pic,MyPoint->x,MyPoint->y,MyPoint);
					}
					break;
				case EDIT2:
					/* Editing in both windows,
					 * erase current postion and redraw in original
					 */
					DrawPixels(&Pic1,CurX,CurY,MyPoint);
					DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
					DrawPixels(&Pic2,CurX,CurY,MyPoint);
					DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
					break;
				case EDITREL:
					/* Editing relatively in both windows,
					 * erase current postions and redraw in original
					 */
					if (pic == &Pic1) {
						DrawPixels(&Pic1,CurX,CurY,MyPoint);
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
						DrawPixels(&Pic2,CurX1,CurY1,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
					}
					else {
						DrawPixels(&Pic2,CurX,CurY,MyPoint);
						DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
						DrawPixels(&Pic1,CurX1,CurY1,MyPoint);
						DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
					}
					break;
				case DELETE:
					/* Deleting points
					 * Redraw in original position
					 */
					DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
					DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
					break;
				case LINK2A:
					/* Linking points
					 * Re-Unlink
					 */
					Record(MyGetMsg(MSG_RECUNLINK),(ULONG)MyPoint->x,(ULONG)MyPoint->y,(ULONG)MyPoint1->x,(ULONG)MyPoint1->y);
					UnlinkPoints(MyPoint,MyPoint1,TRUE);	// no break
				case LINK2:
					/* and reset title and pointer */
					SetWindowTitles(ControlWindow,MyGetMsg(MSG_L1),(UBYTE *)-1);
					Mode = LINK1;
					SetMyPointer();
					break;
				case UNLINK2A:
					/* Unlinking points
					 * re-link
					 */
					Record(MyGetMsg(MSG_RECLINK),(ULONG)MyPoint->x,(ULONG)MyPoint->y,(ULONG)MyPoint1->x,(ULONG)MyPoint1->y);
					LinkPoints(MyPoint,MyPoint1);				// no break
				case UNLINK2:
					/* and reset title and pointer */
					SetWindowTitles(ControlWindow,MyGetMsg(MSG_U1),(UBYTE *)-1);
					Mode = UNLINK1;
					SetMyPointer();
					break;
				default:
					// some other mode?
					break;
				}
				if (!EGS) {
					/* Scroll the images back to
					 * their original position
					 */
					pic->XLeft=pic->Left;
					pic->XTop=pic->Top;
					pic->Left=OldLeft;
					pic->Top=OldTop;
					SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
						PGA_Top, pic->Top, TAG_END);
					SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
						PGA_Top, pic->Left, TAG_END);
					checkGadget(pic); 
					if (pic == &Pic1) {
						pic1 = &Pic2;
					}
					else {
						pic1 = &Pic1;
					}
					pic1->XLeft=pic1->Left;
					pic1->XTop=pic1->Top;
					pic1->Left=OldLeft1;
					pic1->Top=OldTop1;
					SetGadgetAttrs(pic1->SideGad, pic1->Win, NULL,
						PGA_Top, pic1->Top, TAG_END);
					SetGadgetAttrs(pic1->BotGad, pic1->Win, NULL,
						PGA_Top, pic1->Left, TAG_END);
					checkGadget(pic1); 
				}
			}
			break;
		default:
			// Some other mouse button?
			break;
		}
	}
}

void
MouseMove(struct Picture *pic) {
	/* The mouse moved
	 * If we are currently doing something
	 * then update
	 */
	if (SelDown) {
		OldX = CurX;
		OldY = CurY;
		CurX=EGS?pic->EGS_Win->MouseX:(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
		CurY=EGS?pic->EGS_Win->MouseY:(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
		CurX *= xfact;
		CurY *= yfact;
		LimitPoints(&CurX,&CurY,pic);
		switch(Mode) {
		case EDIT1:
			/* Editing one window
			 * Erase old position
			 */
			DrawPixels(pic,OldX,OldY,MyPoint);
			break;
		case ADD:
			/* Adding
			 * Erase old positions
			 */
			DrawPixels(&Pic1,OldX,OldY,NULL);
			DrawPixels(&Pic2,OldX,OldY,NULL);
			break;
		case EDIT2:
			/* Editing both windows
			 * Erase old positions
			 */
			DrawPixels(&Pic1,OldX,OldY,MyPoint);
			DrawPixels(&Pic2,OldX,OldY,MyPoint);
			break;
		case EDITREL:
			/* Editing relatively both windows
			 * Erase old positions
			 */
			OldX1 = CurX1;
			OldY1 = CurY1;
			CurX1 += (CurX - OldX);
			CurY1 += (CurY - OldY);
			if (pic == &Pic1){
				DrawPixels(&Pic1,OldX,OldY,MyPoint);
				DrawPixels(&Pic2,OldX1,OldY1,MyPoint);
			}
			else {
				DrawPixels(&Pic1,OldX1,OldY1,MyPoint);
				DrawPixels(&Pic2,OldX,OldY,MyPoint);
			}
			break;
		default:
			break;
		}
		if (!EGS) {
			// Scroll the current window if required
			pic->XLeft=pic->Left;
			pic->XTop=pic->Top;
			SetMyGadgets(pic,CurX,CurY);
		}
		// Draw new positions
		switch(Mode) {
		case EDIT1:
			/* Editing one window
			 * Draw new position
			 */
			DrawPixels(pic,CurX,CurY,MyPoint);
			break;
		case ADD:
			/* Adding
			 * Draw new positions
			 */
			DrawPixels(&Pic1,CurX,CurY,NULL);
			DrawPixels(&Pic2,CurX,CurY,NULL);
			break;
		case EDIT2:
			/* Editing both windows
			 * Draw new positions
			 */
			DrawPixels(&Pic1,CurX,CurY,MyPoint);
			DrawPixels(&Pic2,CurX,CurY,MyPoint);
			break;
		case EDITREL:
			/* Editing both windows relatively
			 * Draw new positions
			 */
			LimitPoints(&CurX1,&CurY1,pic);
			if (pic == &Pic1){
				DrawPixels(&Pic1,CurX,CurY,MyPoint);
				DrawPixels(&Pic2,CurX1,CurY1,MyPoint);
			}
			else {
				DrawPixels(&Pic2,CurX,CurY,MyPoint);
				DrawPixels(&Pic1,CurX1,CurY1,MyPoint);
			}
			break;
		default:
			// Some other mode
			break;
		}
		if (!EGS) {
			/* If we are affecting the other window then
			 * we may need to scroll it
			 */
			if ((Mode == ADD) || (Mode == EDIT2) || (Mode == EDITREL)) {
				if (pic == &Pic1) {
					pic1 = &Pic2;
				}
				else {
					pic1 = &Pic1;
				}
				if (Mode != EDITREL) {
					// Points both in the same position
					CurX1 = CurX;
					CurY1 = CurY;
				}
				pic1->XLeft=pic1->Left;
				pic1->XTop=pic1->Top;
				SetMyGadgets(pic1,CurX1,CurY1);
			}
		}
	}
}
