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

// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

// mpaddock@cix.compulink.co.uk

//	$Author: M_J_Paddock $
//	$Date: 1993/09/12 14:22:47 $
//	$Revision: 1.16 $

// include normally precompiled headers if required
#ifndef TSMORPH_H
#include "TSMorph.h"
#endif

/* Disable CTRL-C checking	*/
int CXBRK(void) { return(0); }
int chkabort(void) { return(0); }

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

struct OpalBase *OpalBase;

/* Table of system gadget sizes
 * See TSMorph.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 struct FileRequester 	*sfilereq	= 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 BOOL							PaletteAllowed			= TRUE;
extern char 						**ArgArray				= NULL;
extern char 						**ArgArraySettings	= NULL;
extern AMIGAGUIDECONTEXT 		handle 		= NULL;
extern BOOL							palette		= TRUE;
extern BOOL							CreateIcons = TRUE;
extern BOOL							CreateIconsR = FALSE;/* TRUE if to write Render Icons	*/
extern BOOL							CreateIconsP = TRUE;	/* TRUE if to write prefs Icons	*/
extern BOOL							KeepSettings = TRUE; /* TRUE to save settings on quit */
extern ULONG						DX=0;
extern ULONG						DY=0;
char							LoadScript[128] = "Rexx/Loadscript";
char							PreScript[128] = "Rexx/Prescript";
char							PostScript[128] = "Rexx/Postscript";
char							PreviewScript[128] = "Rexx/Preview";
char							ScreenName[128] = "";
char							ScreenNameR[128] = "";
char							CustomName[128] = "";
extern ULONG						CustomDepth = 4;
extern BOOL							OpenedScreen = FALSE;/* Did we open the screen			*/
extern ULONG						Depth=2;
extern ULONG						RenderMode=0;
extern ULONG						SaveFormat=0;
extern ULONG						Quality=75;
extern ULONG						ASig			= 0;
extern ULONG						OpenMode		= 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							AntiAlias	= FALSE;	// Anti Alias?
extern BOOL							GHelp			= FALSE;	// Gadget Help?

struct MsgPort		*WMsgPortp;			// Message port for Picture Windows
ULONG 				IDCMPFlags;			// IDCMP flags for windows
LONG 					Start;				// Start frame
struct NewAmigaGuide		nag 	= {NULL};	// .guide stuff

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

/* Properties for IFF read	*/
extern LONG props[] = {	ID_ILBM,	ID_BMHD,	// Just need BitMapHeader
						ID_ILBM,	ID_CAMG,			// CAMG (not sure why)
						ID_ILBM, ID_CMAP,			// And ColourMap
						TAG_DONE };

extern LONG stops[] = {	ID_ILBM,	ID_BODY,	// Stop on Body chunk
						TAG_DONE };

extern LONG nowt[] = { TAG_DONE };			// Nothing else is required

extern LONG FrameNumber = 0;					// Current frame number

/* Wait pointer */
extern USHORT __chip BusyPointerData[] =
{
	0x0000,0x0000,
	0x0400,0x07C0,0x0000,0x07C0,0x0100,0x0380,0x0000,0x07E0,
	0x07C0,0x1FF8,0x1FF0,0x3FEC,0x3FF8,0x7FDE,0x3FF8,0x7FBE,
	0x7FFC,0xFF7F,0x7EFC,0xFFFF,0x7FFC,0xFFFF,0x3FF8,0x7FFE,
	0x3FF8,0x7FFE,0x1FF0,0x3FFC,0x07C0,0x1FF8,0x0000,0x07E0,
	0x0000,0x0000,
};


/* Version string for CLI version */
char *Version = "$VER: TSMorph 2.3 (6.10.93)";

/* Display About requester
 * using reqtools.library if available
 */
void
About(void) {
	UBYTE *body = "TSMorph\n©1993 Topicsave Ltd/M J Paddock\n\n"
					  "TSMorph comes with ABSOLUTELY NO WARRANTY\n\n"
					  "This is free software, and you are welcome to redistribute it\n"
					  "under certain conditions\n\n"
					  "See file COPYING for details";
	UBYTE *title = "TSMorph 2.3 (6.10.93)";
	UBYTE *gad = "OK";
	struct EasyStruct EasyStruct = {
	  	sizeof(struct EasyStruct),
		0,
		NULL,
		NULL,
		NULL
	};
	DisableWindows(DI_About);
	if (ReqToolsBase) {
		rtEZRequestTags(body,"_OK",NULL,NULL,
							RT_Window,		TSMorphWnd,
							RTEZ_ReqTitle,	title,
							RTEZ_Flags,		EZREQF_CENTERTEXT,
							RT_Underscore,	'_',
							TAG_END);
	}
	else {
		EasyStruct.es_Title = title;
		EasyStruct.es_TextFormat = body;
		EasyStruct.es_GadgetFormat = gad;
		EasyRequestArgs(TSMorphWnd,&EasyStruct,NULL,NULL);
	}
	EnableWindows();
}

/* The main procedure	*/
void
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

 /* Initalise list of points	*/
 NewList(&PointList);
 // try and open optional libraries
 DCTVBase = OpenLibrary("dctv.library",3L);
 OpalBase = (struct OpalBase *)OpenLibrary("opal.library",0L);
 ReqToolsBase = OpenLibrary("reqtools.library",38);
 /* If we can open amigaguide.library
  * then set up the help stuff
  */
 if (AmigaGuideBase = OpenLibrary ("amigaguide.library", 34L)) {
  nag.nag_BaseName		= "TSMorph";
  nag.nag_Name				= "TSMorph.guide";
  nag.nag_ClientPort		= "TSMorph_HELP";
  nag.nag_Context			= context;
  nag.nag_Flags			= HTF_NOACTIVATE;
  nag.nag_PubScreen		= NULL;
  if (handle = OpenAmigaGuideAsync(&nag, NULL)) {
   ASig = AmigaGuideSignal(handle);
  }
 }
 /* Open all the libraries/devices/message ports/file requesters etc.	*/
 if (IntuitionBase = OpenLibrary("intuition.library",37L)) {
  if (RexxSysBase = 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",37L)) {
      if (LayersBase = OpenLibrary("layers.library",37L)) {
       if (GadToolsBase = OpenLibrary("gadtools.library",37L)) {
        if (AslBase = OpenLibrary("asl.library",37L)) {
         if (UtilityBase = OpenLibrary("utility.library",37)) {
          if (DiskfontBase = OpenLibrary("diskfont.library",36)) {
           if (WMsgPortp = CreateMsgPort()) {
            if (filereq = (struct FileRequest *)AllocFileRequest()) {
              /* Read all the parameters/tooltypes/settings file	*/
              MyArgArrayInit(argc,argv);
              InitParams(TRUE);
              /* 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, NULL)) {
                  ASig = AmigaGuideSignal(handle);
                 }
                }
               }
               /* Update the Info window menus and open	*/
               if (!SetupScreen()) {
                if (!OpenTSMorphWindow()) {
                 /* Set up system requester redirection	*/
                 process = (struct Process *)FindTask(NULL);
                 oldWindowPtr = process->pr_WindowPtr;
                 process->pr_WindowPtr = TSMorphWnd;
                 /* Activate the window and disable		*/
                 ActivateWindow(TSMorphWnd);
                 DisableWindows(DI_LoadBrush);
                 /* Load brushes if possible					*/
                 LoadBrushes();
                 /* No filename as yet							*/
 		           *savedfilename = 0;
 		           if (argc) {
 	               if (filename = ArgString(ArgArray,"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();
                 doMsgLoop();
                 if (KeepSettings) {
                  SaveSettings("ENV:TSMorph/TSMorph.prefs");	// 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;
                }
                CloseTSMorphWindow();
                if (!OkFlag && !e) {
                 e = "Failure %s";					// e and e1 to save memory as e is reused
                 e1 = "opening TSMorph Window";
                 hnum = HE_OMorph;
                }
               }
               CloseDownScreen();
               if (!OkFlag && !e) {
                e = "Failure %s";
                e1 = "setting up screen";
                hnum = HE_Screen;
               }
              }
              else {
               // Displayed error message elsewhere
               OkFlag = TRUE;
              }
              MyArgArrayDone();
              FreeFileRequest(filereq);
            }
            if (!OkFlag && !e) {
             e = "Unable to %s";
             e1 = "Allocate FileRequest";
             hnum = HE_FileReq;
            }
            Forbid();
            while (Message = GetMsg(WMsgPortp)) {
             ReplyMsg(Message);
            }
            DeleteMsgPort(WMsgPortp);
            Permit();
           }
           if (!OkFlag && !e) {
            e = "Unable to %s";
            e1 = "Create Window Message Port";
            hnum = HE_WPort;
           }
           CloseLibrary(DiskfontBase);
          }
          if (!OkFlag && !e) {
           e = "Can not Open %s";
           e1= "diskfont.library(36)";
           hnum = HE_Library;
	 	 	 }
          CloseLibrary(UtilityBase);
         }
         if (!OkFlag && !e) {
          e = "Can not Open %s";
          e1 = "utility.library(37)";
          hnum = HE_Library;
         }
         CloseLibrary(AslBase);
        }
        if (!OkFlag && !e) {
         e = "Can not Open %s";
         e1 = "asl.library(37)";
         hnum = HE_Library;
        }
        CloseLibrary(GadToolsBase);
       }
       if (!OkFlag && !e) {
        e = "Can not Open %s";
        e1 = "gadtools.library(37)";
        hnum = HE_Library;
       }
       CloseLibrary(LayersBase);
      }
      if (!OkFlag && !e) {
       e = "Can not Open %s";
       e1 = "layers.library(37)";
       hnum = HE_Library;
      }
      CloseLibrary(GfxBase);
     }
     if (!OkFlag && !e) {
      e = "Can not Open %s";
      e1 = "graphics.library(37)";
      hnum = HE_Library;
     }
     CloseDevice(&InputIO);
    }
    if (!OkFlag && !e) {
     e = "Can not Open %s";
     e1 = "input.device";
     hnum = HE_IDevice;
    }
    CloseLibrary(IFFParseBase);
   }
   if (!OkFlag && !e) {
    e = "Can not Open %s";
    e1 = "iffparse.library(37)";
    hnum = HE_Library;
   }
 	CloseLibrary(IconBase);
  }
  if (!OkFlag && !e) {
   e = "Can not Open %s";
   e1 = "icon.library(37)";
   hnum = HE_Library;
  }
 	CloseLibrary(RexxSysBase);
  }
  if (!OkFlag && !e) {
   e = "Can not Open %s";
   e1 = "rexxsyslib.library(0)";
   hnum = HE_Library;
  }
  if (!OkFlag) {
   Error(e,"Quit",e1,hnum);			// Display error message if it failed
  }
 }
 if (AmigaGuideBase) {
  if (handle) {
 	CloseAmigaGuide(handle);
  }
  CloseLibrary(AmigaGuideBase);
 }
 if (OpalBase) {
  CloseLibrary((struct Library *)OpalBase);
 }
 if (ReqToolsBase) {
  CloseLibrary(ReqToolsBase);
 }
 if (DCTVBase) {
  CloseLibrary(DCTVBase);
 }
 if (OpenedScreen) {
  CloseCustomScreen();
 }
 if (IntuitionBase) {
  CloseLibrary(IntuitionBase);
 }
}

