#include "mpp.h"
#include "palettereq.h"//                                                                              (4.64.10) (09/17/00)
#include <clib/extras_protos.h>
#include <TagItemMacros.h>
#include <exec/memory.h>
#include <math.h>
#include <string.h>
#include <stdio.h>

#include <extras/ext_text.h>
#include <extras/layoutgt.h>
#include "palettereq.h"//                                                                              (4.64.9) (09/17/00)
#include <datatypes/pictureclass.h>

#include <proto/asl.h>
#include <proto/dos.h>
#include <proto/diskfont.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/iffparse.h>
#include <proto/utility.h>

#define PRFLAG_OBTAINPENS       (1<<1)
#define PRFLAG_USER_REDBITS     (1<<2)
#define PRFLAG_USER_GREENBITS   (1<<3)
#define PRFLAG_USER_BLUEBITS    (1<<4)

/*
#define MSG_M_PROJECT  "Project"
#define MSG_PRG_PALETTE "_Palette"
#define MSG_PRG_RED "_Red:"
#define MSG_PRG_GREEN "_Green:"
#define MSG_PRG_BLUE "_Blue:"
#define MSG_PRG_RESET "Re_set"
#define MSG_PRG_UNDO "_Undo"
#define MSG_PRG_COPY "_Copy"
#define MSG_PRG_SWAP "S_wap"
#define MSG_PRG_SPREAD "Sprea_d"
#define MSG_PRG_OK "_Ok"
#define MSG_PRG_CANCEL "Cance_l"
#define MSG_PRM_LOADPALETTE "Load Palette"
#define MSG_PRM_LOADPALETTE_KEY "L"
#define MSG_PRM_SAVEPALETTE "Save Palette"
#define MSG_PRM_SAVEPALETTE_KEY "S"
#define MSG_PRM_OK "Ok"
#define MSG_PRM_OK_KEY "O"
#define MSG_PRM_CANCEL "Cancel"
#define MSG_PRM_CANCEL_KEY "C"
*/

//#define GetString(x) (STRPTR)x

BOOL pr_ProcessPaletteTags(struct PaletteRequest *PReq, struct TagItem *TagList);
BOOL pr_ObtainPens(struct PaletteRequest *PReq);
void pr_ReleasePens(struct PaletteRequest *PReq);
void pr_PaletteReq(struct PaletteRequest *PReq);

struct PaletteRequest *PR_AllocPaletteRequest(Tag Tags, ... )
{
  struct PaletteRequest *preq;
  
  //printf("PR_AllocPaletteRequest()\n");
  
  if(preq=AllocVec(sizeof(*preq),MEMF_PUBLIC|MEMF_CLEAR))
  {
    //printf("  %8lx\n",preq);
    preq->pr_WinLeft=preq->pr_WinTop=preq->pr_WinWidth=preq->pr_WinHeight=-1;
    if(pr_ProcessPaletteTags(preq,(struct TagItem *)&Tags))
    {
      preq->pr_V39=(((struct Library *)IntuitionBase)->lib_Version)>=39;

      return(preq);
    }
    PR_FreePaletteRequest(preq);
  }
  return(0);
}

void PR_FreePaletteRequest(struct PaletteRequest *PReq)
{
  //printf("PR_FreePaletteRequest %8x\n",PReq);
  if(PReq)
  {
    //printf("pr_Palette %8x\n",PReq->pr_Palette);
    FreeVec(PReq->pr_Palette);
    //printf("pr_FileReq %8x\n",PReq->pr_FileReq);
    //FreeAslRequest(PReq->pr_FileReq);
    FreeVec(PReq);
  }
}


ULONG PR_DoPaletteRequest(struct PaletteRequest *PReq, Tag Tags, ... )
{
  ULONG retval=0;
  
  //printf("PR_DoPaletteRequest %8x\n",PReq);
  
  if(PReq)
  {
    if(pr_ProcessPaletteTags(PReq,(struct TagItem *)&Tags))
    {
      FreeVec(PReq->pr_Palette);
      
      if(PReq->pr_Palette=AllocVec(sizeof(*PReq->pr_Palette) * PReq->pr_Colors,MEMF_CLEAR))
      {
        if(PReq->pr_UndoPalette=AllocVec(sizeof(*PReq->pr_UndoPalette) * PReq->pr_Colors,MEMF_CLEAR))
        {
          if(PReq->pr_TextFont=OpenDiskFont(PReq->pr_TextAttr))
          {
            if(PReq->pr_ColorTable=AllocVec(sizeof(*PReq->pr_ColorTable) * PReq->pr_Colors,MEMF_CLEAR))
            {
              PReq->pr_Screen=PReq->pr_UserScreen;
              if(pr_ObtainPens(PReq))
              {
                pr_PaletteReq(PReq);
                
                retval=PReq->pr_RetVal;
                
                pr_ReleasePens(PReq);          
              }
              FreeVec(PReq->pr_ColorTable);
            }
            CloseFont(PReq->pr_TextFont);
          }
          FreeVec(PReq->pr_UndoPalette);
        }
      }
    }
  }  
  return(retval);
}


BOOL pr_ProcessPaletteTags(struct PaletteRequest *PReq, struct TagItem *TagList)
{
  struct TagItem *tag,*tstate;
  ULONG data;
  
  //printf("pr_ProcessPaletteTags %8x\n",PReq);
  
  ProcessTagList(TagList,tag,tstate)
  {
    data=tag->ti_Data;
    switch(tag->ti_Tag)
    {
      case PR_Screen:
        //printf("  PR_Screen %8x\n",data);
        PReq->pr_UserScreen=(struct Screen *)data;
        break;

      case PR_Window:
        //printf("  PR_Window %8x\n",data);
        PReq->pr_UserScreen=((struct Window *)data)->WScreen;
        PReq->pr_UserWindow=((struct Window *)data);
        break;
   
      case PR_Colors:
        //printf("  PR_Colors %8x\n",data);
        PReq->pr_Colors=data;
        break;
   
      case PR_InitialPalette:
        //printf("  PR_InitialPalette %8x\n",data);
        PReq->pr_InitialPalette=(APTR)data;
        break;
        
      case PR_ObtainPens:
        //printf("  PR_ObtainPens %8x\n",data);
        PReq->pr_Flags|=PRFLAG_OBTAINPENS;
        break;
        
      case PR_ColorTable:
        //printf("  PR_ColorTable %8x\n",data);
        PReq->pr_UserColorTable=(APTR)data;
        break;
        
      case PR_TextAttr:
        //printf("  PR_TextAttr %8x\n",data);
        PReq->pr_TextAttr=(APTR)data;
        break;
        
      case PR_Title:
        PReq->pr_WindowTitle=(APTR)data;
        break;
        
      case PR_RedBits:
        PReq->pr_Flags&=(~PRFLAG_USER_REDBITS);
        if(data)
        {
          PReq->pr_RedBits=data;
          PReq->pr_Flags|=PRFLAG_USER_REDBITS;
        }
        break;
        
      case PR_GreenBits:
        PReq->pr_Flags&=(~PRFLAG_USER_GREENBITS);
        if(data)
        {
          PReq->pr_GreenBits=data;
          PReq->pr_Flags|=PRFLAG_USER_GREENBITS;
        }
        break;
        
      case PR_BlueBits:
        PReq->pr_Flags&=(~PRFLAG_USER_BLUEBITS);
        if(data)
        {
          PReq->pr_BlueBits=data;
          PReq->pr_Flags|=PRFLAG_USER_BLUEBITS;
        }
        break;
        
      case PR_ModeIDRGBBits:
        {
          struct DisplayInfo di;
          
          if(GetDisplayInfoData(0,(UBYTE *)&di,sizeof(di),DTAG_DISP,data))
          {
            if(PReq->pr_V39)
            { 
              PReq->pr_RedBits   =max(di.RedBits,1);
              PReq->pr_GreenBits =max(di.GreenBits,1);
              PReq->pr_BlueBits  =max(di.BlueBits,1);
            }
            else
            {
              // v38 orless
              PReq->pr_RedBits   =PReq->pr_GreenBits =PReq->pr_BlueBits  =4;
            }
            
            PReq->pr_Flags|=PRFLAG_USER_REDBITS|PRFLAG_USER_GREENBITS|PRFLAG_USER_BLUEBITS;
          }
        }
        break;
        
      case PR_InitialLeftEdge:
        PReq->pr_WinLeft=data;
        break;
        
      case PR_InitialTopEdge:
        PReq->pr_WinTop=data;
        break;
        
      case PR_InitialWidth:
        PReq->pr_WinWidth=data;
        break;
      case PR_InitialHeight:
        PReq->pr_WinHeight=data;
        break;
    }
  }
  return(1);
}



