[comp.sources.amiga] color loader/twiddler

ain@j.cc.purdue.edu (Patrick White) (12/18/87)

Program Name:	colour
Submitted By:	john13@garfield.mun.edu (John Russell)
Summary:	This program allows loading/setting/saving/adjusting of
		screen colors.  It can also be compiled to not allow
		*adjusting* of colors (although setting, loading,
		and saving still work) -- saves ~6K.
Poster Boy:  Pat White  (ain@j.cc.purdue.edu)
Untested  (meaning that I didn't try and compile it).

NOTES:
   The built-in help for the un'FANCY' version tells about the "adjust"
mode which is not available in it -- a simple code change that I didn't
make.
   The binary copies of these two programs were posted to
comp.binaries.amiga.

-- Pat White   (co-moderator comp.sources/binaries.amiga)
UUCP: k.cc.purdue.edu!ain  BITNET: PATWHITE@PURCCVM   PHONE: (317) 743-8421
U.S.  Mail:  320 Brown St. apt. 406,    West Lafayette, IN 47906

----------------------------------------


#	This is a shell archive.
#	Remove everything above and including the cut line.
#	Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar:	Shell Archiver
#	Run the following text with /bin/sh to create:
#	README
#	colour.doc
#	colorreq.c
#	colour.c
#	amber.col
#	cyan.col
#	gray.col
#	green.col
#	lace.col
#	modem.col
#	pastel.col
#	red.col
#	royal.col
#	silver.col
#	silver2.col
#	wb.col
# This archive created: Thu Dec 17 10:16:28 1987
# By:	Patrick White (PUCC Land, USA)
cat << \SHAR_EOF > README
Please note that there are 2 versions of this program, a "large model" with
all features implemented, and a "small model" that doesn't incorporate the
colour requester. You can decide which one you want by making sure that the
symbol FANCY is either defined or undefined during compilation.

If you don't want the colour requester in your version (ie you compile with
FANCY undefined) you don't need to compile the file colorreq.c or link with
colorreq.o.

John
SHAR_EOF
if test 462 -ne "`wc -c README`"
then
echo shar: error transmitting README '(should have been 462 characters)'
fi
cat << \SHAR_EOF > colour.doc

/*------------------------------------------------------------------------*/

Colour	- make a screen any colour you like, and load & save colour sets.
------

Copyright 1987, John Russell

5 Alderdice Place
St. John's, Newfoundland
Canada	 A1B 2P8
(709) 726-7847

UseNet: john13@garfield.uucp
	john13@garfield.mun.cdn

Freely redistributable.

/*------------------------------------------------------------------------*/

    This program has 4 uses:

    First, you can experiment with different colour combinations by actually
specifying numeric parameters for Red, Green, and Blue. You can also do the
same with numerous programs which use "slider gadgets", but I include the
capability for completeness. Note there's also a slider-gadget option in
this program which you can enable at compile time.

    Second, once you have found a colour combination you like, whether it's
on your Workbench screen, or on the screen of some other program, you
can save it to disk. The format of the saved file is very simple - for a
screen with N colours, there are N lines with 3 integer values each, for
Red, Green, and Blue which combine to any of the Amiga's 4096 possible
colours.

    Third, you can instantly load this definition back in, and specify the
screen whose colours you want to change. You can thus have special colours
to use when running a word processor, terminal program, CLI session, etc.
I personally have about 5 sets of colours I use depending on my mood, if
my eyes are tired, if my monitor will be on for a long time and I want to
save a few phosphor molecules, etc.

    Fourth, if you want to experiment with different colour combinations
interactively, you can bring up a colour window requestor on a specified
screen. This has the standard slider gadgets for adjusting colours and
also features like copy, undo, and range. The range option is the only
one that is not immediately obvious -- after selecting it, choose 2
colours in the palette and all colours in between will be changed to
a gradation somewhere between the two endpoints.

NB: This last option of the colour requestor may be omitted when the
program is compiled (this saves about 5K), since many other programs
are available that accomplish the same function. However I prefer to
leave it enabled since the code doesn't have to stay in memory at all
times as it does in most other similar utilities.

------
SYNTAX
------

To set one particular colour, on one particular screen -
colour set <screen> index red green blue

To load a group of colours -
colour load <screen> [from] <filename>

To save a group of colours -
colour save <screen> [to] <filename>

