home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 8 / FreshFishVol8-CD1.bin / new / gfx / edit / tsmorph / src / subroutines.c < prev    next >
C/C++ Source or Header  |  1994-02-27  |  72KB  |  2,814 lines

  1. // TSMorph - Amiga Morphing program
  2. // Copyright (C) © 1993  Topicsave Limited
  3.  
  4. // This program is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // any later version.
  8.  
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU General Public License for more details.
  13.  
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program; if not, write to the Free Software
  16. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  
  18. // mpaddock@cix.compulink.co.uk
  19.  
  20. // include precompiled headers if required
  21. #ifndef TSMORPH_H
  22. #include "TSMorph.h"
  23. #endif
  24.  
  25. extern char TempFilename[256]="";    // file name buffer set up and used in various places
  26.  
  27. UBYTE r[256],g[256],b[256];            // Saved rgb colors
  28. ULONG rl[256],gl[256],bl[256];            // Saved rgb32 colors
  29.  
  30. /* display short help message
  31.  * at top of window
  32.  * helpnum : number of help node
  33.  */
  34. void
  35. ihelp(ULONG helpnum) {
  36.     // only display if not zero, and there is a short message and the window is open
  37.     if (helpnum) {
  38.         if (*(ShortHelp[helpnum])) {
  39.             if (TSMorphWnd) {
  40.                 GT_SetGadgetAttrs(TSMorphGadgets[GDX_Help],TSMorphWnd,NULL,
  41.                                     GTTX_Text,ShortHelp[helpnum], TAG_END );
  42.             }
  43.         }
  44.     }
  45. }
  46.  
  47. /* Display help using amigaguide (if available)
  48.  * based on a number. Also displays short help message
  49.  */
  50. void
  51. help(ULONG helpnum) {
  52.     // display amigaguide if available
  53.     if (handle) {
  54.         SetAmigaGuideContext(handle,helpnum,NULL);
  55.         SendAmigaGuideContext(handle,NULL);
  56.     }
  57.     // display short message
  58.     ihelp(helpnum);
  59. }
  60.  
  61. /* Colour the picture based on it colormap
  62.  * Saving the palette for later use
  63.  * The palette is only set when the window is active and a menu is not displayed
  64.  */
  65. void
  66. ColorWindow(struct Picture *pic) {
  67.     UWORD i;                    // Loop counter
  68.     UWORD color;            // Colour
  69.     ULONG col[4];            // Table for get RGB32
  70.     if (!EGS) {
  71.         if (palette) {
  72.             if (pic) {
  73.                 if (pic->ilbm->colortable) {
  74.                     // Store and set up to 256 colours
  75.                      if (GfxBase->lib_Version > 38) {
  76.                         for (i=0; i<min((1 << pic->Win->WScreen->BitMap.Depth),256); i++) {
  77.                             GetRGB32(pic->Win->WScreen->ViewPort.ColorMap,i,1,col);
  78.                             rl[i]=col[0];
  79.                             gl[i]=col[1];
  80.                             bl[i]=col[2];
  81.                         }
  82.                     }
  83.                     else {
  84.                         for (i=0; i<min((1 << pic->Win->WScreen->BitMap.Depth),256); i++) {
  85.                             color = GetRGB4(pic->Win->WScreen->ViewPort.ColorMap,i);
  86.                             r[i]=(color&0x0f00)>>8;
  87.                             g[i]=(color&0x00f0)>>4;
  88.                             b[i]=(color&0x000f);
  89.                         }
  90.                     }
  91.                     LoadRGB4(&(pic->Win->WScreen->ViewPort),(UWORD *)pic->ilbm->colortable,
  92.                         MIN(pic->ilbm->ncolors,pic->Win->WScreen->ViewPort.ColorMap->Count));
  93.                 }
  94.             }
  95.         }
  96.     }
  97. }
  98.  
  99. /* Reset the palette to the original
  100.  * stored in ColorWindow()
  101.  * Called when window becomes inactive or menu is to be displayed
  102.  *
  103.  * Note: This routine and the one above are not really allowed by CBM
  104.  *       But if no other program is changing the palette whilst its
  105.  *       window is inactive then everything should (amy) be OK.
  106.  */
  107. void
  108. UnColorWindow(struct Picture *pic) {
  109.     UWORD i;        // Loop counter
  110.     if (!EGS) {
  111.         if (palette) {
  112.             if (pic) {
  113.                 if (pic->ilbm->colortable) {
  114.                      if (GfxBase->lib_Version > 38) {
  115.                         for (i=0; i<min((1 << pic->Win->WScreen->BitMap.Depth),256); i++) {
  116.                             SetRGB32(&(pic->Win->WScreen->ViewPort),i,rl[i],gl[i],bl[i]);
  117.                         }
  118.                      }
  119.                      else {
  120.                         for (i=0; i<min((1 << pic->Win->WScreen->BitMap.Depth),256); i++) {
  121.                             SetRGB4(&(pic->Win->WScreen->ViewPort),i,r[i],g[i],b[i]);
  122.                         }
  123.                     }
  124.                 }
  125.             }
  126.         }
  127.     }
  128. }
  129.  
  130. /* Standard CloseWindowSafely
  131.  * removing messages on shared ports
  132.  */
  133. void
  134. CloseWindowSafely(struct Window *win) {
  135.     Forbid();
  136.     StripIntuiMessages(win->UserPort,win);
  137.     win->UserPort = NULL;
  138.     ModifyIDCMP(win,0);
  139.     Permit();
  140.     CloseWindow(win);
  141. }
  142.  
  143. /* Standard StripIntuiMessages    */
  144. void
  145. StripIntuiMessages(struct MsgPort *mp,struct Window *win) {
  146.     struct IntuiMessage *msg, *succ;
  147.     msg = (struct IntuiMessage *)mp->mp_MsgList.lh_Head;
  148.     while(succ = (struct IntuiMessage *)msg->ExecMessage.mn_Node.ln_Succ) {
  149.         if(msg->IDCMPWindow == win) {
  150.             Remove((struct Node *)msg);
  151.             ReplyMsg((struct Message *)msg);
  152.         }
  153.         msg = succ;
  154.     }
  155. }
  156.  
  157. /* Display an error message
  158.  * ErrorMessage    : The main text
  159.  * Gadget            : Text for one gadget
  160.  * extra                : more of the text
  161.  * helpnum            : Number of a help node
  162.  *
  163.  * Uses reqtools.library if available
  164.  */
  165. void
  166. Error(char *ErrorMessage,char *Gadget,char *extra,ULONG helpnum) {
  167.     struct EasyStruct EasyStruct = {
  168.         sizeof(struct EasyStruct),
  169.         0,
  170.         NULL,
  171.         NULL,
  172.         NULL
  173.     };
  174.     UBYTE *title;
  175.     struct Window *req;
  176.     UBYTE gad[32];
  177.     UBYTE gad1[32];
  178.     UBYTE buffer[512];
  179.     UBYTE *p;
  180.     ULONG ret = CALL_HANDLER;
  181.     struct AmigaGuideMsg *agm;
  182.     ULONG signals;
  183.     struct rtHandlerInfo *rth;
  184.     struct ER_SimpleRequest *EGS_Request;
  185.     BOOL finished = FALSE;
  186.     // Disable the windows and display the requester
  187.     title = MyGetMsg(MSG_TSMERR);
  188.     strcpy(gad,MyGetMsg(MSG_HELPOR));
  189.     strcpy(gad1,MyGetMsg(MSG__HELPOR));
  190.     DisableWindows(helpnum);
  191.     if (EGS && Pic1_Open) {
  192.         sprintf(buffer,ErrorMessage,extra);
  193.         p = buffer;
  194.         while (*p) {
  195.             if (*p == '\n') {
  196.                 *p = '|';
  197.             }
  198.             p++;
  199.         }
  200.         if (handle) {
  201.             strcat(gad,Gadget);
  202.         }
  203.         else {
  204.             strcpy(gad,Gadget);
  205.         }
  206.         if (EGS_Request = ER_CreateSimpleRequest(NULL,buffer,gad)) {
  207.             ER_ChangeRequestPos(EGS_Request,
  208.                     max(Pic1.EGS_Win->WScreen->EScreen->MouseX-20,0),
  209.                     max(Pic1.EGS_Win->WScreen->EScreen->MouseY-20,0));
  210.             while (!finished) {
  211.                 if (ER_DoRequest(EGS_Request)) {
  212.                     if ((!EGS_Request->Selected) && handle) {
  213.                         help(helpnum);
  214.                     }
  215.                     else {
  216.                         finished = TRUE;
  217.                     }
  218.                       while (agm = GetAmigaGuideMsg(handle)) {
  219.                          ReplyAmigaGuideMsg(agm);
  220.                      }
  221.                 }
  222.                 else {
  223.                     finished = TRUE;
  224.                 }
  225.             }
  226.             ER_DeleteRequest(EGS_Request);
  227.         }
  228.     }
  229.     else {
  230.         if (ReqToolsBase) {
  231.             // Set up gadgets depending on if amigaguide is available
  232.             if (!handle) {
  233.                 strcpy(gad1,"_");
  234.             }
  235.             strcat(gad1,Gadget);
  236.             // This loops until OK is pressed, displaying help if Help is pressed (if present)
  237.             while (ret) {
  238.                 ret = CALL_HANDLER;
  239.                 if (rtEZRequestTags(ErrorMessage,gad1,NULL,&extra,
  240.                                             RT_ReqHandler,    &rth,
  241.                                             RT_Window,        TSMorphWnd,
  242.                                             RT_Underscore,    '_',
  243.                                             RTEZ_ReqTitle,    title,
  244.                                             TAG_END) == CALL_HANDLER) {
  245.                     while (ret == CALL_HANDLER) {
  246.                         if (!rth->DoNotWait) {
  247.                             signals = Wait(rth->WaitMask | ASig);
  248.                         }
  249.                         ret = rtReqHandlerA(rth,signals,NULL);
  250.                         if (ret == 1) {
  251.                             help(helpnum);
  252.                         }
  253.                         if (signals & ASig) {
  254.                               while (agm = GetAmigaGuideMsg(handle)) {
  255.                                  ReplyAmigaGuideMsg(agm);
  256.                              }
  257.                          }
  258.                     }
  259.                 }
  260.                 else {
  261.                     ret = 0;
  262.                 }
  263.             }
  264.         }
  265.         else {
  266.             EasyStruct.es_TextFormat = ErrorMessage;
  267.             EasyStruct.es_Title = title;
  268.             // Set up gadgets depending on if amigaguide is available
  269.             if (handle) {
  270.                 strcat(gad,Gadget);
  271.             }
  272.             else {
  273.                 strcpy(gad,Gadget);
  274.             }
  275.             EasyStruct.es_GadgetFormat = gad;
  276.             req = BuildEasyRequest(TSMorphWnd,&EasyStruct,NULL,extra);
  277.             // This loops until OK is pressed, displaying help if Help is pressed (if present)
  278.             while (ret) {
  279.                 signals  = Wait((1L << req->UserPort->mp_SigBit) | ASig);
  280.                 if (signals & (1L << req->UserPort->mp_SigBit)) {
  281.                     ret = SysReqHandler(req,NULL,FALSE);
  282.                     if (ret == 1) {
  283.                         help(helpnum);
  284.                     }
  285.                 }
  286.                 if (signals & ASig) {
  287.                       while (agm = GetAmigaGuideMsg(handle)) {
  288.                          ReplyAmigaGuideMsg(agm);
  289.                      }
  290.                 }
  291.             }
  292.             FreeSysRequest(req);
  293.         }
  294.     }
  295.     EnableWindows();
  296. }
  297.  
  298. /* As Error but
  299.  * pic    : a picture to uncolor if required
  300.  */
  301. void
  302. XError(struct Picture *pic,char *ErrorMessage,char *Gadget,char *extra,ULONG helpnum) {
  303.     UnColorWindow(pic);
  304.     Error(ErrorMessage,Gadget,extra,helpnum);
  305.     ColorWindow(pic);
  306. }
  307.  
  308. /* Draw all points
  309.  * in both windows
  310.  */
  311. void
  312. DrawAllPoints(void) {
  313.     struct MyPoint *MyPoint;
  314.     int i;
  315.     // For each point
  316.     for (MyPoint = (struct MyPoint *)PointList.lh_Head;
  317.                           MyPoint->MyNode.mln_Succ;
  318.                           MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
  319.         // Draw point in image 1
  320.         DrawPixels(&Pic1,MyPoint->x,MyPoint->y,NULL);
  321.         // Same stuff for image 2
  322.         DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,NULL);
  323.         /* For each linked point draw a line
  324.          * to the other if the other is a "later" point
  325.          */
  326.         for (i = 0;
  327.               i < MAX_LINKS;
  328.               i++) {
  329.             if (MyPoint->p[i]) {
  330.                 if (EGS) {
  331.                     if (MyPoint->p[i] > MyPoint) {
  332.                         EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint->p[i]->x,MyPoint->p[i]->y,MyPoint->x,MyPoint->y);
  333.                         EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint->p[i]->x1,MyPoint->p[i]->y1,MyPoint->x1,MyPoint->y1);
  334.                     }
  335.                 }
  336.                 else {
  337.                     if (MyPoint->p[i] > MyPoint) {
  338.                         MyDraw(Pic1.Win->RPort,MyPoint->p[i]->x<<Zoom,MyPoint->p[i]->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
  339.                         MyDraw(Pic2.Win->RPort,MyPoint->p[i]->x1<<Zoom,MyPoint->p[i]->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
  340.                     }
  341.                 }
  342.             }
  343.         }
  344.     }
  345. }
  346.  
  347. /* Handle Raw Key in Information
  348.  * Window - from GadToolsBox
  349.  */
  350. int
  351. TSMorphRawKey(void) {
  352.     UWORD X,Y;        // Mouse position
  353.     ULONG HNum;        // Help node
  354.     X = TSMorphWnd->MouseX;
  355.     Y = TSMorphWnd->MouseY;
  356.     switch (TSMorphMsg.Code) {
  357.     // only help key does anything
  358.     case 0x5f:
  359.         /* Find gadget pointer is in
  360.          * otherwise use whole window
  361.          */
  362.         if (PointInBox(X,Y,Rect[GDX_Help].MinX,Rect[GDX_Help].MinY,
  363.                                 Rect[GDX_Help].MaxX,Rect[GDX_Help].MaxY))
  364.             HNum = H_HelpGad;
  365.         else
  366.         if (PointInBox(X,Y,Rect[GDX_GetFile1].MinX,Rect[GDX_GetFile1].MinY,
  367.                                 Rect[GDX_GetFile1].MaxX,Rect[GDX_GetFile1].MaxY))
  368.             HNum = H_G24File1;
  369.         else
  370.         if (PointInBox(X,Y,Rect[GDX_GetFile2].MinX,Rect[GDX_GetFile2].MinY,
  371.                                 Rect[GDX_GetFile2].MaxX,Rect[GDX_GetFile2].MaxY))
  372.             HNum = H_G24File2;
  373.         else
  374.         if (PointInBox(X,Y,Rect[GDX_Width].MinX,Rect[GDX_Width].MinY,
  375.                                 Rect[GDX_Width].MaxX,Rect[GDX_Width].MaxY))
  376.             HNum = H_Width;
  377.         else
  378.         if (PointInBox(X,Y,Rect[GDX_Height].MinX,Rect[GDX_Height].MinY,
  379.                                 Rect[GDX_Height].MaxX,Rect[GDX_Height].MaxY))
  380.             HNum = H_Height;
  381.         else
  382.         if (PointInBox(X,Y,Rect[GDX_GetFileOne].MinX,Rect[GDX_GetFileOne].MinY,
  383.                                 Rect[GDX_GetFileOne].MaxX,Rect[GDX_GetFileOne].MaxY))
  384.             HNum = H_GFileOne;
  385.         else
  386.         if (PointInBox(X,Y,Rect[GDX_GetFileTwo].MinX,Rect[GDX_GetFileTwo].MinY,
  387.                                 Rect[GDX_GetFileTwo].MaxX,Rect[GDX_GetFileTwo].MaxY))
  388.             HNum = H_GFileTwo;
  389.         else
  390.         if (PointInBox(X,Y,Rect[GDX_EditPoints].MinX,Rect[GDX_EditPoints].MinY,
  391.                                 Rect[GDX_EditPoints].MaxX,Rect[GDX_EditPoints].MaxY))
  392.             HNum = H_EPoints;
  393.         else
  394.         if (PointInBox(X,Y,Rect[GDX_SinglePicture].MinX,Rect[GDX_SinglePicture].MinY,
  395.                                 Rect[GDX_SinglePicture].MaxX,Rect[GDX_SinglePicture].MaxY))
  396.             HNum = H_Single;
  397.         else
  398.         if (PointInBox(X,Y,Rect[GDX_GetSaveName].MinX,Rect[GDX_GetSaveName].MinY,
  399.                                 Rect[GDX_GetSaveName].MaxX,Rect[GDX_GetSaveName].MaxY))
  400.             HNum = H_GName;
  401.         else
  402.         if (PointInBox(X,Y,Rect[GDX_FileOne].MinX,Rect[GDX_FileOne].MinY,
  403.                                 Rect[GDX_FileOne].MaxX,Rect[GDX_FileOne].MaxY))
  404.             HNum = H_FileOne;
  405.         else
  406.         if (PointInBox(X,Y,Rect[GDX_FileTwo].MinX,Rect[GDX_FileTwo].MinY,
  407.                                 Rect[GDX_FileTwo].MaxX,Rect[GDX_FileTwo].MaxY))
  408.             HNum = H_FileTwo;
  409.         else
  410.         if (PointInBox(X,Y,Rect[GDX_File241].MinX,Rect[GDX_File241].MinY,
  411.                                 Rect[GDX_File241].MaxX,Rect[GDX_File241].MaxY))
  412.             HNum = H_24File1;
  413.         else
  414.         if (PointInBox(X,Y,Rect[GDX_File242].MinX,Rect[GDX_File242].MinY,
  415.                                 Rect[GDX_File242].MaxX,Rect[GDX_File242].MaxY))
  416.             HNum = H_24File2;
  417.         else
  418.         if (PointInBox(X,Y,Rect[GDX_Frames].MinX,Rect[GDX_Frames].MinY,
  419.                                 Rect[GDX_Frames].MaxX,Rect[GDX_Frames].MaxY))
  420.             HNum = H_Frames;
  421.         else
  422.         if (PointInBox(X,Y,Rect[GDX_Start].MinX,Rect[GDX_Start].MinY,
  423.                                 Rect[GDX_Start].MaxX,Rect[GDX_Start].MaxY))
  424.             HNum = H_Start;
  425.         else
  426.         if (PointInBox(X,Y,Rect[GDX_Name].MinX,Rect[GDX_Name].MinY,
  427.                                 Rect[GDX_Name].MaxX,Rect[GDX_Name].MaxY))
  428.             HNum = H_Name;
  429.         else
  430.         // following should use the gadget sizing stuff - doubt if anybody will notice
  431.         if (PointInBox(X,Y,0,0,
  432.                                 20,TSMorphWnd->BorderTop))
  433.             HNum = H_IClose;
  434.         else
  435.         if (PointInBox(X,Y,(TSMorphWnd->Width - 24),0,
  436.                                 TSMorphWnd->Width,TSMorphWnd->BorderTop))
  437.             HNum = H_IDepth;
  438.         else
  439.         if (PointInBox(X,Y,(TSMorphWnd->Width - 24 - 24),0,
  440.                                 (TSMorphWnd->Width - 24),TSMorphWnd->BorderTop))
  441.             HNum = H_IZoom;
  442.         else
  443.             HNum = H_IWindow;
  444.         help(HNum);
  445.         break;
  446.     }
  447.     return 1;
  448. }
  449.  
  450. /* Handle Vanilla Key in Information
  451.  * Window - from GadToolsBox
  452.  */
  453. int
  454. TSMorphVanillaKey(void) {
  455.     switch (TSMorphMsg.Code) {
  456.     case 'o':
  457.     case 'O':
  458.         /* O - if control window not open
  459.          * either activate string gadget
  460.          * or display file requester with shift
  461.          */
  462.         if (!ControlWindow) {
  463.             if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  464.                 GetFileOneClicked();
  465.             }
  466.             else {
  467.                 ActivateGadget(TSMorphGadgets[GDX_FileOne],TSMorphWnd,NULL);
  468.             }
  469.         }
  470.         break;
  471.     case 't':
  472.     case 'T':
  473.         /* T - if control window not open
  474.          * either activate string gadget
  475.          * or display file requester with shift
  476.          */
  477.         if (!ControlWindow) {
  478.             if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  479.                 GetFileTwoClicked();
  480.             }
  481.             else {
  482.                 ActivateGadget(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,NULL);
  483.             }
  484.         }
  485.         break;
  486.     case '1':
  487.     case '!':
  488.         /* 1 - either activate string gadget
  489.          * or display file requester with shift
  490.          */
  491.         if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  492.             GetFile1Clicked();
  493.         }
  494.         else {
  495.             ActivateGadget(TSMorphGadgets[GDX_File241],TSMorphWnd,NULL);
  496.         }
  497.         break;
  498.     case '2':
  499.     case '"':
  500.         /* 2 - either activate string gadget
  501.          * or display file requester with shift
  502.          */
  503.         if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  504.             GetFile2Clicked();
  505.         }
  506.         else {
  507.             ActivateGadget(TSMorphGadgets[GDX_File242],TSMorphWnd,NULL);
  508.         }
  509.         break;
  510.     case 'r':
  511.     case 'R':
  512.         // R - Cycle Single
  513.         if (!ControlWindow) {
  514.             if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  515.                 if (!SinglePicture) {
  516.                     // If we do not have reqtools then do not allow Anims
  517.                     if (ReqToolsBase) {
  518.                         SinglePicture = 3;
  519.                     }
  520.                     else {
  521.                         SinglePicture = 1;
  522.                     }
  523.                 }
  524.                 else {
  525.                     --SinglePicture;
  526.                 }
  527.             }
  528.             else {
  529.                 if (ReqToolsBase) {
  530.                     // If we do not have reqtools then do not allow Anims
  531.                     if (SinglePicture == 3) {
  532.                         SinglePicture = 0;
  533.                     }
  534.                     else {
  535.                         ++SinglePicture;
  536.                     }
  537.                 }
  538.                 else {
  539.                     if (SinglePicture == 1) {
  540.                         SinglePicture = 0;
  541.                     }
  542.                     else {
  543.                         ++SinglePicture;
  544.                     }
  545.                 }
  546.             }
  547.             Saved = FALSE;
  548.             GT_SetGadgetAttrs(TSMorphGadgets[GDX_SinglePicture],TSMorphWnd,NULL,
  549.                                     GTCY_Active,SinglePicture, TAG_END );
  550.         }
  551.         break;
  552.     case 'f':
  553.     case 'F':
  554.         // F - activate string gadgtet
  555.         if (!ControlWindow) {
  556.             ActivateGadget(TSMorphGadgets[GDX_Frames],TSMorphWnd,NULL);
  557.         }
  558.         break;
  559.     case 'a':
  560.     case 'A':
  561.         // A - activate string gadgtet
  562.         if (!ControlWindow) {
  563.             ActivateGadget(TSMorphGadgets[GDX_Start],TSMorphWnd,NULL);
  564.         }
  565.         break;
  566.     case 'n':
  567.     case 'N':
  568.         /* N - either activate string gadget
  569.          * or display file requester with shift
  570.          */
  571.         if (TSMorphMsg.Qualifier & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) {
  572.             GetSaveNameClicked();
  573.         }
  574.         else {
  575.             ActivateGadget(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL);
  576.         }
  577.         break;
  578.     case 'p':
  579.     case 'P':
  580.         /* P - either open Control and image windows
  581.          * or activate and bring control window to front
  582.          */
  583.         if (!ControlWindow) {
  584.             OpenPointsEdit();
  585.         }
  586.         else {
  587.             ActivateWindow(ControlWindow);
  588.             WindowToFront(ControlWindow);
  589.         }
  590.         break;
  591.     default:
  592.         // other key
  593.         break;
  594.     }
  595.     return 1;
  596. }
  597.  
  598. /* Open... menu item in Info window */
  599. int
  600. TSMorphMenuOpen(void) {
  601.     // Just call MyOpen();
  602.     DisableWindows(DI_WaitOpen);
  603.     MyOpen(NULL,FALSE,TRUE);
  604.     EnableWindows();
  605.     return 1;
  606. }
  607.  
  608. /* Save menu item in Info window */
  609. int TSMorphMenuSave(void) {
  610.     // Just call SaveAs(last saved name)
  611.     DisableWindows(DI_WaitSave);
  612.     SaveAs(savedfilename);
  613.     EnableWindows();
  614.       return 1;
  615. }
  616.  
  617. /* Save As... menu item in Info window */
  618. int
  619. TSMorphMenuSaveAs(void) {
  620.     // Just call SaveAs(no name)
  621.     DisableWindows(DI_WaitSave);
  622.     SaveAs(NULL);
  623.     EnableWindows();
  624.     return 1;
  625. }
  626.  
  627. /* Delete... menu item in Info window */
  628. int
  629. TSMorphMenuDelete(void) {
  630.     BPTR cd;
  631.     BOOL ok = TRUE;
  632.     struct AnchorPath ap = {0};
  633.     // Delete a project with Icon and all .nnn files
  634.     DisableWindows(DI_Delete);
  635.     if (GetAFile("",MyGetMsg(MSG_DELETEP),FILF_SAVE)) {
  636.         // delete main file and icon
  637.         DeleteFile(TempFilename);
  638.         DeleteDiskObject(TempFilename);
  639.         // delete "project.nnn" files
  640.         strcat(TempFilename,".[0-9][0-9][0-9]");
  641.         if (!MatchFirst(TempFilename,&ap)) {
  642.             while (ok) {
  643.                 cd = CurrentDir(ap.ap_Current->an_Lock);
  644.                 DeleteFile(ap.ap_Info.fib_FileName);
  645.                 CurrentDir(cd);
  646.                 ok = !MatchNext(&ap);
  647.             }
  648.         }
  649.         MatchEnd(&ap);
  650.     }
  651.     EnableWindows();
  652.     return 1;
  653. }
  654.  
  655. /* About menu item in Info window */
  656. int
  657. TSMorphMenuAbout(void) {
  658.     // Just Call About()
  659.     DisableWindows(DI_About);
  660.     About();
  661.     EnableWindows();
  662.     return 1;
  663. }
  664.  
  665. /* Quit menu item in Info window */
  666. int
  667. TSMorphMenuQuit(void) {
  668.     // Suggest save - quit if requested
  669.       if (!Saved) {
  670.          return !SaveRequester();
  671.       }
  672.       else {
  673.           return 0;
  674.       }
  675. }
  676.  
  677. /* Edit Points... menu item in Info window */
  678. int
  679. TSMorphMenuEditPoints(void) {
  680.     // Open window if not open
  681.     if (!ControlWindow) {
  682.         OpenPointsEdit();
  683.     }
  684.     // Otherwise activate and bring to front
  685.     else {
  686.         ActivateWindow(ControlWindow);
  687.         WindowToFront(ControlWindow);
  688.     }
  689.     return 1;
  690. }
  691.  
  692. /* Window closed, acts like quit    */
  693. int TSMorphCloseWindow(void) {
  694.     // Suggest save - quit if required
  695.       if (!Saved) {
  696.          return !SaveRequester();
  697.       }
  698.       else {
  699.           return 0;
  700.       }
  701. }
  702.  
  703. /* Help pressed on a menu in the info window    */
  704. int
  705. TSMorphMenuHelp(void) {
  706.     ULONG HNum;        // Help node
  707.     // Forget any previous changes
  708.     // This means all menu selections before help is pressed are ignored
  709.     RemoveMenus();
  710.     SwitchMenuItem(MM_PALETTE,palette,FALSE);
  711.     SwitchMenuItem(MM_ZOOM,Zoom,FALSE);
  712.     SwitchMenuItem(MM_ICONSP,CreateIconsP,FALSE);
  713.     UpdateOpenMode(FALSE);
  714.     SwitchMenuItem(MM_ICONSR,CreateIconsR,FALSE);
  715.     UpdateRenderMode(FALSE);
  716.     UpdateSaveFormat(FALSE);
  717.     AddMenus();
  718.     // Determine help number from menu position
  719.     switch (TSMorphMsg.Code) {
  720.     case FULLMENUNUM(0,NOITEM,NOSUB):
  721.     case FULLMENUNUM(0,2,NOSUB):
  722.     case FULLMENUNUM(0,6,NOSUB):
  723.     case FULLMENUNUM(0,8,NOSUB):
  724.     case FULLMENUNUM(0,10,NOSUB):
  725.         HNum = H_IMP;
  726.         break;
  727.     case FULLMENUNUM(0,0,NOSUB):
  728.         HNum = H_IMPN;
  729.         break;
  730.     case FULLMENUNUM(0,1,NOSUB):
  731.         HNum = H_IMPO;
  732.         break;
  733.     case FULLMENUNUM(0,3,NOSUB):
  734.         HNum = H_IMPS;
  735.         break;
  736.     case FULLMENUNUM(0,4,NOSUB):
  737.         HNum = H_IMPSA;
  738.         break;
  739.     case FULLMENUNUM(0,5,NOSUB):
  740.         HNum = H_IMPD;
  741.         break;
  742.     case FULLMENUNUM(0,7,NOSUB):
  743.         HNum = H_IMPA;
  744.         break;
  745.     case FULLMENUNUM(0,9,NOSUB):
  746.         HNum = H_IMPQ;
  747.         break;
  748.     case FULLMENUNUM(0,11,NOSUB):
  749.         HNum = H_IMPP;
  750.         break;
  751.     case FULLMENUNUM(0,12,NOSUB):
  752.         HNum = H_IMPE;
  753.         break;
  754.     case FULLMENUNUM(1,NOITEM,NOSUB):
  755.     case FULLMENUNUM(1,MM_C1,NOSUB):
  756.     case FULLMENUNUM(1,MM_C2,NOSUB):
  757.     case FULLMENUNUM(1,MM_C3,NOSUB):
  758.     case FULLMENUNUM(1,MM_C4,NOSUB):
  759.         HNum = H_IMS;
  760.         break;
  761.     case FULLMENUNUM(1,MM_ICONS,NOSUB):
  762.         HNum = H_P_CI;
  763.         break;
  764.     case FULLMENUNUM(1,MM_PALETTE,NOSUB):
  765.         HNum = H_P_CP;
  766.         break;
  767.     case FULLMENUNUM(1,MM_ZOOM,NOSUB):
  768.         HNum = H_P_ZO;
  769.         break;
  770.     case FULLMENUNUM(1,MM_OPENMODE,NOSUB):
  771.     case FULLMENUNUM(1,MM_OPENMODE,MI_ALWAYS):
  772.     case FULLMENUNUM(1,MM_OPENMODE,MI_IFILBM):
  773.     case FULLMENUNUM(1,MM_OPENMODE,MI_IFCOLOURS):
  774.     case FULLMENUNUM(1,MM_OPENMODE,MI_REMAP):
  775.     case FULLMENUNUM(1,MM_OPENMODE,MI_OPAL):
  776.         HNum = H_P_OM;
  777.         break;
  778.     case FULLMENUNUM(1,MM_SCREEN,NOSUB):
  779.         HNum = H_P_PS;
  780.         break;
  781.     case FULLMENUNUM(1,MM_CUSTOM,NOSUB):
  782.         HNum = H_PCUSTM;
  783.         break;
  784.     case FULLMENUNUM(1,MM_CDEPTH,NOSUB):
  785.         HNum = H_PCUSTD;
  786.         break;
  787.     case FULLMENUNUM(1,MM_SPREVIEW,NOSUB):
  788.         HNum = H_P_Preview;
  789.         break;
  790.     case FULLMENUNUM(1,MM_ICONSP,NOSUB):
  791.         HNum = H_P_CIP;
  792.         break;
  793.     case FULLMENUNUM(1,MM_KEEPS,NOSUB):
  794.         HNum = H_P_KS;
  795.         break;
  796.     case FULLMENUNUM(1,MM_LOADS,NOSUB):
  797.         HNum = H_P_LOADS;
  798.         break;
  799.     case FULLMENUNUM(1,MM_SAVES,NOSUB):
  800.         HNum = H_P_SAVES;
  801.         break;
  802.     case FULLMENUNUM(1,MM_SAVESAS,NOSUB):
  803.         HNum = H_P_SAVESAS;
  804.         break;
  805.     case FULLMENUNUM(1,MM_ICONSR,NOSUB):
  806.         HNum = H_P_CIR;
  807.         break;
  808.     case FULLMENUNUM(1,MM_DX,NOSUB):
  809.         HNum = H_P_DX;
  810.         break;
  811.     case FULLMENUNUM(1,MM_DY,NOSUB):
  812.         HNum = H_P_DY;
  813.         break;
  814.     case FULLMENUNUM(1,MM_LOADSCRIPT,NOSUB):
  815.         HNum = H_P_LS;
  816.         break;
  817.     case FULLMENUNUM(1,MM_PRESCRIPT,NOSUB):
  818.         HNum = H_P_PES;
  819.         break;
  820.     case FULLMENUNUM(1,MM_POSTSCRIPT,NOSUB):
  821.         HNum = H_P_POS;
  822.         break;
  823.     case FULLMENUNUM(1,MM_DEPTH,NOSUB):
  824.         HNum = H_P_DE;
  825.         break;
  826.     case FULLMENUNUM(1,MM_RENDERMODE,NOSUB):
  827.     case FULLMENUNUM(1,MM_RENDERMODE,MI_MODE1):
  828.     case FULLMENUNUM(1,MM_RENDERMODE,MI_MODE2):
  829.     case FULLMENUNUM(1,MM_RENDERMODE,MI_MODE4):
  830.     case FULLMENUNUM(1,MM_RENDERMODE,MI_MODE8):
  831.         HNum = H_P_MO;
  832.         break;
  833.     case FULLMENUNUM(1,MM_SAVEFORMAT,NOSUB):
  834.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_ILBM24):
  835.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_OPAL24):
  836.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_OPAL24T):
  837.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_OPAL24F):
  838.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_OPAL24FT):
  839.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_JPEG):
  840.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_JPEGT):
  841.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_PBM):
  842.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_BW16):
  843.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_BW256):
  844.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_HAM6):
  845.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_HAM8):
  846.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_DCTV3):
  847.     case FULLMENUNUM(1,MM_SAVEFORMAT,MI_DCTV4):
  848.         HNum = H_P_SF;
  849.         break;
  850.     case FULLMENUNUM(1,MM_QUALITY,NOSUB):
  851.         HNum = H_P_QU;
  852.         break;
  853.     case FULLMENUNUM(1,MM_SCREENR,NOSUB):
  854.         HNum = H_P_PSR;
  855.         break;
  856.     case FULLMENUNUM(1,MM_ANTIALIAS,NOSUB):
  857.         HNum = H_P_AA;
  858.         break;
  859.     case FULLMENUNUM(1,MM_INTEGER,NOSUB):
  860.         HNum = H_P_INT;
  861.         break;
  862.     case FULLMENUNUM(1,MM_RESETD,NOSUB):
  863.         HNum = H_S_RD;
  864.         break;
  865.     case FULLMENUNUM(1,MM_LASTS,NOSUB):
  866.         HNum = H_S_LS;
  867.         break;
  868.     case FULLMENUNUM(1,MM_RESTORE,NOSUB):
  869.         HNum = H_S_R;
  870.         break;
  871.     case FULLMENUNUM(1,MM_HELP,NOSUB):
  872.         HNum = H_P_HE;
  873.         break;
  874.     case MENUNULL:
  875.     default:
  876.         HNum = H_IM;
  877.         break;
  878.     }
  879.     // Display help
  880.     help(HNum);
  881.     return 1;
  882. }
  883.  
  884. /* String gadget clicked */
  885. int
  886. File241Clicked(void) {
  887.     // Only read when required    - display help if help pressed
  888.     if (TSMorphMsg.Code == 0x5F) {
  889.         help(H_24File1);
  890.     }
  891.     Saved = FALSE;
  892.     return 1;
  893. }
  894.  
  895. /* String gadget clicked */
  896. int
  897. File242Clicked(void) {
  898.     // Only read when required    - display help if help pressed
  899.     if (TSMorphMsg.Code == 0x5F) {
  900.         help(H_24File2);
  901.     }
  902.     Saved = FALSE;
  903.     return 1;
  904. }
  905.  
  906. /* String gadget clicked */
  907. int
  908. FramesClicked(void) {
  909.     // Only read when required    - display help if help pressed
  910.     if (TSMorphMsg.Code == 0x5F) {
  911.         help(H_Frames);
  912.     }
  913.     Saved = FALSE;
  914.     return 1;
  915. }
  916.  
  917. /* String gadget clicked */
  918. int
  919. FileOneClicked(void) {
  920.     // Only read when required    - display help if help pressed
  921.     if (TSMorphMsg.Code == 0x5F) {
  922.         help(H_FileOne);
  923.     }
  924.     Saved = FALSE;
  925.     return 1;
  926. }
  927.  
  928. /* String gadget clicked */
  929. int FileTwoClicked(void) {
  930.     // Only read when required    - display help if help pressed
  931.     if (TSMorphMsg.Code == 0x5F) {
  932.         help(H_FileTwo);
  933.     }
  934.     Saved = FALSE;
  935.     return 1;
  936. }
  937.  
  938. /* CheckBox clicked */
  939. int
  940. SinglePictureClicked(void) {
  941.     // Toggle BOOL
  942.     SinglePicture = TSMorphMsg.Code;
  943.     Saved = FALSE;
  944.     return 1;
  945. }
  946.  
  947. /* String gadget clicked */
  948. int
  949. NameClicked(void) {
  950.     // Only read when required    - display help if help pressed
  951.     if (TSMorphMsg.Code == 0x5F) {
  952.         help(H_Name);
  953.     }
  954.     Saved = FALSE;
  955.     return 1;
  956. }
  957.  
  958. /* String gadget clicked */
  959. int
  960. StartClicked(void) {
  961.     // Read when required - display help if help pressed
  962.     if (TSMorphMsg.Code == 0x5F) {
  963.         help(H_Start);
  964.     }
  965.     Saved = FALSE;
  966.     return 1;
  967. }
  968.  
  969. /* Edit Points gadget clicked */
  970. int
  971. EditPointsClicked(void) {
  972.     // Open window if not open
  973.     if (!ControlWindow) {
  974.         OpenPointsEdit();
  975.     }
  976.     // Otherwise activate and bring to front
  977.     else {
  978.         ActivateWindow(ControlWindow);
  979.         WindowToFront(ControlWindow);
  980.     }
  981.     return 1;
  982. }
  983.  
  984. /* Open the Control and Image Windows    */
  985. void
  986. OpenPointsEdit(void) {
  987.     char buffer[257];
  988.     BOOL ok=TRUE;
  989.     // Open Control window, Pic1 and Pic2
  990.     if ((SinglePicture == 2) || (SinglePicture == 3)) {    // Anim so need frame number
  991.         ok = GetFrameNumber();
  992.     }
  993.     if (ok) {
  994.         if (ControlWindow = OpenControlWindow()) {            // note multiple calls to DisableWindows()
  995.             DisableWindows(DI_Image1);                                // are safe, required to disable just opened window
  996.             Pic1_Open = openAPicture(GetString(TSMorphGadgets[GDX_FileOne]),&Pic1,TRUE);
  997.             if (Pic1_Open) {
  998.                 DisableWindows(DI_Image2);
  999.                   Pic2_Open = openAPicture(GetString(TSMorphGadgets[GDX_FileTwo]),&Pic2,TRUE);
  1000.                 if (Pic2_Open) {
  1001.                      DisableWindows(DI_Draw);
  1002.                      // validate image sizes
  1003.                        if ((Pic1.ilbm->Bmhd.w != Pic2.ilbm->Bmhd.w) ||
  1004.                             (Pic1.ilbm->Bmhd.h != Pic2.ilbm->Bmhd.h)) {
  1005.                            Error(MyGetMsg(MSG_BISIZE),MyGetMsg(MSG_OK),NULL,HE_Size);
  1006.                         CloseAPicture(&Pic2);
  1007.                           Pic2_Open = FALSE;
  1008.                         CloseAPicture(&Pic1);
  1009.                           Pic1_Open = FALSE;
  1010.                         }
  1011.                         else {
  1012.                             // if we have changed from non anim to anim then we may still have
  1013.                             // points in memory - so draw, otherwise try and load points file
  1014.                         if ((!(((struct MyPoint *)PointList.lh_Head)->MyNode.mln_Succ)) &&
  1015.                             ((SinglePicture == 2) || (SinglePicture == 3))) {
  1016.                             strcpy(TempFilename,savedfilename);
  1017.                             strcat(TempFilename,".%03ld");
  1018.                             sprintf(buffer,TempFilename,FrameNumber);
  1019.                             MyOpen(buffer,TRUE,FALSE);
  1020.                         }
  1021.                         else {
  1022.                             DrawAllPoints();
  1023.                         }
  1024.                             // disable some menus, generally set up and activate things
  1025.                         SetMyPointer();
  1026.                         EnableWindows();
  1027.                         OffMenu(TSMorphWnd,FULLMENUNUM(0,0,NOSUB));
  1028.                         OffMenu(TSMorphWnd,FULLMENUNUM(0,1,NOSUB));
  1029.                         ActivateWindow(ControlWindow);
  1030.                         return;
  1031.                     }
  1032.                 }
  1033.                 // Tidy up and close down cleanly
  1034.                 else {
  1035.                     CloseAPicture(&Pic1);
  1036.                       Pic1_Open = FALSE;
  1037.                 }
  1038.             }
  1039.             CloseControlWindow();
  1040.         }
  1041.         EnableWindows();
  1042.     }
  1043. }
  1044.  
  1045. /* Display ASL requesters    */
  1046. int
  1047. GetFile1Clicked(void) {
  1048.     if (GetAFile(GetString(TSMorphGadgets[GDX_File241]),MyGetMsg(MSG_GET241),0)) {
  1049.         GT_SetGadgetAttrs(TSMorphGadgets[GDX_File241],TSMorphWnd,NULL,
  1050.                                 GTST_String, TempFilename, TAG_END );
  1051.         Saved = FALSE;
  1052.     }
  1053.     return 1;
  1054. }
  1055.  
  1056. /* Display ASL requesters    */
  1057. int
  1058. GetFile2Clicked(void) {
  1059.     if (GetAFile(GetString(TSMorphGadgets[GDX_File242]),MyGetMsg(MSG_GET242),0)) {
  1060.         GT_SetGadgetAttrs(TSMorphGadgets[GDX_File242],TSMorphWnd,NULL,
  1061.                                 GTST_String, TempFilename, TAG_END );
  1062.         Saved = FALSE;
  1063.     }
  1064.     return 1;
  1065. }
  1066.  
  1067. /* Display ASL requesters    */
  1068. int
  1069. GetFileOneClicked(void) {
  1070.     if (!ControlWindow) {
  1071.         if (GetAFile(GetString(TSMorphGadgets[GDX_FileOne]),MyGetMsg(MSG_PIC1),0)) {
  1072.             GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileOne],TSMorphWnd,NULL,
  1073.                                     GTST_String, TempFilename, TAG_END );
  1074.             Saved = FALSE;
  1075.         }
  1076.     }
  1077.     return 1;
  1078. }
  1079.  
  1080. /* Display ASL requesters    */
  1081. int
  1082. GetFileTwoClicked(void) {
  1083.     if (!ControlWindow) {
  1084.         if (GetAFile(GetString(TSMorphGadgets[GDX_FileTwo]),MyGetMsg(MSG_PIC2),0)) {
  1085.             GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,NULL,
  1086.                                     GTST_String, TempFilename, TAG_END );
  1087.             Saved = FALSE;
  1088.         }
  1089.     }
  1090.     return 1;
  1091. }
  1092.  
  1093. /* Display ASL requesters    */
  1094. int
  1095. GetSaveNameClicked(void) {
  1096.     if (GetAFile(GetString(TSMorphGadgets[GDX_Name]),MyGetMsg(MSG_MFILEN),0)) {
  1097.         GT_SetGadgetAttrs(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL,
  1098.                                 GTST_String, TempFilename, TAG_END );
  1099.         Saved = FALSE;
  1100.     }
  1101.     return 1;
  1102. }
  1103.  
  1104. /* Displays requester to add a grid of points */
  1105. void
  1106. AddGrid(void) {
  1107.     int flag = 1;
  1108.     // Open window and wait till close selected then close it
  1109.     DisableWindows(DI_Grid);
  1110.     if (!OpenGridRequestWindow()) {
  1111.         while (flag) {
  1112.             Wait((1L << GridRequestWnd->UserPort->mp_SigBit));
  1113.             flag = HandleGridRequestIDCMP();
  1114.         }
  1115.     }
  1116.     else {
  1117.         Error(MyGetMsg(MSG_UNABLE),MyGetMsg(MSG_OK),MyGetMsg(MSG_OPGRIDR),HE_OGrid);
  1118.     }
  1119.     CloseGridRequestWindow();
  1120.     EnableWindows();
  1121. }
  1122.  
  1123. /* Actually add the grid of points    */
  1124. void
  1125. ReallyAddGrid(void) {
  1126.     UWORD xgrid;    //    Number horizontally
  1127.     UWORD ygrid;    // Number vertically
  1128.     UWORD x;            // X coord
  1129.     UWORD y;            // Y coord
  1130.     BOOL ok = TRUE;// Is it working?
  1131.     struct MyPoint **MyPointp;    // Point Pointer
  1132.     struct MyPoint *MyPoint;    // Point
  1133.     // Read X and Y numbers
  1134.     xgrid = GetNumber(GridRequestGadgets[GDX_XCells]);
  1135.     ygrid = GetNumber(GridRequestGadgets[GDX_YCells]);
  1136.     if (xgrid && ygrid) {
  1137.         /* Allocate Pointer to points memory
  1138.          * We need an array but cannot allocate all points
  1139.          * as one block of memory as a single point can be deleted
  1140.          */
  1141.         if (MyPointp = AllocMem(sizeof(struct MyPoint *)*((xgrid+1)*(ygrid+1)),MEMF_CLEAR)) {
  1142.             // Create and draw all points
  1143.             for (x = 0;
  1144.                     ok && (x <= xgrid);
  1145.                     ++x) {
  1146.                 for (y = 0;
  1147.                         ok  && (y <= ygrid);
  1148.                         ++y) {
  1149.                     if (MyPoint = MyPointp[x*(xgrid+1)+y] = AllocMem(sizeof(struct MyPoint),MEMF_CLEAR)) {
  1150.                         Saved = FALSE;
  1151.                         MyPoint->x = (x * (Width-1))/xgrid;
  1152.                         MyPoint->y = (y * (Height-1))/ygrid;
  1153.                         MyPoint->x1 = MyPoint->x;
  1154.                         MyPoint->y1 = MyPoint->y;
  1155.                         AddTail(&PointList,(struct Node *)MyPoint);
  1156.                         DrawPixels(&Pic1,MyPoint->x,MyPoint->y,MyPoint);
  1157.                         DrawPixels(&Pic2,MyPoint->x1,MyPoint->y1,MyPoint);
  1158.                     }
  1159.                     else {
  1160.                         ok = FALSE;
  1161.                     }
  1162.                 }
  1163.             }
  1164.             if (ok) {
  1165.                 // Link all points - link top left to bottom right
  1166.                 for (x = 0;
  1167.                         x <= xgrid;
  1168.                         ++x) {
  1169.                     for (y = 0;
  1170.                             y <= ygrid;
  1171.                             ++y) {
  1172.                         if (x < xgrid) {
  1173.                             LinkPoints(MyPointp[x*(xgrid+1)+y],MyPointp[(x+1)*(xgrid+1)+y]);
  1174.                         }
  1175.                         if (y < ygrid) {
  1176.                             LinkPoints(MyPointp[x*(xgrid+1)+y],MyPointp[x*(xgrid+1)+y+1]);
  1177.                         }
  1178.                     }
  1179.                 }
  1180.             }
  1181.             // Free the Points pointers
  1182.             FreeMem(MyPointp,sizeof(struct MyPoint *)*((xgrid+1)*(ygrid+1)));
  1183.         }
  1184.         else {
  1185.             ok = FALSE;
  1186.         }
  1187.     }
  1188.     else {
  1189.         Error(MyGetMsg(MSG_BOTHGT0),MyGetMsg(MSG_OK),NULL,HE_Grid0);
  1190.     }
  1191.     if (!ok) {
  1192.         Error(MyGetMsg(MSG_OUTMP),MyGetMsg(MSG_OK),NULL,HE_MPoints);
  1193.     }
  1194. }
  1195.  
  1196. /* Display help on a control or image window menu
  1197.  * Code    : menu code
  1198.  * Note: this is a virtual clone of the code above (with 1 changed to M_SETTINGS)
  1199.  */
  1200. void
  1201. DoMenuHelp(USHORT Code) {
  1202.     ULONG HNum;        // Help node
  1203.     /* Reset everything which could have been set
  1204.      * using the menu
  1205.      */
  1206.     RemoveMenus();
  1207.     MySetMode(Mode);
  1208.     // Forget any previous changes
  1209.     SwitchMenuItem(MM_PALETTE,palette,FALSE);
  1210.     SwitchMenuItem(MM_ZOOM,Zoom,FALSE);
  1211.     SwitchMenuItem(MM_ICONSP,CreateIconsP,FALSE);
  1212.     UpdateOpenMode(FALSE);
  1213.     SwitchMenuItem(MM_ICONSR,CreateIconsR,FALSE);
  1214.     UpdateRenderMode(FALSE);
  1215.     UpdateSaveFormat(FALSE);
  1216.     AddMenus();
  1217.     // Determine help node
  1218.     switch (Code) {
  1219.     case FULLMENUNUM(M_PROJECT,NOITEM,NOSUB):
  1220.     case FULLMENUNUM(M_PROJECT,MM_B1,NOSUB):
  1221.     case FULLMENUNUM(M_PROJECT,MM_B2,NOSUB):
  1222.     case FULLMENUNUM(M_PROJECT,MM_B3,NOSUB):
  1223.     case FULLMENUNUM(M_PROJECT,MM_B4,NOSUB):
  1224.     case FULLMENUNUM(M_PROJECT,MM_B5,NOSUB):
  1225.         HNum = H_CMP;
  1226.         break;
  1227.     case FULLMENUNUM(M_PROJECT,MM_NEW,NOSUB):
  1228.         HNum = H_CMPN;
  1229.         break;
  1230.     case FULLMENUNUM(M_PROJECT,MM_OPEN,NOSUB):
  1231.         HNum = H_CMPO;
  1232.         break;
  1233.     case FULLMENUNUM(M_PROJECT,MM_SAVE,NOSUB):
  1234.         HNum = H_CMPS;
  1235.         break;
  1236.     case FULLMENUNUM(M_PROJECT,MM_SAVEAS,NOSUB):
  1237.         HNum = H_CMPSA;
  1238.         break;
  1239.     case FULLMENUNUM(M_PROJECT,MM_ABOUT,NOSUB):
  1240.         HNum = H_CMPA;
  1241.         break;
  1242.     case FULLMENUNUM(M_PROJECT,MM_EXITPOINTS,NOSUB):
  1243.         HNum = H_CMPE;
  1244.         break;
  1245.     case FULLMENUNUM(M_PROJECT,MM_QUIT,NOSUB):
  1246.         HNum = H_CMPQ;
  1247.         break;
  1248.     case FULLMENUNUM(M_PROJECT,MM_PPREVIEW,NOSUB):
  1249.         HNum = H_CMPP;
  1250.         break;
  1251.     case FULLMENUNUM(M_EDIT,NOITEM,NOSUB):
  1252.         HNum = H_CME;
  1253.         break;
  1254.     case FULLMENUNUM(M_EDIT,MM_GRID,NOSUB):
  1255.         HNum = H_CMEG;
  1256.         break;
  1257.     case FULLMENUNUM(M_EDIT,MM_TRIANGULATE,NOSUB):
  1258.         HNum = H_CMET;
  1259.         break;
  1260.     case FULLMENUNUM(M_EDIT,MM_FRAME,NOSUB):
  1261.         HNum = H_CMEF;
  1262.         break;
  1263.     case FULLMENUNUM(M_EDIT,MM_FRAME,MI_FIRST):
  1264.         HNum = H_CMEFF;
  1265.         break;
  1266.     case FULLMENUNUM(M_EDIT,MM_FRAME,MI_PREV):
  1267.         HNum = H_CMEFP;
  1268.         break;
  1269.     case FULLMENUNUM(M_EDIT,MM_FRAME,MI_GOTO):
  1270.         HNum = H_CMEFG;
  1271.         break;
  1272.     case FULLMENUNUM(M_EDIT,MM_FRAME,MI_NEXT):
  1273.         HNum = H_CMEFN;
  1274.         break;
  1275.     case FULLMENUNUM(M_EDIT,MM_FRAME,MI_LAST):
  1276.         HNum = H_CMEFL;
  1277.         break;
  1278.     case FULLMENUNUM(M_EDIT,MM_MODE,NOSUB):
  1279.         HNum = H_CMSM;
  1280.         break;
  1281.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITONE):
  1282.         HNum = H_EOne;
  1283.         break;
  1284.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITTWO):
  1285.         HNum = H_ETwo;
  1286.         break;
  1287.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_EDITREL):
  1288.         HNum = H_ERel;
  1289.         break;
  1290.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_ADD):
  1291.         HNum = H_EAdd;
  1292.         break;
  1293.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_DELETE):
  1294.         HNum = H_EDel;
  1295.         break;
  1296.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_LINK):
  1297.         HNum = H_ELnk;
  1298.         break;
  1299.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_UNLINK):
  1300.         HNum = H_EUnl;
  1301.         break;
  1302.     case FULLMENUNUM(M_EDIT,MM_MODE,MI_NONE):
  1303.         HNum = H_EMov;
  1304.         break;
  1305.     case FULLMENUNUM(M_SETTINGS,NOITEM,NOSUB):
  1306.     case FULLMENUNUM(M_SETTINGS,MM_C1,NOSUB):
  1307.     case FULLMENUNUM(M_SETTINGS,MM_C2,NOSUB):
  1308.     case FULLMENUNUM(M_SETTINGS,MM_C3,NOSUB):
  1309.     case FULLMENUNUM(M_SETTINGS,MM_C4,NOSUB):
  1310.         HNum = H_IMS;
  1311.         break;
  1312.     case FULLMENUNUM(M_SETTINGS,MM_ICONS,NOSUB):
  1313.         HNum = H_P_CI;
  1314.         break;
  1315.     case FULLMENUNUM(M_SETTINGS,MM_PALETTE,NOSUB):
  1316.         HNum = H_P_CP;
  1317.         break;
  1318.     case FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB):
  1319.         HNum = H_P_ZO;
  1320.         break;
  1321.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,NOSUB):
  1322.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,MI_ALWAYS):
  1323.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,MI_IFILBM):
  1324.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,MI_IFCOLOURS):
  1325.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,MI_REMAP):
  1326.     case FULLMENUNUM(M_SETTINGS,MM_OPENMODE,MI_OPAL):
  1327.         HNum = H_P_OM;
  1328.         break;
  1329.     case FULLMENUNUM(M_SETTINGS,MM_SCREEN,NOSUB):
  1330.         HNum = H_P_PS;
  1331.         break;
  1332.     case FULLMENUNUM(M_SETTINGS,MM_CUSTOM,NOSUB):
  1333.         HNum = H_PCUSTM;
  1334.         break;
  1335.     case FULLMENUNUM(M_SETTINGS,MM_CDEPTH,NOSUB):
  1336.         HNum = H_PCUSTD;
  1337.         break;
  1338.     case FULLMENUNUM(M_SETTINGS,MM_SPREVIEW,NOSUB):
  1339.         HNum = H_P_Preview;
  1340.         break;
  1341.     case FULLMENUNUM(M_SETTINGS,MM_ICONSP,NOSUB):
  1342.         HNum = H_P_CIP;
  1343.         break;
  1344.     case FULLMENUNUM(M_SETTINGS,MM_KEEPS,NOSUB):
  1345.         HNum = H_P_KS;
  1346.         break;
  1347.     case FULLMENUNUM(M_SETTINGS,MM_LOADS,NOSUB):
  1348.         HNum = H_P_LOADS;
  1349.         break;
  1350.     case FULLMENUNUM(M_SETTINGS,MM_SAVES,NOSUB):
  1351.         HNum = H_P_SAVES;
  1352.         break;
  1353.     case FULLMENUNUM(M_SETTINGS,MM_SAVESAS,NOSUB):
  1354.         HNum = H_P_SAVESAS;
  1355.         break;
  1356.     case FULLMENUNUM(M_SETTINGS,MM_ICONSR,NOSUB):
  1357.         HNum = H_P_CIR;
  1358.         break;
  1359.     case FULLMENUNUM(M_SETTINGS,MM_DX,NOSUB):
  1360.         HNum = H_P_DX;
  1361.         break;
  1362.     case FULLMENUNUM(M_SETTINGS,MM_DY,NOSUB):
  1363.         HNum = H_P_DY;
  1364.         break;
  1365.     case FULLMENUNUM(M_SETTINGS,MM_LOADSCRIPT,NOSUB):
  1366.         HNum = H_P_LS;
  1367.         break;
  1368.     case FULLMENUNUM(M_SETTINGS,MM_PRESCRIPT,NOSUB):
  1369.         HNum = H_P_PES;
  1370.         break;
  1371.     case FULLMENUNUM(M_SETTINGS,MM_POSTSCRIPT,NOSUB):
  1372.         HNum = H_P_POS;
  1373.         break;
  1374.     case FULLMENUNUM(M_SETTINGS,MM_DEPTH,NOSUB):
  1375.         HNum = H_P_DE;
  1376.         break;
  1377.     case FULLMENUNUM(M_SETTINGS,MM_RENDERMODE,NOSUB):
  1378.     case FULLMENUNUM(M_SETTINGS,MM_RENDERMODE,MI_MODE1):
  1379.     case FULLMENUNUM(M_SETTINGS,MM_RENDERMODE,MI_MODE2):
  1380.     case FULLMENUNUM(M_SETTINGS,MM_RENDERMODE,MI_MODE4):
  1381.     case FULLMENUNUM(M_SETTINGS,MM_RENDERMODE,MI_MODE8):
  1382.         HNum = H_P_MO;
  1383.         break;
  1384.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,NOSUB):
  1385.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_ILBM24):
  1386.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_OPAL24):
  1387.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_OPAL24T):
  1388.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_OPAL24F):
  1389.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_OPAL24FT):
  1390.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_JPEG):
  1391.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_JPEGT):
  1392.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_PBM):
  1393.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_BW16):
  1394.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_BW256):
  1395.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_HAM6):
  1396.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_HAM8):
  1397.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_DCTV3):
  1398.     case FULLMENUNUM(M_SETTINGS,MM_SAVEFORMAT,MI_DCTV4):
  1399.         HNum = H_P_SF;
  1400.         break;
  1401.     case FULLMENUNUM(M_SETTINGS,MM_QUALITY,NOSUB):
  1402.         HNum = H_P_QU;
  1403.         break;
  1404.     case FULLMENUNUM(M_SETTINGS,MM_SCREENR,NOSUB):
  1405.         HNum = H_P_PSR;
  1406.         break;
  1407.     case FULLMENUNUM(M_SETTINGS,MM_ANTIALIAS,NOSUB):
  1408.         HNum = H_P_AA;
  1409.         break;
  1410.     case FULLMENUNUM(M_SETTINGS,MM_INTEGER,NOSUB):
  1411.         HNum = H_P_INT;
  1412.         break;
  1413.     case FULLMENUNUM(M_SETTINGS,MM_RESETD,NOSUB):
  1414.         HNum = H_S_RD;
  1415.         break;
  1416.     case FULLMENUNUM(M_SETTINGS,MM_LASTS,NOSUB):
  1417.         HNum = H_S_LS;
  1418.         break;
  1419.     case FULLMENUNUM(M_SETTINGS,MM_RESTORE,NOSUB):
  1420.         HNum = H_S_R;
  1421.         break;
  1422.     case FULLMENUNUM(M_SETTINGS,MM_HELP,NOSUB):
  1423.         HNum = H_P_HE;
  1424.         break;
  1425.     case MENUNULL:
  1426.     default:
  1427.         HNum = H_CM;
  1428.         break;
  1429.     }
  1430.     help(HNum);
  1431. }
  1432.  
  1433. /* String gadget clicked */
  1434. int
  1435. XCellsClicked(void) {
  1436.     // Display help if required
  1437.     if (GridRequestMsg.Code == 0x5F) {
  1438.         help(H_RAGGX);
  1439.     }
  1440.     return 1;
  1441.  
  1442. }
  1443.  
  1444. /* String gadget clicked */
  1445. int
  1446. YCellsClicked(void) {
  1447.     // Display help if required
  1448.     if (GridRequestMsg.Code == 0x5F) {
  1449.         help(H_RAGGY);
  1450.     }
  1451.     return 1;
  1452. }
  1453.  
  1454. /* OK gadget clicked so add the grid    */
  1455. int
  1456. OKClicked(void) {
  1457.     ReallyAddGrid();
  1458.     return 0;
  1459. }
  1460.  
  1461. /* Cancel clicked  - do not add grid    */
  1462. int
  1463. CancelClicked(void) {
  1464.     return 0;
  1465. }
  1466.  
  1467. /* Close Window - do not add grid    */
  1468. int
  1469. GridRequestCloseWindow(void) {
  1470.     return 0;
  1471. }
  1472.  
  1473. /* Vanilla Key in Add Grid    */
  1474. int
  1475. GridRequestVanillaKey(void) {
  1476.     switch (GridRequestMsg.Code) {
  1477.     case 'o':
  1478.     case 'O':
  1479.         // Same as OK
  1480.         OKClicked();
  1481.         return 0;
  1482.         break;
  1483.     case 'x':
  1484.     case 'X':
  1485.         // Activate string gadget
  1486.         ActivateGadget(GridRequestGadgets[GDX_XCells],GridRequestWnd,NULL);
  1487.         break;
  1488.     case 'y':
  1489.     case 'Y':
  1490.         // Activate string gadget
  1491.         ActivateGadget(GridRequestGadgets[GDX_YCells],GridRequestWnd,NULL);
  1492.         break;
  1493.     case 'c':
  1494.     case 'C':
  1495.         // Cancel
  1496.         return 0;
  1497.         break;
  1498.     }
  1499.     return 1;
  1500. }
  1501.  
  1502. /* Raw key - Only help does anything    */
  1503. int
  1504. GridRequestRawKey(void) {
  1505.     UWORD X,Y;            // Mouse coords
  1506.     ULONG HNum;            // Help node
  1507.     X = GridRequestWnd->MouseX;
  1508.     Y = GridRequestWnd->MouseY;
  1509.     switch (GridRequestMsg.Code) {
  1510.     case 0x5f:
  1511.         // Help key - determine gadget or whole window
  1512.         if (PointInBox(X,Y,GRect[GDX_XCells].MinX,GRect[GDX_XCells].MinY,
  1513.                                 GRect[GDX_XCells].MaxX,GRect[GDX_XCells].MaxY))
  1514.             HNum = H_RAGGX;
  1515.         else
  1516.         if (PointInBox(X,Y,GRect[GDX_YCells].MinX,GRect[GDX_YCells].MinY,
  1517.                                 GRect[GDX_YCells].MaxX,GRect[GDX_YCells].MaxY))
  1518.             HNum = H_RAGGY;
  1519.         else
  1520.         if (PointInBox(X,Y,GRect[GDX_OK].MinX,GRect[GDX_OK].MinY,
  1521.                                 GRect[GDX_OK].MaxX,GRect[GDX_OK].MaxY))
  1522.             HNum = H_RAGGOK;
  1523.         else
  1524.         if (PointInBox(X,Y,GRect[GDX_Cancel].MinX,GRect[GDX_Cancel].MinY,
  1525.                                 GRect[GDX_Cancel].MaxX,GRect[GDX_Cancel].MaxY))
  1526.             HNum = H_RAGGCA;
  1527.         else
  1528.         // should really use dynamic gadget size stuff
  1529.         if (PointInBox(X,Y,0,0,
  1530.                                 20,GridRequestWnd->BorderTop))
  1531.             HNum = H_RAGGCL;
  1532.         else
  1533.         if (PointInBox(X,Y,(GridRequestWnd->Width - 24),0,
  1534.                                 GridRequestWnd->Width,GridRequestWnd->BorderTop))
  1535.             HNum = H_RAGGDE;
  1536.         else
  1537.             HNum = H_RAG;
  1538.         help(HNum);
  1539.         break;
  1540.     }
  1541.     return 1;
  1542. }
  1543.  
  1544. /* If project not saved then
  1545.  * display requester and then
  1546.  * save if required
  1547.  * Returns:    TRUE keep going
  1548.  */
  1549. BOOL
  1550. SaveRequester(void) {
  1551.     struct EasyStruct EasyStruct = {
  1552.         sizeof(struct EasyStruct),
  1553.         0,
  1554.         NULL,
  1555.         NULL,
  1556.         NULL
  1557.     };
  1558.     UBYTE *title = "TSMorph";
  1559.     UBYTE *body;
  1560.     UBYTE *gadget;
  1561.     struct Window *req;
  1562.     LONG gad=-1;
  1563.     ULONG ret = 2;
  1564.     ULONG signals;
  1565.     struct rtHandlerInfo *rth;
  1566.     struct AmigaGuideMsg *agm;
  1567.     BOOL ret1;
  1568.     char *other = &(savedfilename[0]);
  1569.     // Disable the windows and display the requester - using reqtools if available
  1570.     DisableWindows(DI_Unsaved);
  1571.     body = MyGetMsg(MSG_UNSAVED);
  1572.     if (ReqToolsBase) {
  1573.         // set up gadgets depending on availability of amigaguide
  1574.         if (handle) {
  1575.             gadget = MyGetMsg(MSG__SHAC);
  1576.         }
  1577.         else {
  1578.             gadget = MyGetMsg(MSG__SAC);
  1579.         }
  1580.         // Loop until Save,Abandon or Cancel pressed
  1581.         while (((ret == 2) && handle) || (gad == -1)) {
  1582.             ret = CALL_HANDLER;
  1583.             if (rtEZRequestTags(body,gadget,NULL,&other,
  1584.                                         RT_ReqHandler, &rth,
  1585.                                         RT_Window, TSMorphWnd,
  1586.                                         RT_Underscore, '_',
  1587.                                         RTEZ_ReqTitle, title,
  1588.                                         TAG_END) == CALL_HANDLER) {
  1589.                 while (ret == CALL_HANDLER) {
  1590.                     if (!rth->DoNotWait) {
  1591.                         signals = Wait(rth->WaitMask | ASig);
  1592.                     }
  1593.                     ret = rtReqHandlerA(rth,signals,NULL);
  1594.                     if ((ret == 2) && handle) {
  1595.                         help(H_Unsaved);
  1596.                     }
  1597.                     if (signals & ASig) {
  1598.                           while (agm = GetAmigaGuideMsg(handle)) {
  1599.                              ReplyAmigaGuideMsg(agm);
  1600.                          }
  1601.                      }
  1602.                 }
  1603.             }
  1604.             else {
  1605.                 ret = 0;
  1606.             }
  1607.             gad = ret;
  1608.         }
  1609.     }
  1610.     else {
  1611.         EasyStruct.es_TextFormat = body;
  1612.         EasyStruct.es_Title = title;
  1613.         // set up gadgets depending on availability of amigaguide
  1614.         if (handle) {
  1615.             EasyStruct.es_GadgetFormat = MyGetMsg(MSG_SHAC);
  1616.         }
  1617.         else {
  1618.             EasyStruct.es_GadgetFormat = MyGetMsg(MSG_SAC);
  1619.         }
  1620.         req = BuildEasyRequest(TSMorphWnd,&EasyStruct,NULL,savedfilename);
  1621.         // Loop until Save,Abandon or Cancel pressed
  1622.         while ((((gad = SysReqHandler(req,NULL,TRUE)) == 2) && handle) ||
  1623.                  (gad == -1)) {
  1624.             if (handle) {
  1625.                 help(H_Unsaved);
  1626.             }
  1627.         }
  1628.         FreeSysRequest(req);
  1629.     }
  1630.     switch(gad) {
  1631.     case 1:
  1632.         if (*savedfilename) {
  1633.             ret1 = SaveAs(savedfilename);
  1634.         }
  1635.         else {
  1636.             ret1 = SaveAs(NULL);
  1637.         }
  1638.         break;
  1639.     case 2:
  1640.     case 3:                // 2 if no help, 3 otherwise
  1641.         ret1 = TRUE;
  1642.         break;
  1643.     case 0:
  1644.         ret1 = FALSE;
  1645.         break;
  1646.     }
  1647.     EnableWindows();
  1648.     return ret1;
  1649. }
  1650.  
  1651. /* Link two points
  1652.  * Drawing in the windows if open
  1653.  * Does not link already linked points
  1654.  */
  1655. void
  1656. LinkPoints(struct MyPoint* MyPoint,struct MyPoint *MyPoint1) {
  1657.     int i,j=0,j1=0;
  1658.     BOOL Ok = TRUE;
  1659.     // Link in first free position
  1660.     if ((MyPoint->NumLinks < MAX_LINKS) &&
  1661.          (MyPoint1->NumLinks < MAX_LINKS)) {
  1662.         for (i = 0;
  1663.               i < MAX_LINKS;
  1664.               i++) {
  1665.             if (MyPoint->p[i] == MyPoint1) {
  1666.                 Ok = FALSE;
  1667.             }
  1668.             if ((!MyPoint->p[i]) && (!j)) {
  1669.                 j = i;
  1670.             }
  1671.         }
  1672.         for (i = 0;
  1673.               (i < MAX_LINKS) && !j1;
  1674.               i++) {
  1675.             if ((!MyPoint1->p[i]) && (!j1)) {
  1676.                 j1 = i;
  1677.             }
  1678.         }
  1679.         if (Ok) {
  1680.             MyPoint->NumLinks++;
  1681.             MyPoint1->NumLinks++;
  1682.             MyPoint->p[j] = MyPoint1;
  1683.             MyPoint1->p[j1] = MyPoint;
  1684.             // If windows open then draw points and lines
  1685.             if (EGS) {
  1686.                 if (Pic1_Open) {
  1687.                     EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint1->x,MyPoint1->y,MyPoint->x,MyPoint->y);
  1688.                 }
  1689.                 if (Pic2_Open) {
  1690.                     EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint1->x1,MyPoint1->y1,MyPoint->x1,MyPoint->y1);
  1691.                 }
  1692.             }
  1693.             else {
  1694.                 if (Pic1_Open) {
  1695.                     MyDraw(Pic1.Win->RPort,MyPoint1->x<<Zoom,MyPoint1->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
  1696.                 }
  1697.                 if (Pic2_Open) {
  1698.                     MyDraw(Pic2.Win->RPort,MyPoint1->x1<<Zoom,MyPoint1->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
  1699.                 }
  1700.             }
  1701.         }
  1702.     }
  1703. }
  1704.  
  1705. /* Unlink two points
  1706.  * Drawing on the screen if required
  1707.  */
  1708. void
  1709. UnlinkPoints(struct MyPoint* MyPoint,struct MyPoint *MyPoint1,BOOL MYDraw) {
  1710.     int i;
  1711.     // Erase lines if required
  1712.     if (MYDraw) {
  1713.         if (EGS) {
  1714.             EGSMyDraw(Pic1.EGS_Win->RPort,MyPoint1->x,MyPoint1->y,MyPoint->x,MyPoint->y);
  1715.             EGSMyDraw(Pic2.EGS_Win->RPort,MyPoint1->x1,MyPoint1->y1,MyPoint->x1,MyPoint->y1);
  1716.         }
  1717.         else {
  1718.             MyDraw(Pic1.Win->RPort,MyPoint1->x<<Zoom,MyPoint1->y<<Zoom,MyPoint->x<<Zoom,MyPoint->y<<Zoom);
  1719.             MyDraw(Pic2.Win->RPort,MyPoint1->x1<<Zoom,MyPoint1->y1<<Zoom,MyPoint->x1<<Zoom,MyPoint->y1<<Zoom);
  1720.         }
  1721.     }
  1722.     // Unlink each way
  1723.     for (i = 0;
  1724.           i < MAX_LINKS;
  1725.           i++) {
  1726.         if (MyPoint->p[i] == MyPoint1) {
  1727.             MyPoint->p[i] = NULL;
  1728.             MyPoint->NumLinks--;
  1729.         }
  1730.     }
  1731.     for (i = 0;
  1732.           i < MAX_LINKS;
  1733.           i++) {
  1734.         if (MyPoint1->p[i] == MyPoint) {
  1735.             MyPoint1->p[i] = NULL;
  1736.             MyPoint1->NumLinks--;
  1737.         }
  1738.     }
  1739. }
  1740.  
  1741. /* Unlink all points
  1742.  * Erasing lines if images are open
  1743.  */
  1744. void
  1745. UnlinkAllPoints(BOOL Draw) {
  1746.     int i;
  1747.     struct MyPoint *MyPoint;
  1748.     /* Loop round looking at the first point every time
  1749.      * since DeletePoint removes it from the list
  1750.      */
  1751.     for (MyPoint = (struct MyPoint *)PointList.lh_Head;
  1752.             MyPoint->MyNode.mln_Succ;
  1753.             MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
  1754.         for (i = 0;
  1755.               i < MAX_LINKS;
  1756.               i++) {
  1757.             if (MyPoint->p[i]) {
  1758.                 UnlinkPoints(MyPoint,MyPoint->p[i],Draw);
  1759.             }
  1760.         }
  1761.     }
  1762. }
  1763.  
  1764. /* Find a point in an image given
  1765.  * x and y coordinates
  1766.  * Returns    : NULL if none closeby
  1767.  */
  1768. struct MyPoint *
  1769. FindPoint(struct Picture *pic,WORD x,WORD y) {
  1770.     struct MyPoint *MyPoint;            // Point to look at
  1771.     LONG diff = 36;                        // Must be closer than sqrt(36) pixels
  1772.     LONG diff1;                                // sqr(distance apart) for current point
  1773.     struct MyPoint *RetPoint = NULL;    // Point being returned
  1774.     // adjust coords for zoom and scroll
  1775.     x+=(pic->Left>>Zoom);
  1776.     y+=(pic->Top>>Zoom);
  1777.     // Step thru all points and find closest
  1778.     for (MyPoint = (struct MyPoint *)PointList.lh_Head;
  1779.             MyPoint->MyNode.mln_Succ;
  1780.             MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
  1781.         if (pic == &Pic1) {
  1782.             diff1 = ((MyPoint->x-x)*(MyPoint->x-x)+
  1783.                         (MyPoint->y-y)*(MyPoint->y-y));
  1784.         }
  1785.         else {
  1786.             diff1 = ((MyPoint->x1-x)*(MyPoint->x1-x)+
  1787.                         (MyPoint->y1-y)*(MyPoint->y1-y));
  1788.         }
  1789.           if (diff1<diff) {
  1790.               diff = diff1;
  1791.               RetPoint = MyPoint;
  1792.           }
  1793.     }
  1794.     return RetPoint;
  1795. }
  1796.  
  1797. /* Delete a point
  1798.  * removing all links
  1799.  */
  1800. void
  1801. DeletePoint(struct MyPoint *MyPoint){
  1802.     int i;
  1803.     // Unlink any links
  1804.     for (i = 0;
  1805.           i < MAX_LINKS;
  1806.           i++) {
  1807.         if (MyPoint->p[i]) {
  1808.             UnlinkPoints(MyPoint,MyPoint->p[i],FALSE);
  1809.         }
  1810.     }
  1811.     // remove from list and free memory
  1812.     Remove((struct Node *)MyPoint);
  1813.     FreeMem(MyPoint,sizeof(struct MyPoint));
  1814. }
  1815.  
  1816. /* Similar to Draw() but always draws top left to bottom right
  1817.  * to prevent stray pixels if erasing by drawing in the other direction
  1818.  */
  1819. void
  1820. MyDraw(struct RastPort *rp, SHORT x, SHORT y, SHORT oldx, SHORT oldy) {
  1821.     if ((oldx < x) || ((oldx == x) && (oldy < y))) {
  1822.         Move(rp,oldx,oldy);
  1823.         Draw(rp,x,y);
  1824.     }
  1825.     else {
  1826.         Move(rp,x,y);
  1827.         Draw(rp,oldx,oldy);
  1828.     }
  1829. }
  1830.  
  1831. /* Similar to EG_Draw() but always draws top left to bottom right
  1832.  * to prevent stray pixels if erasing by drawing in the other direction
  1833.  */
  1834. void
  1835. EGSMyDraw(struct EG_RastPort *rp, SHORT x, SHORT y, SHORT oldx, SHORT oldy) {
  1836.     if ((oldx < x) || ((oldx == x) && (oldy < y))) {
  1837.         EG_Move(rp,oldx,oldy);
  1838.         EG_Draw(rp,x,y);
  1839.     }
  1840.     else {
  1841.         EG_Move(rp,x,y);
  1842.         EG_Draw(rp,oldx,oldy);
  1843.     }
  1844. }
  1845.  
  1846. /* Shows ASL file requester for a file
  1847.  * name    : current file name
  1848.  * Prompt: Title
  1849.  * flags    : e.g. for save flag
  1850.  * Returns: TRUE if file selected, name is TempFileName
  1851.  */
  1852. BOOL
  1853. GetAFile(char *name,char *Prompt,ULONG flags) {
  1854.     char rtfilename[108] = "\0";    // reqtools filename from requester
  1855.     // Split of directory name
  1856.     strncpy(TempFilename,name,PathPart(name) - name);
  1857.     TempFilename[PathPart(name) - name] = 0;
  1858.     // Show requesters
  1859.     if (rtfilereq) {
  1860.         rtChangeReqAttr(rtfilereq,
  1861.                             RTFI_Dir, TempFilename,
  1862.                             TAG_DONE);
  1863.         strcpy(rtfilename,FilePart(name));
  1864.         if (rtFileRequest(rtfilereq, rtfilename, Prompt,
  1865.                                 RT_Window, TSMorphWnd,
  1866.                                 RTFI_Flags,(flags & FILF_SAVE)?FREQF_SAVE:0,
  1867.                                 TAG_DONE)) {
  1868.             strncpy(TempFilename,rtfilereq->Dir,256);
  1869.             AddPart(TempFilename,rtfilename,256);
  1870.             return TRUE;
  1871.         }
  1872.         else {
  1873.             return FALSE;
  1874.         }
  1875. }
  1876.     else {
  1877.         if (AslRequestTags((APTR) filereq,
  1878.                                 ASL_Hail,(Tag) Prompt,
  1879.                                 ASL_FuncFlags,flags,
  1880.                                 ASL_Dir, (Tag) TempFilename,
  1881.                                 ASL_File,(Tag) FilePart(name),
  1882.                                 ASL_Window, TSMorphWnd,
  1883.                                 TAG_DONE)) {
  1884.             // rejoin name
  1885.             strncpy(TempFilename,filereq->rf_Dir,256);
  1886.             AddPart(TempFilename,filereq->rf_File,256);
  1887.             return TRUE;
  1888.         }
  1889.         else {
  1890.             return FALSE;
  1891.         }
  1892.     }
  1893. }
  1894.  
  1895. /* New selected on the Info window */
  1896. int
  1897. TSMorphMenuNew(void) {
  1898.     // Suggest save if unsaved
  1899.     if (!Saved) {
  1900.         if (!SaveRequester()) {
  1901.             return 1;
  1902.         }
  1903.         DisableWindows(DI_New);
  1904.     }
  1905.     // Reset everything
  1906.     Saved = TRUE;
  1907.     savedfilename[0]=0;
  1908.     DeleteAllPoints();
  1909.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileOne],TSMorphWnd,NULL,
  1910.                             GTST_String, "", TAG_END );
  1911.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_FileTwo],TSMorphWnd,NULL,
  1912.                             GTST_String, "", TAG_END );
  1913.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_File241],TSMorphWnd,NULL,
  1914.                             GTST_String, "", TAG_END );
  1915.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_File242],TSMorphWnd,NULL,
  1916.                             GTST_String, "", TAG_END );
  1917.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_Name],TSMorphWnd,NULL,
  1918.                             GTST_String, "", TAG_END );
  1919.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_Frames],TSMorphWnd,NULL,
  1920.                             GTIN_Number,1, TAG_END );
  1921.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_Start],TSMorphWnd,NULL,
  1922.                             GTIN_Number,0, TAG_END );
  1923.     SinglePicture = 0;
  1924.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_SinglePicture],TSMorphWnd,NULL,
  1925.                             GTCY_Active,SinglePicture, TAG_END );
  1926.     Width = 0;
  1927.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_Width],TSMorphWnd,NULL,
  1928.                             GTNM_Number,Width, TAG_END );
  1929.     Height = 0;
  1930.     GT_SetGadgetAttrs(TSMorphGadgets[GDX_Height],TSMorphWnd,NULL,
  1931.                             GTNM_Number,Height, TAG_END );
  1932.     MaxWidth = 0;
  1933.     MaxHeight = 0;
  1934.     EnableWindows();
  1935.     return 1;
  1936. }
  1937.  
  1938. /* Limit the coordinates of a point to the image size */
  1939. void
  1940. LimitPoints(SHORT *x,SHORT *y,struct Picture *pic) {
  1941.     if (*x < 0)
  1942.         *x = 0;
  1943.     if (*x > pic->width-1)
  1944.         *x = pic->width-1;
  1945.     if (*y < 0)
  1946.         *y = 0;
  1947.     if (*y > pic->height-1)
  1948.         *y = pic->height-1;
  1949. }
  1950.  
  1951. static BOOL realfirstcall = TRUE;    // Is this really the first call
  1952.                                                 // not sure I understand this!
  1953.                                                 // but some parameters (e.g. Public screen) must
  1954.                                                 // only be set on the very first call
  1955. // Initialise all settings values from parameters etc.
  1956. void
  1957. InitParams(BOOL firstcall) {
  1958.     UBYTE *omode;
  1959.     ULONG OZoom = Zoom;
  1960.     UBYTE *FormatStr;
  1961.     if (realfirstcall) {
  1962.         PubScreenName     = MyArgString("PUBSCREEN",NULL,!firstcall);
  1963.     }
  1964.     if (realfirstcall || !ControlWindow) {
  1965.         PaletteAllowed = !MatchToolValue(MyArgString("CHANGEPALETTE",PaletteAllowed?"YES":"OFF",!firstcall),"OFF");
  1966.         ZoomAllowed     = !MatchToolValue(MyArgString("ZOOM",ZoomAllowed?"NO":"OFF",!firstcall),"OFF");
  1967.     }
  1968.     realfirstcall = FALSE;
  1969.     strcpy(ScreenName,MyArgString("PUBSCREEN",ScreenName,!firstcall));
  1970.     strcpy(CustomName,MyArgString("CUSTOMMODE",CustomName,!firstcall));
  1971.     CustomDepth = MyArgInt("CUSTOMDEPTH",CustomDepth,!firstcall);
  1972.     strcpy(ScreenNameR,MyArgString("PUBSCREENR",ScreenNameR,!firstcall));
  1973.     CreateIcons     = MatchToolValue(MyArgString("CREATEICONS",CreateIcons?"YES":"NO",!firstcall),"YES");
  1974.     CreateIconsR     = MatchToolValue(MyArgString("CREATEICONSR",CreateIconsR?"YES":"NO",!firstcall),"YES");
  1975.     CreateIconsP     = MatchToolValue(MyArgString("CREATEICONSP",CreateIconsP?"YES":"NO",!firstcall),"YES");
  1976.     KeepSettings   = MatchToolValue(MyArgString("KEEPSETTINGS",KeepSettings?"YES":"NO",!firstcall),"YES");
  1977.     if (PaletteAllowed) {
  1978.         palette             = MatchToolValue(MyArgString("CHANGEPALETTE",palette?"YES":"NO",!firstcall),"YES");
  1979.     }
  1980.     else {
  1981.         palette = FALSE;
  1982.     }
  1983.     if (ZoomAllowed) {
  1984.         Zoom = (MatchToolValue(MyArgString("ZOOM",Zoom?"YES":"NO",!firstcall),"YES") ? 1 : 0);    // Note: not a BOOL
  1985.     }
  1986.     else {
  1987.         Zoom = FALSE;
  1988.     }
  1989.     switch (OpenMode) {
  1990.     case OPEN_ILBM_IF_ILBM:
  1991.         omode = "IFILBM";
  1992.         break;
  1993.     case OPEN_ILBM_ALWAYS:
  1994.         omode = "ALWAYS";
  1995.         break;
  1996.     case OPEN_REMAP:
  1997.         omode = "REMAP";
  1998.         break;
  1999.     case OPEN_OPAL:
  2000.         omode = "OPAL";
  2001.         break;
  2002.     default:
  2003.         omode = "IFCOLOURS";
  2004.         break;
  2005.     }
  2006.     omode = MyArgString("OPENMODE",omode,!firstcall);
  2007.     if (MatchToolValue(omode,"IFILBM")) {
  2008.         OpenMode = OPEN_ILBM_IF_ILBM;
  2009.     }
  2010.     else {
  2011.         if (MatchToolValue(omode,"ALWAYS")) {
  2012.             OpenMode = OPEN_ILBM_ALWAYS;
  2013.         }
  2014.         else {
  2015.             if (MatchToolValue(omode,"REMAP")) {
  2016.                 OpenMode = OPEN_REMAP;
  2017.             }
  2018.             else {
  2019.                 if (MatchToolValue(omode,"OPAL")) {
  2020.                     OpenMode = OPEN_OPAL;
  2021.                 }
  2022.                 else {
  2023.                     OpenMode = OPEN_ILBM_IF_COLOURS;
  2024.                 }
  2025.             }
  2026.         }
  2027.     }
  2028.     switch (SaveFormat) {
  2029.     case MI_OPAL24:
  2030.         FormatStr = "OPAL24";
  2031.         break;
  2032.     case MI_OPAL24T:
  2033.         FormatStr = "OPAL24T";
  2034.         break;
  2035.     case MI_OPAL24F:
  2036.         FormatStr = "OPAL24F";
  2037.         break;
  2038.     case MI_OPAL24FT:
  2039.         FormatStr = "OPAL24FT";
  2040.         break;
  2041.     case MI_JPEG:
  2042.         FormatStr = "JPEG";
  2043.         break;
  2044.     case MI_JPEGT:
  2045.         FormatStr = "JPEGT";
  2046.         break;
  2047.     case MI_PBM:
  2048.         FormatStr = "PPM";
  2049.         break;
  2050.     case MI_BW16:
  2051.         FormatStr = "BW16";
  2052.         break;
  2053.     case MI_BW256:
  2054.         FormatStr = "BW256";
  2055.         break;
  2056.     case MI_HAM6:
  2057.         FormatStr = "HAM6";
  2058.         break;
  2059.     case MI_HAM8:
  2060.         FormatStr = "HAM8";
  2061.         break;
  2062.     case MI_DCTV3:
  2063.         FormatStr = "DCTV3";
  2064.         break;
  2065.     case MI_DCTV4:
  2066.         FormatStr = "DCTV4";
  2067.         break;
  2068.     default:
  2069.         FormatStr = "ILBM24";
  2070.         break;
  2071.     }
  2072.     FormatStr = MyArgString("SAVEFORMAT",FormatStr,!firstcall);
  2073.     if (MatchToolValue(FormatStr,"OPAL24")) {
  2074.         SaveFormat = MI_OPAL24;
  2075.     }
  2076.     else {
  2077.         if (MatchToolValue(FormatStr,"OPAL24T")) {
  2078.             SaveFormat = MI_OPAL24T;
  2079.         }
  2080.         else {
  2081.             if (MatchToolValue(FormatStr,"OPAL24F")) {
  2082.                 SaveFormat = MI_OPAL24F;
  2083.             }
  2084.             else {
  2085.                 if (MatchToolValue(FormatStr,"OPAL24FT")) {
  2086.                     SaveFormat = MI_OPAL24FT;
  2087.                 }
  2088.                 else {
  2089.                     if (MatchToolValue(FormatStr,"JPEG")) {
  2090.                         SaveFormat = MI_JPEG;
  2091.                     }
  2092.                     else {
  2093.                         if (MatchToolValue(FormatStr,"JPEGT")) {
  2094.                             SaveFormat = MI_JPEGT;
  2095.                         }
  2096.                         else {
  2097.                             if (MatchToolValue(FormatStr,"PPM")) {
  2098.                                 SaveFormat = MI_PBM;
  2099.                             }
  2100.                             else {
  2101.                                 if (MatchToolValue(FormatStr,"BW16")) {
  2102.                                     SaveFormat = MI_BW16;
  2103.                                 }
  2104.                                 else {
  2105.                                     if (MatchToolValue(FormatStr,"BW256")) {
  2106.                                         SaveFormat = MI_BW256;
  2107.                                     }
  2108.                                     else {
  2109.                                         if (MatchToolValue(FormatStr,"HAM6")) {
  2110.                                             SaveFormat = MI_HAM6;
  2111.                                         }
  2112.                                         else {
  2113.                                             if (MatchToolValue(FormatStr,"HAM8")) {
  2114.                                                 SaveFormat = MI_HAM8;
  2115.                                             }
  2116.                                             else {
  2117.                                                 if (MatchToolValue(FormatStr,"DCTV3")) {
  2118.                                                     SaveFormat = MI_DCTV3;
  2119.                                                 }
  2120.                                                 else {
  2121.                                                     if (MatchToolValue(FormatStr,"DCTV4")) {
  2122.                                                         SaveFormat = MI_DCTV4;
  2123.                                                     }
  2124.                                                     else {
  2125.                                                         SaveFormat = MI_ILBM24;
  2126.                                                     }
  2127.                                                 }
  2128.                                             }
  2129.                                         }
  2130.                                     }
  2131.                                 }
  2132.                             }
  2133.                         }
  2134.                     }
  2135.                 }
  2136.             }
  2137.         }
  2138.     }
  2139.     Quality = MyArgInt("QUALITY",Quality,!firstcall);
  2140.     strcpy(PreScript,MyArgString("PRESCRIPT",PreScript,!firstcall));
  2141.     strcpy(PostScript,MyArgString("POSTSCRIPT",PostScript,!firstcall));
  2142.     strcpy(LoadScript,MyArgString("LOADSCRIPT",LoadScript,!firstcall));
  2143.     strcpy(PreviewScript,MyArgString("PREVIEW",PreviewScript,!firstcall));
  2144.     DX = MyArgInt("DX",DX,!firstcall);
  2145.     DY = MyArgInt("DY",DY,!firstcall);
  2146.     Depth = MyArgInt("DEPTH",Depth,!firstcall);
  2147.     RenderMode = MyArgInt("MODE",RenderMode,!firstcall);
  2148.     AntiAlias = MatchToolValue(MyArgString("ANTIALIAS",AntiAlias?"YES":"NO",!firstcall),"YES");
  2149.     Integer = MatchToolValue(MyArgString("INTEGER",Integer?"YES":"NO",!firstcall),"YES");
  2150.     GHelp = MatchToolValue(MyArgString("HELP",GHelp?"YES":"NO",!firstcall),"YES");
  2151.     // Update with the new parameters
  2152.     UpdateParams(OZoom);
  2153. }
  2154.  
  2155. // Update to new settings - OZoom is old zoom mode
  2156. void
  2157. UpdateParams(ULONG OZoom) {
  2158.     // remove all the menus
  2159.     RemoveMenus();
  2160.     // change all the menu items
  2161.     SwitchMenuItem(MM_PALETTE,palette,FALSE);
  2162.     if (ZoomAllowed && (Zoom != OZoom)) {
  2163.         // If windows are open and changing zoom then update the zoom
  2164.         if (ControlWindow) {
  2165.             DisableWindows(DI_Zoom);
  2166.             if (OZoom) {
  2167.                 UnZoom();
  2168.             }
  2169.             else {
  2170.                 ReZoom();
  2171.             }
  2172.             EnableWindows();
  2173.         }
  2174.         SwitchMenuItem(MM_ZOOM,Zoom,FALSE);
  2175.     }
  2176.     UpdateOpenMode(FALSE);
  2177.     SwitchMenuItem(MM_ICONSR,CreateIconsR,FALSE);
  2178.     SwitchMenuItem(MM_ICONSP,CreateIconsP,FALSE);
  2179.     SwitchMenuItem(MM_KEEPS,KeepSettings,FALSE);
  2180.     SwitchMenuItem(MM_ANTIALIAS,AntiAlias,FALSE);
  2181.     SwitchMenuItem(MM_INTEGER,Integer,FALSE);
  2182.     SwitchMenuItem(MM_HELP,GHelp,FALSE);
  2183.     UpdateRenderMode(FALSE);
  2184.     UpdateSaveFormat(FALSE);
  2185.     // Add the menus back
  2186.     AddMenus();
  2187.     // and disable/enable items
  2188.     if (PaletteAllowed) {
  2189.         if (TSMorphWnd) {
  2190.             OnMenu(TSMorphWnd,FULLMENUNUM(1,MM_PALETTE,NOSUB));
  2191.         }
  2192.         if (ControlWindow) {
  2193.             OnMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_PALETTE,NOSUB));
  2194.         }
  2195.     }
  2196.     else {
  2197.         if (TSMorphWnd) {
  2198.             OffMenu(TSMorphWnd,FULLMENUNUM(1,MM_PALETTE,NOSUB));
  2199.         }
  2200.         if (ControlWindow) {
  2201.             OffMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_PALETTE,NOSUB));
  2202.         }
  2203.     }
  2204.     if (ZoomAllowed) {
  2205.         if (TSMorphWnd) {
  2206.             OnMenu(TSMorphWnd,FULLMENUNUM(1,MM_ZOOM,NOSUB));
  2207.         }
  2208.         if (ControlWindow) {
  2209.             OnMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB));
  2210.         }
  2211.     }
  2212.     else {
  2213.         if (TSMorphWnd) {
  2214.             OffMenu(TSMorphWnd,FULLMENUNUM(1,MM_ZOOM,NOSUB));
  2215.         }
  2216.         if (ControlWindow) {
  2217.             OffMenu(ControlWindow,FULLMENUNUM(M_SETTINGS,MM_ZOOM,NOSUB));
  2218.         }
  2219.     }
  2220. }
  2221.  
  2222. /* Preview render
  2223.  * Basically calls ARexx script with parameters - frame number and filename
  2224.  */
  2225. int
  2226. Preview(void) {
  2227.     UBYTE buffer[140];
  2228.     UBYTE buffer1[256];
  2229.     // save first if not saved
  2230.     if (!Saved) {
  2231.         if (!SaveRequester()) {
  2232.             return 1;
  2233.         }
  2234.     }
  2235.     if (GetFrameNumber()) {    // Get the frame number
  2236.         SaveSettings("T:TSMorph.prefs");    // save temporary settings
  2237.         DisableWindows(DI_Preview);        // disable all windows
  2238.         strcpy(buffer,PreviewScript);        // call ARexx script
  2239.         strcat(buffer," %ld %s");
  2240.         sprintf(buffer1,buffer,FrameNumber,savedfilename);
  2241.         SendRxMsg(buffer1,FALSE);
  2242.         EnableWindows();                        // and re-enable windows
  2243.         return 1;
  2244.     }
  2245.     return 1;
  2246. }
  2247.  
  2248. /* Tries to execute a Rexx script
  2249.  * msgtxt = name of script
  2250.  * IgnoreError = TRUE then do not display error message
  2251.  * Returns:    error message
  2252.  */
  2253. LONG
  2254. SendRxMsg(char *msgtxt,BOOL IgnoreError) {
  2255.     struct MsgPort *reply_port;
  2256.     struct MsgPort *rx_port;
  2257.     struct RexxMsg *rx_msg;
  2258.     LONG                 ret             = RC_FATAL;
  2259.  
  2260.     if (reply_port = CreateMsgPort()) {
  2261.        if (rx_msg = CreateRexxMsg(reply_port,"TSM","REXX")) {
  2262.           rx_msg->rm_Args[0] = msgtxt;
  2263.             if (FillRexxMsg(rx_msg,1,0)) {
  2264.                 rx_msg->rm_Action = RXCOMM;
  2265.                 Forbid();
  2266.                 if (rx_port = (struct MsgPort *)FindPort("REXX")) {
  2267.                   PutMsg(rx_port, (struct Message *)rx_msg);
  2268.                   Permit();
  2269.                   WaitPort(reply_port);
  2270.                   ReplyMsg(GetMsg(reply_port));
  2271.                   ret = rx_msg->rm_Result1;
  2272.                  }
  2273.                 else {
  2274.                   Permit();
  2275.                 }
  2276.                 ClearRexxMsg(rx_msg, 1);
  2277.           }
  2278.              DeleteRexxMsg(rx_msg);
  2279.         }
  2280.         DeleteMsgPort(reply_port);
  2281.       }
  2282.     // Display an error message (if required)
  2283.       if (!IgnoreError && ret) {
  2284.           Error(MyGetMsg(MSG_EAREXX),MyGetMsg(MSG_OK),msgtxt,H_Arexx);
  2285.       }
  2286.       return ret;
  2287. }
  2288.  
  2289. struct Screen *myscreen = NULL;
  2290.  
  2291. /* Opens a custom screen
  2292.  * Public Screen name is ScreenName
  2293.  * Mode name is CustomName
  2294.  * Depth is CustomDepth
  2295.  * Most other stuff is cloned from the WorkBench
  2296.  *
  2297.  * This whole thing needs redoing a bit
  2298.  */
  2299. BOOL
  2300. OpenCustomScreen(void) {
  2301.     struct Screen *Screen;
  2302.     struct NameInfo buff;
  2303.     ULONG id = INVALID_ID;
  2304.     ULONG myid = INVALID_ID;
  2305.     BOOL used[256] = {0,0,0,0,0,0,0,0,    // table of in use palette entry
  2306.                             0,0,0,0,0,0,0,0,    // we use the rest for grey scale
  2307.                             0,0,0,0,0,0,0,0,
  2308.                             0,0,0,0,0,0,0,0,
  2309.                             0,0,0,0,0,0,0,0,
  2310.                             0,0,0,0,0,0,0,0,
  2311.                             0,0,0,0,0,0,0,0,
  2312.                             0,0,0,0,0,0,0,0,
  2313.                             };
  2314.     UWORD numcols;
  2315.     UWORD i;
  2316.     ULONG diff;
  2317.     UBYTE Color;
  2318.     ULONG Color32;
  2319.     BOOL usedri = TRUE;
  2320.     UWORD mydir = 0xFFFF;
  2321.     struct DrawInfo *dri;
  2322.     struct DrawInfo *mydri;
  2323.     BOOL retflag = TRUE;
  2324.     char *emsg;
  2325.     char *e1=NULL;
  2326.     ULONG err=0;
  2327.  
  2328.     // check we have a name and a mode and depth
  2329.     if (ScreenName && *ScreenName && CustomName && *CustomName && (CustomDepth > 0)) {
  2330.         // check public screen not already open
  2331.         if (!(Screen = LockPubScreen(ScreenName))) {
  2332.             // try and find modeid
  2333.             id = NextDisplayInfo(id);
  2334.             while ((id != INVALID_ID) && (myid == INVALID_ID)) {
  2335.                 if (GetDisplayInfoData(NULL,(UBYTE *)&buff,sizeof(struct NameInfo),DTAG_NAME,id)) {
  2336.                     if (!Stricmp(buff.Name,CustomName)) {
  2337.                         myid = id;
  2338.                     }
  2339.                 }
  2340.                 id = NextDisplayInfo(id);
  2341.             }
  2342.             if (myid != INVALID_ID) {
  2343.                 // Get info from the workbench
  2344.                 if (Screen = LockPubScreen("Workbench")) {
  2345.                     if (dri = GetScreenDrawInfo(Screen)) {
  2346.                         for (i = 0;
  2347.                               i < dri->dri_NumPens;
  2348.                               ++i) {
  2349.                             if (!(dri->dri_Pens[i] < (1<<CustomDepth))) {
  2350.                                 usedri = FALSE;
  2351.                             }
  2352.                         }
  2353.                         // open sort of cloned screen
  2354.                         if (myscreen = OpenScreenTags(NULL,
  2355.                                     SA_Depth, CustomDepth,
  2356.                                     SA_Overscan, OSCAN_TEXT,
  2357.                                     SA_Pens, usedri?((ULONG) (dri->dri_Pens)):((ULONG) &mydir),
  2358.                                     SA_SysFont, 1,
  2359.                                     SA_DisplayID, myid,
  2360.                                     SA_Type, PUBLICSCREEN,
  2361.                                     SA_PubName, ScreenName,
  2362.                                     SA_Title, ScreenName,
  2363.                                     SA_FullPalette, TRUE,
  2364.                                     SA_Interleaved, TRUE,
  2365.                                     TAG_END)) {
  2366.                             // set unused palette entries to grey scale
  2367.                             if (mydri = GetScreenDrawInfo(myscreen)) {
  2368.                                 numcols = 1<<CustomDepth;
  2369.                                 for (i = 0;
  2370.                                       i < mydri->dri_NumPens;
  2371.                                       ++i) {
  2372.                                     if (!used[min(mydri->dri_Pens[i],256)]) {
  2373.                                         used[min(mydri->dri_Pens[i],256)] = TRUE;
  2374.                                         --numcols;
  2375.                                     }
  2376.                                 }
  2377.                                 if (numcols) {
  2378.                                      if (GfxBase->lib_Version > 38) {
  2379.                                         diff = (0xFFFFFFFF / (numcols + 1));
  2380.                                         Color32 = diff;
  2381.                                         if (!diff) {
  2382.                                             diff = 1;
  2383.                                         }
  2384.                                         for (i = 0;
  2385.                                               (i < (1<<CustomDepth));
  2386.                                               ++i) {
  2387.                                             if (!used[i]) {
  2388.                                                 SetRGB32(&(myscreen->ViewPort),i,Color32,Color32,Color32);
  2389.                                                 Color32 += diff;
  2390.                                             }
  2391. //                                            else {
  2392. //                                                if (i < (1<< dri->dri_Depth)) {
  2393. //                                                    rgb = GetRGB4(Screen->ViewPort.ColorMap,i);
  2394. //                                                    SetRGB4(&(myscreen->ViewPort),i,rgb>>8,(rgb & 0x0f0)>>4,rgb & 0x0f);
  2395. //                                                }
  2396. //                                            }
  2397.                                         }
  2398.                                      }
  2399.                                       else {
  2400.                                         diff = (16 / (numcols + 1));
  2401.                                         Color = diff;
  2402.                                         if (!diff) {
  2403.                                             diff = 1;
  2404.                                         }
  2405.                                         for (i = 0;
  2406.                                               (i < (1<<CustomDepth));
  2407.                                               ++i) {
  2408.                                             if (!used[i] && (Color<16)) {
  2409.                                                 SetRGB4(&(myscreen->ViewPort),i,Color,Color,Color);
  2410.                                                 Color += diff;
  2411.                                             }
  2412. //                                            else {
  2413. //                                                if (i < (1<< dri->dri_Depth)) {
  2414. //                                                    rgb = GetRGB4(Screen->ViewPort.ColorMap,i);
  2415. //                                                    SetRGB4(&(myscreen->ViewPort),i,rgb>>8,(rgb & 0x0f0)>>4,rgb & 0x0f);
  2416. //                                                }
  2417. //                                            }
  2418.                                         }
  2419.                                     }
  2420.                                 }
  2421.                                 // Free everything, set screen to public and return
  2422.                                 FreeScreenDrawInfo(myscreen,mydri);
  2423.                             }
  2424.                             PubScreenStatus(myscreen,NULL);
  2425.                             FreeScreenDrawInfo(Screen,dri);
  2426.                             UnlockPubScreen(NULL,Screen);
  2427.                             OpenedScreen = TRUE;
  2428.                             return TRUE;
  2429.                         }
  2430.                         // Free everything and display error
  2431.                         else {
  2432.                             retflag = FALSE;
  2433.                             emsg = MyGetMsg(MSG_EOPSCR);
  2434.                             err = HE_OScreen;
  2435.                         }
  2436.                         FreeScreenDrawInfo(Screen,dri);
  2437.                     }
  2438.                     else {
  2439.                         retflag = FALSE;
  2440.                         emsg = MyGetMsg(MSG_UNDRI);
  2441.                         err = HE_DrawI;
  2442.                     }
  2443.                     UnlockPubScreen(NULL,Screen);
  2444.                 }
  2445.                 else {
  2446.                     retflag = FALSE;
  2447.                     emsg = MyGetMsg(MSG_LOCKWB);
  2448.                     err = HE_LockW;
  2449.                 }
  2450.             }
  2451.             else {
  2452.                 retflag = FALSE;
  2453.                 emsg = MyGetMsg(MSG_INVMODE);
  2454.                 e1 = CustomName;
  2455.                 err = HE_ScreenMode;
  2456.             }
  2457.         }
  2458.         else {
  2459.             UnlockPubScreen(NULL,Screen);
  2460.         }
  2461.     }
  2462.     if (!retflag) {
  2463.         Error(emsg,MyGetMsg(MSG_QUIT),e1,err);
  2464.     }
  2465.     return retflag;
  2466. }
  2467.  
  2468. /* Attempt to close the public screen
  2469.  *
  2470.  * Now does it sort of properly
  2471.  *
  2472.  * Has to reopen AmigaGuide if required
  2473.  */
  2474. void
  2475. CloseCustomScreen(void) {
  2476.     while (!CloseScreen(myscreen)) {
  2477.         // Open backdrop window to force requesters to screen
  2478.         TSMorphWnd = OpenWindowTags(NULL,
  2479.             WA_Width,            1,
  2480.             WA_Height,            1,
  2481.             WA_IDCMP,            0,
  2482.             WA_Flags,            WFLG_BACKDROP |
  2483.                                     WFLG_BORDERLESS |
  2484.                                     WFLG_NOCAREREFRESH,
  2485.             WA_PubScreen,        myscreen,
  2486.             TAG_END );
  2487.         if (AmigaGuideBase) {
  2488.             if (handle = OpenAmigaGuideAsync(&nag, NULL)) {
  2489.                 ASig = AmigaGuideSignal(handle);
  2490.             }
  2491.         }
  2492.         Error("TSMorph is attempting to close this screen.\n"
  2493.                 "Please close all windows on this screen.",
  2494.                 "Retry","",HE_CScreen);
  2495.         if (handle) {
  2496.             CloseAmigaGuide(handle);
  2497.             handle = NULL;
  2498.             ASig = NULL;
  2499.         }
  2500.         if (TSMorphWnd) {
  2501.             CloseWindow(TSMorphWnd);
  2502.             TSMorphWnd = NULL;
  2503.         }
  2504.     }
  2505. }
  2506.  
  2507. /* Unlinks all points and triangulates */
  2508. void
  2509. Triangulate(void) {
  2510.     // Open window and wait till close selected then close it
  2511.       if (!Saved) {
  2512.         if (!SaveRequester()) {
  2513.             return;
  2514.         }
  2515.     }
  2516.     DisableWindows(DI_Triangulate);
  2517.     UnlinkAllPoints(TRUE);
  2518.     GenerateTriangles();
  2519.     Saved = FALSE;
  2520.     EnableWindows();
  2521. }
  2522.  
  2523. /* nsort() was written by Dave Watson and uses the algorithm described in -
  2524.  *    Watson, D.F., 1981, Computing the n-dimensional Delaunay tessellation with 
  2525.  *          application to Voronoi polytopes: The Computer J., 24(2), p. 167-172. 
  2526.  */
  2527.  
  2528. #define SQ(x)                (x) * (x)
  2529. #define BIGNUM                1E37
  2530. #define EPSILON         0.00001
  2531. #define TSIZE                75                  /* temporary storage size factor*/
  2532. #define XRANGE          10.0                /* factor (>=1) for radius of control points */
  2533. #define FILENAMELEN     32
  2534. #define AND             &&
  2535. #define OR              ||
  2536. #define EQ              ==
  2537. #define NE              !=
  2538.  
  2539. BOOL
  2540. GenerateTriangles(void) {
  2541.     BOOL ok = FALSE;
  2542.     BOOL flag = TRUE;
  2543.    double xx, bgs, **mxy, **wrk, **pts, **ccr;
  2544.    int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i11, ii[3], 
  2545.        dm, nts, tsz, *id, **tmp, **a3s;
  2546.    struct MyPoint *MyPoint,**MyPoints,*MyPoint1,*MyPoint2,*MyPoint3;
  2547.     ULONG PointCount;
  2548.  
  2549.     PointCount = 0;
  2550.     for (MyPoint = (struct MyPoint *)PointList.lh_Head;
  2551.             MyPoint->MyNode.mln_Succ;
  2552.             MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ) {
  2553.         PointCount++;
  2554.     }
  2555. if (PointCount && (MyPoints = (struct MyPoint **)AllocVec((sizeof (struct MyPoint *))*PointCount,MEMF_CLEAR))) {
  2556.    if (mxy = DoubleMatrix(2, 2)) {
  2557.        for (i0=0; i0<2; i0++) {
  2558.               mxy[0][i0] = - (mxy[1][i0] = BIGNUM);
  2559.        }
  2560.        if (wrk = DoubleMatrix(2, 3)) {
  2561.            for (i0=0; i0<2; i0++) {
  2562.                for (i1=0; i1<3; i1++) {
  2563.                    wrk[i0][i1] = -XRANGE;
  2564.                }
  2565.            }
  2566.            for (i0=0; i0<2; i0++) {
  2567.                wrk[i0][i0] = XRANGE * (3 * 2 - 1);
  2568.            }
  2569.             if (pts = DoubleMatrix(PointCount + 3, 2)) {
  2570.                 for (i0=0, MyPoint = (struct MyPoint *)PointList.lh_Head;
  2571.                         i0<PointCount;
  2572.                         MyPoint = (struct MyPoint *)MyPoint->MyNode.mln_Succ, i0++) {
  2573.                     MyPoints[i0] = MyPoint;
  2574.                     pts[i0][0] = (MyPoint->x + MyPoint->x1)>>1;
  2575.                     pts[i0][1] = (MyPoint->y + MyPoint->y1)>>1;
  2576.                     for (i1=0; i1<2; i1++) {
  2577.                         if (mxy[0][i1] < pts[i0][i1]) {
  2578.                             mxy[0][i1] = pts[i0][i1];
  2579.                         }
  2580.                         if (mxy[1][i1] > pts[i0][i1]) {
  2581.                             mxy[1][i1] = pts[i0][i1];
  2582.                         }
  2583.                     }
  2584.                 }
  2585.                 for (bgs=0, i0=0; i0<2; i0++) {
  2586.                     mxy[0][i0] -= mxy[1][i0];
  2587.                   if (bgs < mxy[0][i0]) {
  2588.                       bgs = mxy[0][i0];
  2589.                   }
  2590.                }
  2591.                 bgs *= EPSILON;
  2592.                for (i0=0; i0<PointCount; i0++) {
  2593.                    for (i1=0; i1<2; i1++) {
  2594.                         pts[i0][i1] += bgs * (0.5 - (double)rand() / 0x7fffffff);
  2595.                     }
  2596.                 }
  2597.                 for (i0=0; i0<3; i0++) {
  2598.                     for (i1=0; i1<2; i1++) {
  2599.                         pts[PointCount+i0][i1] = mxy[1][i1] + wrk[i1][i0] * mxy[0][i1];
  2600.                     }
  2601.                 }
  2602.                for (i1=1, i0=2; i0<3; i0++) {
  2603.                    i1 *= i0;
  2604.                }
  2605.                tsz = TSIZE * i1;
  2606.                if (tmp = IntMatrix(tsz + 1, 2)) {
  2607.                    i1 *= (PointCount + i1);
  2608.                    if (id = IntVect(i1)) {
  2609.                        for (i0=0; i0<i1; i0++) {
  2610.                            id[i0] = i0;
  2611.                        }
  2612.                         if (a3s = IntMatrix(i1,3)) {
  2613.                               if (ccr = DoubleMatrix(i1,3)) {
  2614.                                   for (a3s[0][0]=PointCount, i0=1; i0<3; i0++) {
  2615.                                       a3s[0][i0] = a3s[0][i0-1] + 1;
  2616.                                   }
  2617.                                 for (ccr[0][2]=BIGNUM, i0=0; i0<2; i0++) {
  2618.                                     ccr[0][i0] = 0;
  2619.                                 }
  2620.                                nts = i4 = 1;
  2621.                                dm = 2 - 1;
  2622.                                for (i0=0; i0<PointCount; i0++) {
  2623.                                   i1 = i7 = -1;
  2624.                                   i9 = 0;
  2625.                                   for (i11=0; i11<nts; i11++) {
  2626.                                      i1++;
  2627.                                      while (a3s[i1][0] < 0) { 
  2628.                                          i1++;
  2629.                                      }
  2630.                                      xx = ccr[i1][2];
  2631.                                      for (i2=0; i2<2; i2++) {
  2632.                                         xx -= SQ(pts[i0][i2] - ccr[i1][i2]);
  2633.                                            if (xx<0) {
  2634.                                                goto Corner3;
  2635.                                            }
  2636.                                      }
  2637.                                      i9--;
  2638.                                         i4--;
  2639.                                         id[i4] = i1;
  2640.                                         for (i2=0; i2<3; i2++) {
  2641.                                            ii[0] = 0;
  2642.                                         if (ii[0] EQ i2) {
  2643.                                             ii[0]++;
  2644.                                         }
  2645.                                         for (i3=1; i3<2; i3++) {
  2646.                                            ii[i3] = ii[i3-1] + 1;
  2647.                                            if (ii[i3] EQ i2) {
  2648.                                                ii[i3]++;
  2649.                                            }
  2650.                                         }
  2651.                                         if (i7>dm) {
  2652.                                                i8 = i7;
  2653.                                                 for (i3=0; i3<=i8; i3++) {
  2654.                                                    for (i5=0; i5<2; i5++) {
  2655.                                                        if (a3s[i1][ii[i5]] NE tmp[i3][i5]) {
  2656.                                                            goto Corner1;
  2657.                                                        }
  2658.                                                    }
  2659.                                                     for (i6=0; i6<2; i6++) {
  2660.                                                         tmp[i3][i6] = tmp[i8][i6];
  2661.                                                     }
  2662.                                                     i7--;
  2663.                                                     goto Corner2;
  2664. Corner1:;
  2665.                                                 }
  2666.                                             }
  2667.                                             if (++i7 > tsz) {
  2668.                                                 goto returnfail;
  2669.                                             }
  2670.                                             for (i3=0; i3<2; i3++) {
  2671.                                                 tmp[i7][i3] = a3s[i1][ii[i3]];
  2672.                                             }
  2673. Corner2:;
  2674.                                         }
  2675.                                       a3s[i1][0] = -1;
  2676. Corner3:;
  2677.                                    }
  2678.                                    for (i1=0; i1<=i7; i1++) {
  2679.                                       for (i2=0; i2<2; i2++) {
  2680.                                            for (wrk[i2][2]=0, i3=0; i3<2; i3++) {
  2681.                                             wrk[i2][i3] = pts[tmp[i1][i2]][i3] - pts[i0][i3];
  2682.                                                wrk[i2][2] += wrk[i2][i3] * (pts[tmp[i1][i2]][i3] + pts[i0][i3]) / 2;
  2683.                                             }
  2684.                                         }
  2685.                                         xx = wrk[0][0] * wrk[1][1] - wrk[1][0] * wrk[0][1];
  2686.                                         ccr[id[i4]][0] = (wrk[0][2] * wrk[1][1] - wrk[1][2] * wrk[0][1]) / xx;
  2687.                                         ccr[id[i4]][1] = (wrk[0][0] * wrk[1][2] - wrk[1][0] * wrk[0][2]) / xx;
  2688.                                       for (ccr[id[i4]][2]=0, i2=0; i2<2; i2++) {
  2689.                                             ccr[id[i4]][2] += SQ(pts[i0][i2] - ccr[id[i4]][i2]);
  2690.                                            a3s[id[i4]][i2] = tmp[i1][i2];
  2691.                                       }
  2692.                                         a3s[id[i4]][2] = i0;
  2693.                                         i4++;
  2694.                                       i9++;
  2695.                                    }
  2696.                                    nts += i9;
  2697.                                 }
  2698.                                 i0 = -1;
  2699.                                 for (i11=0; flag && (i11<nts); i11++) {
  2700.                                     i0++;
  2701.                                    while (a3s[i0][0] < 0) {
  2702.                                        i0++;
  2703.                                    }
  2704.                                    if (a3s[i0][0] < PointCount) {
  2705.                                         for (i1=0; i1<2; i1++) for (i2=0; i2<2; i2++)  {
  2706.                                           wrk[i1][i2] = pts[a3s[i0][i1]][i2] - pts[a3s[i0][2]][i2];
  2707.                                       }
  2708.                                       xx = wrk[0][0] * wrk[1][1] - wrk[0][1] * wrk[1][0];
  2709.                                       if (fabs(xx) > EPSILON) {
  2710.                                           MyPoint1 = MyPoints[a3s[i0][0]];
  2711.                                           MyPoint2 = MyPoints[a3s[i0][1]];
  2712.                                           MyPoint3 = MyPoints[a3s[i0][2]];
  2713.                                           LinkPoints(MyPoint1,MyPoint2);
  2714.                                           LinkPoints(MyPoint2,MyPoint3);
  2715.                                           LinkPoints(MyPoint3,MyPoint1);
  2716.                                           // Could set flag
  2717.                                       }
  2718.                                    }
  2719.                                 }
  2720.                                ok = flag;
  2721. returnfail:
  2722.                                 FreeMatrixd(ccr);
  2723.                             }
  2724.                             FreeMatrixi(a3s);
  2725.                         }
  2726.                         MyFreeVecti(id);
  2727.                     }
  2728.                    FreeMatrixi(tmp);
  2729.                 }
  2730.                 FreeMatrixd(pts);
  2731.             }
  2732.             FreeMatrixd(wrk);
  2733.         }
  2734.         FreeMatrixd(mxy);
  2735.     }
  2736.     FreeVec(MyPoints);
  2737. }
  2738. else {
  2739.     ok = FALSE;
  2740. }
  2741. return ok;
  2742. }
  2743.     
  2744. int
  2745. *IntVect(int ncols) {  
  2746.     return (int *) AllocVec(ncols * sizeof(int),0);
  2747. }
  2748.  
  2749. void
  2750. MyFreeVecti(int *vectptr) {
  2751.     if (vectptr) {
  2752.         FreeVec(vectptr);
  2753.     }
  2754. }
  2755.  
  2756. int
  2757. **IntMatrix(int nrows, int ncols) {
  2758.    int i0;
  2759.    int **matptr;
  2760.    if (nrows<2) nrows = 2;
  2761.    if (ncols<2) ncols = 2;
  2762.    if ((matptr = (int **) AllocVec(nrows * sizeof(int *),0)) EQ NULL) {
  2763.        return NULL;
  2764.    }
  2765.    if ((matptr[0] = (int *) AllocVec(nrows * ncols * sizeof(int),0)) EQ NULL) {
  2766.        FreeVec(matptr);
  2767.        return NULL;
  2768.    }
  2769.    for (i0=1; i0<nrows; i0++) {
  2770.        matptr[i0] = matptr[0] + i0 * ncols;
  2771.    }
  2772.    return matptr;
  2773. }
  2774.  
  2775. void
  2776. FreeMatrixi(int **matptr) {  
  2777.     if (matptr) {
  2778.         if (matptr[0]) {
  2779.             FreeVec(matptr[0]);
  2780.         }
  2781.         FreeVec(matptr);
  2782.     }
  2783. }
  2784.  
  2785. double
  2786. **DoubleMatrix(int nrows, int ncols) {
  2787.    int i0;
  2788.    double **matptr;
  2789.    if (nrows<2) nrows = 2;
  2790.    if (ncols<2) ncols = 2;
  2791.    if ((matptr = (double **) AllocVec(nrows * sizeof(double *),0)) EQ NULL) {
  2792.        return NULL;
  2793.    }
  2794.    if ((matptr[0] = (double *) AllocVec(nrows * ncols * sizeof(double),0)) EQ NULL) {
  2795.        FreeVec(matptr);
  2796.        return NULL;
  2797.    }
  2798.    for (i0=1; i0<nrows; i0++) {
  2799.        matptr[i0] = matptr[0] + i0 * ncols;
  2800.     }
  2801.    return matptr;
  2802. }
  2803.  
  2804. void
  2805. FreeMatrixd(double **matptr) {
  2806.     if (matptr) {
  2807.         if (matptr[0]) {
  2808.            FreeVec(matptr[0]);
  2809.         }
  2810.         FreeVec(matptr);
  2811.     }
  2812. }
  2813.  
  2814.