/****************************************************************************
 *	ColorSaver --- A popup color palette commodity
 *
 *	05 January 1993
 *	Compiled with DICE
 *
 *	Copyright © 1993, 1994 By Dan Fish
 *	All rights reserved.
 *
 *	Permission is granted to freely redistribute this program provided 
 *	the source code and documentation are included in the distribution,
 *	changes are clearly documented, and this copyright notice remains
 *      unchanged.
 *
 ****************************************************************************/


#include <exec/memory.h>                        /*N*/
#include <clib/macros.h>                        /*N*/
#include <libraries/commodities.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <workbench/startup.h>

#include <stdlib.h>                             
#include <string.h>                             
#include <stdarg.h>                             
#include <stdio.h>

#include <clib/exec_protos.h>
#include <clib/commodities_protos.h>
#include <clib/utility_protos.h>
#include <clib/intuition_protos.h>
#include <clib/alib_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>

#include "gadgets.h"       		/* GadToolsBox file 	*/
#include "protos.h"			/* Routine prototypes	*/
#include "simplerexx.h"			/* ARexx stuff		*/
#include "defs.h"

/*-------------------------------------------------------------------------
 * The following strings represent the
 * possible tooltypes of the ColorSaver icon.
 *-------------------------------------------------------------------------*/

UBYTE   *CX_PRIORITY        =       "CX_PRIORITY";
UBYTE   *CX_POPUP           =       "CX_POPUP";
UBYTE   *CX_POPKEY          =       "CX_POPKEY";
UBYTE   *CX_QUIT            =       "CX_QUIT";
UBYTE   *CX_HSV 	    =       "HSV";
UBYTE   *CX_SEL 	    =       "SELECT";
UBYTE   *CX_PATH            =       "PATH";
UBYTE   *CX_POP_X           =       "POP_X";
UBYTE   *CX_POP_Y           =       "POP_Y";

/*-------------------------------------------------------------------------
 * Following are the default ColorSaver
 * settings which can be changed with
 * the command line or the icon tooltypes.
 *-------------------------------------------------------------------------*/

#define  CX_DEFPRI           0
#define  CX_DEFSEL           0
#define  CX_DEFPOP_X       175
#define  CX_DEFPOP_Y        50
UBYTE   *CX_DEFPOPKEY       =       "lalt ralt c";
UBYTE   *CX_DEFPOPUP        =       "YES";
UBYTE   *CX_DEFMODE         =       "RGB";
UBYTE   *CX_DEFQUIT         =       "lalt ralt q";
UBYTE   *CX_DEFPATH         =       "SYS:Prefs/Presets";

/*-------------------------------------------------------------------------
 * Some Commodity definitions
 *-------------------------------------------------------------------------*/

#define  CX_SHOW            1L                      /* show window */
#define  CX_SHUTUP          2L                      /* quit ColorSaver */
#define  CxOn( b )          ActivateCxObj( b, TRUE )
#define  CxOff( b )         ActivateCxObj( b, FALSE );

/*-------------------------------------------------------------------------
 * I used this stuff for debugging
 *-------------------------------------------------------------------------*/
#ifdef CS_DEBUG
UBYTE *conwinname   = "CON:10/10/620/180/CS_Debug";
FILE *conwin = NULL;
#endif

/*-------------------------------------------------------------------------
 * Miscellaneous program information.
 *-------------------------------------------------------------------------*/

#define  CSVersion          "v1.19"
#define  CSName             "ColorSaver"
#define  CSDescr            "Color Palette Tool"
#define  CSCopy             "© 1994, Dan Fish"
#define  CSDate             "(10.12.1994)"
#define  CSTitle            CSName " " CSVersion ", " CSCopy

/*-------------------------------------------------------------------------
 * Shell version string.
 *-------------------------------------------------------------------------*/
#define  CSVerString        "$VER:" CSName " "CSVersion " "CSDate"\r\n"
static UBYTE CsVer[]        = {  CSVerString  };

/*-------------------------------------------------------------------------
 * The NewBroker structure defining
 * some important information for
 * the commodities.library and Exchange.
 *-------------------------------------------------------------------------*/

