/**********************************************************************\
 *             Color Palette Adjuster v2.0 enhanced                   *
 *								      *
 *   By Syd L. Bolton, with mods from code by Carolyn Schepper, CBM   *
 *          ©1990,91 Legendary Design Technologies, Inc.              *
 *								      *
 *         Version: 2.0  Date: May 17, 1990  Time: 10:30 pm           *
 *         Version: 2.1  Date: May 2, 1991   Time: 08:12 pm           *
 *                       NOTE: SIMPLY REMOVED SPREAD ROUTINE          *
\**********************************************************************/

#define MAXCOLORS 32
#define RGB_BODY  0xFFF

#define PWIDE 192         /* Palette Window Width */
#define PBASEHIGH 87      /* Height before adjust for color rows */
 
/* Gadget ID's */
#define colID  1
#define okID   MAXCOLORS + 1
#define resID  MAXCOLORS + 2
#define canID  MAXCOLORS + 3
#define rID    MAXCOLORS + 4
#define bID    MAXCOLORS + 5
#define gID    MAXCOLORS + 6
#define copID  MAXCOLORS + 8
#define swpID  MAXCOLORS + 9

/* Proportional RGB Gadgets */

#define PRPX  52
#define PRPY -77  /* Top prop, relative to bottom */
#define PRPW  90
#define PRPH  11

struct IntuiText
   rTxt = {1,0,JAM1,-11,2,0,"R",0},
   gTxt = {1,0,JAM1,-11,2,0,"G",0},
   bTxt = {1,0,JAM1,-11,2,0,"B",0};
 
struct Image  rImg, gImg, bImg;

struct PropInfo
   rInf = {AUTOKNOB|FREEHORIZ,0,0,RGB_BODY,0,0,0,0,0,0,0},
   gInf = {AUTOKNOB|FREEHORIZ,0,0,RGB_BODY,0,0,0,0,0,0,0},
   bInf = {AUTOKNOB|FREEHORIZ,0,0,RGB_BODY,0,0,0,0,0,0,0};

struct Gadget
   bGad = { NULL, PRPX,PRPY+30, PRPW,PRPH,
            GADGHNONE|GADGIMAGE|GRELBOTTOM,
            GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE,
            PROPGADGET,(APTR)&bImg, 0,
            &bTxt, 0,(APTR)&bInf, bID, 0 },   /* Last Gadget */

   gGad = { &bGad, PRPX,PRPY+15, PRPW,PRPH,
            GADGHNONE|GADGIMAGE|GRELBOTTOM,
            GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE,
            PROPGADGET,(APTR)&gImg, 0,
            &gTxt, 0,(APTR)&gInf, gID, 0 },

   rGad = { &gGad, PRPX,PRPY, PRPW,PRPH,
            GADGHNONE|GADGIMAGE|GRELBOTTOM,
            GADGIMMEDIATE|RELVERIFY|FOLLOWMOUSE,
            PROPGADGET,(APTR)&rImg, 0,
            &rTxt, 0,(APTR)&rInf, rID, 0 };

/* Text Selection Gadgets */
#define TXTX  8
#define TXTY -32      /* Relative to bottom */
#define TXTW  54
#define TXTH  13
#define NEWY -17      /* also relative to bottom */

SHORT  txtBorXY[10] = {0,0, TXTW-1,0, TXTW-1,TXTH-1, 0,TXTH-1, 0,0};
struct Border txtBor = { 0,0,3,0,JAM1,5,&txtBorXY[0],NULL };

struct IntuiText canTxt = {1,0,JAM1,4,3,0,"CANCEL",0};
struct Gadget canGad = {
   &rGad,   TXTX+122,NEWY,TXTW,TXTH, GADGHCOMP|GRELBOTTOM,
   RELVERIFY, BOOLGADGET, (APTR)&txtBor, 0,
   &canTxt, 0,0, canID, 0 };      /* Linked to red Prop Gadget */

struct IntuiText resTxt = {1,0,JAM1,8,3,0,"RESET",0};
struct Gadget resGad = {
   &canGad, TXTX,TXTY,TXTW,TXTH, GADGHCOMP|GRELBOTTOM,
   RELVERIFY, BOOLGADGET, (APTR)&txtBor, 0,
   &resTxt, 0,0, resID, 0 };

struct IntuiText swpTxt = {1,0,JAM1,12,3,0,"SWAP",0};
struct Gadget swpGad = {
   &resGad, TXTX+122,TXTY,TXTW,TXTH,GADGHCOMP|GRELBOTTOM,
   RELVERIFY, BOOLGADGET, (APTR)&txtBor,0,
   &swpTxt, 0, 0, swpID, 0};

