
/* I had nothing to do with this section other than removing a couple of */
/* Latticisms. -- John */

/* This color requester was hacked out of a Mandelbrot program by
   RJ Mical, Mike Ballantyne and R French.  I'm not sure which one of these
deserves most of the credit for the colour requester but I suspect RJ Mical.
I merely neatened up the code, fixed it so it wouldn't go glitchy with
fast ram, got rid of 33 unnecessary gadgets, put in the numeric display of
the rgb values of the current colour, fixed the display so it looks
reasonable in less than 5 bit planes (it used to always try to show 32
coloured squares, even if it only had two colours to work with), and made it
as easy as possible to call from any program.  To access it from your
program simply put in the statement  DoColorWindow(screen)  where screen is
a pointer to your screen.  That's it.  This program (subroutine actually)
may be freely distributed as long as this notice giving credit to the four
contributing authors is left intact.  Pls address any correspondence
regarding this program to :
      Bruce Dawson
      c/o CantorSoft.
      407-1280 Haro St,
      Vancouver
      B.C.
      V6E1E8

			    */





#include <clib/macros.h>
#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/devices.h>
#include <devices/keymap.h>
#include <graphics/copper.h>
#include <graphics/display.h>
#include <graphics/gels.h>
#include <graphics/regions.h>
#include <hardware/blit.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>

/* Lattice sticks these two in a subdirectory. -- John */

#include <ctype.h>
#include <stdio.h>

#include <libraries/dos.h>

/* === the definitions for the ColorWindow =============================== */
#define KNOB_BODY      0x1111

#define WINDOW_WIDTH   208
#define WINDOW_HEIGHT  106

#define WINDOW_LEFT   (320 - WINDOW_WIDTH)
#define WINDOW_TOP   (200 - WINDOW_HEIGHT)

#define CHARACTER_WIDTH      8
#define CHARACTER_HEIGHT   8

#define CURRENT_LEFT	  6
#define CURRENT_TOP	 16
#define CURRENT_RIGHT	   (CURRENT_LEFT + 15)
#define CURRENT_BOTTOM	 (CURRENT_TOP + 29)

#define COLORS_TOP	55

#define PROP_LEFT      38
#define PROP_TOP       14
#define PROP_WIDTH    149
#define PROP_HEIGHT    10

#define ACTIONS_LEFT  141
#define ACTIONS_TOP    51
#define ACTIONS_WIDTH	(CHARACTER_WIDTH * 6 + 4)
#define ACTIONS_HEIGHT	 9

/* GREEN and RED are out of order.  Do you wonder why?	Some day I'll
 * tell you.  =RJ=
 */
#define COLOR_COPY	      0
#define COLOR_RANGE	      1
#define COLOR_OK	      2
#define COLOR_CANCEL	      3
#define COLOR_GREEN	      4
#define COLOR_RED	      5
#define COLOR_BLUE	      6
#define COLOR_GADGETS_COUNT   7



/***************************************************************************
 *
 * Color window template initialization and routines,
 * for colorwindow and cyclewindow
 *
 * Throughout this file, the COLOR_RED and COLOR_GREEN gadgets are in the
 * opposite order you would expect.
 *
 ****************************************************************************/

struct TextAttr safefont = {
   (UBYTE *)"topaz.font",
   TOPAZ_EIGHTY,
   0,
   0,
};

struct IntuiText string =
{
   1, 0,	     /* frontpen, backpen */
   JAM2,	     /* drawmode	  */
   0,0, 	     /* leftedge, topedge */
   &safefont,	     /* pointer to font   */
   NULL,	     /* pointer to text data */
   NULL 	     /* next text */
};


SHORT actions_corners[] = {
   -1, -1,
   -1, ACTIONS_HEIGHT,
   ACTIONS_WIDTH, ACTIONS_HEIGHT,
   ACTIONS_WIDTH, -1,
   -1, -1,
};

struct Border actions_border = {
   0, 0,
   1, 0,
   JAM1,
   5,
   actions_corners,
   NULL,
};