struct NewBroker             CSNBrok  = {
    NB_VERSION, CSName, CSTitle, CSDescr,
    NBU_NOTIFY | NBU_UNIQUE, COF_SHOW_HIDE, NULL, 0
};

/*-------------------------------------------------------------------------
 * DCBack required data. DCBack is a tiny link library
 * written by Jan van den Baard to make it possible to write
 * auto-detachable programs with DICE. DCBack also parses the
 * argument line for you using ReadArgs().
 *-------------------------------------------------------------------------*/

UBYTE                       *_procname      = CSName "_" CSVersion;
UBYTE                       *_template      = "PRIORITY/K/N,POPUP/K,POPKEY/K,QUIT/K,POP_X/K/N,POP_Y/K/N,PATH/K,SELECT/K/N,HSV/S";
UBYTE                       *_exthelp       = NULL;
LONG                         _stack         = 4096L;
LONG                         _priority      = NULL;
LONG                         _BackGroundIO  = NULL;

/*-------------------------------------------------------------------------
 * ARexx declarations
 *-------------------------------------------------------------------------*/

AREXXCONTEXT	RexxStuff;
UBYTE RexxName[64];

/*-------------------------------------------------------------------------
 * Required libraries that are not in DICE's
 * auto-init library.
 *-------------------------------------------------------------------------*/

struct Library              *CxBase        = NULL;
struct Library              *IconBase      = NULL;
struct Library              *WorkbenchBase = NULL;

/*-------------------------------------------------------------------------
 * The following libraries are all auto-init.
 *-------------------------------------------------------------------------*/

extern struct IntuitionBase        *IntuitionBase;
extern struct UtilityBase          *UtilityBase;
extern struct GadToolsBase         *GadToolsBase;

/*-------------------------------------------------------------------------
 * Some other useful global variables
 *-------------------------------------------------------------------------*/

struct MsgPort          *CSComPort  = NULL;	/* commodity port	*/
struct MsgPort          *CSIdPort   = NULL;     /* IDCMP port		*/
CxObj                   *CSBroker   = NULL;	/* the broker		*/
ULONG                    CSMask     = NULL;	/* the port bit-mask 	*/
ULONG                    CSIdMask   = NULL;     /* IDCMP port bit-mask	*/
ULONG                    RexxMask   = NULL;     /* ARexx port bit-mask	*/
UBYTE                   *CSTTypes   = NULL;	/* the tooltype array	*/
ULONG                   *CSArgs;		/* shell args array	*/
struct Screen 		*Scr        = NULL;	/* screen we open up on	*/
struct WBStartup        *WbMsg      = NULL;     /* workbench message	*/
UBYTE                   *CSPopkey;              /* popkey string ptr	*/
UBYTE                   *Palette_Dir;           /* default palette path */
UBYTE                    CSIsOpen   = FALSE;    /* window open? 	*/
UBYTE                    CSPop      = TRUE;     /* open on startup?	*/
UBYTE                    CSWTitle[80];          /* window title 	*/
UWORD                    ColorSaverLeft;	/* left edge of window  */
UWORD                    ColorSaverTop;		/* top edge of window   */
UWORD 			 RedVal;		/* RGB red value	*/
UWORD 			 GreenVal;		/* RGB green value	*/
UWORD 			 BlueVal;		/* RGB blue value	*/
UWORD 			 HueLevel;		/* HSV hue 		*/
UWORD 			 SatLevel;              /* HSV saturation	*/
UWORD 			 ValLevel;              /* HSV value 		*/
ULONG			 NumColors;		/* # of colors in palette   */
SHORT			 CurrentColor=0;	/* Currently selected color */
USHORT              	*ResetPal = NULL;	/* Palette w/window first opens */
USHORT              	*SavePal = NULL;       	/* Snapshot of current palette*/
UBYTE   		 ScanFileSpec[256];	/* filename for binary scan */
UWORD  		         CycleSelect = 0;	/* ordinal value of cycle gad */
USHORT			 ColorMode = RGB_COLORMODE;	/* Color selection mode	    */

UBYTE   LoadFile[32];		
UBYTE   LoadDir[224];		
UBYTE   ScanFile[32];		
UBYTE   ScanDir[224];		
UBYTE   FileSpec[224];

