/***************************************************************************
 *
 *                      MandleVroom Color Palette
 *
 *                         Kevin L. Clague
 *
 *                        Copyright (C) 1987
 *
 **************************************************************************/

#include "mand.h"

extern USHORT CurContour;

extern struct Gadget *ContGadget[], *SelGadget[];

extern struct Window *ContWind, *MandWind;

/*
 * Holder for Allocated color potentiometer gadgets.
 */
struct ColorGads {
  struct Gadget *RedPot;
  struct Gadget *GreenPot;
  struct Gadget *BluePot;
};

extern struct Screen        *screen;
extern struct ViewPort      *vp;
extern struct IntuitionBase *IntuitionBase;
extern char                 *ColorBase;
extern struct IntuiText     *MakeIntui();

struct Window          *PalWind;
extern SHORT XScale, YScale;

extern struct Window   *ContWind;

struct ColorGads        PalGads;

USHORT CmdMode;
USHORT CurPen;

struct NewWindow NewPal = {
   122,0,                    /* start position           */
   90,120,                   /* width, height            */
   (UBYTE) 0, (UBYTE) 1,     /* detail pen, block pen    */
                             /* IDCMP flags */
   MENUPICK | GADGETDOWN | GADGETUP | MOUSEMOVE | REQCLEAR| CLOSEWINDOW,
                             /* MandWind flags */
   WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | SIMPLE_REFRESH | NOCAREREFRESH,
   (struct Gadget *) NULL,   /* first gadget             */
   (struct Image *) NULL,    /* user checkmark           */
   (UBYTE *) "Colors",       /* window title             */
   (struct Screen *) NULL,   /* pointer to screen        */
   (struct BitMap *) NULL,   /* pointer to superbitmap   */
   80,80,80,80,              /* sizing                   */
   CUSTOMSCREEN              /* type of screen           */
   };

extern struct Windows *WindowList;

/*
 * Interpret the gadgets and do the right thing
 */
DoPalette(gadget)
  struct Gadget *gadget;
{
  switch (gadget->GadgetID >> TYPEBITS & TYPEMASK) {

  case PALPENS:
       ColorPenGotten(gadget);
       SetNormPointer();
       break;

  case PALCNTLS:
       ColorCntlGotten(gadget);
       break;

  case PALPOTS:
       SetNormPointer();
       CmdMode = COLORSLIDE;
       break;
  }
} /* DoPalette */

/*
 * We got a color palette command gadget
 */
int ColorCntlGotten(gadget)
struct Gadget *gadget;
{
  switch (gadget->GadgetID) {

  case PALCOPY:
       SetToPointer();
       CmdMode = COPY;
       break;

  case PALRANGE:
       SetToPointer();
       CmdMode = RANGE;
       break;

  case PALEXCG:
       SetToPointer();
       CmdMode = EXCG;
       break;
  }
} /* ColorCntlGotten */

/*
 * We got a color pen. Now what was the command we were supposed to perform?
 */
int ColorPenGotten(gadget)
struct Gadget *gadget;
{
  USHORT rgb, rgb2, pen;

  struct Image *Image;

  BoxPen((USHORT) CurPen, 0);

  pen = gadget->GadgetID & 0x003f;

  switch (CmdMode) {
    case COPY:
         rgb = GetRGB4(vp->ColorMap, CurPen);
         SetRGB4(vp, pen, rgb >> 8, rgb >> 4, rgb);
         break;

    case RANGE:
         ColorRange(CurPen, pen);
         break;

    case EXCG:
         rgb  = GetRGB4(vp->ColorMap, CurPen);
         rgb2 = GetRGB4(vp->ColorMap, pen);
         SetRGB4(vp, CurPen, rgb2 >> 8, rgb2 >> 4, rgb2 );
         SetRGB4(vp, pen,       rgb  >> 8, rgb  >> 4, rgb  );
         break;

    case IMPLIEDSET:
         Image = (struct Image *) SelGadget[ CurContour ]->GadgetRender;
         Image->PlaneOnOff = pen;

         RefreshGList( SelGadget[ CurContour ], ContWind, NULL, 1);

         *(ColorBase + CurContour) = pen;
         break;
  }
  CurPen = pen;
  SetColorProps( pen );
  BoxPen( pen, 1);
} /* ColorPenGotten */