BOOL pr_ObtainPens(struct PaletteRequest *PReq)
{
  LONG l,ok;

  ok=1;

  if(PReq->pr_InitialPalette)
  {
    for(l=0;l<PReq->pr_Colors;l++)
    {
      PReq->pr_Palette[l]=PReq->pr_InitialPalette[l];
    }
  }
 
  if((PReq->pr_Flags & PRFLAG_OBTAINPENS))
  {
    PReq->pr_CMap=PReq->pr_Screen->ViewPort.ColorMap;
    
    for(l=0;l<PReq->pr_Colors && ok;l++)
    {
      LONG pen;
      pen=ObtainPen(PReq->pr_CMap,-1,
              PReq->pr_Palette[l].Red,
              PReq->pr_Palette[l].Green,
              PReq->pr_Palette[l].Blue,
              PEN_EXCLUSIVE);
      if(pen<0)
      {
        ok=0;
      }
      
      PReq->pr_ColorTable[l]=pen;
      
//      //printf("Obtained pen %d %d\n",pen,PReq->pr_ColorTable[l]);
    }
    if(!ok)
    {
      for(;l>=0;l--)
        ReleasePen(PReq->pr_CMap,PReq->pr_ColorTable[l]);
    }
  }    
  else
  {
    if(PReq->pr_UserColorTable)
    {
      for(l=0;l<PReq->pr_Colors;l++)
      {
        PReq->pr_ColorTable[l]=PReq->pr_UserColorTable[l];
      }
    }
    else
    {
      for(l=0;l<PReq->pr_Colors;l++)
      {
        PReq->pr_ColorTable[l]=l;
      }
    }
  }

  return((BOOL)ok);
}

void pr_ReleasePens(struct PaletteRequest *PReq)
{
  ULONG l;
  
  //printf("pr_ReleasePens PReq=%8x\n",PReq);
  
  if(PReq->pr_Flags & PRFLAG_OBTAINPENS )
  {
    if(PReq->pr_CMap)
    {
      for(l=0;l<PReq->pr_Colors;l++)
      {
        //printf("  %d\n",PReq->pr_ColorTable[l]);
        ReleasePen(PReq->pr_CMap,PReq->pr_ColorTable[l]);
      }
    }
  }
  
  PReq->pr_CMap=0;
}

/* Gad IDs */
#define PGD_PALETTE 0
#define PGD_RED     1
#define PGD_GREEN   2
#define PGD_BLUE    3
#define PGD_OK      4
#define PGD_CANCEL  5
#define PGD_RESET   6
#define PGD_UNDO    7
#define PGD_COPY    8
#define PGD_SWAP    9
#define PGD_SPREAD  10

/* Project Menu */
#define M_PALETTELOAD       FULLMENUNUM(0,0,NOSUB)
#define M_PALETTESAVE       FULLMENUNUM(0,1,NOSUB)
/* Bar */
#define M_PALETTEOK         FULLMENUNUM(0,3,NOSUB)
#define M_PALETTECANCEL     FULLMENUNUM(0,4,NOSUB)



struct   NewMenu pr_PaletteMenu[]=
{
  {NM_TITLE ,(STRPTR)MSG_M_PROJECT              ,0  ,0,0,0},
  {NM_ITEM  ,(STRPTR)MSG_PRM_LOADPALETTE        ,(STRPTR)MSG_PRM_LOADPALETTE_KEY        ,0,0,(APTR)M_PALETTELOAD},
  {NM_ITEM  ,(STRPTR)MSG_PRM_SAVEPALETTE        ,(STRPTR)MSG_PRM_SAVEPALETTE_KEY        ,0,0,(APTR)M_PALETTESAVE},
  {NM_ITEM  ,NM_BARLABEL                ,0  ,0,0,0},
  {NM_ITEM  ,(STRPTR)MSG_PRM_OK                 ,(STRPTR)MSG_PRM_OK_KEY                 ,0,0,(APTR)M_PALETTEOK},
  {NM_ITEM  ,(STRPTR)MSG_PRM_CANCEL             ,(STRPTR)MSG_PRM_CANCEL_KEY             ,0,0,(APTR)M_PALETTECANCEL},
  {NM_END   ,NULL                       ,0 ,0,0,0}
};

#define PRM_NORMAL 0
#define PRM_COPY   1
#define PRM_SWAP   2
#define PRM_SPREAD 3

void pr_ProcessPalGads(struct PaletteRequest *PReq, struct IntuiMessage *IMsg);
void pr_ProcessPalKeys(struct PaletteRequest *PReq, struct IntuiMessage *Imsg);
LONG pr_LongestTextLen(struct TextFont *TF, STRPTR String, ... );

struct LG_Control *pr_LayoutPaletteGads(struct PaletteRequest *PReq);
void pr_SetPalette(struct PaletteRequest *PReq);
void pr_UpdateSliders(struct PaletteRequest *PReq);
void pr_GetPalette(struct PaletteRequest *PReq);
void pr_SetUndoBuffer(struct PaletteRequest *PReq);
void pr_GetUndoBuffer(struct PaletteRequest *PReq);
ULONG pr_Mix(ULONG A,ULONG B, float Percent);
void pr_ProcessPalMenus(struct PaletteRequest *PReq, struct Menu *MenuStrip, struct IntuiMessage *imsg);

void pr_PGD_Cancel (struct PaletteRequest *PReq);
void pr_PGD_Ok     (struct PaletteRequest *PReq);
//void pr_PGD_Palette        (struct PaletteRequest *PReq, LONG Active, BOOL Keyed);
void pr_PGD_PaletteModed(struct PaletteRequest *PReq, LONG Active, BOOL DoModes, BOOL Keyed);
void pr_PGD_Red    (struct PaletteRequest *PReq, LONG Value, BOOL Keyed);
void pr_PGD_Green  (struct PaletteRequest *PReq, LONG Value, BOOL Keyed);
void pr_PGD_Blue   (struct PaletteRequest *PReq, LONG Value, BOOL Keyed);
void pr_PGD_Undo   (struct PaletteRequest *PReq);
void pr_PGD_Reset  (struct PaletteRequest *PReq);
BOOL pr_PGD_Copy   (struct PaletteRequest *PReq);
BOOL pr_PGD_Swap   (struct PaletteRequest *PReq);
BOOL pr_PGD_Spread (struct PaletteRequest *PReq);

void pr_DrawPenBox   (struct PaletteRequest *PReq);
void pr_DrawPenRect  (struct PaletteRequest *PReq);

BOOL pr_SelectPaletteFile(struct PaletteRequest *PReq, UBYTE *title,UBYTE save,struct Window *Parent);
BOOL pr_ReadCMAP(STRPTR Filename, struct prRGB *CReg, ULONG Colors);
BOOL pr_SaveCMAP(STRPTR Filename, struct prRGB *CReg, ULONG Colors);

LONG pr_LongestTextLen(struct TextFont *TF, STRPTR String, ... )
{
  STRPTR *str;
  LONG len=0,n;
  
  str=&String;
  
  while(*str)
  {
    n=gui_StrLength(SL_TextFont     ,TF,//                                                             (4.64.8) (09/17/00)
                SL_String       ,*str,
                SL_IgnoreChars  , "_",
                TAG_DONE);
    len=max(n,len);
    str++;
  }
  
  return(len);
}

struct LG_Control *pr_LayoutPaletteGads(struct PaletteRequest *PReq)
{
  WORD width,height,
       sliderlabellen,slidertopedge,slidernumlen,
       buttontopedge,buttonheight,buttonwidth,
       undobuttontopedge, undobuttonwidth,
       editbuttontopedge, editbuttonwidth;
  struct LG_Control *pr_control;
  STRPTR ok,cancel,red,green,blue,reset,undo,copy,swap,spread;