/*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
 *
 *    E X E C U T A B L E      C O D E      B E G I N S    H E R E 
 *
 *=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*/

/*=============================================================================
 * Starting point if called from the Shell
 *===========================================================================*/

void main( long argc, long *array )
{
    CSArgs = array;

    SetupCS();
    EventHandler();
    CloseDownCS( NULL );
}

/*=============================================================================
 * Starting point if called from the WorkBench
 *===========================================================================*/

void wbmain( struct WBStartup *wbs )
{
    WbMsg = wbs;

    SetupCS();
    EventHandler();
    CloseDownCS( NULL );
}

/*-------------------------------------------------------------------------
 * Open up all required resources. Check the
 * arguments passed to ColorSaver from the argument
 * line if run from the shell or the tool types
 * when run from the workbench.
 *-------------------------------------------------------------------------*/

void SetupCS( void )
{
    CxObj           *tmp;
    UBYTE           *quitkey, *popup;
    WORD             priority;
    LONG             error;
    UBYTE 	    *str;

    /*  Initialize all the file names/paths	*/

    LoadFile[0] = '\0';
    ScanFile[0] = '\0';
    ScanDir[0]  = '\0';


    if ( ! ( CxBase = OpenLibrary( "commodities.library", 37L ))) {
        error = 20L;
    	CloseDownCS( error );
    }

   /*
    * This one is required by the Argxxxx()
    * routines from the amigas20.lib.
    */

    if ( ! ( IconBase = OpenLibrary( "icon.library", 34L ))) {
        error = 21L;
    	CloseDownCS( error );
    }

    if ( ! ( WorkbenchBase = OpenLibrary( "workbench.library", 37L ))) {
        error = 22L;
    	CloseDownCS( error );
    }

#ifdef CS_DEBUG
    if(!(conwin = fopen(conwinname,"r+"))){
        error = 30;
 	CloseDownCS( error );
      }
#endif

/*-------------------------------------------------------------------------
 * When WbMsg is non-null it means that  ColorSaver was started from the
 * workbench, otherwise it was started from the shell.
 *-----------------------------------------------------------------------*/

    if ( WbMsg ) {

       CSTTypes = ( UBYTE * )ArgArrayInit( NULL, ( UBYTE ** )WbMsg );

       priority = ArgInt(( char ** )CSTTypes, CX_PRIORITY, CX_DEFPRI );
       popup    = ArgString(( char ** )CSTTypes, CX_POPUP,    CX_DEFPOPUP  );
       CSPopkey = ArgString(( char ** )CSTTypes, CX_POPKEY,   CX_DEFPOPKEY );
       quitkey  = ArgString(( char ** )CSTTypes, CX_QUIT,     CX_DEFQUIT   );
       ColorSaverLeft = ArgInt(( char ** )CSTTypes, CX_POP_X,  CX_DEFPOP_X );
       ColorSaverTop = ArgInt(( char ** )CSTTypes, CX_POP_Y,  CX_DEFPOP_Y  );
       Palette_Dir = ArgString(( char ** )CSTTypes, CX_PATH,  CX_DEFPATH   );
       CurrentColor  = ArgInt(( char ** )CSTTypes, CX_SEL,   CX_DEFSEL     );

       if( ArgString(( char ** )CSTTypes, CX_HSV,NULL))
	    ColorMode = HSV_COLORMODE;

    } else {   /* started from shell */

        if ( CSArgs[ 0 ] )  priority = ( WORD )*(( ULONG * )CSArgs[ 0 ] );
        else                priority = CX_DEFPRI;
        if ( CSArgs[ 1 ] )  popup    = ( UBYTE * )CSArgs[ 1 ];
        else                popup    = CX_DEFPOPUP;
        if ( CSArgs[ 2 ] )  CSPopkey = ( UBYTE * )CSArgs[ 2 ];
        else                CSPopkey = CX_DEFPOPKEY;
        if ( CSArgs[ 3 ] )  quitkey  = ( UBYTE * )CSArgs[ 3 ];
        else                quitkey  = CX_DEFQUIT;
        if ( CSArgs[ 4 ] )  ColorSaverLeft = ( UWORD )*((ULONG *)CSArgs[ 4 ]);
        else                ColorSaverLeft = CX_DEFPOP_X;
        if ( CSArgs[ 5 ] )  ColorSaverTop = ( UWORD )*((ULONG *)CSArgs[ 5 ]);
        else                ColorSaverTop = CX_DEFPOP_Y;
        if ( CSArgs[ 6 ] )  Palette_Dir = ( UBYTE * )CSArgs[ 6 ];
        else                Palette_Dir  = CX_DEFPATH;
        if ( CSArgs[ 7 ] )  CurrentColor = ( SHORT )*(( ULONG * )CSArgs[ 7 ] );
        else                CurrentColor  = CX_DEFSEL;
        if ( CSArgs[ 8 ] )  ColorMode  = HSV_COLORMODE;

#ifdef CS_DEBUG

    if(CSArgs[0])
      fprintf(conwin,"CSArgs[0] = %x, %d\n",CSArgs[0], priority);
    if(CSArgs[1])
      fprintf(conwin,"CSArgs[1] = %s\n",CSArgs[1]);
    if(CSArgs[2])
      fprintf(conwin,"CSArgs[2] = %s\n",CSArgs[2]);
    if(CSArgs[3])
      fprintf(conwin,"CSArgs[3] = %s\n",CSArgs[3]);
    if(CSArgs[4])
      fprintf(conwin,"CSArgs[4] = %s\n",CSArgs[4]);
    if(CSArgs[5])
      fprintf(conwin,"CSArgs[5] = %x, %d\n",CSArgs[5], CurrentColor);
    if(CSArgs[6])
      fprintf(conwin,"CSArgs[6] = HSV\n");
    fflush(conwin);
#endif

    }

/*
 * If a palette path tooltype was specified, use it...
 * If a palette path tooltype was NOT specified (or the default was 
 * specified), check for an environment variable.  If the environment 
 * variable exists, use it... otherwise use the default path
 */

    strcpy(LoadDir,CX_DEFPATH);
    if((str = getenv("CS_PALETTES")) != NULL)
       strcpy(LoadDir,str);

    if (stricmp(Palette_Dir, CX_DEFPATH) != 0)
       strcpy(LoadDir,Palette_Dir);

    strcpy(RexxName,"ColorSaver.");
    RexxStuff=InitARexx(RexxName,NULL);
    RexxMask = ARexxSignal(RexxStuff);

    if(!(ResetPal = AllocMem(64L,MEMF_PUBLIC)))
      CloseDownCS( 43L );

    if(!(SavePal = AllocMem(64L,MEMF_PUBLIC)))
      CloseDownCS( 44L );

    CSNBrok.nb_Pri = priority;

    if ( Stricmp( popup, CX_DEFPOPUP )) CSPop = FALSE;

    if ( CSComPort = CreateMsgPort()) {

        CSMask          = ( 1L << CSComPort->mp_SigBit );
        CSNBrok.nb_Port = CSComPort;

        if ( CSBroker = CxBroker( &CSNBrok, NULL )) {
            if ( tmp = HotKey( CSPopkey, CSComPort, CX_SHOW )) {

                AttachCxObj( CSBroker, tmp );

                if ( tmp = HotKey( quitkey, CSComPort, CX_SHUTUP )) {

                    AttachCxObj( CSBroker, tmp );

                    if ( ! CxObjError( CSBroker )) {
                        CxOn( CSBroker );
                        return;  
                    } else
                        error = 24L;
                } else
                    error = 25L;
            } else
                error = 26L;
        } else
            error = 27L;
    } else
        error = 28L;

CloseDownCS( error );

}