/* 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
 int i;							// Loop counter for bit planes
 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,ASL_Hail,(Tag) "TSMorph - Pick ILBM",TAG_DONE)) {
   strncpy(dirname,filereq->rf_Dir,256);
   if (AddPart(dirname,filereq->rf_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 IFF stuff
     * and do some validation and set some gadgets
     */
    if (pic->ilbm = (struct ILBMInfo *)AllocMem(sizeof(struct ILBMInfo),MEMF_PUBLIC|MEMF_CLEAR)) {
     if (!MyLoadBrush(pic,ifilename)) {
      e = (char *)-1;
      GUI = FALSE;	// already displayed message
     }
     else {
      if (pic == &Pic1) {
		 if ((Pic1.ilbm->Bmhd.w < MaxWidth) ||
           (Pic1.ilbm->Bmhd.h < MaxHeight)) {
        e = "Image smaller than points";
        hnum = HE_ISmall;
       }
      }
      else {
       if ((Pic1.ilbm->Bmhd.w != Pic2.ilbm->Bmhd.w) ||
           (Pic1.ilbm->Bmhd.w != Pic2.ilbm->Bmhd.w)) {
        e = "Images different sizes";
        hnum = HE_IDifferent;
       }
       else {
        Width = Pic1.ilbm->Bmhd.w;
        Height = Pic1.ilbm->Bmhd.h;
		  GT_SetGadgetAttrs(TSMorphGadgets[GDX_Width],TSMorphWnd,NULL,
								GTNM_Number,Width,
								TAG_END );
		  GT_SetGadgetAttrs(TSMorphGadgets[GDX_Height],TSMorphWnd,NULL,
								GTNM_Number,Height,
								TAG_END );
       }
      }
      /* 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) {
        InitBitMap(&(pic->BitMap),min(min(pic->ilbm->Bmhd.nPlanes,8),pic->Screen->BitMap.Depth),pic->ilbm->Bmhd.w<<1,pic->ilbm->Bmhd.h<<1);
 		  for (i=0;
 				(i < pic->ilbm->Bmhd.nPlanes) && (i < 8) && (i < pic->Screen->BitMap.Depth) && !e; // Allow up to 8 bitplanes
 				++i) {
		   if (!(pic->BitMap.Planes[i] = AllocRaster(pic->ilbm->Bmhd.w<<1,pic->ilbm->Bmhd.h<<1))) {
          e = "Unable to Allocate %s";
          e1 = "Zoom raster";
          hnum = HE_ZRaster;
         }
		  }
		  if (!e) {
		   pic->BitScaleArgs.bsa_SrcX 		= 0;
		   pic->BitScaleArgs.bsa_SrcY 		= 0;
		   pic->BitScaleArgs.bsa_SrcWidth 	= pic->ilbm->Bmhd.w;
		   pic->BitScaleArgs.bsa_SrcHeight 	= pic->ilbm->Bmhd.h;
		   pic->BitScaleArgs.bsa_DestX 		= 0;
		   pic->BitScaleArgs.bsa_DestY 		= 0;
		   pic->BitScaleArgs.bsa_DestWidth 	= pic->ilbm->Bmhd.w<<1;
		   pic->BitScaleArgs.bsa_DestHeight = pic->ilbm->Bmhd.h<<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->ilbm->brbitmap;
		   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->ilbm->brbitmap,0,0,
		     			  &(pic->BitMap),0,0,
		     			  pic->ilbm->Bmhd.w,pic->ilbm->Bmhd.h,
		     			  0xC0,0xff,NULL);
		   }
		  }
		 }
		}
      if (!e) {
       pic->Left = 0;	//	Need to do this as Pic structures can be closed and reopened
       pic->Top = 0;
       /* Allocate all gadgets and images	*/
       if (pic->BotGad = (struct Gadget *)NewObject(NULL,"propgclass",
         PGA_Freedom,		FREEHORIZ,
         PGA_NewLook,		TRUE,
         PGA_Borderless,	TRUE,
         PGA_Top,				pic->Left,
         PGA_Visible,		pic->ilbm->Bmhd.w<<Zoom,
         PGA_Total,			pic->ilbm->Bmhd.w<<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,
         ICA_MAP,				MapToIdcmp,
         GA_UserData,		pic,
         TAG_END)) {
        if (pic->SideGad = (struct Gadget *)NewObject(NULL,"propgclass",
          PGA_Freedom,		FREEVERT,
          PGA_NewLook,		TRUE,
          PGA_Borderless,	TRUE,
          PGA_Top,			pic->Top,
          PGA_Visible,		pic->ilbm->Bmhd.h<<Zoom,
          PGA_Total,			pic->ilbm->Bmhd.h<<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,
          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,
               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,
                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,
                 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,
                  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_PUBLIC|MEMF_CLEAR)) {	// Extra for other frames
                  strcpy(pic->filename,ifilename);
                  if (pic->Win = OpenWindowTags(NULL,
                    WA_Width,			(pic->ilbm->Bmhd.w<<Zoom)+
                    						pic->Screen->WBorLeft+SIZEIMAGE_W(n),
                    WA_Height,		(pic->ilbm->Bmhd.h<<Zoom)+
                    						pic->Screen->WBorTop+pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n),
                    WA_AutoAdjust,	TRUE,
                    WA_MaxWidth,		(pic->ilbm->Bmhd.w<<Zoom)+
                    						pic->Screen->WBorLeft+SIZEIMAGE_W(n),
                    WA_MaxHeight,	(pic->ilbm->Bmhd.h<<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->ilbm->brbitmap),
                    /* 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,
                    TAG_DONE)) {
                   // Enable gadget Help if possible
						 if (IntuitionBase->lib_Version > 38) {
                    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;
                   IDCMPFlags = IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN |
                                IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE |
                                IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUVERIFY |
                                IDCMP_MENUHELP | IDCMP_RAWKEY | IDCMP_VANILLAKEY |
                                IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_CHANGEWINDOW |
                                IDCMP_GADGETHELP;
                   ModifyIDCMP(pic->Win,IDCMPFlags);
                   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 = "Unable to %s";
                    e1 = "SetMenuStrip";
                    hnum = HE_Menu;
                   }
                  }
                  if (!e) {
                   e = "Unable to %s";
                   e1 = "OpenWindowTags";
                   hnum = HE_OWindow;
                  }
                 }
                 if (!e) {
                  e = "Unable to %s";
                  e1 = "AllocMem for Filename";
                  hnum = HE_MemFile;
                 }
                }
                if (!e) {
                 e = "Unable to Allocate %s";
                 e1 = "Down Gadget";
                 hnum = HE_AllocGadget;
                }
               }
               if (!e) {
                e = "Unable to Allocate %s";
                e1 = "Up Gadget";
                hnum = HE_AllocGadget;
               }
              }
              if (!e) {
               e = "Unable to Allocate %s";
               e1 = "Right Gadget";
               hnum = HE_AllocGadget;
              }
             }
             if (!e) {
              e = "Unable to Allocate %s";
              e1 = "Left Gadget";
              hnum = HE_AllocGadget;
             }
            }
            if (!e) {
             e = "Unable to Allocate %s";
             e1 = "Up Image";
             hnum = HE_AllocImage;
            }
           }
           if (!e) {
            e = "Unable to Allocate %s";
            e1 = "Down Image";
            hnum = HE_AllocImage;
           }
          }
          if (!e) {
           e = "Unable to Allocate %s";
           e1 = "Right Image";
           hnum = HE_AllocImage;
          }
         }
         if (!e) {
          e = "Unable to Allocate %s";
          e1 = "Left Image";
          hnum = HE_AllocImage;
         }
        }
        if (!e) {
         e = "Unable to Allocate %s";
         e1 = "Vertical Gadget";
         hnum = HE_AllocGadget;
        }
       }
       if (!e) {
        e = "Unable to Allocate %s";
        e1 = "Horizontal Gadget";
        hnum = HE_AllocGadget;
       }
      }
     }
    }
    if (!e) {
     e = "Unable to %s";
     e1 = "AllocMem for ILBMInfo";
     hnum = HE_AllocILBM;
    }
   }
   if (!e) {
    e = "Unable to %s";
    e1 = "GetScreenDrawInfo";
    hnum = HE_GetDRI;
   }
  }
  if (!e) {
   e = "Unable to LockPubScreen(%s)";
   e1 = PubScreenName;
   hnum = HE_LockScreen;
  }
  /* Clear everything down
   * and display an error message if requested
   */
  CloseAPicture(pic);
  if (GUI)
   Error(e,"OK",e1,hnum);
 }
 return(FALSE);
}

/* Close a (partially open)
 * picture, clearing everything
 * down in reverse order
 */
void
CloseAPicture(struct Picture *pic) {
	int i;	// Loop counter for bitmaps
	if (pic) {
		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 (ZoomAllowed) {
			for (i=0;
				(i < pic->ilbm->Bmhd.nPlanes) && (i < 8);
				++i) {
				if (pic->BitMap.Planes[i]) {
					FreeRaster(pic->BitMap.Planes[i],pic->ilbm->Bmhd.w<<1,pic->ilbm->Bmhd.h<<1);
					pic->BitMap.Planes[i] = NULL;
				}
			}
		}
		if (pic->ilbm) {
			unloadbrush(pic->ilbm);
			if (pic->ilbm->ParseInfo.iff) {
				FreeIFF(pic->ilbm->ParseInfo.iff);
			}
			FreeMem(pic->ilbm,sizeof(struct ILBMInfo));
			pic->ilbm = 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->ilbm->Bmhd.w<<Zoom)) {
		ScrollLayer(0,pic->Win->RPort->Layer,(pic->ilbm->Bmhd.w<<Zoom)-tmp,0);
		pic->Left += (pic->ilbm->Bmhd.w<<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->ilbm->Bmhd.w<<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->ilbm->Bmhd.h<<Zoom)) {
		ScrollLayer(0,pic->Win->RPort->Layer,0,(pic->ilbm->Bmhd.h<<Zoom)-tmp);
		pic->Top += (pic->ilbm->Bmhd.h<<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->ilbm->Bmhd.h<<Zoom) - pic->Win->GZZHeight;
}

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

/* 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;
	/* Scale coordinates if zoomed
	 * and draw 3x3 point
	 */
	zx = x << Zoom;
	zy = y << Zoom;
	WritePixel(pic->Win->RPort,zx-2,zy-2);
	WritePixel(pic->Win->RPort,zx-1,zy-2);
	WritePixel(pic->Win->RPort,zx,zy-2);
	WritePixel(pic->Win->RPort,zx+1,zy-2);
	WritePixel(pic->Win->RPort,zx+2,zy-2);
	WritePixel(pic->Win->RPort,zx-2,zy-1);
	WritePixel(pic->Win->RPort,zx-1,zy-1);
	WritePixel(pic->Win->RPort,zx,zy-1);
	WritePixel(pic->Win->RPort,zx+1,zy-1);
	WritePixel(pic->Win->RPort,zx+2,zy-1);
	WritePixel(pic->Win->RPort,zx-2,zy);
	WritePixel(pic->Win->RPort,zx-1,zy);
	WritePixel(pic->Win->RPort,zx,zy);
	WritePixel(pic->Win->RPort,zx+1,zy);
	WritePixel(pic->Win->RPort,zx+2,zy);
	WritePixel(pic->Win->RPort,zx-2,zy+1);
	WritePixel(pic->Win->RPort,zx-1,zy+1);
	WritePixel(pic->Win->RPort,zx,zy+1);
	WritePixel(pic->Win->RPort,zx+1,zy+1);
	WritePixel(pic->Win->RPort,zx+2,zy+1);
	WritePixel(pic->Win->RPort,zx-2,zy+2);
	WritePixel(pic->Win->RPort,zx-1,zy+2);
	WritePixel(pic->Win->RPort,zx,zy+2);
	WritePixel(pic->Win->RPort,zx+1,zy+2);
	WritePixel(pic->Win->RPort,zx+2,zy+2);
	/* 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 (MyPoint) {
			if (MyPoint->p1) {
				MyDraw(pic->Win->RPort,MyPoint->p1->x1<<Zoom,MyPoint->p1->y1<<Zoom,zx,zy);
			}	
			if (MyPoint->p2) {
				MyDraw(pic->Win->RPort,MyPoint->p2->x1<<Zoom,MyPoint->p2->y1<<Zoom,zx,zy);
			}
			if (MyPoint->p3) {
				MyDraw(pic->Win->RPort,MyPoint->p3->x1<<Zoom,MyPoint->p3->y1<<Zoom,zx,zy);
			}
			if (MyPoint->p4) {
				MyDraw(pic->Win->RPort,MyPoint->p4->x1<<Zoom,MyPoint->p4->y1<<Zoom,zx,zy);
			}
		}
	}
	else {
		if (MyPoint) {
			if (MyPoint->p1) {
				MyDraw(pic->Win->RPort,MyPoint->p1->x<<Zoom,MyPoint->p1->y<<Zoom,zx,zy);
			}
			if (MyPoint->p2) {
				MyDraw(pic->Win->RPort,MyPoint->p2->x<<Zoom,MyPoint->p2->y<<Zoom,zx,zy);
			}
			if (MyPoint->p3) {
				MyDraw(pic->Win->RPort,MyPoint->p3->x<<Zoom,MyPoint->p3->y<<Zoom,zx,zy);
			}
			if (MyPoint->p4) {
				MyDraw(pic->Win->RPort,MyPoint->p4->x<<Zoom,MyPoint->p4->y<<Zoom,zx,zy);
			}
		}
	}
}	

/* 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);
	}
}

/* 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;					// Number of frames
	struct MyPoint *MyPoint,	// Points to create and link
						*MyPoint1;
	BOOL JP = FALSE;				// Set if 2.0 points file
	/* If current project not saved then suggest it is saved	*/
	if (!Saved) {
		if (!SaveRequester()) {
			return ok;
		}
		DisableWindows(DI_WaitOpen);
	}
	/* Get filename, from parameter or ASL requester, save name for saving later */
	if (filename) {
		ifilename = filename;
		if (!JustPoints) {
			strncpy(savedfilename,filename,256);
		}
	}
	else {
		if (GetAFile(*savedfilename?savedfilename:"",
						 (Tag) JustPoints ? "TSMorph - Load Points": "TSMorph - Load Project",
						 0)) {
			ifilename=TempFilename;
			if (!JustPoints) {
				strncpy(savedfilename,TempFilename,256);
			}
		}
  	}
  	/* If we have a filename then delete current points and set the window title	*/
	if (ifilename) {
		if (!JustPoints) {
			OpenNewArgs(ifilename);		// Load new parameters
			InitParams(FALSE);
		}
		DeleteAllPoints();
		SetWindowTitles(TSMorphWnd,(UBYTE *)-1,savedfilename);
		if (fh=Open(ifilename,MODE_OLDFILE)) {
			// Get header
			FGets(fh,buffer,256);
			if (JustPoints && (JP = !strcmp(buffer,"TSMorph 2.0\n"))) {
				DeleteAllPoints();
			}
			else {
				if (strcmp(buffer,"TSMorph 1.2\n")) {
					Error("Assuming version 1.0 file format","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(TSMorphGadgets[GDX_FileOne],TSMorphWnd,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(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,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(TSMorphGadgets[GDX_File241],TSMorphWnd,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(TSMorphGadgets[GDX_File242],TSMorphWnd,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(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL,
											GTST_String, buffer, TAG_END );
				}
				// General stuff
				FGets(fh,buffer,256);
				if (!JustPoints) {
					if (ok && (sscanf(buffer,"w=%ld,h=%ld,Frames=%ld,Single=%ld,Start=%ld",&w,&h,&Frames,&SinglePicture,&Start) != 5)) {
						Error("Invalid file format\nLine '%s'","OK",buffer,HE_FileFormat);
						ok = FALSE;
					}
					else {
						GT_SetGadgetAttrs(TSMorphGadgets[GDX_Frames],TSMorphWnd,NULL,
												GTIN_Number,Frames, TAG_END );
						GT_SetGadgetAttrs(TSMorphGadgets[GDX_Start],TSMorphWnd,NULL,
													GTIN_Number,Start, TAG_END );
						GT_SetGadgetAttrs(TSMorphGadgets[GDX_SinglePicture],TSMorphWnd,NULL,
												GTCY_Active,SinglePicture, TAG_END );
						if (ok && ControlWindow &&
								((w > Pic1.ilbm->Bmhd.w) ||
							 (h > Pic1.ilbm->Bmhd.h))) {
							Error("Images are too small","OK",NULL,HE_TooSmall);
							ok = FALSE;
						}
					}
				}
			}
			if (ok) {
				MaxWidth 	= 0;
				MaxHeight 	= 0;
				// Read and validate point
				while (ok &&
					FGets(fh,buffer,256) &&
					(sscanf(buffer,"x=%ld,y=%ld,x1=%ld,y1=%ld",&x,&y,&x1,&y1) == 4)) {
					if (Pic1_Open) {
						if ((x<0)||(x>(Pic1.ilbm->Bmhd.w-1)) ||
							 (y<0)||(y>(Pic1.ilbm->Bmhd.h-1))) {
							Error("Point out of range\nLine '%s'","OK",buffer,HE_Range);
							ok = FALSE;
						}
					}
					// 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("Out of memory for points","OK",NULL,HE_MemPoints);
						ok=FALSE;
					}
				}
				Width = max(w,MaxWidth);
				Height = max(h,MaxHeight);
				if (Pic1_Open) {
					Width = max(Width,Pic1.ilbm->Bmhd.w);
					Height = max(Height,Pic1.ilbm->Bmhd.h);
				}
				GT_SetGadgetAttrs(TSMorphGadgets[GDX_Width],TSMorphWnd,NULL,
										GTNM_Number,Width, TAG_END );
				GT_SetGadgetAttrs(TSMorphGadgets[GDX_Height],TSMorphWnd,NULL,
										GTNM_Number,Height, TAG_END );
				// Read all the links
				while (ok &&
					(sscanf(buffer,"p1=%ld,p2=%ld",&p1,&p2) == 2)) {
					if ((p1>PointCount) || (p2>PointCount)) {
						Error("Invalid point link\nLine '%s'","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)) {
						ok = FALSE;
					}
				}
			}
			// Close file and return cleanly
			if (!Close(fh)) {
				if (ok) {
					Error("Error closing file '%s'","OK",ifilename,HE_Close);
					ok = FALSE;
				}
			}
		}
		else {
			if (Gui) {
				Error("Error opening file '%s'","OK",ifilename,HE_Open);
			}
			ok = FALSE;
		}
	}
	if (ok && !JustPoints) {
		Saved = TRUE;
	}
	else {
		if (ok && JustPoints) {
			Saved = 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 buffer[257];				// buffer to write records
	char *ifilename	= NULL;	// File name to use
	BPTR fh;							// File handle
	LONG i,							// Loop counters
		  j;
	BOOL ok;							// How well is it going
	struct MyPoint *MyPoint,	// Points to write
						*MyPoint1;
	struct DiskObject *MyDiskObject;	// The Icon
	/* 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:"","TSMorph - Save Project",FILF_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) {
		SetWindowTitles(TSMorphWnd,(UBYTE *)-1,savedfilename);
		if (fh=Open(ifilename,MODE_NEWFILE)) {
			FPuts(fh,"TSMorph 1.2\n");
			FPuts(fh,GetString(TSMorphGadgets[GDX_FileOne]));
			FPuts(fh,"\n");
			FPuts(fh,GetString(TSMorphGadgets[GDX_FileTwo]));
			FPuts(fh,"\n");
			FPuts(fh,GetString(TSMorphGadgets[GDX_File241]));
			FPuts(fh,"\n");
			if ((SinglePicture == 0) || (SinglePicture == 2)) {
				FPuts(fh,GetString(TSMorphGadgets[GDX_File242]));
			}
			FPuts(fh,"\n");
			FPuts(fh,GetString(TSMorphGadgets[GDX_Name]));
			FPuts(fh,"\n");
			sprintf(buffer,"w=%ld,h=%ld,Frames=%ld,Single=%ld,Start=%ld\n",
					Width,Height,GetNumber(TSMorphGadgets[GDX_Frames]),SinglePicture,GetNumber(TSMorphGadgets[GDX_Start]));
			ok = !FPuts(fh,buffer);
			if ((SinglePicture == 2) || (SinglePicture == 3)) {
				if (ControlWindow) {
					if (!Close(fh)) {
						if (ok) {
							Error("Error closing file '%s'","OK",ifilename,HE_Close);
							ok = FALSE;
						}
					}
					strcpy(buffer,ifilename);
					strcat(buffer,".%03ld");
					sprintf(TempFilename,buffer,FrameNumber);
					ifilename = TempFilename;
					if (fh=Open(ifilename,MODE_NEWFILE)) {
						FPuts(fh,"TSMorph 2.0\n");
					}
					else {
						Error("Error opening file '%s'","OK",ifilename,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,"x=%ld,y=%ld,x1=%ld,y1=%ld\n",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) {
						if ((MyPoint->p1 == MyPoint1) ||
							 (MyPoint->p2 == MyPoint1) ||
							 (MyPoint->p3 == MyPoint1) ||
							 (MyPoint->p4 == MyPoint1)) {
							sprintf(buffer,"p1=%ld,p2=%ld\n",i,j);
							ok = !FPuts(fh,buffer);
						}
					}
					++j;
				}
				++i;
			}
			if (!ok) {
				Error("Error writing to '%s'","OK",ifilename,HE_Write);
			}
			// Close file and clean up
			if (!Close(fh)) {
				if (ok) {
					Error("Error closing file '%s'","OK",ifilename,HE_Close);
					ok = FALSE;
				}
			}
		}
		else {
			Error("Error opening file '%s'","OK",ifilename,HE_Open);
			ok = FALSE;
		}
		// Write Icon if required and none already exists
		if (ok) {
			if (CreateIcons) {
				if (MyDiskObject = GetDiskObject(savedfilename)) {
					FreeDiskObject(MyDiskObject);
				}
				else {
					if ((MyDiskObject = GetDiskObject("ENV:TSMorph/def_points")) ||
					    (MyDiskObject = GetDiskObject("ENV:SYS/def_points")) ||
						 (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;				// menu pointer
	struct Gadget 	*Gadget1	= NULL;	// Gadget to update
	ULONG				HNum;
	// 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?)
	 */
	ClearMenuStrip(Pic1.Win);
	ClearMenuStrip(Pic2.Win);
	ClearMenuStrip(ControlWindow);
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,0)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,1)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,2)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,3)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,4)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,5)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,6)))->Flags &= ~CHECKED;
	(ItemAddress(MyMenu,FULLMENUNUM(M_EDIT,MM_MODE,7)))->Flags &= ~CHECKED;
	// Determine "new" title, gadget and menu
	switch (NewMode) {
	case EDIT1:
		SetWindowTitles(ControlWindow,"1",(UBYTE *)-1);
		Gadget1 = &OneGadget;
		menupos = MI_EDITONE;
		HNum = H_EOne;
		break;
	case EDIT2:
		SetWindowTitles(ControlWindow,"2",(UBYTE *)-1);
		Gadget1 = &TwoGadget;
		menupos = MI_EDITTWO;
		HNum = H_ETwo;
		break;
	case EDITREL:
		SetWindowTitles(ControlWindow,"Rel",(UBYTE *)-1);
	 	Gadget1 = &RelGadget;
		menupos = MI_EDITREL;
		HNum = H_ERel;
		break;
	case ADD:
		SetWindowTitles(ControlWindow,"Add",(UBYTE *)-1);
	  	Gadget1 = &MyAddGadget;
		menupos = MI_ADD;
		HNum = H_EAdd;
		break;
	case DELETE:
		SetWindowTitles(ControlWindow,"Del",(UBYTE *)-1);
	  	Gadget1 = &DelGadget;
		menupos = MI_DELETE;
		HNum = H_EDel;
		break;
	case LINK1:
		SetWindowTitles(ControlWindow,"L1",(UBYTE *)-1);
	  	Gadget1 = &LinkGadget;
		menupos = MI_LINK;
		HNum = H_ELnk;
		break;
	case UNLINK1:
		SetWindowTitles(ControlWindow,"U1",(UBYTE *)-1);
	  	Gadget1 = &UnlinkGadget;
		menupos = MI_UNLINK;
		HNum = H_EUnl;
		break;
	case NONE:
		SetWindowTitles(ControlWindow,"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);
	ResetMenuStrip(Pic1.Win,MyMenu);
	ResetMenuStrip(Pic2.Win,MyMenu);
	// Set mode and set the pointer
	Mode = NewMode;
	SetMyPointer();
	// Display (short) help
	if (GHelp) {
		help(HNum);
	}
	else {
		ihelp(HNum);
	}
}

/* The main program
 * this loops until the program is quited
 */
void
doMsgLoop(void) {
	UWORD 					X,				// Coordinates
								Y;
	struct IntuiMessage 	*msg;			// Message from the Control window
	struct Picture 		*pic;			// Main image pointer
	struct Picture 		*pic1;		// The other image
	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
	SHORT 					OldX,			// Old coordinates
								OldY;
	SHORT 					OldX1,		// Old coordinates in other window
								OldY1;
	SHORT 					CurX,			// Current coordinates
								CurY;
	SHORT 					CurX1,		// Current coordinates in other window
								CurY1;
	UWORD 					OldLeft,		// Old position of image
								OldTop;
	UWORD 					OldLeft1,	// Old position of other image
								OldTop1;
	BOOL 						SelDown = FALSE;	// Set if left button currently pressed
	struct MyPoint 		*MyPoint,	// Points to add, link etc.
								*MyPoint1;
	struct AmigaGuideMsg *agm;			// message from amigaguide
	ULONG HNum;								// The Help node to use
	/* Loop until we quit	*/
	while (flag==1) {
		// Wait on open windows etc.
		Signals = Wait((ASig) |
							(1L << TSMorphWnd->UserPort->mp_SigBit) |
							(1L << WMsgPortp->mp_SigBit) |
							(ControlWindow ? (1L << ControlWindow->UserPort->mp_SigBit) : 0));
		// Something for the Information window
		if (Signals & (1L << TSMorphWnd->UserPort->mp_SigBit)) {
			flag = HandleTSMorphIDCMP();
		}
		/* 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) {
	 					HNum = 0;
	 				}
	 				else {
	 					if (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 {
	 						switch (((struct Gadget *)msg->IAddress)->GadgetType &0xf0) {
	 						case GTYP_WDRAGGING:
	 							HNum = H_CWindow;
	 							break;
	 						case GTYP_WUPFRONT:
	 							HNum = H_CDepth;
	 							break;
	 						case GTYP_CLOSE:
	 							HNum = H_CClose;
	 							break;
	 						case 0:
	 							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;
	 							}
	 							break;
	 						default:
	 							HNum = H_CWindow;
	 							break;
	 						}
	 					}
	 				}
	 				if (HNum) {
	 					if (GHelp) {
			 				help(HNum);
			 			}
			 			else {
			 				ihelp(HNum);
			 			}
		 			}
		 			break;
		 		case IDCMP_VANILLAKEY:
			 		// No vanilla keys currently defined
		 			break;
		 		case IDCMP_RAWKEY:
			 		// only raw key is the help key
		 			switch (msg->Code) {
		 			case 0x5F:
		 				/* determine if pointer is in a gadget
		 				 * otherwise show help on the whole window
		 				 */
						X = ControlWindow->MouseX;
						Y = ControlWindow->MouseY;
						if (PointInBox(X,Y,0,0,
												CLOSEIMAGE_W(n),ControlWindow->BorderTop))
							HNum = H_CClose;
						else
						if (PointInBox(X,Y,(ControlWindow->Width - DEPTHIMAGE_W(n)),0,
												ControlWindow->Width,ControlWindow->BorderTop))
							HNum = H_CDepth;
						else
						if (PointInBox(X,Y,OneGadget.LeftEdge,OneGadget.TopEdge,
												OneGadget.LeftEdge+OneGadget.Width,OneGadget.TopEdge+OneGadget.Height))
							HNum = H_EOne;
						else
						if (PointInBox(X,Y,TwoGadget.LeftEdge,TwoGadget.TopEdge,
												TwoGadget.LeftEdge+TwoGadget.Width,TwoGadget.TopEdge+TwoGadget.Height))
							HNum = H_ETwo;
						else
						if (PointInBox(X,Y,RelGadget.LeftEdge,RelGadget.TopEdge,
												RelGadget.LeftEdge+RelGadget.Width,RelGadget.TopEdge+RelGadget.Height))
							HNum = H_ERel;
						else
						if (PointInBox(X,Y,DelGadget.LeftEdge,DelGadget.TopEdge,
												DelGadget.LeftEdge+DelGadget.Width,DelGadget.TopEdge+DelGadget.Height))
							HNum = H_EDel;
						else
						if (PointInBox(X,Y,UnlinkGadget.LeftEdge,UnlinkGadget.TopEdge,
												UnlinkGadget.LeftEdge+UnlinkGadget.Width,UnlinkGadget.TopEdge+UnlinkGadget.Height))
							HNum = H_EUnl;
						else
						if (PointInBox(X,Y,LinkGadget.LeftEdge,LinkGadget.TopEdge,
												LinkGadget.LeftEdge+LinkGadget.Width,LinkGadget.TopEdge+LinkGadget.Height))
							HNum = H_ELnk;
						else
						if (PointInBox(X,Y,NoneGadget.LeftEdge,NoneGadget.TopEdge,
												NoneGadget.LeftEdge+NoneGadget.Width,NoneGadget.TopEdge+NoneGadget.Height))
							HNum = H_EMov;
						else
						if (PointInBox(X,Y,MyAddGadget.LeftEdge,MyAddGadget.TopEdge,
												MyAddGadget.LeftEdge+MyAddGadget.Width,MyAddGadget.TopEdge+MyAddGadget.Height))
							HNum = H_EAdd;
						else
						if (PointInBox(X,Y,stGadget.LeftEdge,stGadget.TopEdge,
												stGadget.LeftEdge+stGadget.Width,stGadget.TopEdge+stGadget.Height))
							HNum = HC_First;
						else
						if (PointInBox(X,Y,prevGadget.LeftEdge,prevGadget.TopEdge,
												prevGadget.LeftEdge+prevGadget.Width,prevGadget.TopEdge+prevGadget.Height))
							HNum = HC_Previous;
						else
						if (PointInBox(X,Y,gotoGadget.LeftEdge,gotoGadget.TopEdge,
												gotoGadget.LeftEdge+gotoGadget.Width,gotoGadget.TopEdge+gotoGadget.Height))
							HNum = HC_Goto;
						else
						if (PointInBox(X,Y,nextGadget.LeftEdge,nextGadget.TopEdge,
												nextGadget.LeftEdge+nextGadget.Width,nextGadget.TopEdge+nextGadget.Height))
							HNum = HC_Next;
						else
						if (PointInBox(X,Y,lastGadget.LeftEdge,lastGadget.TopEdge,
												lastGadget.LeftEdge+lastGadget.Width,lastGadget.TopEdge+lastGadget.Height))
							HNum = HC_Last;
						else
							HNum = H_CWindow;
						help(HNum);
		 				break;
		 			default:
		 				// any other key
		 				break;
		 			}
		 			break;
		 		case IDCMP_MENUHELP:
			 		// Show help on the Control and image windows menus
		 			DoMenuHelp(msg->Code);
		 			break;
		 		case IDCMP_GADGETDOWN:
			 		// 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:
			 		// 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:
			 		// 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)) {
		 // 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) {
 					HNum = 0;
 				}
 				else {
 					if (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 {
 						switch (((struct Gadget *)msg->IAddress)->GadgetType &0xf0) {
 						case GTYP_SIZING:
 							HNum = H_ESize;
 							break;
 						case GTYP_WDRAGGING:
 							HNum = H_EWindow;
 							break;
 						case GTYP_WUPFRONT:
 							HNum = H_EDepth;
 							break;
 						case GTYP_WDOWNBACK:
 							HNum = H_EZoom;
 							break;
 						case GTYP_CLOSE:
 							HNum = H_EClose;
 							break;
 						case 0:
 							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;
 							}
 							break;
 						default:
 							HNum = H_EWindow;
 							break;
 						}
 					}
 				}
 				if (HNum) {
 					if (GHelp) {
		 				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->ilbm->Bmhd.w+pic->Screen->WBorLeft+SIZEIMAGE_W(n),
										pic->ilbm->Bmhd.h+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->ilbm->Bmhd.w+pic->Screen->WBorLeft+SIZEIMAGE_W(n)),
										 min(pic->Win->Height,pic->ilbm->Bmhd.h+pic->Screen->WBorTop + pic->Screen->Font->ta_YSize+1+SIZEIMAGE_H(n)));
						}
					}
				}
				// Reset gadgets etc. for new size
				doNewSize(pic);
				break;
		 	case IDCMP_VANILLAKEY:
	  			switch (msg->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;
				}
				break;
	  		case IDCMP_RAWKEY:
	  			// Only raw key currently used is the help key
	  			switch (msg->Code) {
	 			case 0x5F:
	 				/* Determine the gadget the pointer is over
	 				 * or show help on the whole window
	 				 */
					X = msg->IDCMPWindow->MouseX;
					Y = msg->IDCMPWindow->MouseY;
					if (PointInBox(X,Y,0,0,
											CLOSEIMAGE_W(n),msg->IDCMPWindow->BorderTop))
						HNum = H_EClose;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width - DEPTHIMAGE_W(n)),0,
											msg->IDCMPWindow->Width,msg->IDCMPWindow->BorderTop))
						HNum = H_EDepth;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width - DEPTHIMAGE_W(n) - ZOOMIMAGE_W(n)),0,
											(msg->IDCMPWindow->Width - DEPTHIMAGE_W(n)),msg->IDCMPWindow->BorderTop))
						HNum = H_EZoom;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width - SIZEIMAGE_W(n)),(msg->IDCMPWindow->Height-10),
											msg->IDCMPWindow->Width,msg->IDCMPWindow->Height))
						HNum = H_ESize;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)-LEFTIMAGE_W(n)-RIGHTIMAGE_W(n)),(msg->IDCMPWindow->Height-LEFTIMAGE_H(n)),
											(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)-RIGHTIMAGE_W(n)),msg->IDCMPWindow->Height))
						HNum = H_Left;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)-RIGHTIMAGE_W(n)),(msg->IDCMPWindow->Height-RIGHTIMAGE_H(n)),
											(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)),msg->IDCMPWindow->Height))
						HNum = H_Right;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width-UPIMAGE_W(n)),(msg->IDCMPWindow->Height-SIZEIMAGE_H(n)-DOWNIMAGE_H(n)-UPIMAGE_H(n)),
											msg->IDCMPWindow->Width,(msg->IDCMPWindow->Height-SIZEIMAGE_H(n)-DOWNIMAGE_H(n))))
						HNum = H_Up;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width-UPIMAGE_W(n)),(msg->IDCMPWindow->Height-SIZEIMAGE_H(n)-DOWNIMAGE_H(n)),
											msg->IDCMPWindow->Width,(msg->IDCMPWindow->Height-SIZEIMAGE_H(n))))
						HNum = H_Down;
					else
					if (PointInBox(X,Y,0,(msg->IDCMPWindow->Height-SIZEIMAGE_H(n)),
											(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)-LEFTIMAGE_W(n)-RIGHTIMAGE_W(n)),msg->IDCMPWindow->Height))
						HNum = H_Horiz;
					else
					if (PointInBox(X,Y,(msg->IDCMPWindow->Width-SIZEIMAGE_W(n)),msg->IDCMPWindow->BorderTop,
											msg->IDCMPWindow->Width,(msg->IDCMPWindow->Height-SIZEIMAGE_H(n)-UPIMAGE_H(n)-DOWNIMAGE_H(n))))
						HNum = H_Vert;
					else
						HNum = H_EWindow;
					help(HNum);
	  				break;
	  			default:
	  				// some other key
	  				break;
	  			}
	  			break;
	  		case IDCMP_MENUHELP:
	  			// 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)
				 * and change the screen palette (if required)
				 */
				pic->JustSeconds = msg->Seconds;
				if (flag == 1) {
					ColorWindow(pic);
				}
				break;
			case IDCMP_INACTIVEWINDOW:
				/* Window just became inactive
				 * change the screen palette back if required
				 */
				UnColorWindow(pic);
				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
				 * otherwise change the screen palette back if required
				 * so that our menus can be readably displayed
				 */
				switch (msg->Code) {
				case MENUWAITING:
					break;
				case MENUHOT:
					pic->JustSeconds = 0;
					if (SelDown) {
						msg->Code = MENUCANCEL;
					}
					else {
						UnColorWindow(pic);
					}
					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;
		 		}
		 		/* If we are changing palettes and quit
		 		 * was not just selected then change
		 		 * palette back to the image palette
		 		 * after a menu selections
		 		 */
				if (palette && pic && (flag==1)) {
					ColorWindow(pic);
				}
				break;
	 		case IDCMP_CLOSEWINDOW:
	 			/* Close the window with Control and other image windows
	 			 * and change the palette back to original if required
	 			 */
	 			UnColorWindow(pic);
				flag = 2;
	  			break;
			case IDCMP_MOUSEBUTTONS:
				/* Somebody pressed a button
				 * If the second is the same as the activate window
				 * message then ignore this click
				 */
				if (pic->JustSeconds && (pic->JustSeconds == msg->Seconds)) {
					pic->JustSeconds = 0;
				}
				else {
					/* otherwise process the mouse click/release */
					pic->JustSeconds = 0;
					switch (msg->Code) {
					case SELECTDOWN:
						/* Left button pressed
						 * remember the currentimage positions
						 * in case Cancelled
						 */
						SelDown = TRUE;
						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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									if (pic == &Pic2) {
										DrawPixels(pic,MyPoint->x1,MyPoint->y1,MyPoint);
									}
									else {
										DrawPixels(pic,MyPoint->x,MyPoint->y,MyPoint);
									}
									CurX=(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
									CurY=(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
									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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
									DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
									CurX=(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
									CurY=(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
									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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
									DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
									CurX=(pic->Win->GZZMouseX + Zoom + pic->Left)>>Zoom;
									CurY=(pic->Win->GZZMouseY + Zoom + pic->Top)>>Zoom;
									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=(pic->Win->GZZMouseX + Zoom+pic->Left) >> Zoom;
								CurY=(pic->Win->GZZMouseY + Zoom+pic->Top) >> Zoom;
								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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									if (MyPoint->p1 && MyPoint->p2 && MyPoint->p3 && MyPoint->p4) {
	  									SelDown = FALSE;
										XError(pic,"Point already linked to 4 points","OK",NULL,HE_4points);
									}
									else {
	  									SetWindowTitles(ControlWindow,"L2",(UBYTE *)-1);
										Mode = LINK2;
										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,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									if (MyPoint->p1 || MyPoint->p2 || MyPoint->p3 || MyPoint->p4) {
	  									SetWindowTitles(ControlWindow,"U2",(UBYTE *)-1);
										Mode = UNLINK2;
										SetMyPointer();
									}
									else {
										SelDown = FALSE;
										XError(pic,"Point not linked","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 (MyPoint1 = FindPoint(pic,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									if (MyPoint == MyPoint1) {
	  									SelDown = FALSE;
										XError(pic,"Cannot link point to itself","OK",NULL,HE_LinkSelf);
									}
									else {
										if (MyPoint1->p1 && MyPoint1->p2 && MyPoint1->p3 && MyPoint1->p4) {
		  									SelDown = FALSE;
											XError(pic,"Point already linked to 4 points","OK",NULL,HE_4points);
										}
										else {
											if ((MyPoint->p1 == MyPoint1) || (MyPoint->p2 == MyPoint1) ||
												 (MyPoint->p3 == MyPoint1) || (MyPoint->p4 == MyPoint1)) {
			  									SelDown = FALSE;
												XError(pic,"Points already linked","OK",NULL,HE_Linked);
											}
											else {
												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 (MyPoint1 = FindPoint(pic,(pic->Win->GZZMouseX + Zoom) >> Zoom,(pic->Win->GZZMouseY + Zoom) >> Zoom)) {
									if (MyPoint == MyPoint1) {
										SelDown = FALSE;
										XError(pic,"Cannot unlink point from itself","OK",NULL,HE_UnlinkSelf);
									}
									else {
										if ((MyPoint->p1 != MyPoint1) && (MyPoint->p2 != MyPoint1) &&
											 (MyPoint->p3 != MyPoint1) && (MyPoint->p4 != MyPoint1)) {
											SelDown = FALSE;
											XError(pic,"Point not linked","OK",NULL,HE_NotLinked);
										}
										else {
											UnlinkPoints(MyPoint,MyPoint1,TRUE);
											Mode = UNLINK2A;
										}
									}
								}
								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 ((CurY1<<Zoom) < pic1->Top) {
									pic1->Top = CurY1<<Zoom;
									SetGadgetAttrs(pic1->SideGad, pic1->Win, NULL,
										PGA_Top, pic1->Top, TAG_END);
								}
								if ((CurX1<<Zoom) < pic1->Left) {
									pic1->Left = CurX1<<Zoom;
									SetGadgetAttrs(pic1->BotGad, pic1->Win, NULL,
									PGA_Top, pic1->Left, TAG_END);
								}
								if ((CurY1<<Zoom) > (pic1->Win->GZZHeight+pic1->Top)) {
									pic1->Top = ((CurY1<<Zoom) - pic1->Win->GZZHeight);
									SetGadgetAttrs(pic1->SideGad, pic1->Win, NULL,
										PGA_Top, pic1->Top, TAG_END);
								}
								if ((CurX1<<Zoom) > (pic1->Win->GZZWidth+pic1->Left)) {
									pic1->Left = ((CurX1<<Zoom) - pic1->Win->GZZWidth);
									SetGadgetAttrs(pic1->BotGad, pic1->Win, NULL,
										PGA_Top, pic1->Left, TAG_END);
								}
								checkGadget(pic1);
							}
						}
						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;
									MaxWidth = max(CurX,MaxWidth);
									MaxHeight = max(CurY,MaxHeight);
									AddTail(&PointList,(struct Node *)MyPoint);
									Saved = FALSE;
								}
								else {
									XError(pic,"Error no memory for new point","OK",NULL,HE_MemNewPoint);
								}
								break;
							case EDIT1:
								// Editing one window, update actual point
								if (pic == &Pic2) {
									MyPoint->x1 = CurX;
									MyPoint->y1 = CurY;
								}
								else {
									MyPoint->x = CurX;
									MyPoint->y = CurY;
								}
								Saved = FALSE;
								break;
							case EDIT2:
								// Editing two windows, update actual point
								MyPoint->x = CurX;
								MyPoint->y = CurY;
								MyPoint->x1 = CurX;
								MyPoint->y1 = CurY;
								Saved = FALSE;
								break;
							case EDITREL:
								// Editing relative, update actual point
								if (pic == &Pic1) {
									CurX1 = CurX - MyPoint->x + MyPoint->x1;
									CurY1 = CurY - MyPoint->y + MyPoint->y1;
									MyPoint->x = CurX;
									MyPoint->y = CurY;
								}
								else {
									CurX1 = CurX - MyPoint->x1 + MyPoint->x;
									CurY1 = CurY - MyPoint->y1 + MyPoint->y;
									MyPoint->x1 = CurX;
									MyPoint->y1 = CurY;
								}
								Saved = FALSE;
								LimitPoints(&CurX1,&CurY1,((pic == &Pic1)?&Pic2:&Pic1));
								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) {
									DeletePoint(MyPoint);
								}
								Saved = FALSE;
								break;
							case LINK2A:
								// Linking, reset window title and pointer
	  							SetWindowTitles(ControlWindow,"L1",(UBYTE *)-1);
								Mode = LINK1;
								Saved = FALSE;
								SetMyPointer();
								break;
							case UNLINK2A:
								// Unlinking, reset window title and pointer
		  						SetWindowTitles(ControlWindow,"U1",(UBYTE *)-1);
								Mode = UNLINK1;
								Saved = FALSE;
								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
								 */
								UnlinkPoints(MyPoint,MyPoint1,TRUE);	// no break
							case LINK2:
								/* and reset title and pointer */
	  							SetWindowTitles(ControlWindow,"L1",(UBYTE *)-1);
								Mode = LINK1;
								SetMyPointer();
								break;
							case UNLINK2A:
								/* Unlinking points
								 * re-link
								 */
								LinkPoints(MyPoint,MyPoint1);				// no break
							case UNLINK2:
								/* and reset title and pointer */
		  						SetWindowTitles(ControlWindow,"U1",(UBYTE *)-1);
								Mode = UNLINK1;
								SetMyPointer();
								break;
							default:
								// some other mode?
								break;
							}
							/* 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;
					}
				}
				break;
			case IDCMP_MOUSEMOVE:
				/* The mouse moved
				 * If we are currently doing something
				 * then update
				 */
				if (SelDown) {
					OldX = CurX;
					OldY = CurY;
					CurX=(pic->Win->GZZMouseX + Zoom+pic->Left) >> Zoom;
					CurY=(pic->Win->GZZMouseY + Zoom+pic->Top) >> Zoom;
					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;
					}
					// Scroll the current window if required
					pic->XLeft=pic->Left;
					pic->XTop=pic->Top;
					if ((CurY<<Zoom) < pic->Top) {
						pic->Top = (CurY<<Zoom);
						SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
							PGA_Top, pic->Top, TAG_END);
					}
					if ((CurX<<Zoom) < pic->Left) {
						pic->Left = (CurX<<Zoom);
						SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
							PGA_Top, pic->Left, TAG_END);
					}
					if ((CurY<<Zoom) > (pic->Win->GZZHeight+pic->Top)) {
						pic->Top = ((CurY<<Zoom) - pic->Win->GZZHeight);
						SetGadgetAttrs(pic->SideGad, pic->Win, NULL,
							PGA_Top, pic->Top, TAG_END);
					}
					if ((CurX<<Zoom) > (pic->Win->GZZWidth+pic->Left)) {
						pic->Left = ((CurX<<Zoom) - pic->Win->GZZWidth);
						SetGadgetAttrs(pic->BotGad, pic->Win, NULL,
							PGA_Top, pic->Left, TAG_END);
					}
					checkGadget(pic);
					// 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 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;
						if ((CurY1<<Zoom) < pic1->Top) {
							pic1->Top = (CurY1<<Zoom);
							SetGadgetAttrs(pic1->SideGad, pic1->Win, NULL,
								PGA_Top, pic1->Top, TAG_END);
						}
						if ((CurX1<<Zoom) < pic1->Left) {
							pic1->Left = (CurX1<<Zoom);
							SetGadgetAttrs(pic1->BotGad, pic1->Win, NULL,
								PGA_Top, pic1->Left, TAG_END);
						}
						if ((CurY1<<Zoom) > (pic1->Win->GZZHeight+pic1->Top)) {
							pic1->Top = ((CurY1<<Zoom) - pic1->Win->GZZHeight);
							SetGadgetAttrs(pic1->SideGad, pic1->Win, NULL,
								PGA_Top, pic1->Top, TAG_END);
						}
						if ((CurX1<<Zoom) > (pic1->Win->GZZWidth+pic1->Left)) {
							pic1->Left = ((CurX1<<Zoom) - pic1->Win->GZZWidth);
							SetGadgetAttrs(pic1->BotGad, pic1->Win, NULL,
								PGA_Top, pic1->Left, TAG_END);
						}
						// Update image scroll
						checkGadget(pic1);
					}
				}
				break;
			case IDCMP_GADGETDOWN:
				// 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) {
				OnMenu(TSMorphWnd,FULLMENUNUM(0,0,NOSUB));
				OnMenu(TSMorphWnd,FULLMENUNUM(0,1,NOSUB));
				if (Pic1_Open) {
					CloseAPicture(&Pic1);
					Pic1_Open = FALSE;
				}
				if (Pic2_Open) {
					CloseAPicture(&Pic2);
					Pic2_Open = FALSE;
				}
				CloseControlWindow();
			}
			// Below just updates the correct gadgets
			EnableWindows();
 			flag = 1;
		}
	}
}