struct IntuiText actions_text[4] = {
   { /* "COPY" */
      1, 0,
      JAM2,
      2 + CHARACTER_WIDTH, 1,
      &safefont,
      (UBYTE *)"COPY",
      NULL,
   },
   { /* "RANGE" */
      1, 0,
      JAM2,
      2 + (CHARACTER_WIDTH >> 1), 1,
      &safefont,
      (UBYTE *)"RANGE",
      NULL,
   },
   { /* "OK" */
      1, 0,
      JAM2,
      2 + (CHARACTER_WIDTH << 1), 1,
      &safefont,
      (UBYTE *)"OK",
      NULL,
   },
   { /* "CANCEL" */
      1, 0,
      JAM2,
      2, 1,
      &safefont,
      (UBYTE *)"CANCEL",
      NULL,
   },
};


/* ======================================================================== */
/* ======================================================================== */
/* ======================================================================== */
/* RJM anchor */
struct Image   ColorPropsImages[3];
struct Image   ColorImage =
   {
   CURRENT_LEFT, COLORS_TOP,	       /* left edge, top edge */
   15, 10, 0,			       /* width, height, depth */
   NULL,			       /* image data */
   0,				       /* planepick */
   0,				       /* planeonoff - set later */
   NULL 			       /* NextImage */
   };

struct PropInfo ColorPropsInfos[3] = {
   { /* COLOR_GREEN */
      AUTOKNOB | FREEHORIZ,
      0,
      0,
      KNOB_BODY,
      0,
      0, 0, 0, 0, 0, 0,
   },
   { /* COLOR_RED */
      AUTOKNOB | FREEHORIZ,
      0,
      0,
      KNOB_BODY,
      0,
      0, 0, 0, 0, 0, 0,
   },
   { /* COLOR_BLUE */
      AUTOKNOB | FREEHORIZ,
      0,
      0,
      KNOB_BODY,
      0,
      0, 0, 0, 0, 0, 0,
   },
};

struct Gadget gadglist[COLOR_GADGETS_COUNT] = {
   { /* COLOR_COPY */
      NULL,
      ACTIONS_LEFT,
      ACTIONS_TOP + (0 * (ACTIONS_HEIGHT + 3)),
      ACTIONS_WIDTH,
      ACTIONS_HEIGHT,
      GADGHCOMP,
      RELVERIFY,
      BOOLGADGET,
      (APTR)&actions_border,
      NULL,
      &actions_text[0],
      NULL,
      NULL,
      COLOR_COPY,
      NULL,
   },
   { /* COLOR_RANGE */
      &gadglist[COLOR_COPY],
      ACTIONS_LEFT,
      ACTIONS_TOP + (01 * (ACTIONS_HEIGHT + 3)),
      ACTIONS_WIDTH,
      ACTIONS_HEIGHT,
      GADGHCOMP,
      RELVERIFY,
      BOOLGADGET,
      (APTR)&actions_border,
      NULL,
      &actions_text[01],
      NULL,
      NULL,
      COLOR_RANGE,
      NULL,
   },
   { /* COLOR_OK */
      &gadglist[COLOR_RANGE],
      ACTIONS_LEFT,
      ACTIONS_TOP + (02 * (ACTIONS_HEIGHT + 3)),
      ACTIONS_WIDTH,
      ACTIONS_HEIGHT,
      GADGHCOMP,
      RELVERIFY,
      BOOLGADGET,
      (APTR)&actions_border,
      NULL,
      &actions_text[02],
      NULL,
      NULL,
      COLOR_OK,
      NULL,
   },
   { /* COLOR_CANCEL */
      &gadglist[COLOR_OK],
      ACTIONS_LEFT,
      ACTIONS_TOP + (03 * (ACTIONS_HEIGHT + 3)),
      ACTIONS_WIDTH,
      ACTIONS_HEIGHT,
      GADGHCOMP,
      RELVERIFY,
      BOOLGADGET,
      (APTR)&actions_border,
      NULL,
      &actions_text[03],
      NULL,
      NULL,
      COLOR_CANCEL,
      NULL,
   },
   { /* COLOR_GREEN */
      &gadglist[COLOR_CANCEL],
      PROP_LEFT,
      PROP_TOP + (01 * (PROP_HEIGHT + 1)),
      PROP_WIDTH,
      PROP_HEIGHT,
      GADGHCOMP | GADGIMAGE,
      FOLLOWMOUSE,
      PROPGADGET,
      (APTR)&ColorPropsImages[01],
      NULL,
      NULL,
      NULL,
      (APTR)&ColorPropsInfos[01],
      COLOR_GREEN,
      NULL,
   },
   { /* COLOR_RED */
      &gadglist[COLOR_GREEN],
      PROP_LEFT,
      PROP_TOP + (00 * (PROP_HEIGHT + 1)),
      PROP_WIDTH,
      PROP_HEIGHT,
      GADGHCOMP | GADGIMAGE,
      FOLLOWMOUSE,
      PROPGADGET,
      (APTR)&ColorPropsImages[00],
      NULL,
      NULL,
      NULL,
      (APTR)&ColorPropsInfos[00],
      COLOR_RED,
      NULL,
   },
   { /* COLOR_BLUE */
      &gadglist[COLOR_RED],
      PROP_LEFT,
      PROP_TOP + (02 * (PROP_HEIGHT + 1)),
      PROP_WIDTH,
      PROP_HEIGHT,
      GADGHCOMP | GADGIMAGE,
      FOLLOWMOUSE,
      PROPGADGET,
      (APTR)&ColorPropsImages[02],
      NULL,
      NULL,
      NULL,
      (APTR)&ColorPropsInfos[02],
      COLOR_BLUE,
      NULL,
   },
};