/*=============================================================================
 * Here it is...
 * The main program loop which wait for events from the different ports set
 * up... Commodity, IDCMP, ARexx 
 *===========================================================================*/

void EventHandler( void )
{
    ULONG      sig;
    UBYTE      running = TRUE;

   /*
    * Open ColorSaver window when
    * CX_POPUP is YES.
    */

    if ( CSPop ) OpenTheWindow();
 
    /*
     * Wait for the commodity, ARexx, and (if open) the window ports.
     */
    do {
        sig = Wait( CSMask | CSIdMask | RexxMask);

        if (( sig & CSMask ) == CSMask ) running = HandleCXEvent();
        if (( sig & CSIdMask ) == CSIdMask )
            if ( CSIsOpen ) running = HandleIDCMPEvent();
        if (( sig & RexxMask ) == RexxMask ) running = HandleARexxEvent();
       
    } while ( running );

    CloseTheWindow();
    CxOff( CSBroker );
}

void GetScrInfo( void )
{
   Scr = IntuitionBase->FirstScreen;   
   NumColors = (1L << Scr->BitMap.Depth);
 }

void ResetPalette( int mode )
{
  if(mode == RETRIEVE_IT)
    {
     LoadRGB4(&Scr->ViewPort,ResetPal,1L << Scr->BitMap.Depth);
     SetProps(CurrentColor);
   }
  if(mode == STORE_IT)
    CopyMem((void *)Scr->ViewPort.ColorMap->ColorTable,(void *)ResetPal,64L);

 }