/* SetPointer
 * based on the current mode
 */
void
SetMyPointer(void) {
	UWORD __chip *Pointer;	// Pointer image
	// Set pointer based on mode
	switch (Mode) {
	case EDIT1:
		Pointer = One;
 		break;
	case EDIT2:
		Pointer = Two;
		break;
	case EDITREL:
		Pointer = Rel;
		break;
	case ADD:
		Pointer = Add;
		break;
	case DELETE:
		Pointer = Del;
		break;
	case LINK1:
		Pointer = L1;
		break;
	case UNLINK1:
		Pointer = U1;
		break;
	case NONE:
		Pointer = Mov;
		break;
	case UNLINK2:
		Pointer = U2;
		break;
	case LINK2:
		Pointer = L2;
		break;
	}
	// Set the window pointers
	if (Pic1_Open) {
		SetPointer(Pic1.Win, Pointer, 16, 16, -1, 0);
	}
	if (Pic2_Open) {
		SetPointer(Pic2.Win, Pointer, 16, 16, -1, 0);
	}
	if (ControlWindow) {
		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) {
				DeleteAllPoints();
				MaxWidth = 0;
				MaxHeight = 0;
				Saved = FALSE;
			}
			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;
		case MM_PPREVIEW:
			Preview();
			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_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;
	default:
		// something else ??
		break;
	}
	// return 0,1 or 2
	return flag;
}

