/*=============================================================================
  gadio.c - Functions to save/retrieve a gadget to/from disk.
  Brent Southard, 7/10/86
  CIS   76657,415
  Well  brent
 
  -Change History-
  7/6/86  rbs  Changed dumpGad() and grabGad() to only write/read one Gadget
               at a time, rather than a list.  The NextGadget field will now
               be ignored at 'dump' time, and NULLed at 'grab' time.
=============================================================================*/
 
/*  The usual header files to be inserted later  */
#include <intuition/intuition.h>
#include <libraries/dosextens.h>
#include <graphics/gfxbase.h>
#include <graphics/gfx.h>
#include <graphics/display.h>
#include <exec/memory.h>
#include <workbench/workbench.h>
#include <workbench/startup.h>
#include <devices/narrator.h>
#include <devices/audio.h>
#include <libraries/translator.h>
#include "gad.h"
 
/*================== external functions ===================*/
 
extern int  strlen();
extern char *strcpy();
extern APTR AllocRemember();
 
/*================== external variables ==================*/
 
extern char gadimage[MAX_PROPINFOS][NAM_SIZ];
extern char selectimage[MAX_PROPINFOS][NAM_SIZ];
 
/*====================== globals ==========================*/
 
#define CLRMEM      MEMF_CHIP | MEMF_CLEAR
#define VERY_BIG    512
 
static UBYTE        scratch[VERY_BIG];
extern struct Remember  *rememberBase;
extern char def_font[]; /* name of the default font used in intuitexts */ 
/*==================== sub-functions ======================*/
 
void freeGadMem()  /* free allocated gadget memory (use carefully!) */
/*  Call this function before ending main().  This may not be an elegant way
    to free up space, but it works... */
{
    FreeRemember(rememberBase, TRUE);
    rememberBase = NULL;
}
 
void putString(str, fd)  /* write a null-terminated string to a file */
UBYTE   *str;
long     fd;
{
    /* Write the text, including the null byte. */
    Write(fd, str, (long)(strlen(str)+1));
}
 
UBYTE *getString(fd,stringsize)  /* read a null-terminated string from a file */
long     fd;
long     stringsize;
{
    UBYTE   *str;
    int     i = 0;
    
    /* Read the text, including the null byte, into scratch area. */
    do { Read(fd, &scratch[i], 1L); }
        while (scratch[i++] != '\0');
        
    /* Allocate memory for string and move it there. */
    /* ### changed to allocate only enough for the   */
    /* string if the stringsize parm is zero, and    */
    /* whatever specified if string size is not zero */
    /* This prevents crashes where the user inserts  */
    /* to a string gadget after reading it.    RRL   */
    if (stringsize == 0L)
        str = (UBYTE *) 
          AllocRemember(rememberBase, (LONG)(strlen(scratch)+1), CLRMEM);
    else  str = (UBYTE *) 
          AllocRemember(rememberBase, stringsize, CLRMEM);
          
    strcpy(str, scratch);
 
    return(str);
}

/* write (list of) image structure(s) to a file */ 
void putImages(anImage, fd, ind)  
struct Image    *anImage;
long            fd;
int             ind;
{
    short   wordWidth, size;
 
   while (anImage != NULL) {
        /* Write name of Image to file */
        /* ### only if it's not an autoknob image for a prop gad. RRL */
        if (ind >= 0) {
           Write(fd, gadimage[ind], (long)NAM_SIZ);
           Write(fd, selectimage[ind], (long)NAM_SIZ);
        }
 
        /*  Write image structure itself. */
 
        Write(fd, anImage, (long)sizeof(struct Image));
        /* There should be some data to write (we would hope!) */
        if (anImage->ImageData != NULL) {
            wordWidth = anImage->Width / 16;
            if (anImage->Width % 16 != 0)
                wordWidth++;
            /* size is wordWidth (x 2 bytes/word) x Height x Depth */
            size = wordWidth * 2 * anImage->Height * anImage->Depth;
 
            Write(fd, anImage->ImageData, (long)size);
        }
 
        /* Another image? */
        anImage = anImage->NextImage;
    }
}
 