struct IntuiText copTxt = {1,0,JAM1,12,3,0,"COPY",0};
struct Gadget copGad = {
   &swpGad, TXTX+61, TXTY,TXTW,TXTH,GADGHCOMP|GRELBOTTOM,
   RELVERIFY, BOOLGADGET, (APTR)&txtBor,0,
   &copTxt, 0, 0, copID, 0};

struct IntuiText okTxt = {1,0,JAM1,19,3,0,"OK",0};
struct Gadget okGad = {
   &copGad, TXTX,NEWY,TXTW,TXTH, GADGHCOMP|GRELBOTTOM,
   RELVERIFY, BOOLGADGET, (APTR)&txtBor, 0,
   &okTxt, 0,0, okID, 0 };  /* Color gads will be linked to this one */


/* Palette Color Gadgets */

#define COLX  10     /* Offsets of first color gadget */
#define COLY  14
#define COLSW  4     /* Spacing between color gadgets */
#define COLSH  4
#define COLW8 18     /* Image width if 8 or more colors */
#define COLW4 (COLW8+COLW8+COLSW)  /* 4 colors */
#define COLW2 (COLW4+COLW4+COLSW)  /* 2 colors */
#define COLH  10     /* Image height */
#define COLDY (COLH+COLSH)
SHORT   colW, colDX;

/* Drawn with DrawBorder() when color is selected */
/* Note - the border coords will be filled in by initColGads() */
SHORT  colBorXY[10] = {-2,-2, NULL,-2, NULL,COLH+1, -2,COLH+1, -2,-2};
struct Border colBor = { 0,0,1,0,JAM1,5,&colBorXY[0],NULL };

SHORT colGadX[MAXCOLORS], colGadY[MAXCOLORS];
struct Image  *colImgs;
struct Gadget *colGads;


/* Palette Window */ 
struct NewWindow newpWin = {
   224,24, PWIDE,NULL,   /* Height set before opening */
   2,1,
   MOUSEMOVE | GADGETUP | GADGETDOWN,             /* IDCMP Flags */
   ACTIVATE | SMART_REFRESH | WINDOWDRAG | WINDOWDEPTH, /* Flags */
   NULL,             /* First Gadget - set before OpenWindow */
   NULL,             /* CheckMark */
   "Color Palette",   /* Title */
   NULL,             /* Set up screen pointer before opening */
   NULL,             /* No superbitmap */
   0,0,0,0,          /* Max and Min (no sizing) */
   NULL              /* Screen type - set before opening */
   };
 
 
struct Window   *pWin;      /* Palette window pointer */
struct ViewPort *pVp;
struct RastPort *pRp;
struct IntuiMessage *pMsg;
struct Gadget   *pMGad;
int    pDepth, pColors, pReg, pTopSize;
ULONG  pMClass, colGadMem, colGadMemSize;
UWORD  curColor[MAXCOLORS], resColor[MAXCOLORS];
USHORT pMGadID;
BOOL Done;

/* 
 * doPalette(screen)
 */