/* Disable all windows,
 * menus, pointers,
 * gadgets etc.
 *
 * Note: This must be able to be called multiple times without EnableWindows()
 */
void
DisableWindows(ULONG dnum) {
	if (dnum < 1000) {
		ihelp(dnum);
	}
	else {
		if (*(disabled[dnum-1000])) {
			if (TSMorphWnd) {
				GT_SetGadgetAttrs(TSMorphGadgets[GDX_Help],TSMorphWnd,NULL,
									GTTX_Text,disabled[dnum-1000], TAG_END );
			}
		}
	}
	if (ControlWindow) {
		// All 3 menus off
		OffMenu(ControlWindow,FULLMENUNUM(M_PROJECT,NOITEM,NOSUB));
		OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,NOITEM,NOSUB));
		OffMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,NOITEM,NOSUB));
		// All gadgets off
		OffGadget(&OneGadget,ControlWindow,NULL);
		OffGadget(&TwoGadget,ControlWindow,NULL);
		OffGadget(&RelGadget,ControlWindow,NULL);
		OffGadget(&MyAddGadget,ControlWindow,NULL);
		OffGadget(&DelGadget,ControlWindow,NULL);
		OffGadget(&LinkGadget,ControlWindow,NULL);
		OffGadget(&UnlinkGadget,ControlWindow,NULL);
		OffGadget(&NoneGadget,ControlWindow,NULL);
		OffGadget(&stGadget,ControlWindow,NULL);
		OffGadget(&prevGadget,ControlWindow,NULL);
		OffGadget(&gotoGadget,ControlWindow,NULL);
		OffGadget(&nextGadget,ControlWindow,NULL);
		OffGadget(&lastGadget,ControlWindow,NULL);
		// Wait pointer
		SetPointer(ControlWindow, BusyPointerData, 16, 16, -6, 0);
	}
	if (Pic1_Open) {
		// Turn verify off
		IDCMPFlags = IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN |
						 IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE |
						 IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUHELP | IDCMP_RAWKEY | IDCMP_VANILLAKEY |
						 IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_CHANGEWINDOW |
						 IDCMP_GADGETHELP | IDCMP_MOUSEMOVE;
		ModifyIDCMP(Pic1.Win,IDCMPFlags);
		Pic1.Win->Flags |= WFLG_REPORTMOUSE;
		// All 3 menus off
//		OffMenu(Pic1.Win,FULLMENUNUM(0,NOITEM,NOSUB));	// These are now shared menus
//		OffMenu(Pic1.Win,FULLMENUNUM(1,NOITEM,NOSUB));
//		OffMenu(Pic1.Win,FULLMENUNUM(2,NOITEM,NOSUB));
		// Wait pointer
		SetPointer(Pic1.Win, BusyPointerData, 16, 16, -6, 0);
		// all gadgets off
		SetGadgetAttrs(Pic1.Lgad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic1.Ugad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic1.Dgad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic1.Rgad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic1.SideGad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic1.BotGad,Pic1.Win,0,GA_Disabled,TRUE,TAG_END);
		RefreshGadgets(Pic1.BotGad,Pic1.Win,NULL);
	}
	if (Pic2_Open) {
		// Turn verify off
		IDCMPFlags = IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN |
						 IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE |
						 IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUHELP | IDCMP_RAWKEY | IDCMP_VANILLAKEY |
						 IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_CHANGEWINDOW |
						 IDCMP_GADGETHELP | IDCMP_MOUSEMOVE;
		ModifyIDCMP(Pic2.Win,IDCMPFlags);
		Pic2.Win->Flags |= WFLG_REPORTMOUSE;
		// All 3 menus off
//		OffMenu(Pic2.Win,FULLMENUNUM(0,NOITEM,NOSUB));	// These are now shared menus
//		OffMenu(Pic2.Win,FULLMENUNUM(1,NOITEM,NOSUB));
//		OffMenu(Pic2.Win,FULLMENUNUM(2,NOITEM,NOSUB));
		// Wait pointer
		SetPointer(Pic2.Win, BusyPointerData, 16, 16, -6, 0);
		// all gadgets off
		SetGadgetAttrs(Pic2.Lgad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic2.Ugad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic2.Dgad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic2.Rgad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic2.SideGad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		SetGadgetAttrs(Pic2.BotGad,Pic2.Win,0,GA_Disabled,TRUE,TAG_END);
		RefreshGadgets(Pic2.BotGad,Pic2.Win,NULL);
	}
	/* Disable gadgets in the Info window
	 * Do not disable the GetFile gadgets
	 * as it causes enforcer hits
	 */
	if (TSMorphWnd) {
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFile1],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);	// GetFile gadgets do not like being disabled
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFile2],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFileOne],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFileTwo],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_EditPoints],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_SinglePicture],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetSaveName],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileOne],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_File241],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_File242],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_Frames],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_Start],TSMorphWnd,NULL,GA_Disabled,TRUE,TAG_END);
		// Both menus off
		OffMenu(TSMorphWnd,FULLMENUNUM(0,NOITEM,NOSUB));
		OffMenu(TSMorphWnd,FULLMENUNUM(1,NOITEM,NOSUB));
		// Wait pointer
		SetPointer(TSMorphWnd, BusyPointerData, 16, 16, -6, 0);
	}
}