struct Image *getImages(fd, ind)  /* read image structure(s) from a file */
long  fd;
int   ind;
{
    struct Image    *anImage, *first;
    BOOL            done = FALSE;
    short           wordWidth;
    LONG            size;
 
    first = anImage = (struct Image *)
        AllocRemember(rememberBase, (long)sizeof(struct Image), CLRMEM);
 
    do {
        /* Get name of select and render images */
        /* ### only if it is not an autoknob RRL*/
        if (ind >= 0) {
           Read(fd, gadimage[ind], (long)NAM_SIZ);
           Read(fd, selectimage[ind], (long)NAM_SIZ);
        }
 
        /* Read image structure itself. */
        Read(fd, anImage, (long)sizeof(struct Image));
 
        /* There should be some data to read (we would hope!) */
        if (anImage->ImageData != NULL) {
            wordWidth = anImage->Width / 16;
            if (anImage->Width % 16 != 0)
                wordWidth++;
            /* size is wordWidth (x 2 bytes/word) x Height x Depth */
            size = wordWidth * 2 * anImage->Height * anImage->Depth;
            anImage->ImageData = (USHORT *)
                AllocRemember(rememberBase, size, CLRMEM);
            Read(fd, anImage->ImageData, size);
        }
 
        /* Another image? */
        if (anImage->NextImage != NULL) {
            anImage->NextImage = (s, (long)sizeof(struct Border));
 
        /* There should be some data to write (we would hope!) */
        if (aBorder->Count > 0 && aBorder->XY != NULL) {
            Write(fd, aBorder->XY, (long)(aBorder->Count*4));
        }
 
        /* Another border? */
        aBorder = aBorder->NextBorder;
    }
}
 
struct Border *getBorders(fd)  /* read border structure(s) from file */
long  fd;
{
    struct Border   *aBorder, *first;
    BOOL            done = FALSE;
 
    first = aBorder rst = 5;                 /* remove later */
 
       /* We should prabably have an option here to change the border
          around the gadget if it gets re-sized.  We must check the
          option flag, if TRUE,  then change the "appropriate pairs"
          value in the gadget.
       */
       ModifyIDCMP(w, nw.IDCMPFlags);
       if (!oldgad && Width > 8 && Height > 4) {
            addgad();                 /* $$$ Allocate the gadget */
       }
      flags = (long)testgad.UserData;
 
       if ((testgad.GadgetType != PROPGADGET) &&
          ((flags & GAD_IMAGE_TYPE) != GAD_IMAGE_TYPE)) {
          bd = (struct Border *)testgad.GadgetRender;
          pairs = bd->XY;
          pairs[2] = pairs[4] = Width;
          pairs[5] = pairs[7] = Height;
       }
       if (gads[curgad] != NULL) {
          *gads[curgad] = testgad;       /* Update Gadget data */
 
           /* Force user to enter gadget name */
           if (gadnames[curgad] == NULL) {
             str = getrname("Enter Gadget name");
             strcpy(names[curgad], str);
             gadnames[curgad] = names[curgad];
           }
       }
       /* $$$ Erase the border - perhaps            */
/*         draw_box(rp, Left-1, Top-1, Width, Height);
          erase = FALSE;
*/
       /* ### Refresh the gadgets */
       if (nextlink == nextgad && nextlink != NULL) {
          draw_box(rp, Left-1, Top-1, Width, Height);
          SetAPen(rp, 0L);
          SetDrMd(rp, JAM1);
          /* remove old intuitexts */
          ClearAllTexts(gads[curgad],Lf+1L,Tp+1L);
          RectFill(rp, Lf-1L, Tp-1L, Lf+Wd+2L, Tp+Ht+2L);
          RefreshGadgets(gads[0], w, NULL);
       }
    }
}
/* ----------------------------------------------------------------------
  Find the location of the mouse and determine if it falls on any gadget,
  return an index into the gadget structure where the mouse is pointing
  to.  It involves searching each of the "Gadget" structures looking for
  a "LeftEdge/TopEdge" that falls "under" the mouse.
-----------------------------------------------------------------------*/
int findmouse(x, y)
SHORT x, y;           /* Coordinates of the mouse */
{
     int   ind = 0;  /* Index into Gadget pointer array */
     if (nextgad == NULL) return(-1);
 
     for (ind = 0;  ind < nextgad; ind++) {
        if (x >= gads[ind]->LeftEdge &&
           x <= (gads[ind]->LeftEdge + gads[ind]->Width) &&
           y >= gads[ind]->TopEdge &&
           y <= (gads[ind]->TopEdge + gads[ind]->Height))
          return(ind);
     }
     return(-1);
}
/*------------------------------------------------------------------------
  Determine if the mouse was pressed in the corner of the box, indicating
  that the user wants to change the gadget's size.
------------------------------------------------------------------------*/
int in_corner(which, x, y)
int which;                    /* Index to specific gadget */
SHORT x, y;                   /* Mouse location */
{
    SHORT left, top, deltx, delty;
 
    top  = y - gads[which]->Height;
    left = x - gads[which]->Width;
    deltx = gads[which]->LeftEdge - left;
    delty = gads[which]->TopEdge - top;
 
    if (deltx < 8 && deltx > -8 && delty < 6 && delty > -6)
       return(TRUE);
    else
       return(FALSE);
}
                                                                            &ITx     ÍX,            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    ITXT4GADGET,             /* gadget id   */
    NULL                     /* special info*/
    },
    { /* ITxt name selection 5 */
    &ITxtListGadget[6],      /* next gadget */
    5,64,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    RELVERIFY ,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    &ITxtList[5],            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    ITXT5GADGET,             /* gadget id   */
    NULL                     /* special info*/
    },
    { /* ITxt name selection 6 */
    &ITxtListGadget[7],      /* next gadget */
    5,74,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    RELVERIFY ,           /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    &ITxtList[6],            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    ITXT6GADGET,             /* gadget id   */
    NULL                     /* special info*/
    },
    { /* ITxt name selection 7 */
    NULL,           /* next gadget */
    5,84,                    /* location    */
    244,8,
    GADGHCOMP,               /* flags       */
    RELVERIFY ,              /* activation  */
    BOOLGADGET|REQGADGET,    /* type        */
    NULL,                    /* rendering   */
    NULL,                    /* rendering   */
    &ITxtList[7],            /* text        */
    0,                       /* mutual exlcude */
    NULL,                    /* string info */
    ITXT7GADGET,             /* gadget id   */
    NULL                     /* special info*/
    }
  };