/*
 * Blend a range of colors between two pens
 */
int ColorRange(first, last)
SHORT first, last;
{
    SHORT i;
    LONG whole, redfraction, greenfraction, bluefraction;
    USHORT rgb;
    SHORT firstred, firstgreen, firstblue;
    SHORT lastred, lastgreen, lastblue;
    SHORT workred, workgreen, workblue;

    if (first > last) {
        i = first;
        first = last;
        last = i;
     }

    /* I need to see a spread of at least two, where there's at least one
     * spot between the endpoints, else there's no work to do so I
     * might as well just return now.
     */
    if (first >= last - 1) return;

    rgb = GetRGB4(vp->ColorMap, first);
    firstred = (rgb >> 8) & 0xF;
    firstgreen = (rgb >> 4) & 0xF;
    firstblue = (rgb >> 0) & 0xF;

    rgb = GetRGB4(vp->ColorMap, last);
    lastred = (rgb >> 8) & 0xF;
    lastgreen = (rgb >> 4) & 0xF;
    lastblue = (rgb >> 0) & 0xF;

    whole = (lastred - firstred) << 16;
    redfraction = whole / (last - first);
    whole = (lastgreen - firstgreen) << 16;
    greenfraction = whole / (last - first);
    whole = (lastblue - firstblue) << 16;
    bluefraction = whole / (last - first);

    for (i = first + 1; i < last; i++)
        {
        lastred = (redfraction * (i - first) + 0x8000) >> 16;
        workred = firstred + lastred;
        lastgreen = (greenfraction * (i - first) + 0x8000) >> 16;
        workgreen = firstgreen + lastgreen;
        lastblue = (bluefraction * (i - first) + 0x8000) >> 16;
        workblue = firstblue + lastblue;
        SetRGB4(vp, i, workred, workgreen, workblue);
        }
} /* ColorRange */

/*
 * Modify the colors in the current pen
 */
ModifyColors()
{
  USHORT newred, newgreen, newblue;

  newred = ((struct PropInfo *)
           PalGads.RedPot->SpecialInfo)->VertPot >> 12;
  newgreen = ((struct PropInfo *)
           PalGads.GreenPot->SpecialInfo)->VertPot >> 12;
  newblue = ((struct PropInfo *)
           PalGads.BluePot->SpecialInfo)->VertPot >> 12;

  SetRGB4(vp, CurPen, newred, newgreen, newblue);
} /* ModifyColors */

/*
 * Reflect a pen's new color in the proportional gadget
 */
SetColorProps(pen)
  USHORT pen;
{
  USHORT rgb, red, green, blue;

  rgb = GetRGB4(vp->ColorMap, pen);

  red = (rgb >> 8) & 0xF;
  green = (rgb >> 4) & 0xF;
  blue = (rgb >> 0) & 0xF;

  red = (red << 12);
  green = (green << 12);
  blue = (blue << 12);

  ModifyProp(PalGads.RedPot,  PalWind,NULL,FREEVERT|PROPBORDERLESS,
             0L,red,0L,0L);
  ModifyProp(PalGads.GreenPot,PalWind,NULL,FREEVERT|PROPBORDERLESS,
             0L,green,0L,0L);
  ModifyProp(PalGads.BluePot, PalWind,NULL,FREEVERT|PROPBORDERLESS,
             0L,blue,0L,0L);
} /* SetColorProps */

BoxPen(BoxPen, DrawPen)
  USHORT BoxPen, DrawPen;
{
  ULONG  row, column;
  SHORT  Top, Bot, Left, Right;

#define PALTOP    (12 << YScale)
#define PALLEFT   (4 << XScale)
#define PENWIDTH  (4 << XScale)
#define PENHEIGHT (4 << YScale)
#define PENXPITCH (6 << XScale)
#define PENYPITCH (6 << YScale)

  column = BoxPen/8;

  row = BoxPen - column*8;

  SetAPen(PalWind->RPort, DrawPen);

  Left  = PALLEFT + PENXPITCH * column - 1;
  Top   = PALTOP  + PENYPITCH * row    - 1;
  Right = Left    + PENWIDTH  + 1;
  Bot   = Top     + PENHEIGHT + 1;

  Move(PalWind->RPort, Left,  Top);
  Draw(PalWind->RPort, Right, Top);
  Draw(PalWind->RPort, Right, Bot);
  Draw(PalWind->RPort, Left,  Bot);
  Draw(PalWind->RPort, Left,  Top + 1);
}