/*----------------------*/
/* Graphics definitions */

struct	 RastPort    *rstport;
struct	 ViewPort    *vp;

struct	 Window      *ColorWindow;

/*****************************************************************************
 *
 * Color initialization and routines
 *
 ****************************************************************************/

#define COPYCOLOR	1
#define RANGE_FIRST	2
#define RANGE_SECOND	3

USHORT	 ColorMode;

USHORT	 SavePalette[32];

#define COLOR_IDCMP_FLAGS (GADGETDOWN | GADGETUP | MOUSEBUTTONS \
      | MENUPICK | MOUSEMOVE | ACTIVEWINDOW | INACTIVEWINDOW)

struct NewWindow ColorNewWindow =
   {
   WINDOW_LEFT, WINDOW_TOP,
   WINDOW_WIDTH, WINDOW_HEIGHT,
   -1, -1,
   COLOR_IDCMP_FLAGS,
   WINDOWDRAG | SMART_REFRESH | NOCAREREFRESH | ACTIVATE,
   NULL,			 /* struct Gadget *FirstGadget; */
   NULL,			 /* struct Image *CheckMark; */
   "Modify Colours.",  /* the title text for this window */
   NULL,			 /* struct Screen *Screen; */
   NULL,			 /* struct BitMap *BitMap; */
   0, 0,
   0, 0,
   CUSTOMSCREEN,		 /* USHORT Type; */
   };

USHORT	 RangeFirst;   /* the first selection of the range-color pair */

/* ======================================================================== */
/* ======================================================================== */

BOOL OpenColorWindow(screen, colours)
struct Screen *screen;
short	       colours;
{
   REGISTER LONG   i;

   ColorNewWindow.Screen = screen;
   ColorNewWindow.FirstGadget=&gadglist[COLOR_GADGETS_COUNT - 1];
   ColorMode = NULL;
   if ( ! (ColorWindow = (struct Window *)OpenWindow(&ColorNewWindow)))
      return(FALSE);
   rstport = ColorWindow->RPort;
   SetAPen(rstport, 1);
   SetColorProps();
   for (i = 0; i < 32; i++)
      SavePalette[i] = GetRGB4(vp->ColorMap, i);
   DrawColorWindow(colours);
   return(TRUE);
}

VOID CloseColorWindow(accept)
BOOL accept;
{
   if ( NOT ColorWindow)
      return;
   CloseWindow(ColorWindow);
   ColorWindow = NULL;
   if (NOT accept)
      LoadRGB4(vp, &SavePalette[0], 32L);
}