doPalette(pScr)
struct Screen *pScr;
   {
   int k;

   /* For safe pcleanup */
   pWin    = NULL;
   colGadMem = NULL;

   /* From the screen - needed by Allocations */
   pVp = &pScr->ViewPort;
   pDepth = pScr->RastPort.BitMap->Depth;
   if (pDepth > 5) pDepth=5;
   pColors = 1 << pDepth;

   /* Allocations - Note: Requires initialized pDepth, pColors ! */
   colGadMemSize =
      (sizeof(struct Gadget)<<pDepth)+(sizeof(struct Image)<<pDepth);
   if(!(colGadMem=(ULONG)AllocMem(colGadMemSize,MEMF_PUBLIC|MEMF_CLEAR)))
      {
      pcleanup("Can't alloc gadget mem\n");
      return(0);
      }

   colGads = (struct Gadget *)colGadMem;
   colImgs = (struct Image *)(colGadMem+(sizeof(struct Gadget)<<pDepth));

   /* Init Color Gadgets, linking last one to okGad */
   initColGads(colGads,colImgs,pColors,&okGad);

   newpWin.FirstGadget = colGads;
   newpWin.Screen = pScr;
   newpWin.Type = pScr->Flags & 0x000f;
   /* Color rows * color gad Y spacing + 10 for top border */
   pTopSize = ((((pColors-1) >> 3)+1) * COLDY)+ 10;
   newpWin.Height = PBASEHIGH + pTopSize;
   newpWin.TopEdge=(pScr->Height-PBASEHIGH)/2;
   newpWin.LeftEdge=(pScr->Width-PWIDE)/2;

   if (!(pWin = (struct Window *)OpenWindow(&newpWin)))
      {
      pcleanup("Can't open palette window\n");
      return(0);
      }
   pRp = pWin->RPort;

   /* Get current colors and save for RESET */
   for (k=0; k < pColors; k++)
      curColor[k] = resColor[k] = GetRGB4(pVp->ColorMap,k);

   pReg = 0;  /* initially select color 0 */
   selectColor(0, pReg);

   Done = FALSE;
   while(! Done)
      {
      Wait(1<<pWin->UserPort->mp_SigBit);

      while (pMsg=(struct IntuiMessage *)GetMsg(pWin->UserPort))
         {
         /*  Note that rbg values are modified in 3 cases:
          *     GADGETDOWN of the props
          *     GADGETUP   of the props
          *     MOUSEMOVE (reporting turned on by the props)
          */

         pMClass  = pMsg->Class;
         pMGad   = (struct Gadget *)pMsg->IAddress;
         pMGadID = pMGad->GadgetID;

         ReplyMsg(pMsg);

         switch(pMClass)
            {
            case MOUSEMOVE:
               modColor(pReg);
               break;

            case GADGETDOWN:
               switch(pMGadID)
                  {
                  case rID:  case gID:  case bID:
                     modColor(pReg);
                     break;

                  default:
                     if ((pMGadID >= colID)&&(pMGadID<(colID+pColors)))
                        {
                        k = pReg;
                        pReg = pMGadID - colID;
                        selectColor(k,pReg);
                        }
                     break;
                  }

            case GADGETUP:
               switch (pMGadID)
                  {
                  case okID:        /* OK */
                     Done = TRUE;
                     break;
 
                  case resID:      /* RESET */
                     resetColors();
                     selectColor(pReg,pReg);
		     break;

                  case canID:      /* CANCEL */
                     resetColors();
                     Done = TRUE;
                     break;

		  case swpID:      /* swap two colors */
		     doswap();
                     break;

		  case copID:      /* copy color a to color b */
		     docopy();
		     break;

                  case rID:  case gID:  case bID:
                     modColor(pReg);
		     break;

                  default:
                     break;
                  }

            default:
               break;
            }
         }
      }
   pcleanup("");
   return(1);
   }


pcleanup(s)
char *s;
   {
   if (*s) printf(s);
   if (pWin)
      {
      while (pMsg=(struct IntuiMessage *)GetMsg(pWin->UserPort))
         {
         ReplyMsg(pMsg);
         }
      CloseWindow(pWin);
   if (colGadMem)  FreeMem(colGadMem,colGadMemSize);
      }
   }


initColGads(gad,img,colors,lastLink)
struct Gadget *gad;
struct Image  *img;
int colors;
struct Gadget *lastLink;
   {
   struct Gadget *nextgad;
   int k, lastk, row, col, rows;

   colW  = COLW8;
   if (colors == 4)  colW = COLW4;
   if (colors == 2)  colW = COLW2;
   colDX = colW + COLSW; /* color width + space between colors */
   colBorXY[2] = colW+1;
   colBorXY[4] = colW+1;

   /*  Make array of colGad xy positions */
   rows = ((colors-1) >> 3) + 1;  /* 8 colors per row */
   for (row=0, k=0; row<rows; row++)
      {
      for (col=0; (col<8)&&(k<colors); col++, k++)
         {
         colGadX[k] = COLX + (col * colDX);
         colGadY[k] = COLY + (row * COLDY);
         }
      }

   nextgad = gad+1;
   lastk = colors-1;
   for (k=0; k<colors; k++, gad++, img++, nextgad++)
      {
      if (k < lastk) gad->NextGadget = nextgad;
      else gad->NextGadget = lastLink;
      gad->LeftEdge = colGadX[k];
      gad->TopEdge =  colGadY[k];
      gad->Width =  colW;
      gad->Height = COLH;
      gad->Flags = GADGHBOX|GADGIMAGE;
      gad->Activation = GADGIMMEDIATE;
      gad->GadgetType = BOOLGADGET;
      gad->GadgetRender = (APTR)img;
      gad->GadgetID = colID + k;

      img->Width  = colW;
      img->Height = COLH;
      img->Depth  = 1;
      img->PlaneOnOff = k;
      }
   }

resetColors()
   {
   int k; 
   for(k=0; k<pColors; k++) curColor[k] = resColor[k];
   LoadRGB4(pVp, &resColor[0], pColors);
   }