/********************************
 * The Load Button gadget stuff *
 *******************************/
SHORT ButtonPoints1[] =
  {
  -4, -4,
  66, -4,
  66, 12,
  -4, 12,
  -4, -4
  };
struct Border ButtonBorder1 =
  {
  0,0,
  2,1,JAM1,
  5,
  &ButtonPoints1[0],
  NULL
  };
SHORT ButtonPoints0[] =
  {
  -3, -2,
  65, -2,
  65, 10,
  -3, 10,
  -3, -2
  };
struct Border ButtonBorder0 =
  {
  0,0,
  1,0,JAM1,
  5,
  &ButtonPoints0[0],
  &ButtonBorder1
  };

struct IntuiText LoadText =
  {
  1,0, JAM2,              /* frontpen, backpen, drawmode */
  0,0,                    /* left,top */
  NULL,                   /* font */
  (UBYTE *)" Modify",                   /* text */
  NULL                    /* next */
  };

struct Gadget LoadGadget =
  { /* Load button */
  &ITxtListGadget[0],      /* next gadget */
  14,130,                  /* location    */
  64,8,
  GADGHCOMP,               /* flags       */
  GADGIMMEDIATE|ENDGADGET, /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &ButtonBorder0,   /* rendering   */
  NULL,                    /* rendering   */
  &LoadText,               /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  LOADGADGET,              /* gadget id   */
  NULL                     /* special info*/
  };