/*=============================================================================
 * Open up the ColorSaver window and get
 * the pointer to the userport and
 * the port it's bit mask.
 *===========================================================================*/

void OpenTheWindow()
{

   if(!CSIsOpen )
    {
        GetScrInfo();             /* Get Screen pointer            */
	ResetPalette(STORE_IT);   /* Store colors for "UNDO"       */

        CSIsOpen = TRUE;

        strcpy( CSWTitle, CSTitle);
        ColorSaverWdt = &CSWTitle[0];

        if ( SetupScreen()) {
            CloseTheWindow();
            return;
        }

        if ( OpenColorSaverWindow()) {
            CloseTheWindow();
            return;
        }

	SetOurPointer(MAIN_POINTER, TRUE);

	SetColorMode(ColorMode);
	SetPaletteColor(CurrentColor);
	SetProps(CurrentColor);

        CSIdPort = ColorSaverWnd->UserPort;
        CSIdMask = ( 1L << CSIdPort->mp_SigBit );

        return;
    }
}

/*=============================================================================
 * Close the ColorSaver window, clear the userport and bit mask
 *===========================================================================*/

void CloseTheWindow( void )
{
    if ( CSIsOpen ) {
        ResetPointerColors();
        CloseColorSaverWindow();
        CloseDownScreen();
        CSIdPort = NULL;
        CSIdMask = NULL;
        CSIsOpen = FALSE;
    }
}

/*=============================================================================
 * Close down and "KILL" ColorSaver, deallocating system resources
 *===========================================================================*/

void CloseDownCS( __D0 LONG code )
{
    struct Message      *tmp;

    if ( CSBroker      )    DeleteCxObjAll( CSBroker );
    if ( CSComPort     ) {
        while ( tmp = GetMsg( CSComPort )) ReplyMsg( tmp );
        DeleteMsgPort( CSComPort );
    }
    if ( ResetPal      )    FreeMem(ResetPal,64L);
    if ( SavePal       )    FreeMem(SavePal,64L);
    if ( RexxStuff     )    FreeARexx(RexxStuff);
    if ( CSTTypes      )    ArgArrayDone();
    if ( WorkbenchBase )    CloseLibrary( WorkbenchBase );
    if ( IconBase      )    CloseLibrary( IconBase );
    if ( CxBase        )    CloseLibrary( CxBase );

#ifdef CS_DEBUG
    if ( conwin        )    fclose(conwin);
#endif

    exit( code );
}

/*=============================================================================
 * Handle Commodity events...
 *===========================================================================*/

BOOL HandleCXEvent( void )
{
    struct Message          *msg;
    ULONG                    type, id;
    UBYTE                    running = TRUE;

    /*
     * A commodity message came through.
     */
      while ( msg = GetMsg( CSComPort )) {

          id      = CxMsgID(( CxMsg * )msg );
          type    = CxMsgType(( CxMsg * )msg );
          ReplyMsg( msg );

          switch ( type ) {

              case    CXM_IEVENT:
                  switch ( id ) {

                      case    CX_SHOW:
                          OpenTheWindow();
                          break;

                      case    CX_SHUTUP:
                          running = FALSE;
                          break;
                  }
                  break;

              case    CXM_COMMAND:
                  switch ( id )  {

                      case    CXCMD_KILL:
                          running = FALSE;
                          break;

                      case    CXCMD_DISABLE:
                          CxOff( CSBroker );
                          break;

                      case    CXCMD_ENABLE:
                          CxOn( CSBroker );
                          break;

                      case    CXCMD_UNIQUE:
                      case    CXCMD_APPEAR:
                          OpenTheWindow();
                          break;

                      case    CXCMD_DISAPPEAR:
                          CloseTheWindow();
                          break;
                  }
                  break;
          }
      }

   return(running);
}

