/***********************************************************************
*  palette.c
*     This program is useful for designing color palettes.
* It may be used stand-alone (I would be setting the 'default map',
* if preferences had a complete color map...), or you can use it
* as a subroutine with minor modifications.
*     One of the unique features of this program is that it prints
* the hex value of the selected color, so you use it to generate
* numeric values for use in programs.
*     (c) 1985 by Charlie Heath of Microsmiths, this program is in
* the public domain.  Not to be used commercially without permission
* from MicroSmiths.
***********************************************************************/
 
#define I_REV   29
#define G_REV   29
 
#define FAST register      /* Register type variable  */
 
#define DPTH 2       /* Raster dimensions */
#define WDTH 640
#define HGHT 200
 
#define BCOL 1          /* Background color for menus, etc   */
 
#define CTSIZ  4       /* In spite of myself, color table size   */
 
/****    Variables Initialized by init_colors()  **********/
struct ColorMap *p_Co;
USHORT *p_ct;           /* Color table as words */
extern struct ViewPort *vp; 
USHORT default_color[CTSIZ];     /* Save a copy of the defaults   */
 
 
init_colors()
{
FAST int i;
 
   p_Co = (struct ColorMap *)GetColorMap(CTSIZ);
   p_ct = (USHORT *)p_Co->ColorTable;
 
   for ( i=0; i<CTSIZ; i++)
      default_color[i] = p_ct[i];
   default_color[0] = 0x0a0; default_color[1] = 0x98b;
   default_color[2] = 0x002; default_color[3] = 0xf80;
   set_defmap();
}

clear_colors()
{
   FreeColorMap(p_Co);
}
 
 
/****************************************************************
* set_defmap()
*    This routine sets up a 'default' color map.  It assumes
* you have initialized the variable p_ct to point to a color
* table, and that default_color has the colors you want.       */
set_defmap()
{
FAST int i;
 
   for (i=0; i<CTSIZ ; i++)
      *(p_ct+i) = default_color[i];
 
   set_cmap();
}
 
 
 
/****************************************************************
* set_cmap()
*     This routine loads an updated p_ct color table into the
* viewport.  You must have initialized the variables p_ct and
* vp to point at color table and ViewPort                     */
set_cmap()
{
   LoadRGB4(vp,p_ct,CTSIZ);
}
 
 
/***   palette modifier routines follow    ************************/
 
#define PLX 200      /* Palette Window Size  */
#define PLY 132
 
#define PGAD 0             /* You can offset the gadgets here  */
#define PGHI   PGAD+CTSIZ  /* Offset frm color selectors       */
 
struct IntuiText rtxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"R",NL};
struct IntuiText gtxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"G",NL};
struct IntuiText btxt = {2,2,JAM1,-9,2,NL,(UBYTE *)"B",NL};
 
struct Image    r_img, g_img, b_img;
struct PropInfo r_prop,g_prop,b_prop;
 
struct Gadget blue_gad = {
   NL, 17,112, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
   PROPGADGET,(APTR)&b_img, NL,
   &btxt, NL,(APTR)&b_prop, PGHI+3, NL };
 
struct Gadget green_gad = {
   &blue_gad, 17,97, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
   PROPGADGET,(APTR)&g_img, NL,
   &gtxt, NL,(APTR)&g_prop, PGHI+4, NL };
 
struct Gadget red_gad = {
   &green_gad, 17,82, 90,11, GADGHCOMP, GADGIMMEDIATE | RELVERIFY,
   PROPGADGET,(APTR)&r_img, NL,
   &rtxt, NL,(APTR)&r_prop, PGHI+5, NL };
 
struct IntuiText oktxt = {3,2,JAM2,8,2,NL,(UBYTE *)" OK ",NL};
struct IntuiText cntxt = {3,2,JAM2,0,2,NL,(UBYTE *)"Cancel",NL};
struct IntuiText retxt = {3,2,JAM2,4,2,NL,(UBYTE *)"Reset",NL};
 
struct IntuiText mstxt={2,2,JAM1,0,0,NL,(UBYTE *)"MicroSmiths Palette",NL};
 
char frog[] = "hex";
struct IntuiText hxtxt = {3,2,JAM2,136,31,NL,(UBYTE *)frog,NL};
 
struct Gadget re_gad = {
   &red_gad, 110,112, 54,11, GADGHCOMP, RELVERIFY,
   BOOLGADGET, NL, NL,
   &retxt, NL,NL, PGHI+2, NL };
struct Gadget cn_gad = {
   &re_gad, 110,97, 54,11, GADGHCOMP, RELVERIFY,
   BOOLGADGET, NL, NL,
   &cntxt, NL,NL, PGHI+1, NL };
struct Gadget ok_gad = {
   &cn_gad, 110,82, 54,11, GADGHCOMP, RELVERIFY,
   BOOLGADGET, NL, NL,
   &oktxt, NL,NL, PGHI, NL };
 
struct Image m3C[CTSIZ] = {
   {0,0,16,16,1, NL ,0,0,NL },   /* Colors   */
   {0,0,16,16,1, NL ,0,1,NL },
   {0,0,16,16,1, NL ,0,2,NL },
   {0,0,16,16,1, NL ,0,3,NL } };
 