  if(PReq->pr_VisualInfo)
  {
//    rp=PReq->pr_Window->RPort; 
    slidernumlen=gui_MaxStrFontLen(PReq->pr_TextFont,4,'0','9');//                                     (4.64.4) (09/17/00)
    buttonheight=PReq->pr_TextAttr->ta_YSize+6;

    /* init strings */
    ok      =GetString(MSG_PRG_OK);
    cancel  =GetString(MSG_PRG_CANCEL);
    red     =GetString(MSG_PRG_RED);
    green   =GetString(MSG_PRG_GREEN);
    blue    =GetString(MSG_PRG_BLUE);
    reset   =GetString(MSG_PRG_RESET);
    undo    =GetString(MSG_PRG_UNDO);
    copy    =GetString(MSG_PRG_COPY);
    swap    =GetString(MSG_PRG_SWAP);
    spread  =GetString(MSG_PRG_SPREAD);
    
    /* init lens */
    buttonwidth     =pr_LongestTextLen(PReq->pr_TextFont,ok,cancel,0)+8;
    sliderlabellen  =pr_LongestTextLen(PReq->pr_TextFont,red,green,blue,0)+8;
    undobuttonwidth =pr_LongestTextLen(PReq->pr_TextFont,reset,undo,0)+8;
    editbuttonwidth =pr_LongestTextLen(PReq->pr_TextFont,copy,swap,spread,0)+8;
  
    PReq->pr_MinHeight=buttonheight*6+6+60+20+8;
    PReq->pr_MinWidth =sliderlabellen+slidernumlen+40;
    PReq->pr_MinWidth =max(PReq->pr_MinWidth,buttonwidth*2);
    PReq->pr_MinWidth =max(PReq->pr_MinWidth,undobuttonwidth*2);
    PReq->pr_MinWidth =max(PReq->pr_MinWidth,editbuttonwidth*3)+8;

    width=height=0;
  
    if(PReq->pr_Window)
    {
      width =PReq->pr_WinWidth  - PReq->pr_Window->BorderLeft - PReq->pr_Window->BorderRight  - 8;
      height=PReq->pr_WinHeight - PReq->pr_Window->BorderTop  - PReq->pr_Window->BorderBottom - 8 - 20;
    }
    
    width  = max(width,  PReq->pr_MinWidth - 8); 
    height = max(height, PReq->pr_MinHeight - 8 - 20);

    PReq->pr_PLeft = PReq->pr_Screen->WBorLeft  + 4;
    PReq->pr_PTop  = PReq->pr_Screen->WBorTop + PReq->pr_Screen->RastPort.TxHeight + 1  + 4;
    PReq->pr_PWidth= width;
    PReq->pr_PHeight= 16;
    
    buttontopedge=height-buttonheight;
    slidertopedge=buttontopedge-6-(buttonheight*3);
    undobuttontopedge=slidertopedge-buttonheight-3;
    editbuttontopedge=undobuttontopedge-buttonheight;
  
  
    undobuttonwidth =max(width/2,undobuttonwidth);

    if(PReq->pr_Window)
    {
      pr_control=LG_CreateGadgets( /* init shit */
                                   LG_VisualInfo            ,PReq->pr_VisualInfo,
                                   LG_UseScreenOffsets      ,PReq->pr_Screen,
                                   LG_EraseRemoved          ,FALSE,
                                   LG_BoundsLeft    ,4,
                                   LG_BoundsTop     ,4 + 20,
                                   LG_BoundsWidth   ,width,
                                   LG_BoundsHeight  ,height,
                                   LG_TextAttr      ,PReq->pr_TextAttr,
                                   
                                   /* Palette Gadget */
                                   LG_GadgetKind    ,PALETTE_KIND,
                                   LG_GadgetID      ,PGD_PALETTE,
                                   LG_LeftEdge      ,0,
                                   LG_TopEdge       ,0,
                                   LG_Width         ,LG_REL_WIDTH(0),
                                   LG_Height        ,editbuttontopedge-4,
                                   LG_Flags         ,PLACETEXT_ABOVE,
                                   LG_LabelFlags    ,LGLF_FITLABEL,
                                   LG_GadgetText    ,GetString(MSG_PRG_PALETTE),
                                   LG_GadgetTags    ,6,
                                     GT_Underscore    ,'_',
                                     GTPA_NumColors   ,PReq->pr_Colors,
                                     GTPA_ColorTable  ,PReq->pr_ColorTable,
                                     GTPA_Depth       ,PReq->pr_Screen->RastPort.BitMap->Depth,
                                     GTPA_Color       ,PReq->pr_ColorTable[PReq->pr_ActiveColor],
                                     GTPA_IndicatorWidth,32,
                                   LG_CreateGadget  ,0,
                                   
                                   
                                   /* Slider init */
                                   LG_LeftEdge      ,sliderlabellen,
                                   LG_Width         ,width-sliderlabellen-slidernumlen-8,
                                   LG_Height        ,buttonheight-2,
                                   LG_LabelFlags    ,0,
                                   LG_Flags         ,0,
                                   
                                   /* Red Slider */
                                   LG_GadgetKind    ,SLIDER_KIND,
                                   LG_GadgetID      ,PGD_RED,
                                   LG_TopEdge       ,slidertopedge,
                                   LG_GadgetText    ,red,
                                   LG_GadgetTags    ,9,
                                   GTSL_Level       ,PReq->pr_Palette[PReq->pr_ActiveColor].Red>>24 ,
                                   GTSL_MaxPixelLen ,slidernumlen+1,
                                   GTSL_Min         ,0,
                                   GTSL_Max         ,PReq->pr_RedMax,
                                   GTSL_LevelFormat ,"%3ld",
                                   GTSL_MaxLevelLen ,4,
                                   GTSL_LevelPlace  ,PLACETEXT_RIGHT,
                                   GTSL_Justification ,GTJ_RIGHT,
                                   GT_Underscore    ,'_',
                                   LG_CreateGadget  ,0,
                                   
                                   /* Green Slider */
                                   LG_TopEdge       ,slidertopedge+buttonheight,
                                   LG_GadgetText    ,green,
                                   LG_GadgetTags    ,9,
                                   GTSL_Level       ,PReq->pr_Palette[PReq->pr_ActiveColor].Green>>24 ,
                                   GTSL_MaxPixelLen ,slidernumlen+1,
                                   GTSL_Min         ,0,
                                   GTSL_Max         ,PReq->pr_GreenMax,
                                   GTSL_LevelFormat ,"%3ld",
                                   GTSL_MaxLevelLen ,4,
                                   GTSL_LevelPlace  ,PLACETEXT_RIGHT,
                                   GTSL_Justification ,GTJ_RIGHT,
                                   GT_Underscore    ,'_',
                                   LG_CreateGadget  ,0,
                                   
                                   /* Blue Slider */
                                   LG_TopEdge       ,slidertopedge+buttonheight*2,
                                   LG_GadgetText    ,blue,
                                   LG_GadgetTags    ,9,
                                   GTSL_Level       ,PReq->pr_Palette[PReq->pr_ActiveColor].Blue>>24 ,
                                   GTSL_MaxPixelLen ,slidernumlen+1,
                                   GTSL_Min         ,0,
                                   GTSL_Max         ,PReq->pr_BlueMax,
                                   GTSL_LevelFormat ,"%3ld",
                                   GTSL_MaxLevelLen ,4,
                                   GTSL_LevelPlace  ,PLACETEXT_RIGHT,
                                   GTSL_Justification ,GTJ_RIGHT,
                                   GT_Underscore    ,'_',
                                   LG_CreateGadget  ,0,
                                   
                                   /* Ok Button */
                                   LG_GadgetTags    ,1,
                                   GT_Underscore    ,'_',
                                   LG_GadgetKind    ,BUTTON_KIND,
                                   LG_GadgetText    ,ok,
                                   LG_LeftEdge      ,0,
                                   LG_TopEdge       ,buttontopedge,
                                   LG_Width         ,buttonwidth,
                                   LG_Height        ,buttonheight,
                                   LG_CreateGadget  ,0,
                                   
                                   /* Cancel Button */
                                   LG_LeftEdge      ,LG_REL_RIGHT(-buttonwidth),
                                   LG_GadgetText    ,cancel,
                                   LG_CreateGadget  ,0,
                                   
                                   
                                   LG_HorizCells    ,2,
                                   /* Reset Button */
                                   LG_LeftEdge      ,LG_REL_CELL_LEFTEDGE(0),
                                   LG_TopEdge       ,undobuttontopedge,
                                   LG_Width         ,LG_REL_CELL_WIDTH(1),
                                   LG_Height        ,buttonheight,
                                   LG_GadgetText    ,reset,
                                   LG_CreateGadget  ,0,
                                   
                                   /* Undo button */
                                   LG_LeftEdge      ,LG_REL_CELL_LEFTEDGE(1),
                                   LG_GadgetText    ,undo,
                                   LG_CreateGadget  ,0,
                                   
                                   
                                   LG_HorizCells    ,3,
                                   /* Copy */
                                   LG_LeftEdge      ,LG_REL_CELL_LEFTEDGE(0),
                                   LG_TopEdge       ,editbuttontopedge,
                                   LG_Width         ,LG_REL_CELL_WIDTH(1),
                                   LG_GadgetText    ,copy,
                                   LG_CreateGadget  ,0,
                                   
                                   /* Swap */
                                   LG_LeftEdge      ,LG_REL_CELL_LEFTEDGE(1),
                                   LG_GadgetText    ,swap,
                                   LG_CreateGadget  ,0,
                                   
                                   /* Spread */
                                   LG_LeftEdge      ,LG_REL_CELL_LEFTEDGE(2),
                                   LG_GadgetText    ,spread,
                                   LG_CreateGadget  ,0,
                                   
  
                                   TAG_DONE);
      return(pr_control);
    }
  }
  return(0);
}                              