SHORT ATPoints1[] =
  {
  -4, -4,
  97, -4,
  97, 12,
  -4, 12,
  -4, -4
  };
struct Border ATBorder1 =
  {
  0,0,
  2,1,JAM1,
  5,
  &ATPoints1[0],
  NULL
  };
SHORT ATPoints0[] =
  {
  -3, -2,
  96, -2,
  96, 10,
  -3, 10,
  -3, -2
  };
struct Border ATBorder0 =
  {
  0,0,
  1,0,JAM1,
  5,
  &ATPoints0[0],
  &ATBorder1
  };
  
/* AddTxtGadget */
struct IntuiText AddText =
  {
  1,0, JAM2,              /* frontpen, backpen, drawmode */
  0,0,                    /* left,top */
  NULL,                   /* font */
  (UBYTE *)"Add New Text",                   /* text */
  NULL                    /* next */
  };

struct Gadget AddTxtGadget =
  { /* Load button */
  &LoadGadget,      /* next gadget */
  80,105,                  /* location    */
  90,8,
  GADGHCOMP,               /* flags       */
  GADGIMMEDIATE|ENDGADGET, /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &ATBorder0,   /* rendering   */
  NULL,                    /* rendering   */
  &AddText,               /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  ADDTXTGADGET,              /* gadget id   */
  NULL                     /* special info*/
  };

/**********************************
 * The Cancel Button gadget stuff *
 *********************************/
struct IntuiText CancelText =
  {
  1,0, JAM2,              /* frontpen, backpen, drawmode */
  0,0,                    /* left,top */
  NULL,                   /* font */
  (UBYTE *)" Cancel",      /* text */
  NULL                    /* next */
  };

struct Gadget CancelGadget =
  { /* Cancel button */
  &AddTxtGadget,             /* next gadget */
  187,130,                 /* location    */
  64,8,
  GADGHCOMP,               /* flags       */
  GADGIMMEDIATE|ENDGADGET, /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &ButtonBorder0,   /* rendering   */
  NULL,                    /* rendering   */
  &CancelText,             /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  CANCELGADGET,            /* gadget id   */
  NULL                     /* special info*/
  };

/***********************************************
 * The Scroll Selection List up (arrow) gadget *
 **********************************************/
UWORD UpArrowData[15] = {
   0xfffc,
   0xfcfc,
   0xf87c,
   0xf03c,
   0xe01c,
   0xc00c,
   0x8004,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfffc
};

struct Image UpArrow = 
  {
   0,0,
   14,
   14,
   1,
   &UpArrowData[0],
   0x1, 0x0,
   NULL
   };

struct Gadget UpGadget =
  { /* Up a file gadget */
  &CancelGadget,           /* next gadget */
  247,13,                  /* location    */
  12,15,
  GADGIMAGE|GADGHNONE,     /* flags       */
  GADGIMMEDIATE,           /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &UpArrow,         /* rendering   */
  NULL,                    /* rendering   */
  NULL,                    /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  UPGADGET,                /* gadget id   */
  NULL                     /* special info*/
  };
/*************************************************
 * The Scroll Selection List down (arrow) gadget *
 ************************************************/
UWORD DownArrowData[15] = {
   0xfffc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0xfcfc,
   0x8004,
   0xc00c,
   0xe01c,
   0xf03c,
   0xf87c,
   0xfcfc,
   0xfffc
};

struct Image DownArrow = 
  {
   0,0,
   14,
   14,
   1,
   &DownArrowData[0],
   0x1, 0x0,
   NULL
   };

struct Gadget DownGadget =
  { /* Down a file gadget */
  &UpGadget,               /* next gadget */
  247,79,                  /* location    */
  12,15,
  GADGIMAGE|GADGHNONE,     /* flags       */
  GADGIMMEDIATE,           /* activation  */
  BOOLGADGET|REQGADGET,    /* type        */
  (APTR) &DownArrow,       /* rendering   */
  NULL,                    /* rendering   */
  NULL,                    /* text        */
  0,                       /* mutual exlcude */
  NULL,                    /* string info */
  DOWNGADGET,              /*