/*=============================================================================
 * Handle IDCMP events...
 *===========================================================================*/

BOOL HandleIDCMPEvent( void )
{
    struct IntuiMessage     *imsg;
    struct Gadget           *gad;
    BOOL                     hideit;
    ULONG                    class;
    UWORD                    code;
    UBYTE                    running = TRUE;

      /*
       * A window message came through.
       */
        while ( CSIdPort && ( imsg = GT_GetIMsg( CSIdPort ))) {

            class   =   imsg->Class;
            code    =   imsg->Code;
            gad     =   ( struct Gadget * )imsg->IAddress;
            GT_ReplyIMsg( imsg );

            switch ( class ) {

                case    IDCMP_REFRESHWINDOW:
                    GT_BeginRefresh( ColorSaverWnd );
                    GT_EndRefresh( ColorSaverWnd, TRUE );
                    break;

                case    IDCMP_CLOSEWINDOW:
                    hideit =Req("Hide|Quit",
		    "Which do you prefer ?");
                    CloseTheWindow();
        	    if(!hideit)
	               running = FALSE;
                    break;

                case    IDCMP_CHANGEWINDOW:
                    ColorSaverLeft = ColorSaverWnd->LeftEdge;
                    ColorSaverTop  = ColorSaverWnd->TopEdge;
                    break;

                case    IDCMP_GADGETUP:
                case    IDCMP_GADGETDOWN:
                case    IDCMP_MOUSEMOVE:
                    HandleGadgetEvent(gad,code);
                    break;

                case IDCMP_VANILLAKEY:
                    HandleVanillaKey(code);
                    break;
            }
        }

   return(running);
}

/*=============================================================================
 * Handle gadget selections...
 *===========================================================================*/