void pr_PaletteReq(struct PaletteRequest *PReq)
{
  WORD oldleft,oldtop,oldwidth,oldheight;
  struct DisplayInfo di;
//  
  struct IntuiMessage *imsg;

  oldleft=oldtop=oldwidth=oldheight=-1;

  PReq->pr_PalGo=TRUE;
  PReq->pr_ActiveColor=0;
  PReq->pr_Mode=0;

  if(GetDisplayInfoData(0,(UBYTE *)&di,sizeof(di),DTAG_DISP,GetVPModeID(&PReq->pr_Screen->ViewPort)))
  {
    if(PReq->pr_V39)
    {
      if(!(PReq->pr_Flags & PRFLAG_USER_REDBITS))
        PReq->pr_RedBits   =di.RedBits;
      if(!(PReq->pr_Flags & PRFLAG_USER_GREENBITS))
        PReq->pr_GreenBits =di.GreenBits;
      if(!(PReq->pr_Flags & PRFLAG_USER_BLUEBITS))
        PReq->pr_BlueBits  =di.BlueBits;
    }
    else
    {
      if(!(PReq->pr_Flags & PRFLAG_USER_REDBITS))
        PReq->pr_RedBits   =4;
      if(!(PReq->pr_Flags & PRFLAG_USER_GREENBITS))
        PReq->pr_GreenBits =4;
      if(!(PReq->pr_Flags & PRFLAG_USER_BLUEBITS))
        PReq->pr_BlueBits  =4;
      /**********************************************************
      PReq->pr_RedBits   = sqrt(((di.PaletteRange & 0xf00) >> 8)+1);
      PReq->pr_GreenBits = sqrt(((di.PaletteRange & 0xf0) >> 4)+1);
      PReq->pr_BlueBits  = sqrt(((di.PaletteRange & 0xf )  +1));
      PReq->pr_RedBits   = max(PReq->pr_RedBits      ,1);
      PReq->pr_GreenBits = max(PReq->pr_GreenBits    ,1);
      PReq->pr_BlueBits  = max(PReq->pr_BlueBits     ,1);
      */
    }
  }
  else
  {
    if(PReq->pr_V39)
    {
      if(!(PReq->pr_Flags & PRFLAG_USER_REDBITS))
        PReq->pr_RedBits   =8;
      if(!(PReq->pr_Flags & PRFLAG_USER_GREENBITS))
        PReq->pr_GreenBits =8;
      if(!(PReq->pr_Flags & PRFLAG_USER_BLUEBITS))
        PReq->pr_BlueBits  =8;
    }
    else
    {
      if(!(PReq->pr_Flags & PRFLAG_USER_REDBITS))
        PReq->pr_RedBits   =4;
      if(!(PReq->pr_Flags & PRFLAG_USER_GREENBITS))
        PReq->pr_GreenBits =4;
      if(!(PReq->pr_Flags & PRFLAG_USER_BLUEBITS))
        PReq->pr_BlueBits  =4;
    }
  }
      
  PReq->pr_RedBits   =max(PReq->pr_RedBits,1);
  PReq->pr_GreenBits =max(PReq->pr_GreenBits,1);
  PReq->pr_BlueBits  =max(PReq->pr_BlueBits,1);    
      
  pr_GetPalette(PReq);
  
  pr_SetUndoBuffer(PReq);
    
  PReq->pr_PrevColor=PReq->pr_ActiveColor;
    
  if(PReq->pr_VisualInfo=GetVisualInfo(PReq->pr_Screen,0))
  {
    PReq->pr_RedMax   =(1<<PReq->pr_RedBits  )-1;
    PReq->pr_GreenMax =(1<<PReq->pr_GreenBits)-1;
    PReq->pr_BlueMax  =(1<<PReq->pr_BlueBits )-1;
    
    PReq->pr_RedMult   =255/PReq->pr_RedMax;
    PReq->pr_GreenMult =255/PReq->pr_GreenMax;
    PReq->pr_BlueMult  =255/PReq->pr_BlueMax;

    PReq->pr_GadControl=pr_LayoutPaletteGads(PReq);
    //printf("gc = %8lx\n",    PReq->pr_GadControl);
    { 
      if(PReq->pr_Window=OpenWindowTags(0,
              WA_CustomScreen,  PReq->pr_Screen,
              WA_Left,          0,
              WA_Top,           0,
              WA_Width,         1,//                                                                   (4.61.1)
              WA_Height,        1,//                                                                   (4.61.1)
                  
              WA_Title,         PReq->pr_WindowTitle,

              WA_MaxWidth,      -1,
              WA_MaxHeight,     -1,
              WA_IDCMP,         PALETTEIDCMP | SLIDERIDCMP | BUTTONIDCMP | 
                                IDCMP_CLOSEWINDOW|IDCMP_NEWSIZE|IDCMP_VANILLAKEY|IDCMP_MENUPICK|IDCMP_REFRESHWINDOW,
              WA_SizeGadget,    TRUE,
              WA_DragBar,       TRUE,
              WA_DepthGadget,   TRUE,
              WA_CloseGadget,   TRUE,
              WA_SizeBBottom,   TRUE,
              WA_Activate,      TRUE,
              WA_NewLookMenus,  TRUE,
              WA_SimpleRefresh, TRUE,
              TAG_DONE))
      {
        struct Process *proc;
        struct Window *winptr;
    
        if(PReq->pr_WinWidth==-1)
          PReq->pr_WinWidth =PReq->pr_MinWidth  + PReq->pr_Window->BorderLeft + PReq->pr_Window->BorderRight;
        if(PReq->pr_WinHeight==-1)
          PReq->pr_WinHeight=PReq->pr_MinHeight + PReq->pr_Window->BorderTop  + PReq->pr_Window->BorderBottom;
          
        if(PReq->pr_WinLeft==-1)
        {
          if(PReq->pr_UserWindow)
          {
            PReq->pr_WinLeft=(PReq->pr_UserWindow->Width - PReq->pr_WinWidth)/2  + PReq->pr_UserWindow->LeftEdge;
          }
          else
          {
            if(PReq->pr_UserScreen)
            {
              PReq->pr_WinLeft=(PReq->pr_UserScreen->Width - PReq->pr_WinWidth)/2  ;
            }
            else
            {
              PReq->pr_WinLeft=0;
            }
          }
        }
        
        if(PReq->pr_WinTop==-1)
        {
          if(PReq->pr_UserWindow)
          {
            PReq->pr_WinTop=(PReq->pr_UserWindow->Height - PReq->pr_WinHeight)/2 + PReq->pr_UserWindow->TopEdge;
          }
          else
          {
            if(PReq->pr_UserScreen)
            {
              PReq->pr_WinTop=(PReq->pr_UserScreen->Height - PReq->pr_WinHeight)/2 ;
            }
            else
            {
              PReq->pr_WinTop=0;
            }
          }
        }

        /* make sure size is legal */
        PReq->pr_WinWidth=max(PReq->pr_WinWidth         ,PReq->pr_MinWidth  + PReq->pr_Window->BorderLeft + PReq->pr_Window->BorderRight);
        PReq->pr_WinHeight=max(PReq->pr_WinHeight       ,PReq->pr_MinHeight + PReq->pr_Window->BorderTop  + PReq->pr_Window->BorderBottom);
        
        ChangeWindowBox(PReq->pr_Window,PReq->pr_WinLeft,PReq->pr_WinTop, PReq->pr_WinWidth ,PReq->pr_WinHeight); 
        
        proc=(struct Process *)FindTask(0);
        winptr=proc->pr_WindowPtr;
        proc->pr_WindowPtr=PReq->pr_Window;
        
        if(PReq->pr_MenuStrip=CreateMenus(pr_PaletteMenu,TAG_END))
        {
          if(LayoutMenus(PReq->pr_MenuStrip,PReq->pr_VisualInfo,
                          GTMN_NewLookMenus,TRUE,
                          TAG_END))
          {
            if(SetMenuStrip(PReq->pr_Window,PReq->pr_MenuStrip))
            {
              pr_SetPalette(PReq);
              
              ////printf("%8x %8x\n",PReq->pr_Window->RPort,PReq->pr_TextFont);
              SetFont(PReq->pr_Window->RPort,PReq->pr_TextFont);
              
              //printf("setfont\n");
              {
                //printf("Layout\n");
                pr_DrawPenBox(PReq);
                pr_UpdateSliders(PReq);

//                LG_AddGadgets(PReq->pr_Window,PReq->pr_GadControl);
                while(PReq->pr_PalGo)
                {
                  WaitPort(PReq->pr_Window->UserPort);
                  while(imsg=GT_GetIMsg(PReq->pr_Window->UserPort))
                  {
                    switch(imsg->Class)
                    {
                      case IDCMP_REFRESHWINDOW:
                        GT_BeginRefresh(PReq->pr_Window);
                        pr_DrawPenBox(PReq);
                        GT_EndRefresh(PReq->pr_Window,TRUE);
                        break;
                        
                      case IDCMP_CLOSEWINDOW:
                        PReq->pr_RetVal=FALSE;
                        PReq->pr_PalGo=FALSE;
                        break;
                        
                      case IDCMP_NEWSIZE:
                        if(oldleft    !=  PReq->pr_Window->LeftEdge     || 
                           oldtop     !=  PReq->pr_Window->TopEdge      || 
                           oldwidth   !=  PReq->pr_Window->Width        || 
                           oldheight  !=  PReq->pr_Window->Height)
                        {
                          LG_FreeGadgets(PReq->pr_GadControl);
                          
                          WindowLimits(PReq->pr_Window,
                              PReq->pr_MinWidth  + PReq->pr_Window->BorderLeft + PReq->pr_Window->BorderRight,
                              PReq->pr_MinHeight + PReq->pr_Window->BorderTop  + PReq->pr_Window->BorderBottom ,
                              -1,-1);
                          
                          RefreshWindowFrame(PReq->pr_Window);
                          {
                            WORD x1,y1,x2,y2;
                            
                            x1=PReq->pr_Window->BorderLeft;
                            y1=PReq->pr_Window->BorderTop;
                            x2=PReq->pr_Window->Width  -PReq->pr_Window->BorderRight -1;
                            y2=PReq->pr_Window->Height -PReq->pr_Window->BorderBottom-1;
                            if(x2>x1 && y2>y1)
                              EraseRect(PReq->pr_Window->RPort,x1,y1,x2,y2);
                          }
                          
                          PReq->pr_WinLeft=PReq->pr_Window->LeftEdge;
                          PReq->pr_WinTop=PReq->pr_Window->TopEdge;
                          PReq->pr_WinWidth=PReq->pr_Window->Width;
                          PReq->pr_WinHeight=PReq->pr_Window->Height;
                          
                          PReq->pr_GadControl=pr_LayoutPaletteGads(PReq);
                          
                          LG_AddGadgets(PReq->pr_Window,PReq->pr_GadControl);
                          pr_UpdateSliders(PReq);
                          pr_DrawPenBox(PReq);
                        }
                        break;
                      case IDCMP_MOUSEMOVE:
                      case IDCMP_GADGETUP:
                        pr_ProcessPalGads(PReq,imsg);
                        break;
                      case IDCMP_VANILLAKEY:
                        pr_ProcessPalKeys(PReq,imsg);
                        break;
                      case IDCMP_MENUPICK:
                        pr_ProcessPalMenus(PReq,PReq->pr_MenuStrip,imsg);
                        break;            
                    }
                    GT_ReplyIMsg(imsg);
                  }
                }
                LG_FreeGadgets(PReq->pr_GadControl);
              }
              ClearMenuStrip(PReq->pr_Window);
            }
          } 
          FreeMenus(PReq->pr_MenuStrip);
        }
        
        PReq->pr_WinLeft  =PReq->pr_Window->LeftEdge;//                                                (4.61.2)
        PReq->pr_WinTop   =PReq->pr_Window->TopEdge;//                                                 (4.61.2)
        
        proc->pr_WindowPtr=winptr;
        CloseWindow(PReq->pr_Window);
      }
      FreeVisualInfo(PReq->pr_VisualInfo);
    }
  }  
}