To adjust colours with the mouse -
colour adjust <screen>

If the screen has no title, you can specify "-null" in place of the title,
in which case the first screen with no title is used. Only the first word
of the title is considered, and case is not important. When loading a colour
file, the current directory is searched first and then the S: directory.
If the S: directory must be searched, the suffix ".col" is assumed to be
present; thus the following two forms are equivalent :

colour load workbench from black-and-white
colour load workbench from s:black-and-white.col

Examples -

colour set workbench 0 0 0 0	  : sets Workbench background to black.
colour load vt100 from modem.col  : set VT100 seperate screen colours.
colour save -null to dpaint.col   : saves DPaint palette; screen has no title
colour load workbench wb.col	  : use the old Workbench colours
colour save mandelbrot mand.col   : save a pretty-looking palette
colour adjust workbench 	  : fairly powerful interactive control

------------
DISTRIBUTION
------------

    This program is freely redistributable; no fees beyond reasonable charge
for media may be charged. 

    Source is included with this initial posting, along with an encoded
version of the executable. The source may be informative if you are
interested in how colours relate to the structure of the screen they affect.
If you pass this program on, please keep at least this documentation with
the executable. In the spirit of Canadian nationalism, I ask that you not 
change the spelling of the excutable -- the "u" is supposed to be there.

    A portion of the source is derived from a public domain colour
manipulation program. This section carries its own copyright notice and
distribution conditions, which are present in the file colorreq.c if you
have a copy of the source.

    No donations are solicited; however if you send me a disk with public
domain software that you find useful (and possibly hasn't received wide
distribution), I'll do the same from this end with some lesser-known programs
that I use a lot.

John
SHAR_EOF
if test 4724 -ne "`wc -c colour.doc`"
then
echo shar: error transmitting colour.doc '(should have been 4724 characters)'
fi
cat << \SHAR_EOF > colorreq.c

/* 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);
}
SHAR_EOF
if test 17372 -ne "`wc -c colorreq.c`"
then
echo shar: error transmitting colorreq.c '(should have been 17372 characters)'
fi
cat << \SHAR_EOF > colour.c
/*
 *  Colour.c - a program for manipulating the colours of screens.
 *
 *  Written because I like one set of colours in a CLI and another in
 *  my terminal window, and can't always afford the memory for another
 *  screen. Plus, I like a more direct way of changing colours than
 *  twiddling a bunch of slider gadgets (although that way has its uses
 *  too, so I include the capability). Lastly, Americans don't know
 *  how to spell "colour" :-).
 *
 *  Features include:
 *	- save all colours from a given screen
 *	- load a set of colours into a given screen
 *	- set a particular colour register in a given screen
 *	- adjust screen colours interactively (OPTIONAL)
 *
 *  Copyright 1987, John Russell
 *
 *  5 Alderdice Place
 *  St. John's, Newfoundland
 *  Canada   A1B 2P8
 *  (709) 726-7847
 *
 *  Freely redistributable.
 */

/* Manx users compile with "+l" just in case */

/* These includes might not be enough, I use precompiled includes. */
/* anything to do with screens & viewports may be required */

#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <stdio.h>
#include "ctype.h"

#define LOAD 1
#define SAVE 2
#define SET 3
#define ADJUST 4

/* if "fancy" is defined, you have the option to adjust on-the-fly */

#define FANCY 1

/* debug = "puts" to enable tracing, leave blank to disable */

#define debug(x)

struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;

char *usage = "\n\
Bad syntax.\n\n\
Usage 1: colour load   <screen | \"-null\"> [from] <filename>.\n\
Usage 2: colour save   <screen | \"-null\"> [to] <filename>.\n\
Usage 3: colour set    <screen | \"-null\"> index R G B.\n\
Usage 4: colour adjust <screen | \"-null\">.\n\n\
Note  -  Specify screen by first word of title (case doesn't matter).\n\
Note  -  Load file is searched for as \"file\" and \"s:file.col\".\n";