VOID HandleGadgetEvent( struct Gadget *gad, UWORD code )
{

 static BOOL copymode;
 static BOOL swapmode;
 static BOOL rangemode;
 static SHORT copycolor;
 static UBYTE swapred;
 static UBYTE swapgreen;
 static UBYTE swapblue;

 if(gad->GadgetID != GD_PALETTE_GAD)
   if(copymode || swapmode || rangemode)
     {
    	copymode = swapmode = rangemode = FALSE;
	SetOurPointer(MAIN_POINTER, FALSE);
     }

 switch (gad->GadgetID)
    {
      
    case  GD_RED_GAD:
	if(ColorMode == HSV_COLORMODE)
          {
	   HueLevel = code; 
  	   CalcRGB();
          }
  	else
	   RedVal = code;

	SetRGB4(&Scr->ViewPort,CurrentColor,RedVal,GreenVal,BlueVal);
        break;

    case  GD_GREEN_GAD:
	if(ColorMode == HSV_COLORMODE)
          {
	   SatLevel = code;
  	   CalcRGB();
          }
	else
	   GreenVal=code;

	SetRGB4(&Scr->ViewPort,CurrentColor,RedVal,GreenVal,BlueVal);
        break;

    case  GD_BLUE_GAD:
	if(ColorMode == HSV_COLORMODE)
          {
	   ValLevel=code;
  	   CalcRGB();
          }
	else
	   BlueVal=code;

	SetRGB4(&Scr->ViewPort,CurrentColor,RedVal,GreenVal,BlueVal);
        break;

    case  GD_PALETTE_GAD:
	CurrentColor=(SHORT)code;
        if(copymode)
          {
	   GetColors(copycolor);
	   SetRGB4(&Scr->ViewPort,CurrentColor,RedVal,GreenVal,BlueVal);
 	  }
	else if(swapmode)
          {
	   GetColors(CurrentColor);
	   swapred = RedVal;
	   swapgreen = GreenVal;
	   swapblue = BlueVal;
	   GetColors(copycolor);
	   SetRGB4(&Scr->ViewPort,CurrentColor,RedVal,GreenVal,BlueVal);
	   SetRGB4(&Scr->ViewPort,copycolor,swapred,swapgreen,swapblue);
 	  }

	else if(rangemode)
	   ColorRange(copycolor,CurrentColor);

        if(copymode || swapmode || rangemode)
	   SetOurPointer(MAIN_POINTER, FALSE);

	SetProps(CurrentColor);
    	copymode = swapmode = rangemode = FALSE;
        break;

    case  GD_COMP_GAD:
	SetRGB4(&Scr->ViewPort,CurrentColor,(UBYTE)15-RedVal,
          (UBYTE)15-GreenVal,(UBYTE)15-BlueVal);	
	SetProps(CurrentColor);
        break;

    case  GD_COPY_GAD:
	copycolor = CurrentColor;
        copymode = TRUE;
	SetOurPointer(TO_POINTER, FALSE);
        break;

    case  GD_SWAP_GAD:
	copycolor = CurrentColor;
        swapmode = TRUE;
	SetOurPointer(TO_POINTER, FALSE);
        break;

    case  GD_RANGE_GAD:
	copycolor = CurrentColor;
        rangemode = TRUE;
	SetOurPointer(TO_POINTER, FALSE);
        break;

    case  GD_SLEFT_GAD:
	ShiftColorsLeft();
	SetProps(CurrentColor);
        break;

    case  GD_SRIGHT_GAD:
	ShiftColorsRight();
	SetProps(CurrentColor);
        break;

    case  GD_RESET_GAD:
	ResetPalette(RETRIEVE_IT);
        break;

    case  GD_LOAD_GAD:
	if(FileSelect(FILELOAD,LoadDir,LoadFile))
	   LoadColors(FileSpec, NumColors );
	SetProps(CurrentColor);
        break;

    case  GD_SAVE_GAD:
	if(FileSelect(FILESAVE,LoadDir,LoadFile))
	   SaveColors(FileSpec, NumColors );
        break;

    case  GD_OKAY_GAD:
        CloseTheWindow();
        break;

    case  GD_DO_GAD:
        CopyMem((void *)Scr->ViewPort.ColorMap->ColorTable,(void *)ResetPal,64L);
        break;

    case  GD_CANCEL_GAD:
	ResetPalette(RETRIEVE_IT);
        CloseTheWindow();
        break;

    case  GD_SCAN_GAD:
	if(FileSelect(FILESCAN,ScanDir,ScanFile))
           FindTable(FileSpec, ResetPal, NumColors);
        break;

    case  GD_CYCLE_GAD:
        CycleSelect = code;
        break;

    case  GD_WRITE_GAD:
        CopyMem((void *)Scr->ViewPort.ColorMap->ColorTable,(void *)SavePal,64L);
        Patch(ScanFileSpec, SavePal, NumColors);
        break;

    case  GD_EXTRA_GAD:
	About();
        break;

    case  GD_RGBHSV_GAD:
	if (code == 0)
	  ColorMode = RGB_COLORMODE;
        else
	  ColorMode = HSV_COLORMODE;

	SetColorMode(ColorMode);
	SetProps(CurrentColor);
        break;
    
    }
}

/*=============================================================================
 * Handle vanilla keys...
 *===========================================================================*/

VOID HandleVanillaKey( UWORD code )
{

  switch (code)
    {
    case 'U':
    case 'u':
	ResetPalette(RETRIEVE_IT);
        break;

    case 'L':
    case 'l':
	if(FileSelect(FILELOAD,LoadDir,LoadFile))
	   LoadColors(FileSpec, NumColors );
	SetProps(CurrentColor);
        break;

    case 'S':
    case 's':
	if(FileSelect(FILESAVE,LoadDir,LoadFile))
	   SaveColors(FileSpec, NumColors );
        break;

    case 'O':
    case 'o':
        CloseTheWindow();
        break;

    case 'C':
    case 'c':
	ResetPalette(RETRIEVE_IT);
        CloseTheWindow();
        break;

    }
}

/*=============================================================================
 * A simple, programmable system requester...
 *===========================================================================*/