void pr_DrawPenBox(struct PaletteRequest *PReq)
{
  DrawBevelBox(PReq->pr_Window->RPort,
              PReq->pr_PLeft,   PReq->pr_PTop,
              PReq->pr_PWidth,  PReq->pr_PHeight ,
                GTBB_Recessed,     1,
                GT_VisualInfo,     PReq->pr_VisualInfo,
                TAG_DONE);
  pr_DrawPenRect(PReq);
}

void pr_DrawPenRect(struct PaletteRequest *PReq)
{
  SetAPen (PReq->pr_Window->RPort, PReq->pr_ColorTable[PReq->pr_ActiveColor]);
  RectFill(PReq->pr_Window->RPort, 
                PReq->pr_PLeft+2,                       PReq->pr_PTop+1,
                PReq->pr_PLeft+PReq->pr_PWidth-3,       PReq->pr_PTop+PReq->pr_PHeight-2);
}




void pr_ProcessPalGads(struct PaletteRequest *PReq, struct IntuiMessage *IMsg)
{
  struct Gadget *gad;
  ULONG code,id;
  
  code=IMsg->Code;
  gad=(struct Gadget *)IMsg->IAddress;
  id=gad->GadgetID;
  
  switch(id)
  {
    case PGD_CANCEL:
      pr_PGD_Cancel(PReq);
      break;
    case PGD_OK:
      pr_PGD_Ok(PReq);
      break;
    case PGD_PALETTE:
      pr_PGD_PaletteModed(PReq,code,1,FALSE);
      break;
    case PGD_RED:
      pr_PGD_Red(PReq,code,FALSE);
      break;
    case PGD_GREEN:
      pr_PGD_Green(PReq,code,FALSE);
      break;
    case PGD_BLUE:
      pr_PGD_Blue(PReq,code,FALSE);
      break;
    case PGD_UNDO:
      pr_PGD_Undo(PReq);
      break;
    case PGD_RESET:
      pr_PGD_Reset(PReq);
      break;
    case PGD_COPY:
      pr_PGD_Copy(PReq);
      break;
    case PGD_SWAP:
      pr_PGD_Swap(PReq);
      break;
    case PGD_SPREAD:
      pr_PGD_Spread(PReq);
      break;
  }
}