/* Enable all windows,
 * menus, pointers,
 * gadgets etc.
 */
void
EnableWindows(void) {
	LONG Frames,Start;
	if (TSMorphWnd) {
		Frames = GetNumber(TSMorphGadgets[GDX_Frames]);
		Start = GetNumber(TSMorphGadgets[GDX_Start]);
	}
	if (ControlWindow) {
		// Menus and gadgets on
		OnMenu(ControlWindow,FULLMENUNUM(M_PROJECT,NOITEM,NOSUB));
		OnMenu(ControlWindow,FULLMENUNUM(M_EDIT,NOITEM,NOSUB));
		OnMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,NOITEM,NOSUB));
		OnGadget(&OneGadget,ControlWindow,NULL);
		OnGadget(&TwoGadget,ControlWindow,NULL);
		OnGadget(&RelGadget,ControlWindow,NULL);
		OnGadget(&MyAddGadget,ControlWindow,NULL);
		OnGadget(&DelGadget,ControlWindow,NULL);
		OnGadget(&LinkGadget,ControlWindow,NULL);
		OnGadget(&UnlinkGadget,ControlWindow,NULL);
		OnGadget(&NoneGadget,ControlWindow,NULL);
		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 {
				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 {
				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));
			}
		}
		else {
			OffMenu(ControlWindow,FULLMENUNUM(M_EDIT,MM_FRAME,NOSUB));
		}
	}
	if (Pic1_Open) {
		// verify, menus and gadgets on
		IDCMPFlags = IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN |
						 IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE |
						 IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUVERIFY |
						 IDCMP_MENUHELP | IDCMP_RAWKEY | IDCMP_VANILLAKEY |
						 IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_CHANGEWINDOW |
						 IDCMP_GADGETHELP;
		ModifyIDCMP(Pic1.Win,IDCMPFlags);
		Pic1.Win->Flags |= WFLG_REPORTMOUSE;
//		OnMenu(Pic1.Win,FULLMENUNUM(0,NOITEM,NOSUB));	// These are now shared menus
//		OnMenu(Pic1.Win,FULLMENUNUM(1,NOITEM,NOSUB));
//		OnMenu(Pic1.Win,FULLMENUNUM(2,NOITEM,NOSUB));
		SetGadgetAttrs(Pic1.Lgad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic1.Ugad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic1.Dgad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic1.Rgad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic1.SideGad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic1.BotGad,Pic1.Win,0,GA_Disabled,FALSE,TAG_END);
		RefreshGadgets(Pic1.BotGad,Pic1.Win,NULL);
	}
	if (Pic2_Open) {
		// verify, menus and gadgets on
		IDCMPFlags = IDCMP_IDCMPUPDATE | IDCMP_GADGETUP | IDCMP_GADGETDOWN |
						 IDCMP_NEWSIZE | IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE |
						 IDCMP_MENUPICK | IDCMP_CLOSEWINDOW | IDCMP_MENUVERIFY |
						 IDCMP_MENUHELP | IDCMP_RAWKEY | IDCMP_VANILLAKEY |
						 IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW | IDCMP_CHANGEWINDOW |
						 IDCMP_GADGETHELP;
		ModifyIDCMP(Pic2.Win,IDCMPFlags);
		Pic2.Win->Flags |= WFLG_REPORTMOUSE;
//		OnMenu(Pic2.Win,FULLMENUNUM(0,NOITEM,NOSUB));	// These are now shared menus
//		OnMenu(Pic2.Win,FULLMENUNUM(1,NOITEM,NOSUB));
//		OnMenu(Pic2.Win,FULLMENUNUM(2,NOITEM,NOSUB));
		SetGadgetAttrs(Pic2.Lgad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic2.Ugad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic2.Dgad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic2.Rgad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic2.SideGad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		SetGadgetAttrs(Pic2.BotGad,Pic2.Win,0,GA_Disabled,FALSE,TAG_END);
		RefreshGadgets(Pic2.BotGad,Pic2.Win,NULL);
	}
	if (TSMorphWnd) {
		// Set pointer for Control and both image windows
		SetMyPointer();
		/* Turn relevant gadgets back on
		 * Do not enable GetFile gadgets as it causes enforcer hits
		 */
		if (!ControlWindow) {
	//		GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFileOne],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);	// GetFile gadgets do not like being disabled
	//		GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFileTwo],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
			GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileOne],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
			GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
			GT_SetGadgetAttrs(TSMorphGadgets[GDX_SinglePicture],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
			GT_SetGadgetAttrs(TSMorphGadgets[GDX_Frames],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
			GT_SetGadgetAttrs(TSMorphGadgets[GDX_Start],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
		}
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_EditPoints],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFile1],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetFile2],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
	//	GT_SetGadgetAttrs(TSMorphGadgets[GDX_GetSaveName],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_File241],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_File242],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL,GA_Disabled,FALSE,TAG_END);
		// Menus back on
		OnMenu(TSMorphWnd,FULLMENUNUM(0,NOITEM,NOSUB));
		OnMenu(TSMorphWnd,FULLMENUNUM(1,NOITEM,NOSUB));
		// Pointer back on
		ClearPointer(TSMorphWnd);
	}
	if (TSMorphWnd) {
		GT_SetGadgetAttrs(TSMorphGadgets[GDX_Help],TSMorphWnd,NULL,
							GTTX_Text,"Ready", TAG_END );
	}
}