long Req( UBYTE *gadgets, UBYTE *body, ... )
{
    static struct EasyStruct req = {
        sizeof( struct EasyStruct ), NULL, NULL, NULL, NULL };
    va_list                  args;
    LONG                     rc;

    va_start( args, body );

    req.es_Title        = "ColorSaver Info";
    req.es_TextFormat   = body;
    req.es_GadgetFormat = gadgets;

    rc = EasyRequestArgs( ColorSaverWnd, &req, NULL, args );

    va_end( args );

    return( rc );
}

/*=============================================================================
 * Put up one of a variety of requesters and solicit a response.  Placed all
 * requests in a separate routine so that ARexx reponses could be handled
 * separately when the ColorSaver window was not open
 *===========================================================================*/

int Notify( int message, ...)
{
  char *file;
  ULONG offset;
  int response;

  va_list args;

  va_start( args, message);

  if(!CSIsOpen) return(message);  /* If called from ARexx and window is hid */

  if(message == LOAD_MALLOC_FAIL) {
     (void)Req("Uh Oh!","Can not allocate memory\nfor color palette!");
     return(0);
    }

  if(message == BUFFER_MALLOC_FAIL) {
     (void)Req("Uh Oh!","Can not allocate memory\nfor input buffer!");
     return(0);
    }

  if(message == OFFSET_MALLOC_FAIL) {
     (void)Req("Oh No!","Memory Allocation failure\nin routine AddOffSet()");
     return(0);
    }

  if (message == FILE_OPEN_FAIL) {
     (void)Req("Oops!","Could not open file:\n->>> %s <<<-",
           va_arg(args,char *));
     return(0);
    } 

  if (message == FILE_READ_IOERR) {
     (void)Req("Oh No!","I/O error during read of:\n->>> %s <<<-",
           va_arg(args, char *));
     return(0);
    } 

  if (message == FILE_WRITE_IOERR) {
     (void)Req("Oh No!","I/O error during write of:\n->>> %s <<<-",
           va_arg(args, char *));
     return(0);
    } 

  if (message == ABOUT_TO_WRITE) {

/* Can somebody tell me why the following doesn' work??? */

/*
    response=Req("Go Ahead|Cancel",
    "About to write to file:\n->>> %s <<<-\nat offset: %ld",
      va_arg(args,char *), va_arg(args, ULONG));*/
/*

/* Instead, I have to use ...    */

     file = va_arg(args,char *);
     offset = va_arg(args,ULONG);
     response=Req("Go Ahead|Cancel",
     "About to write to file:\n->>> %s <<<-\nat offset: %ld",
      file, offset);

    return(response);
    }

  if (message == PALETTE_SIZE_MISMATCH) {
    response =Req("Load Anyway|Cancel","Number of BitPlanes\ndo not match!\n\n\
      Colors:\n\nScreen: %2ld  File: %2ld",va_arg(args,ULONG), va_arg(args,LONG)); 
    return(response);
    }

  if (message == NO_COLORTABLE_FOUND) {
    (void)Req("Oh Well!","Cannot find Color Table");
    return(0);
    }

  if (message == ONE_COLORTABLE_FOUND) {
    (void)Req("Yippie!","Found One Color Table match");
    return(0);
    }

  if (message == MULT_COLORTABLE_FOUND) {
    (void)Req("Hmm! (?)","Found %ld Color Table matches",
          va_arg(args,SHORT));
    return(0);
    }

  if (message == WRITE_SUCCESS) {
    (void)Req("I Hope it Works!","  >>>>> ALL DONE!! <<<<<  ");
    return(0);
    }

  va_end( args );

}

/*=============================================================================
 * Some program info
 *===========================================================================*/

void About( void )
{
(void)Req("I Promise!","     %s\n\n\
 >>>  This program is \"PostCardWareč\"  <<<\n\n\
You may freely distribute this program in a \n\
non-commercial  manner  as long as original \n\
sources  and  documentation are included...\n\n\
   ( čAnd you send me a PostCard! ;)",CSTitle);

(void)Req("I'll Do It!","Send PostCards, Bug Reports,\n\
Comments and Suggestions to:\n\n\
       Dan Fish\n\
       815 E. Bethany #B135\n\
       Phoenix, Az.   85014\n\n\
Email: daf@daffy.amigalib.com");

}