VOID ColorRange(first, last)
SHORT first, last;
{
   REGISTER SHORT   i;
   LONG      whole, redfraction, greenfraction, bluefraction;
   REGISTER USHORT   rgb;
   SHORT      firstred, firstgreen, firstblue;
   SHORT      lastred, lastgreen, lastblue;
   SHORT      workred, workgreen, workblue;

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

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

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

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

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

BOOL colorchosen(pen)
short pen;
{
   REGISTER USHORT   rgb;

   complementbox(rstport, rstport->FgPen);
   complementbox(rstport, pen);

   if (ColorMode == COPYCOLOR)
      {
      rgb = GetRGB4(vp->ColorMap, (LONG)rstport->FgPen);
      SetRGB4(vp,  pen, (rgb >> 8), (rgb >> 4), rgb );
      ColorMode = NULL;
      }
   if (ColorMode == RANGE_FIRST)
      {
      ColorMode = RANGE_SECOND;
      RangeFirst = pen;
      }
   else if (ColorMode == RANGE_SECOND)
      {
      ColorMode = NULL;
      ColorRange(RangeFirst, pen);
      }

   SetAPen(rstport, (LONG)pen);
   rgb = GetRGB4(vp->ColorMap, (LONG)pen);
   ColorRectFill((LONG)pen);

   SetColorProps();
}



BOOL GadgetGotten(gadgetnum)
short gadgetnum;
{
   switch (gadgetnum)
      {
      case COLOR_OK:
	 CloseColorWindow(TRUE);
	 return(FALSE);
      case COLOR_CANCEL:
	 CloseColorWindow(FALSE);
	 return(FALSE);
      case COLOR_COPY:
	 ColorMode = COPYCOLOR;
	 break;
      case COLOR_RANGE:
	 ColorMode = RANGE_FIRST;
	 break;
      }
   return(TRUE);
}


ModifyColors()
{
   USHORT      pen;
   REGISTER USHORT   newred, newgreen, newblue;

   pen = rstport->FgPen;
   newred = ((struct PropInfo *)
		  gadglist[COLOR_RED].SpecialInfo)->HorizPot >> 12;
   newgreen = ((struct PropInfo *)
		  gadglist[COLOR_GREEN].SpecialInfo)->HorizPot >> 12;
   newblue = ((struct PropInfo *)
		  gadglist[COLOR_BLUE].SpecialInfo)->HorizPot >> 12;
   SetRGB4(vp, (LONG)pen, (LONG)newred, (LONG)newgreen, (LONG)newblue);

   printcolors(newred, newgreen, newblue);
}



printcolors(red, green, blue)
USHORT	 red, green, blue;
{
   char *buffer = "  ";

   sprintf(buffer, "%2d", red);
   printtext(buffer, PROP_WIDTH + PROP_LEFT+2, CURRENT_TOP);

   sprintf(buffer, "%2d", green);
   printtext(buffer, PROP_WIDTH + PROP_LEFT+2, CURRENT_TOP+(PROP_HEIGHT+1));

   sprintf(buffer, "%2d", blue);
   printtext(buffer, PROP_WIDTH + PROP_LEFT+2, CURRENT_TOP
					     + (PROP_HEIGHT+1) * 2);
}



DrawColorWindow(colours)
{
   REGISTER SHORT i;

   ColorRectFill((LONG)rstport->FgPen);
   DrawBox(rstport, CURRENT_LEFT-2,CURRENT_TOP-2,CURRENT_RIGHT+2,CURRENT_BOTTOM+2);
   DrawBox(rstport, CURRENT_LEFT-2, COLORS_TOP-2, CURRENT_LEFT+(8 * 15)+1,
				    COLORS_TOP + (4 * 10) + 1);
   printtext("R", CURRENT_RIGHT + 6, CURRENT_TOP);
   printtext("G", CURRENT_RIGHT + 6, CURRENT_TOP + PROP_HEIGHT+1);
   printtext("B", CURRENT_RIGHT + 6, CURRENT_TOP + (PROP_HEIGHT+1)* 2);

   for (i = 0; i < colours; i++)
      {
      ColorImage.PlaneOnOff = i;
      DrawImage(rstport, &ColorImage, (i % 8) * 15, (i / 8) * 10);
      }
   complementbox(rstport, 1);	    /* starting colour is colour 1 */
}



SetColorProps()
{
   USHORT      rgb;
   REGISTER USHORT   red, green, blue;
   SHORT      greenpos, redpos, bluepos;

   redpos = RemoveGadget(ColorWindow, &gadglist[COLOR_RED]);
   greenpos = RemoveGadget(ColorWindow, &gadglist[COLOR_GREEN]);
   bluepos = RemoveGadget(ColorWindow, &gadglist[COLOR_BLUE]);

   rgb = GetRGB4(vp->ColorMap, (LONG)rstport->FgPen);
   red = (rgb >> 8) & 0xF;
   green = (rgb >> 4) & 0xF;
   blue = (rgb >> 0) & 0xF;

   ((struct PropInfo *)gadglist[COLOR_RED].SpecialInfo)->HorizPot
	       = (red << 12) | (red << 8) | (red << 4) | red;
   ((struct PropInfo *)gadglist[COLOR_GREEN].SpecialInfo)->HorizPot
	       = (green << 12) | (green << 8) | (green << 4) | green;
   ((struct PropInfo *)gadglist[COLOR_BLUE].SpecialInfo)->HorizPot
	       = (blue << 12) | (blue << 8) | (blue << 4) | blue;

   AddGadget(ColorWindow,&gadglist[COLOR_BLUE], (LONG)bluepos);
   AddGadget(ColorWindow,&gadglist[COLOR_GREEN],(LONG)greenpos);
   AddGadget(ColorWindow,&gadglist[COLOR_RED], (LONG)redpos);

   RefreshGadgets(&gadglist[COLOR_GADGETS_COUNT-1],ColorWindow);

   printcolors(red, green, blue);
}


ColorRectFill( pen)
LONG pen;
{
   SetAPen(rstport, pen);
   SetDrMd(rstport, JAM2);
   WaitBOVP(vp);
   RectFill(rstport, CURRENT_LEFT, CURRENT_TOP, CURRENT_RIGHT, CURRENT_BOTTOM);
}

VOID DoColorWindow(screen)
struct Screen *screen;
{
   BOOL 	   GadgetGotten(), OpenColorWindow();
   REGISTER struct IntuiMessage   *message;
   REGISTER ULONG		  class;
   REGISTER struct Gadget	  *gadget;
   USHORT   bitplanes, colours, code;
   short    number, x, y;


   vp = &screen->ViewPort;
   bitplanes = screen->BitMap.Depth;
   for (colours = 1; bitplanes; bitplanes--)
      colours *= 2;
   if (colours > 32)
      colours = 32;

   if (NOT OpenColorWindow(screen, colours))
      return;
   FOREVER {
      Wait((1L << ColorWindow->UserPort->mp_SigBit));
      while (message = (struct IntuiMessage *)GetMsg(ColorWindow->UserPort)) {
	 class = message->Class;
	 code = message->Code;
	 x = message->MouseX;
	 y = message->MouseY;
	 if (class != MOUSEBUTTONS)
	    gadget = (struct Gadget *)(message->IAddress);
	 ReplyMsg(message);
	 switch (class) {
	    case GADGETDOWN:
	    case GADGETUP:
	       if ( NOT GadgetGotten(gadget->GadgetID))
		  return;
	       break;
	    case MOUSEBUTTONS:
	       if ( x >= CURRENT_LEFT && x < CURRENT_LEFT + 8 * 15)
		  if (y >= COLORS_TOP && y < COLORS_TOP + 4 * 10)
		     {
		     number = (x-CURRENT_LEFT)/15 + ((y-COLORS_TOP)/10)*8;
		     if (number < colours && code == SELECTDOWN)
			colorchosen(number);
		     }
	       break;
	    case MOUSEMOVE:
	       ModifyColors();
	       break;
	    default:
	       break;
	 }
      }
   }
}



DrawBox(rp, x1, y1, x2, y2)
struct RastPort *rp;
short	 x1, y1, x2, y2;
/* draws a box without overlapping the edges (in case of complement mode) */
{
   Move(rp, x1, y1 + SIGN(y2 - y1));
   Draw(rp, x1, y2);
   Move(rp, x1 + SIGN(x2 - x1), y2);
   Draw(rp, x2, y2);
   Move(rp, x2, y2 - SIGN(y2 - y1));
   Draw(rp, x2, y1);
   Move(rp, x2 - SIGN(x2 - x1), y1);
   Draw(rp, x1, y1);
}



complementbox(rp, colours)
short colours;
{
short x, y;

   x = CURRENT_LEFT + (colours % 8) * 15;
   y = COLORS_TOP + (colours / 8) * 10;

   SetDrMd(rp, COMPLEMENT);
   DrawBox(rp, x, y, x + 14, y + 9);
   SetDrMd(rp, JAM1);
}



printtext(text, x, y)
char	 *text;
short	 x, y;
{
   string.IText = text;
   PrintIText(rstport, &string, x, y);
}