void pr_ProcessPalKeys(struct PaletteRequest *PReq, struct IntuiMessage *Imsg)
{
//  struct LG_RetVal lgrv;
  WORD direction=1;
  ULONG gadid,code;
  
  /*
  lgrv=MatchKey2Gad(Imsg->Code,PReqLetters);
  
  if(lgrv.Char & 1) direction=-1;
*/

  if(LG_GadForKey(PReq->pr_GadControl,Imsg->Code,&gadid,&code))  
  {
    if(code&1) direction=-1;
    
    switch(gadid)
    {
      case PGD_PALETTE:
        pr_PGD_PaletteModed(PReq,direction,0,TRUE);
        break;
      case PGD_RED:
        pr_PGD_Red(PReq,direction,TRUE);
        break;
      case PGD_GREEN:
        pr_PGD_Green(PReq,direction,TRUE);
        break;
      case PGD_BLUE:
        pr_PGD_Blue(PReq,direction,TRUE);
        break;
      case PGD_RESET:
        pr_PGD_Reset(PReq);
        break;
      case PGD_UNDO:
        pr_PGD_Undo(PReq);
        break;
      case PGD_COPY:
        if(pr_PGD_Copy(PReq))
          pr_PGD_PaletteModed(PReq,0,1,TRUE);
        break;
      case PGD_SWAP:
        if(pr_PGD_Swap(PReq))
          pr_PGD_PaletteModed(PReq,0,1,TRUE);
        break;
      case PGD_SPREAD:
        if(pr_PGD_Spread(PReq))
          pr_PGD_PaletteModed(PReq,0,1,TRUE);
        break;
      case PGD_OK:
        pr_PGD_Ok(PReq);
        break;
      case PGD_CANCEL:
        pr_PGD_Cancel(PReq);
        break;
    }
  }
}

void pr_PGD_Cancel(struct PaletteRequest *PReq)
{
  PReq->pr_PalGo=FALSE;
  PReq->pr_RetVal=0;
}

void pr_PGD_Ok(struct PaletteRequest *PReq)
{
  PReq->pr_PalGo=FALSE;
  PReq->pr_RetVal=1;
}

/*
void pr_PGD_Palette(struct PaletteRequest *PReq, LONG Active, BOOL Keyed)
{
  LONG l;

  if(!Keyed)
  {
    for(l=0;l<PReq->pr_Colors;l++)
    {
      if(PReq->pr_ColorTable[l]==Active)
      {
        Active=l;
        break;
      }
    }
  }



  if(Keyed)
    Active+=PReq->pr_ActiveColor;


  if(Active<0)
    Active=PReq->pr_Colors-1;
  else
    if(Active>=PReq->pr_Colors)
      Active=0;
  
  PReq->pr_ActiveColor=Active;
  if(Keyed)
    LG_SetGadgetAttrs(PReq->pr_GadControl,PGD_PALETTE,
                        GTPA_Color,PReq->pr_ColorTable[Active],
                        TAG_DONE);


  pr_UpdateSliders(PReq);
}
*/
/*
void pr_PGD_PaletteModed(struct PaletteRequest *PReq, LONG Active, BOOL Keyed)
{
  LONG l;

  if(!Keyed)
  {
    for(l=0;l<PReq->pr_Colors;l++)
    {
      if(PReq->pr_ColorTable[l]==Active)
      {
        Active=l;
        break;
      }
    }
  }


  //printf("Active %d\n",Active);
  
  if(Active<0)
    Active=PReq->pr_Colors-1;
  else
    if(Active>=PReq->pr_Colors)
      Active=0;
      
  switch(PReq->pr_Mode)
  {
    case PRM_COPY:
      {
        ULONG color;
        
        pr_SetUndoBuffer(PReq);
    
        color=PReq->pr_ModeColor;
    
        PReq->pr_Palette[Active].Red    =PReq->pr_Palette[color].Red;
        PReq->pr_Palette[Active].Green  =PReq->pr_Palette[color].Green;
        PReq->pr_Palette[Active].Blue   =PReq->pr_Palette[color].Blue;      
      }
      break;
    case PRM_SWAP:
      {
        ULONG color,dr,dg,db;
    
        pr_SetUndoBuffer(PReq);
    
        color=PReq->pr_ModeColor;
      
        dr=PReq->pr_Palette[color].Red;
        dg=PReq->pr_Palette[color].Green;
        db=PReq->pr_Palette[color].Blue;        
    
        PReq->pr_Palette[color].Red    =PReq->pr_Palette[Active].Red;
        PReq->pr_Palette[color].Green  =PReq->pr_Palette[Active].Green;
        PReq->pr_Palette[color].Blue   =PReq->pr_Palette[Active].Blue;      
  
        PReq->pr_Palette[Active].Red   =dr;
        PReq->pr_Palette[Active].Green =dg;
        PReq->pr_Palette[Active].Blue  =db;
      }
      break;
    case PRM_SPREAD:
      {
        ULONG l,color,c1,c2,c3,r1,r2,g1,g2,b1,b2;
        float p;
        
        color=PReq->pr_ModeColor;
        
        pr_SetUndoBuffer(PReq);
        
        if(color>Active)
        {
          c1=Active;
          c2=color;
        }
        else
        {
          c1=color;
          c2=Active;
        }
        
        c3=c2-c1;
        
        if(c3>1)
        {
          r1=PReq->pr_Palette[c1].Red;
          g1=PReq->pr_Palette[c1].Green;
          b1=PReq->pr_Palette[c1].Blue;
          
          r2=PReq->pr_Palette[c2].Red;
          g2=PReq->pr_Palette[c2].Green;
          b2=PReq->pr_Palette[c2].Blue;
          for(l=c1+1;l<c2;l++)
          {
            p=(float)(l-c1)/(float)c3;
            PReq->pr_Palette[l].Red  =pr_Mix(r1,r2,p);
            PReq->pr_Palette[l].Green=pr_Mix(g1,g2,p);
            PReq->pr_Palette[l].Blue =pr_Mix(b1,b2,p);  
          }
        }
      }
      break;
  }
  PReq->pr_Mode=PRM_NORMAL;
  
  pr_SetPalette(PReq);
  pr_PGD_Palette(PReq,Active,Keyed);
}
*/

void pr_PGD_PaletteModed(struct PaletteRequest *PReq, LONG Active, BOOL DoModes, BOOL Keyed)
{
  LONG l,oactive;

  if(Keyed)
  {
    Active+=PReq->pr_ActiveColor;
  }
  else
  {
    {
      for(l=0;l<PReq->pr_Colors;l++)
      {
        if(PReq->pr_ColorTable[l]==Active)
        {
          Active=l;
          break;
        }
      }
    }
  }
  
  if(Active<0)
    Active=PReq->pr_Colors-1;
  else
    if(Active>=PReq->pr_Colors)
      Active=0;
      
  PReq->pr_ActiveColor=Active;

//  DKP("Activr color=%ld\n",Active);

  if(DoModes)
  {
    switch(PReq->pr_Mode)
    {
      case PRM_COPY:
        {
          ULONG color;
          
          pr_SetUndoBuffer(PReq);
      
          color=PReq->pr_ModeColor;
      
          PReq->pr_Palette[Active].Red    =PReq->pr_Palette[color].Red;
          PReq->pr_Palette[Active].Green  =PReq->pr_Palette[color].Green;
          PReq->pr_Palette[Active].Blue   =PReq->pr_Palette[color].Blue;      
        }
        pr_SetPalette(PReq);
        break;
      case PRM_SWAP:
        {
          ULONG color,dr,dg,db;
      
          pr_SetUndoBuffer(PReq);
      
          color=PReq->pr_ModeColor;
        
          dr=PReq->pr_Palette[color].Red;
          dg=PReq->pr_Palette[color].Green;
          db=PReq->pr_Palette[color].Blue;        
      
          PReq->pr_Palette[color].Red    =PReq->pr_Palette[Active].Red;
          PReq->pr_Palette[color].Green  =PReq->pr_Palette[Active].Green;
          PReq->pr_Palette[color].Blue   =PReq->pr_Palette[Active].Blue;      
    
          PReq->pr_Palette[Active].Red   =dr;
          PReq->pr_Palette[Active].Green =dg;
          PReq->pr_Palette[Active].Blue  =db;
        }
        pr_SetPalette(PReq);
        break;
      case PRM_SPREAD:
        {
          ULONG l,color,c1,c2,c3,r1,r2,g1,g2,b1,b2;
          float p;
          
          color=PReq->pr_ModeColor;
          
          pr_SetUndoBuffer(PReq);
          
          if(color>Active)
          {
            c1=Active;
            c2=color;
          }
          else
          {
            c1=color;
            c2=Active;
          }
          
          c3=c2-c1;
          
          if(c3>1)
          {
            r1=PReq->pr_Palette[c1].Red;
            g1=PReq->pr_Palette[c1].Green;
            b1=PReq->pr_Palette[c1].Blue;
            
            r2=PReq->pr_Palette[c2].Red;
            g2=PReq->pr_Palette[c2].Green;
            b2=PReq->pr_Palette[c2].Blue;
            for(l=c1+1;l<c2;l++)
            {
              p=(float)(l-c1)/(float)c3;
              PReq->pr_Palette[l].Red  =pr_Mix(r1,r2,p);
              PReq->pr_Palette[l].Green=pr_Mix(g1,g2,p);
              PReq->pr_Palette[l].Blue =pr_Mix(b1,b2,p);  
            }
          }
        }
        pr_SetPalette(PReq);
        break;
    }
    PReq->pr_Mode=PRM_NORMAL;
  }

  if(Keyed)
    LG_SetGadgetAttrs(PReq->pr_GadControl,PGD_PALETTE,
                        GTPA_Color,  PReq->pr_ColorTable[Active],
                        TAG_DONE);

  pr_UpdateSliders(PReq);
}