selectColor(oldreg,newreg)
int oldreg, newreg;
   {
   USHORT rgb;
   int chx1,chy1,chx2,chy2;

   colBor.FrontPen = 0;
   DrawBorder(pRp,&colBor,colGadX[oldreg],colGadY[oldreg]);
   colBor.FrontPen = 1;
   DrawBorder(pRp,&colBor,colGadX[newreg],colGadY[newreg]);

   /* Large chip of selected color */
   chx1 = 8;  chy1 = pWin->Height - 78;
   chx2 = 34; chy2 = pWin->Height - 38;

   SetDrMd(pRp,JAM1);
   SetAPen(pRp,1);
   Move(pRp,chx1,chy1);
   Draw(pRp,chx2,chy1);
   Draw(pRp,chx2,chy2);
   Draw(pRp,chx1,chy2);
   Draw(pRp,chx1,chy1);
   SetAPen(pRp,newreg);
   RectFill(pRp,chx1+2,chy1+2,chx2-2,chy2-2);

   rgb = curColor[newreg];
   modColorProps(rgb);
   printRGB((rgb>>8)&0xF, (rgb>>4)&0xF, rgb&0xF);
   }


modColor(reg)
int reg;
   {
   USHORT r,g,b;

   r = (rInf.HorizPot >> 12) & 0x0F;
   g = (gInf.HorizPot >> 12) & 0x0F;
   b = (bInf.HorizPot >> 12) & 0x0F;

   curColor[reg] = (r << 8)|(g << 4)|b;

   LoadRGB4(pVp,&curColor[0],pColors);

   printRGB(r,g,b);
   }

doswap()
{
int reg1,reg2;

reg1=pReg;   /* current register */
reg2=secondregister();

swap(reg1,reg2);
}

docopy()
{
int reg1,reg2;

reg1=pReg;
reg2=secondregister();

copy(reg1,reg2);
}

/*** this routine gets second register for swap, copy, or spread ***/
secondregister()
{
int done,r=0;

done=0;

   while(done==0)
      {
      Wait(1<<pWin->UserPort->mp_SigBit);

      while (pMsg=(struct IntuiMessage *)GetMsg(pWin->UserPort))
         {
         pMClass  = pMsg->Class;
         pMGad   = (struct Gadget *)pMsg->IAddress;
         pMGadID = pMGad->GadgetID;

         ReplyMsg(pMsg);

         switch(pMClass)
            {
            case GADGETDOWN:
               switch(pMGadID)
                  {
                  default:
                     if ((pMGadID >= colID)&&(pMGadID<(colID+pColors)))
                        {
                        r = pMGadID - colID;
                        return(r);
                        }
                     break;
                    }
	       }
          }
     }
}

swap(reg1,reg2)
int reg1,reg2;
{
UWORD temp;

temp=curColor[reg1];
curColor[reg1]=curColor[reg2];
curColor[reg2]=temp;
LoadRGB4(pVp,&curColor[0],pColors);
selectColor(reg1,reg2);   /* just redisplay to show changes */
pReg=reg2;
}

copy(reg1,reg2)
int reg1,reg2;
{
curColor[reg2]=curColor[reg1];
LoadRGB4(pVp,&curColor[0],pColors);
selectColor(reg1,reg2);
pReg=reg2;
}

modColorProps(rgb)
USHORT rgb;
   {
   USHORT r,g,b;

   r = (rgb >> 8) & 0xF;
   g = (rgb >> 4) & 0xF;
   b = rgb & 0xF;
   ModifyProp(&rGad,pWin,0,rInf.Flags,(r*0x11111111),
              rInf.VertPot,rInf.HorizBody,rInf.VertBody);
   ModifyProp(&gGad,pWin,0,gInf.Flags,(g*0x11111111),
              gInf.VertPot,gInf.HorizBody,gInf.VertBody);
   ModifyProp(&bGad,pWin,0,bInf.Flags,(b*0x11111111),
              bInf.VertPot,bInf.HorizBody,bInf.VertBody);
   }


printRGB(r,g,b)
USHORT r,g,b;
   {
   char str[4];
   char *xstr;

   xstr = "0123456789ABCDEF";
   str[0] = xstr[r];
   str[1] = xstr[g];
   str[2] = xstr[b];
   SetAPen(pRp,1);
   SetBPen(pRp,0);
   SetDrMd(pRp,JAM2);
   Move(pRp,PWIDE-40,pWin->Height - 40);
   Text(pRp,&str[0],3);
   }