/*
 * Allocate all the gadgets for the color palette window
 */
struct Gadget *MakePalette()
{
  struct Gadget *FirstGadget, *NextGadget;
  extern struct Gadget *MakeBool(), *MakePot();
  SHORT i,Left,x,y,c = 0;

  FirstGadget = NextGadget = MakeBool(4,12,5,5,0,PALPEN);

  i = 1 << (screen->BitMap.Depth);
  Left = 8;
  for (x = 0; x < 6*8 && i > 0; x += 6) {
    for (y = 0; y < 6*8 && i > 0; y += 6) {
      if (c != 0) {
        NextGadget->NextGadget = MakeBool(x+4, y+12, 4, 4, c, PALPEN+c);
        if ((NextGadget = NextGadget->NextGadget) == (struct Gadget *) NULL)
          return(FirstGadget);
      }
      c++;
      i--;
    }
    Left += 8;
  }
  for (c = 0, x = 0; x < 10*3; x += 10) {
    NextGadget->NextGadget = MakeBool(Left+36, x+12, 10, 6, 1, PALCNTL+c);
    if (NextGadget->NextGadget == (struct Gadget *) NULL)
      return(FirstGadget);
    switch (c) {
      case 0:  NextGadget->NextGadget->GadgetText =
                  MakeIntui("Copy",14,-1,3,3,JAM1);
               break;
      case 1:  NextGadget->NextGadget->GadgetText =
                  MakeIntui("Spread",14,-1,3,3,JAM1);
               break;
      case 2:  NextGadget->NextGadget->GadgetText =
                  MakeIntui("Exchg",14,-1,3,3,JAM1);
               break;
    }
    NextGadget = NextGadget->NextGadget;
    c++;
  }
  for (x = y = 0; y < 3; x += 10, y++) {
    NextGadget->NextGadget = MakePot(Left+x, 22, 5, 42, PALPOT + y, y);
    if (NextGadget->NextGadget == (struct Gadget *) NULL)
      return(FirstGadget);
    switch (y) {
      case 0:  PalGads.RedPot = NextGadget->NextGadget;
               NextGadget->NextGadget->GadgetText =
                 MakeIntui("R",-2,-10,3,3,JAM1);
               break;
      case 1:  PalGads.GreenPot = NextGadget->NextGadget;
               NextGadget->NextGadget->GadgetText =
                 MakeIntui("G",-2,-10,3,3,JAM1);
               break;
      case 2:  PalGads.BluePot = NextGadget->NextGadget;
               NextGadget->NextGadget->GadgetText =
                 MakeIntui("B",-2,-10,3,3,JAM1);
               break;
    }
    NextGadget = NextGadget->NextGadget;
    NextGadget->Activation = GADGIMMEDIATE | FOLLOWMOUSE | RELVERIFY;
  }
  return(FirstGadget);
} /* MakePalette */

/*
 * Open the Palette window
 */
OpenPalWind()
{
  struct Window *OpenMyWind();

  if (PalWind == (struct Window *) NULL) {
    PalWind = OpenMyWind(&NewPal,screen,MakePalette(),140,70,140,70);
    if (PalWind) {
      CurPen = 0;
      BoxPen(CurPen, 1);
      SetColorProps( CurPen );
      ForceNormPointer();
    }
  } else {
    WindowToFront( PalWind );
  }
} /* OpenPalWind */

/*
 * Close the Palette window
 */
ClosePalWind()
{
  if (PalWind != (struct Window *) NULL) {
    CloseMyWind(PalWind,NewPal.FirstGadget);
    PalWind = (struct Window *) NULL;
  }
} /* ClosePalWind */