void pr_PGD_Red(struct PaletteRequest *PReq, LONG Value, BOOL Keyed)
{
  ULONG bitval;

  if(Keyed)
    Value+=PReq->pr_RedLevel;

  if(Value>PReq->pr_RedMax)
    Value=0;
  else
    if(Value<0)
      Value=PReq->pr_RedMax;

  
  PReq->pr_RedLevel=Value;

  if(PReq->pr_PrevColor!=PReq->pr_ActiveColor)
  {
    pr_SetUndoBuffer(PReq);
  }    
  bitval=Value*PReq->pr_RedMult;
  bitval=bitval |  bitval << 8 | bitval << 16 | bitval <<24;
  PReq->pr_Palette[PReq->pr_ActiveColor].Red=bitval;
  pr_SetPalette(PReq);
  if(Keyed)
    pr_UpdateSliders(PReq);
}

void pr_PGD_Green(struct PaletteRequest *PReq, LONG Value, BOOL Keyed)
{  
  ULONG bitval;

  if(Keyed)
    Value+=PReq->pr_GreenLevel;

  if(Value>PReq->pr_GreenMax)
    Value=0;
  else
    if(Value<0)
      Value=PReq->pr_GreenMax;

  PReq->pr_GreenLevel=Value;

  if(PReq->pr_PrevColor!=PReq->pr_ActiveColor)
  {
    pr_SetUndoBuffer(PReq);
  }
  bitval=Value*PReq->pr_GreenMult;
  bitval=bitval |  bitval << 8 | bitval << 16 | bitval <<24;
  PReq->pr_Palette[PReq->pr_ActiveColor].Green=bitval;
  pr_SetPalette(PReq);
  if(Keyed)
    pr_UpdateSliders(PReq);
}

void pr_PGD_Blue(struct PaletteRequest *PReq, LONG Value, BOOL Keyed)
{  
  ULONG bitval;

  if(Keyed)
    Value+=PReq->pr_BlueLevel;

  if(Value>PReq->pr_BlueMax)
    Value=0;
  else
    if(Value<0)
      Value=PReq->pr_BlueMax;

  PReq->pr_BlueLevel=Value;

  if(PReq->pr_PrevColor!=PReq->pr_ActiveColor)
  {
    pr_SetUndoBuffer(PReq);
  }
  bitval=Value*PReq->pr_BlueMult;
  bitval=bitval |  bitval << 8 | bitval << 16 | bitval <<24;
  PReq->pr_Palette[PReq->pr_ActiveColor].Blue=bitval;          
  pr_SetPalette(PReq);
  if(Keyed)
    pr_UpdateSliders(PReq);
}

void pr_PGD_Undo(struct PaletteRequest *PReq)
{
  pr_GetUndoBuffer(PReq);
  pr_UpdateSliders(PReq);
  pr_SetPalette(PReq);
}

void pr_PGD_Reset(struct PaletteRequest *PReq)
{
  pr_GetPalette(PReq);
  pr_UpdateSliders(PReq);
  pr_SetPalette(PReq);
}

BOOL pr_PGD_Copy(struct PaletteRequest *PReq)
{
  if( PReq->pr_Mode!=PRM_COPY)
  {
    PReq->pr_ModeColor=PReq->pr_ActiveColor;
    PReq->pr_Mode=PRM_COPY;
    return(FALSE);
  }
  else
    return(TRUE);
}

BOOL pr_PGD_Swap(struct PaletteRequest *PReq)
{
  if( PReq->pr_Mode!=PRM_SWAP)
  {
    PReq->pr_ModeColor=PReq->pr_ActiveColor;
    PReq->pr_Mode=PRM_SWAP;
     return(FALSE);
  }
  else
    return(TRUE);
}
BOOL pr_PGD_Spread(struct PaletteRequest *PReq)
{
  if( PReq->pr_Mode!=PRM_SPREAD)
  {
    PReq->pr_ModeColor=PReq->pr_ActiveColor;
    PReq->pr_Mode=PRM_SPREAD;
   return(FALSE);
  }
  else
    return(TRUE);
}

void pr_SetPalette(struct PaletteRequest *PReq)
{
  LONG l;
  
  if(PReq->pr_V39)
  {
    struct lrgb
    {
      WORD Colors,Index;
      LONG Red,Green,Blue;
      WORD Zero;
    } lrgb;

    lrgb.Colors=1;
    lrgb.Zero=0;

    for(l=0;l<PReq->pr_Colors;l++)
    {
      lrgb.Index=PReq->pr_ColorTable[l];
      lrgb.Red  =PReq->pr_Palette[l].Red;
      lrgb.Green=PReq->pr_Palette[l].Green;
      lrgb.Blue =PReq->pr_Palette[l].Blue;
      
      LoadRGB32(&PReq->pr_Window->WScreen->ViewPort,(ULONG *)&lrgb);
    }
  }
  else
  {
    UWORD palette;
    UWORD l;
    
    for(l=0;l<PReq->pr_Colors;l++)
      palette=((PReq->pr_Palette[l].Red   >> 28) & 0xf00) + 
              ((PReq->pr_Palette[l].Green >> 24) & 0xf0)  + 
              ((PReq->pr_Palette[l].Blue  >> 28) & 0xf);
      
      SetRGB4(&PReq->pr_Screen->ViewPort,PReq->pr_ColorTable[l],
                    (UBYTE)(PReq->pr_Palette[l].Red   >> 28),
                    (UBYTE)(PReq->pr_Palette[l].Green >> 28), 
                    (UBYTE)(PReq->pr_Palette[l].Blue  >> 28) );
    
  }
  pr_DrawPenRect(PReq);  
}

void pr_UpdateSliders(struct PaletteRequest *PReq)
{
  ULONG pen;
  
  pen=PReq->pr_ActiveColor;

  PReq->pr_RedLevel=PReq->pr_Palette[pen].Red>>(32-PReq->pr_RedBits);  
  LG_SetGadgetAttrs(PReq->pr_GadControl,PGD_RED,
                    GTSL_Level,PReq->pr_RedLevel,
                    TAG_DONE);
  
  PReq->pr_GreenLevel=PReq->pr_Palette[pen].Green>>(32-PReq->pr_GreenBits);
  LG_SetGadgetAttrs(PReq->pr_GadControl,PGD_GREEN,
                    GTSL_Level,PReq->pr_GreenLevel,
                    TAG_DONE);

  PReq->pr_BlueLevel=PReq->pr_Palette[pen].Blue>>(32-PReq->pr_BlueBits);
  LG_SetGadgetAttrs(PReq->pr_GadControl,PGD_BLUE,
                    GTSL_Level,PReq->pr_BlueLevel,
                    TAG_DONE);

  pr_DrawPenRect(PReq);
}