struct Gadget palg[CTSIZ] = {
   { &palg[1], 3, 3,  16,16, GADGHBOX | GADGIMAGE, RELVERIFY,
      BOOLGADGET,  (APTR)&m3C[0], NL,NL,NL,NL, PGAD+0, NL},
   { &palg[2], 19,3, 16,16, GADGHBOX | GADGIMAGE, RELVERIFY,
      BOOLGADGET,  (APTR)&m3C[1], NL,NL,NL,NL, PGAD+1, NL},
   { &palg[3], 35,3, 16,16, GADGHBOX | GADGIMAGE, RELVERIFY,
      BOOLGADGET,  (APTR)&m3C[2], NL,NL,NL,NL, PGAD+2, NL},
   { &ok_gad, 51,3, 16,16, GADGHBOX | GADGIMAGE, RELVERIFY,
      BOOLGADGET,  (APTR)&m3C[3], NL,NL,NL,NL, PGAD+3, NL} };
 
 
/* Used to open a Window   */
struct NewWindow NewCmod = {
   40,30, PLX,PLY, 2,BCOL, NL,    /* IDCMP set up AFTER CALL */
   ACTIVATE | SMART_REFRESH,
   &palg[0],NL, NL,    /* FirstGadget, CheckMark, Title  */
   NL,NL,              /* MUST SET SCREEN AFTER OPENSCREEN!!! */
   PLX,PLY,PLX,PLY, CUSTOMSCREEN }; /* MinW, MinH, MaxW, MaxH */
 
 
/********************************************************************
* palette(window)
*    This is the meat. This routine opens the palette window and
* retains control until the user selects the OK or CANCEL gadget.
*     The calling arguement is a window pointer.  That window
* is expected to have opened an IDCMP port, which palette uses.
********************************************************************/
palette(calling_window)
struct Window *calling_window;
{
struct Window *cW;      /* Palette window handle   */
 
FAST struct IntuiMessage *imsg;
FAST struct Gadget *igad;
 
FAST int class,cursel;
BOOL keepon,munge;
 
USHORT backup[CTSIZ];         /* This table restores calling colors... */
 
static char hxtab[16] = { '0','1','2','3','4','5','6','7','8',
   '9','a','b','c','d','e','f' };
 
   for ( cursel=CTSIZ-1; cursel >= 0; cursel--)
      backup[cursel] = p_ct[cursel];
 
   r_prop.Flags = g_prop.Flags = b_prop.Flags = FREEHORIZ | AUTOKNOB;
   r_prop.HorizBody = g_prop.HorizBody = b_prop.HorizBody = 0x1000;
 
   /* Get screen from calling window   */
   NewCmod.Screen = calling_window->WScreen;  /* NEED TO SET SCREEN!!! */
   if ( ! (cW = (struct Window *)OpenWindow(&NewCmod)) ) {
      return(FALSE); /* Oops...  */
      }
 
   PrintIText(cW->RPort,&mstxt,7,71);
 
   cW->UserPort = calling_window->UserPort;
   ModifyIDCMP(cW, GADGETUP | GADGETDOWN | MENUVERIFY );
 
   for ( munge = keepon = TRUE; keepon; ) {
 
      if ( munge ) {
         SetAPen(cW->RPort,cursel);
         RectFill(cW->RPort,133,3,PLX-5,66);
 
         /* RJ will proably cringe if he see's this, but it is proably */
         /* safe to modify the HorizPot values this way, UNLESS the    */
         /* gadgets were being fiddled with when you do it. Here that  */
         /* is quite unlikely, since another gadget was just activated */
         /* to cause the munge flag to be set...                       */
 
         r_prop.HorizPot = (p_ct[cursel] & 0xf00) << 4;
         g_prop.HorizPot = (p_ct[cursel] & 0x0f0) << 8;
         b_prop.HorizPot = p_ct[cursel] << 12;
         RefreshGadgets(&red_gad,cW,NL);
         munge = FALSE;
         hxtxt.FrontPen = cursel ^ 15;
         hxtxt.BackPen  = cursel;
         }
 
      while ( ! (imsg=(struct IntuiMessage *)GetMsg(cW->UserPort)) ) {
         class = p_ct[cursel] = ((r_prop.HorizPot >> 4) & 0xf00) +
            ((g_prop.HorizPot >> 8) & 0xf0) + (b_prop.HorizPot >>12);
         set_cmap();
 
         frog[0] = hxtab[class >> 8];
         frog[1] = hxtab[ (class >> 4) & 0x0f];
         frog[2] = hxtab[class & 0x0f];
         PrintIText(cW->RPort,&hxtxt,0,0);
 
         /* Proably, should do a WaitPort(cW->UserPort); */
         /* I didn't, so the color updates faster.       */
         /* In a multitasking environment, the system is */
         /* being gronked...                             */
         }
 
      igad =(struct Gadget *) imsg->IAddress;
      if ( (class = imsg->Class) == MENUVERIFY ) {
         imsg->Code = MENUCANCEL;      /* Don't Let Em Out! */
         DisplayBeep(NL);
         }
      ReplyMsg(imsg);
 
      switch ( class ) {
         case GADGETUP:
         case GADGETDOWN:
            if ((igad->GadgetID >= PGAD)&&(igad->GadgetID < PGAD+CTSIZ)) {
               cursel = igad->GadgetID - PGAD;
               munge = TRUE;
               }
            else switch ( igad->GadgetID ) {
               case PGHI+1:      /* Cancel   */
                  for ( class =0 ; class<CTSIZ; class++)
                     p_ct[class] = backup[class];
                  set_cmap();
               case PGHI:        /* OK */
                  keepon = FALSE;
                  break;
 
               case PGHI+2:      /* Reset */
                  set_defmap();
                  munge = TRUE;
                  break;
               }
         }
      }
 
   cW->UserPort = NL;
   CloseWindow(cW);
   return(TRUE);
}
 
 
/*************************************************************/