main(argc,argv)
int argc;
char *argv[];
{
    struct Screen *screen;	/* which screen to consider */
    struct ViewPort *vp;	/* controlling viewport for screen */
    FILE *fp;			/* for loading & saving */
    short good_args = 0;	/* right # arguments for syntax? */
    short mode = 0;		/* what type of command is it? */
    int r,g,b;
    int i,n,fname,depth;	/* depth == number of colours in screen */
    UWORD colour;		/* I only remember these typedefs */
    struct ColorMap *map;	  /* when reading includes :-) */
    char name[80];

    /* check for valid arguments and commands */

    if (argc < 3)    /* always need at least 3 */
    {
	puts(usage);
	exit(0);
    }
    else if (!compare(argv[1],"load"))
    {
	debug("Asked to load a colour set.");
	mode = LOAD;
	if (argc == 4 || (!compare(argv[3],"from") && argc == 5))
	    good_args = 1;
    }
    else if (!compare(argv[1],"save"))
    {
	debug("Asked to save a colour set.");
	mode = SAVE;
	if (argc == 4 || (!compare(argv[3],"to") && argc == 5))
	    good_args = 1;
    }
    else if (!compare(argv[1],"set"))
    {
	debug("Asked to set a single colour.");
	mode = SET;
	if (argc == 7) good_args = 1;
    }

#ifdef FANCY
    else if (!compare(argv[1],"adjust"))
    {
	debug("Asked to adjust screen colours.");
	mode = ADJUST;
	if (argc == 3) good_args = 1;
    }
#endif

    fname = argc - 1;	/* argv[fname] = file for load & save */

    if (!good_args) {
	puts(usage);
	exit(0);
    }

    debug("Arguments are legal.");

    if (! (IntuitionBase = (struct IntuitionBase *)
	    OpenLibrary("intuition.library",33L)))
    {
	puts("Please use Kickstart/Workbench V1.2 for latest Intuition.");
	exit(0);
    }

    if (! (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",33L)))
    {
	puts("Please use Kickstart/Workbench V1.2 for latest Graphics.");
	exit(0);
    }

    screen = IntuitionBase->FirstScreen;

/* the target screen is found when the first word of the title matches the
   2nd argument specified, OR if the 2nd argument is -null, the first
   screen with NO title is matched (eg the DPaint screen) */

    LockIBase(NULL);	/* prevent window list from changing while in loop */

    while (screen)	/* do all screens */
    {
	    if (!compare(argv[2],screen->Title) ||
	       ((screen->Title == NULL) && (!compare(argv[2],"-null"))))
	    {
		UnlockIBase(NULL);

		debug("Found the indicated screen.");

		vp = &screen->ViewPort;     /* don't like 'em much myself */
		map = vp->ColorMap;
		depth = 1 << screen->BitMap.Depth;   /* no easier way? */

		switch (mode)
		{

		    case SET:

			i = atoi(argv[3]);  /* colour index */
			r = atoi(argv[4]);  /* RGB values */
			g = atoi(argv[5]);
			b = atoi(argv[6]);

			if (i < depth)
			{
			    SetRGB4(vp,i,r,g,b);
			    debug("Set single colour.");
			}
			else
			    puts("Illegal colour index for this screen.");

			break;

		    case LOAD:	/* (LA Law is on in the background) */

			/* search current directory and S: for file */

			/* look for for file as "file" and "s:file.col" */


			if (!(fp = fopen(argv[fname],"r")))
			{
			    /* Boy do I hate C string functions! */

			    strcpy(name,"s:");
			    strcat(name,argv[fname]);
			    strcat(name,".col");

			    debug("Searching for file in S: directory.");
			    fp = fopen(name,"r");
			}

			if (!fp)
			{
			    puts("Unable to open load file!");
			    goto QUIT;
			}

			debug("Opened file successfully.");

			/* This is an *ugly* loop condition! */

			for (i=0;
			     (i < depth)
				&&
			     (fscanf(fp,"%d %d %d\n",&r,&g,&b)==3);
			     i++)
			{
			    SetRGB4(vp,i,r,g,b);
			    debug("Set a colour.");
			}

			fclose(fp);
			break;

		    case SAVE:

			fp = fopen(argv[fname],"w");

			if (!fp) {
			    puts("Unable to open save file!");
			    goto QUIT;
			}

			for (i=0; i < depth; i++)
			{
			    colour = GetRGB4(map,i);

			    /* each colour component encoded by 4 bits */

			    r = (colour & 0xf00) >> 8;
			    g = (colour & 0x0f0) >> 4;
			    b = (colour & 0x00f);

			    fprintf(fp,"%d %d %d\n",r,g,b);
			    debug("Saved a colour.");
			}

			fclose(fp);

			break;

#ifdef FANCY
		    case ADJUST:
			ScreenToFront(screen);
			DoColorWindow(screen);	/* I can't take credit for */
			break;			/* this section */
#endif

		    default:

			debug("Illegal instruction mode.");
			break;
		}

		goto QUIT;	/* only match 1 screen */

	    }

	    screen = screen->NextScreen;

	}

    UnlockIBase(NULL);	/* didn't find the screen at all */
    debug("Didn't find indicated screen.");

QUIT:
    CloseLibrary(IntuitionBase);
    CloseLibrary(GfxBase);
}

/* case-insensitive string comparison, with \0 and space as end conditions */

compare(string1,string2)
char *string1,*string2;
{
    while ((*string1 != '\0') && (*string1 != ' '))
    {
	if (toupper(*(string1++)) != toupper(*(string2++)))
	    return(1);
    }
    return(0);	/* return weird values like strcmp() */
}

SHAR_EOF
if test 6787 -ne "`wc -c colour.c`"
then
echo shar: error transmitting colour.c '(should have been 6787 characters)'
fi
cat << \SHAR_EOF > amber.col
0 0 1
13 13 2
0 0 8
15 15 15
SHAR_EOF
if test 29 -ne "`wc -c amber.col`"
then
echo shar: error transmitting amber.col '(should have been 29 characters)'
fi
cat << \SHAR_EOF > cyan.col
0 0 0
0 15 15
0 0 7
15 15 0
SHAR_EOF
if test 28 -ne "`wc -c cyan.col`"
then
echo shar: error transmitting cyan.col '(should have been 28 characters)'
fi
cat << \SHAR_EOF > gray.col
3 3 3
15 15 15
0 0 0
15 15 0
SHAR_EOF
if test 29 -ne "`wc -c gray.col`"
then
echo shar: error transmitting gray.col '(should have been 29 characters)'
fi
cat << \SHAR_EOF > green.col
0 2 0
0 13 0
0 0 6
11 11 11
SHAR_EOF
if test 28 -ne "`wc -c green.col`"
then
echo shar: error transmitting green.col '(should have been 28 characters)'
fi
cat << \SHAR_EOF > lace.col
5 5 5
0 0 0
0 2 7
8 8 0
SHAR_EOF
if test 24 -ne "`wc -c lace.col`"
then
echo shar: error transmitting lace.col '(should have been 24 characters)'
fi
cat << \SHAR_EOF > modem.col
0 0 0
10 10 10
12 12 12
12 0 0
SHAR_EOF
if test 31 -ne "`wc -c modem.col`"
then
echo shar: error transmitting modem.col '(should have been 31 characters)'
fi
cat << \SHAR_EOF > pastel.col
6 0 10
15 14 7
4 4 7
13 9 7
SHAR_EOF
if test 28 -ne "`wc -c pastel.col`"
then
echo shar: error transmitting pastel.col '(should have been 28 characters)'
fi
cat << \SHAR_EOF > red.col
6 0 0
13 9 0
0 2 4
15 15 15
SHAR_EOF
if test 28 -ne "`wc -c red.col`"
then
echo shar: error transmitting red.col '(should have been 28 characters)'
fi
cat << \SHAR_EOF > royal.col
2 0 4
15 14 0
0 0 8
15 15 15
SHAR_EOF
if test 29 -ne "`wc -c royal.col`"
then
echo shar: error transmitting royal.col '(should have been 29 characters)'
fi
cat << \SHAR_EOF > silver.col
6 8 9
0 0 0
0 0 8
15 15 15
SHAR_EOF
if test 27 -ne "`wc -c silver.col`"
then
echo shar: error transmitting silver.col '(should have been 27 characters)'
fi
cat << \SHAR_EOF > silver2.col
6 8 9
15 15 15
0 0 11
0 0 0
SHAR_EOF
if test 28 -ne "`wc -c silver2.col`"
then
echo shar: error transmitting silver2.col '(should have been 28 characters)'
fi
cat << \SHAR_EOF > wb.col
0 0 7
15 15 15
0 0 2
15 8 0
SHAR_EOF
if test 28 -ne "`wc -c wb.col`"
then
echo shar: error transmitting wb.col '(should have been 28 characters)'
fi
#	End of shell archive
exit 0