void pr_GetPalette(struct PaletteRequest *PReq)
{
  ULONG l;
  

  if(PReq->pr_InitialPalette)
  {
    for(l=0;l<PReq->pr_Colors;l++)
      PReq->pr_Palette[l]=PReq->pr_InitialPalette[l];
  }
  else
  { 
    if(PReq->pr_V39)
    {
      for(l=0;l<PReq->pr_Colors;l++)
      {
        GetRGB32(PReq->pr_Screen->ViewPort.ColorMap,PReq->pr_ColorTable[l],1,(ULONG *)&PReq->pr_Palette[l]);
      }
    }
    else
    {
      ULONG color;
      struct ColorMap *cm;
      
      cm=PReq->pr_Screen->ViewPort.ColorMap;
      for(l=0;l<PReq->pr_Colors;l++)
      {
        color=GetRGB4(cm,PReq->pr_ColorTable[l]);
        PReq->pr_Palette[l].Red  =(color & 0x00000f00) << 20;
        PReq->pr_Palette[l].Green=(color & 0xf0)       << 24;
        PReq->pr_Palette[l].Blue =(color & 0xf)        << 28;
      }
    }
  }
}

void pr_SetUndoBuffer(struct PaletteRequest *PReq)
{
  ULONG colors;
  
  colors=PReq->pr_Colors;
  
  CopyMem(PReq->pr_Palette, PReq->pr_UndoPalette, colors * sizeof(struct prRGB));
  PReq->pr_PrevColor=PReq->pr_ActiveColor;
}

void pr_GetUndoBuffer(struct PaletteRequest *PReq)
{
  ULONG l;
  struct prRGB dummy;
  
  for(l=0;l<PReq->pr_Colors;l++)
  {
    dummy=PReq->pr_UndoPalette[l];
    PReq->pr_UndoPalette[l]=PReq->pr_Palette[l];
    PReq->pr_Palette[l]=dummy;
  }
}

ULONG pr_Mix(ULONG A,ULONG B, float Percent)
{
  float a,b,diff;
  
  a=A;
  b=B;
  
  diff=b-a;

  a+=diff*Percent;

  return((ULONG) (a));
}



void pr_ProcessPalMenus(struct PaletteRequest *PReq,  struct Menu *MenuStrip, struct IntuiMessage *imsg)
{
  UWORD  menunumber,ns;
  ULONG  menuid;
  struct MenuItem *mi;
  
  menunumber=imsg->Code;
  mi=ItemAddress(MenuStrip,menunumber);
  if(mi)
  do
  {
    menuid=(ULONG)(GTMENUITEM_USERDATA(mi));
    switch(menuid)
    {
      case M_PALETTELOAD:
        if(pr_SelectPaletteFile(PReq,GetString(MSG_PRM_LOADPALETTE),0,PReq->pr_Window))
        {
//          CopyMem(PReq->pr_Palette,palette,PReq->pr_Colors*sizeof(struct prRGB));
          pr_SetUndoBuffer(PReq);
          if(pr_ReadCMAP(PReq->pr_FileName,PReq->pr_Palette,PReq->pr_Colors))
          {

//            CopyMem(palette,PReq->pr_Palette,PReq->pr_Colors*sizeof(struct prRGB));
            pr_SetPalette(PReq);
            pr_UpdateSliders(PReq);
          }
        }
        break;
        
      case M_PALETTESAVE:
        if(pr_SelectPaletteFile(PReq,GetString(MSG_PRM_SAVEPALETTE),1,PReq->pr_Window))
        {
          if(!pr_SaveCMAP(PReq->pr_FileName,PReq->pr_Palette,PReq->pr_Colors))
          {
            LONG error;
//            UBYTE errstr[91];

            if(error=IoErr())
            {
//              Fault(error,MiscText[SAVE_ERROR],errstr,90);
//              EZReq(PReq->pr_Window,0,ModePro,errstr,MiscText[OK],0);
            }
          }
        }
        break;
        
      case M_PALETTEOK:
        PReq->pr_PalGo=FALSE;
        PReq->pr_RetVal=1;
        break;
        
      case M_PALETTECANCEL:
        PReq->pr_PalGo=FALSE;
        PReq->pr_RetVal=0;
        break;
      
    }
    ns=mi->NextSelect;
    mi=ItemAddress(MenuStrip,mi->NextSelect);
  }while(ns!= MENUNULL && mi);
}


BOOL pr_SelectPaletteFile(struct PaletteRequest *PReq, UBYTE *title,UBYTE save,struct Window *Parent)
{ 
  WORD width;
  
  if(!PReq->pr_FileReq)
  {
    width=Parent->Width/2;
    PReq->pr_FileReq=(struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, 
                    ASLFR_TextAttr,        PReq->pr_TextAttr,
                    ASLFR_InitialTopEdge,  Parent->TopEdge+8,
                    ASLFR_InitialLeftEdge, Parent->LeftEdge+width/2,
                    ASLFR_InitialWidth,    width,
                    ASLFR_InitialHeight,   Parent->Height-16,
                    ASLFR_DoPatterns  ,    TRUE,
                    ASLFR_InitialPattern,  "#?",
                    ASLFR_RejectIcons,     TRUE,
                    ASLFR_PrivateIDCMP,    TRUE,
                    TAG_DONE); 
  }
  if(PReq->pr_FileReq)
  {
    if(AslRequestTags(PReq->pr_FileReq, 
                  ASLFR_Window   ,       Parent,
                  ASLFR_SleepWindow,     TRUE,
                  ASLFR_TitleText,       title,
                  ASLFR_DoSaveMode,      save,
                  TAG_DONE))
    {
      strncpy(PReq->pr_FileName,PReq->pr_FileReq->fr_Drawer,512);
      if(AddPart(PReq->pr_FileName,PReq->pr_FileReq->fr_File,512))
        return(TRUE);
    }   
  }
  return(FALSE);
}


BOOL pr_ReadCMAP(STRPTR Filename, struct prRGB *CReg, ULONG Colors)
{
  struct IFFHandle *iff;
  struct StoredProperty *sp;
//  struct BitMapHeader   *bmhd;
  struct ColorRegister  *cmap;
  LONG l;
  
  LONG error=0;
  BOOL rv; 

  rv=0;

  if(iff=AllocIFF())
  { 
    if(iff->iff_Stream = Open (Filename,MODE_OLDFILE))
    {
      InitIFFasDOS(iff);
      if(!(error=OpenIFF(iff,IFFF_READ)) )
      {
        if (!(error=PropChunk(iff,ID_ILBM,ID_CMAP)))
        {
          if(!(error=StopOnExit(iff,ID_ILBM,ID_FORM)))           
          {
            if((error=ParseIFF(iff,IFFPARSE_SCAN))>-3)
            {
              if(sp=FindProp(iff,ID_ILBM,ID_CMAP))
              {
                cmap    =(struct ColorRegister *)sp->sp_Data;
                Colors  =min(sp->sp_Size/3,Colors);
                for(l=0;l<Colors;l++)
                {
                  CReg[l].Red  =cmap[l].red   * 0x01010101;
                  CReg[l].Green=cmap[l].green * 0x01010101;
                  CReg[l].Blue =cmap[l].blue  * 0x01010101;
                }
                rv=1;
              }
            }/* end ParseIFF if */        
          }
        } /* End Prop MPPR */
        CloseIFF(iff);
      }
      Close(iff->iff_Stream);
    }
    FreeIFF(iff);
  }
  
  return(rv);
}


BOOL pr_SaveCMAP(STRPTR Filename, struct prRGB *CReg, ULONG Colors)
{
  struct ColorRegister cmap[256];
  struct IFFHandle *iff;   
  ULONG l;
  LONG error;
  
  SetIoErr(0);
  
  error=1;
  if(iff=AllocIFF())
  { 
    if(iff->iff_Stream = Open (Filename,MODE_NEWFILE))
    {
      InitIFFasDOS(iff);
      if( !(error=OpenIFF(iff,IFFF_WRITE)) )
      {
        if(!(error=PushChunk(iff,ID_ILBM,ID_FORM, IFFSIZE_UNKNOWN)))
        {
          if(!(error=PushChunk(iff,ID_ILBM,ID_CMAP, Colors * sizeof(cmap[0]))))
          {
            for(l=0;l<Colors;l++)
            {
              cmap[l].red   =CReg[l].Red>>24;
              cmap[l].green =CReg[l].Green>>24;
              cmap[l].blue  =CReg[l].Blue>>24;
            }
            error=WriteChunkBytes(iff,cmap,Colors * sizeof(cmap[0]));
          }
          error|=PopChunk(iff);
        }
        CloseIFF(iff);
      }
      Close(iff->iff_Stream);
    }
    FreeIFF(iff);
  }
  if(error<0)
    return(FALSE);
  else
    return(TRUE);
}
