/*
 *  FM_PalettePrefs_React.c
 *
 *  requester for palette-prefs with reaction-support
 *  $VER: V2.1, 08.06.2002
 *  Coded by Edgar Schwan
 */

#include <intuition/gadgetclass.h>
#include <intuition/classusr.h>
#include <intuition/screens.h>
#include <classes/window.h>
#include <classes/arexx.h>
#include <gadgets/palette.h>
#include <gadgets/slider.h>
#include <gadgets/integer.h>

#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/exec_protos.h>
#include <clib/resource_protos.h>
#include <clib/locale_protos.h>
#include <clib/dos_protos.h>
#include <clib/alib_protos.h>

#include <pragmas/intuition_pragmas.h>
#include <pragmas/graphics_pragmas.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/resource_pragmas.h>
#include <pragmas/locale_pragmas.h>
#include <pragmas/dos_pragmas.h>

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

#include "FM_PalettePref_React.h"
#include "FM_ReactionBasics.h"
#include "FM_Reaction.h"
#include "FM_ReactionCD.h"

struct ReactWinData *pal_rwd = NULL;

#define INTERCONNECTION

/* defaults */
#define DEF_PEN		3
#define STARTPEN     (4L)
#define ENDPEN       (255L)
#define MINVALUE     (0L)
#define MAXVALUE     (255L)
#define DELTA        (10L)
#define SHIFT_QUAL (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)

/* local prototypes */
static void Copy(struct Window *Win, ULONG PenNumber, struct RGB *RGBBuffer);
static void Paste(struct Window *Win, const ULONG PenNumber, struct RGB *RGBBuffer, struct loadrgb *Palette);
static void Swap (struct Window *Win, const ULONG Pen_1, const ULONG Pen_2, struct loadrgb *Palette);
static BOOL Spread (struct Window *Win, const ULONG Pen_1, const ULONG Pen_2, struct loadrgb *Palette);
static void InvertPalette(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette);
static void Shl(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette);
static void Shr(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette);
static void UpdateSliders(ULONG Pen, struct loadrgb *Palette);

/* vars */
ULONG RedLevel, GreenLevel, BlueLevel;
ULONG ActPen, OldPen, NewPen, NumColors;
struct RGB UndoRGB = {0}, ClipRGB = {0}, ActRGB = {0};
BOOL Do_Copy, Do_Swap, Do_Spread;

/*	Do_PalettePrefRequest(): palette-requester (full handling).

		SYNOPSIS: BOOL res = Do_PalettePrefWd
						(
						struct Window	  *Win;
						char				  *PubScreenName;
						WORD 					Left;
						WORD					Top;
						struct loadrgb	  *Palette32;
						);

		INPUTS:		Win:
							Pointer to the parent-window.

						PubScreenName:
							name of the public-screen, where the window should appear.

						Left:
							Left edge of palette-window (not supported yet).

						Top:
							Top edge of palette-window (not supported yet).

						Palette32:
							pointer to a loadrgb-structure with palette to edit.

		RETURNS:		res:
							Is TRUE, if something changed.
*/

BOOL Do_PalettePrefRequest(struct Window *Win, char *PubScreenName, WORD Left, WORD Top, struct loadrgb *Palette32)
{
ULONG rc = FALSE, result = RESULT_NOTHING, waitsigs, mask;
ULONG PalLength;
struct loadrgb *WorkPal = NULL;
struct loadrgb *UndoPal = NULL;
struct RGB (*WorkPalColors) [1] = NULL;
struct RGB (*UndoPalColors) [1] = NULL;
struct loadrgb *WorkPalRGB = NULL;
struct DrawInfo *dri = NULL;

Do_Copy = FALSE; Do_Swap = FALSE; Do_Spread = FALSE;

if (dri = GetScreenDrawInfo(Win->WScreen)) {
	NumColors = 1L << dri->dri_Depth;
	if (OpenPalettePrefWindow(PubScreenName) == TRUE) {
		waitsigs = pal_rwd->RWD_WSignals|SIGBREAKF_CTRL_C;

		PalLength = sizeof(struct loadrgb_head) + ((NumColors + 1) * sizeof(struct RGB));
		if (WorkPal = (struct loadrgb *) AllocVec(PalLength, MEMF_PUBLIC|MEMF_CLEAR)) {
			WorkPal->loadrgb_lrgb.lrgb_count = NumColors;
			WorkPal->loadrgb_lrgb.lrgb_first = 0;
			WorkPalColors = (struct RGB (*) [1]) (((ULONG) *(&WorkPal)) + sizeof(struct loadrgb_head));
			if (UndoPal = (struct loadrgb *) AllocVec(PalLength, MEMF_PUBLIC|MEMF_CLEAR)) {
				UndoPal->loadrgb_lrgb.lrgb_count = NumColors;
				UndoPal->loadrgb_lrgb.lrgb_first = 0;
				UndoPalColors = (struct RGB (*) [1]) (((ULONG) *(&UndoPal)) + sizeof(struct loadrgb_head));
				GetRGB32 (ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) WorkPalColors);
				GetRGB32 (ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);

				UpdateSliders(DEF_PEN, WorkPal);
				ActPen = DEF_PEN;
				rc = TRUE;

				while(result == RESULT_NOTHING) {
					mask = Wait(waitsigs);
#ifndef NDEBUG
					printf("mask: %lX\n", mask);
#endif /*NDEBUG*/
					if (mask & pal_rwd->RWD_WSignals) {
						result = HandlePalettePrefWindow(Win, Palette32, WorkPal, UndoPal);
						}
					if (mask & SIGBREAKF_CTRL_C) {
						LoadRGB32(ViewPortAddress(Win), (APTR) Palette32);
						result = RESULT_CANCEL;
						}
					}

				FreeVec(UndoPal);
				} else DisplayError(Win, TXT_ERR_NoMem, 5L);
			FreeVec(WorkPal);
			} else DisplayError(Win, TXT_ERR_NoMem, 5L);
		ClosePalettePrefWindow();
		} else DisplayError(Win, TXT_ERR_Window, 5L);
	FreeScreenDrawInfo(Win->WScreen, dri);
	}
return(rc);
}

/*	OpenPalettePrefWindow(): open window of palette-requester.

		SYNOPSIS: BOOL res = OpenPalettePrefWindow
						(
						char	*PubScreenName;
						);

		INPUTS:		PubScreenName:
							name of the public-screen, where the window should appear.

		RETURNS:		res:
							TRUE, if successfull.
*/

BOOL OpenPalettePrefWindow(char *PubScreenName)
{
if (pal_rwd = OpenReactionWindow(WIN_PALETTE_ID, GROUP_Pal_ID, PubScreenName)) {
	SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_PALETTE_1], pal_rwd->RWD_IWindow, NULL,
						PALETTE_NumColours, NumColors, TAG_DONE);
	SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_PALETTE_1], pal_rwd->RWD_IWindow, NULL,
						PALETTE_Colour, DEF_PEN, TAG_DONE);
	return(TRUE);
	}
return(FALSE);
}

/*	ClosePalettePrefWindow(): close window of palette-requester.

		SYNOPSIS: void = ClosePalettePrefWindow
						(
						void
						);

		INPUTS:		-

		RETURNS:		res:
							result of the request.
*/

void ClosePalettePrefWindow(void)
{
CloseReactionWindow(pal_rwd);
}

/*	HandlePalettePrefWindow(): Handle the messages of the palette-requester.

		SYNOPSIS: LONG = HandlePalettePrefWindow
						(
						struct Window	*Win;
						struct loadrgb	*Palette32;
						struct loadrgb	*WorkPal;
						struct loadrgb	*UndoPal;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						Palette32:
							Pointer to a loadrgb-structure of the Palette to edit.

						WorkPal;
							Pointer to a loadrgb-structure of the Work-Palette.

						UndoPal:
							Pointer to a loadrgb-structure of the Undo-Palette.

		RETURNS:		res:
							result of messages:	RESULT_NOTHING -> nothing happens.
														RESULT_CANCEL  -> user wants to quit without a change.
														RESULT_OK      -> accept changes and quit.
*/

LONG HandlePalettePrefWindow(struct Window *Win, struct loadrgb *Palette32, struct loadrgb *WorkPal,
									  struct loadrgb *UndoPal)
{
ULONG code, result, rc = RESULT_NOTHING;
struct RGB (*Palette32Colors) [1] = (struct RGB (*) [1]) (((ULONG) *(&Palette32)) + sizeof(struct loadrgb_head));
struct RGB (*WorkPalColors) [1] = (struct RGB (*) [1]) (((ULONG) *(&WorkPal)) + sizeof(struct loadrgb_head));
struct RGB (*UndoPalColors) [1] = (struct RGB (*) [1]) (((ULONG) *(&UndoPal)) + sizeof(struct loadrgb_head));

while((result = DoMethod(pal_rwd->RWD_WindowObject, WM_HANDLEINPUT, &code)) != WMHI_LASTMSG) {

#ifndef NDEBUG
	printf("result: %lX\n", result);
#endif /*NDEBUG*/

	switch (result & WMHI_CLASSMASK) {
		case WMHI_CLOSEWINDOW:
			LoadRGB32(ViewPortAddress(Win), (APTR) Palette32);
			rc = RESULT_CANCEL;
			break;

		case WMHI_GADGETUP:
			switch (result & RL_GADGETMASK) {
				case Pal_BUTTON_Accept:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) Palette32Colors);
					rc = RESULT_OK;
					break;
				case Pal_BUTTON_Reset:
					LoadRGB32(ViewPortAddress(Win), (APTR) Palette32);
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) WorkPalColors);
					UpdateSliders(ActPen, WorkPal);
					break;
				case Pal_BUTTON_Cancel:
					LoadRGB32(ViewPortAddress(Win), (APTR) Palette32);
					rc = RESULT_CANCEL;
					break;
				case Pal_BUTTON_Copy:
					Copy(Win, ActPen, &ClipRGB);
					Do_Copy = TRUE; Do_Swap = FALSE; Do_Spread = FALSE;
					break;
				case Pal_BUTTON_Swap:
					OldPen = ActPen;
					Do_Copy = FALSE; Do_Swap = TRUE; Do_Spread = FALSE;
					break;
				case Pal_BUTTON_Spread:
					OldPen = ActPen;
					Do_Copy = FALSE; Do_Swap = FALSE; Do_Spread = TRUE;
					break;
				case Pal_BUTTON_Invert:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					InvertPalette(Win, STARTPEN, NumColors - 1, WorkPal);
					UpdateSliders(ActPen, WorkPal);
					break;
				case Pal_BUTTON_ShiftLeft:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					Shl(Win, STARTPEN, ENDPEN, WorkPal);
					break;
				case Pal_BUTTON_ShiftRight:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					Shr(Win, STARTPEN, ENDPEN, WorkPal);
					break;
				case Pal_BUTTON_Undo:
					LoadRGB32(ViewPortAddress(Win), (APTR) UndoPal);
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) WorkPalColors);
					UpdateSliders(ActPen, WorkPal);
					break;
				case Pal_PALETTE_1:
					GetAttr(PALETTE_Colour, pal_rwd->RWD_GadgetArray[Pal_PALETTE_1], &ActPen);
					if (Do_Copy == TRUE) {
						GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
						Paste(Win, ActPen, &ClipRGB, WorkPal);
						Do_Copy = FALSE;
						}

					if (Do_Swap == TRUE) {
						GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
						NewPen = ActPen;
						Swap(Win, OldPen, NewPen, WorkPal);
						Do_Swap = FALSE;
						}

					if (Do_Spread == TRUE) {
						GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
						NewPen = ActPen;
						Spread(Win, OldPen, NewPen, WorkPal);
						Do_Spread = FALSE;
						}

					UpdateSliders(ActPen, WorkPal);
					break;
				case Pal_INTEGER_RedValue:
#ifndef INTERCONNECTION
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(INTEGER_Number, pal_rwd->RWD_GadgetArray[Pal_INTEGER_RedValue], &RedLevel);
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
										SLIDER_Level, RedLevel, TAG_DONE);
					WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
#endif /*INTERCONNECTION*/
				case Pal_SLIDER_Red:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(SLIDER_Level, pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], &RedLevel);
#ifndef INTERCONNECTION
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_RedValue], pal_rwd->RWD_IWindow, NULL,
										INTEGER_Number, RedLevel, TAG_DONE);
#endif /*INTERCONNECTION*/
					WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
				case Pal_INTEGER_GreenValue:
#ifndef INTERCONNECTION
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(INTEGER_Number, pal_rwd->RWD_GadgetArray[Pal_INTEGER_GreenValue], &GreenLevel);
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
										SLIDER_Level, GreenLevel, TAG_DONE);
					WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
#endif /*INTERCONNECTION*/
				case Pal_SLIDER_Green:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(SLIDER_Level, pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], &GreenLevel);
#ifndef INTERCONNECTION
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_GreenValue], pal_rwd->RWD_IWindow, NULL,
										INTEGER_Number, GreenLevel, TAG_DONE);
#endif /*INTERCONNECTION*/
					WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
				case Pal_INTEGER_BlueValue:
#ifndef INTERCONNECTION
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(INTEGER_Number, pal_rwd->RWD_GadgetArray[Pal_INTEGER_BlueValue], &BlueLevel);
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
										SLIDER_Level, BlueLevel, TAG_DONE);
					WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
#endif /*INTERCONNECTION*/
				case Pal_SLIDER_Blue:
					GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
					GetAttr(SLIDER_Level, pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], &BlueLevel);
#ifndef INTERCONNECTION
					SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_BlueValue], pal_rwd->RWD_IWindow, NULL,
										INTEGER_Number, BlueLevel, TAG_DONE);
#endif /*INTERCONNECTION*/
					WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;;
					LoadRGB32(ViewPortAddress(Win), (APTR) WorkPal);
					break;
#ifndef NDEBUG
				default:
					printf("unknown result: %lX\nunknown gadget: %lX\n", result, result & WMHI_GADGETMASK);
					DisplayBeep(NULL);
					break;
#endif /*NDEBUG*/
				}
			break;

		case WMHI_ICONIFY:
			DoMethod(pal_rwd->RWD_WindowObject, WM_ICONIFY);
			GetAttr(WINDOW_Window, pal_rwd->RWD_WindowObject, (ULONG *) &pal_rwd->RWD_IWindow);
			break;

		case WMHI_UNICONIFY:
			DoMethod(pal_rwd->RWD_WindowObject, WM_OPEN);
			GetAttr(WINDOW_Window, pal_rwd->RWD_WindowObject, (ULONG *) &pal_rwd->RWD_IWindow);
			break;

		case WMHI_RAWKEY:
			{
			struct InputEvent *ie = NULL;
			GetAttr(WINDOW_InputEvent, pal_rwd->RWD_WindowObject, (ULONG *) &ie);
#if 0
printf("Key: %ld, Qualifier: %ld\n", result & WMHI_KEYMASK, ie->ie_Qualifier);
#endif
			switch (result & WMHI_KEYMASK) {
				case 69:   /* esc */
					LoadRGB32(ViewPortAddress(Win), (APTR) Palette32);
					rc = RESULT_CANCEL;
					break;
				case 18:   /* e */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* red - delta */
						RedLevel = WorkPalColors[ActPen]->RGB_Red >> 24L;
						if (RedLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							RedLevel = (RedLevel < (MINVALUE + DELTA)) ? MINVALUE : RedLevel - DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, RedLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* red - 1 */
						RedLevel = WorkPalColors[ActPen]->RGB_Red >> 24L;
						if (RedLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							RedLevel = (RedLevel < (MINVALUE + 1)) ? MINVALUE : RedLevel - 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, RedLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				case 20:   /* t */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* red + delta */
						RedLevel = WorkPalColors[ActPen]->RGB_Red >> 24L;
						if (RedLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							RedLevel = (RedLevel > (MAXVALUE - DELTA)) ? MAXVALUE : RedLevel + DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, RedLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* red + 1 */
						RedLevel = WorkPalColors[ActPen]->RGB_Red >> 24L;
						if (RedLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							RedLevel = (RedLevel > (MAXVALUE - 1)) ? MAXVALUE : RedLevel + 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, RedLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Red = RedLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				case 35:   /* f */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* green - delta */
						GreenLevel = WorkPalColors[ActPen]->RGB_Green >> 24L;
						if (GreenLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							GreenLevel = (GreenLevel < (MINVALUE + DELTA)) ? MINVALUE : GreenLevel - DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, GreenLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* green - 1 */
						if (GreenLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							GreenLevel = (GreenLevel < (MINVALUE + 1)) ? MINVALUE : GreenLevel - 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, GreenLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				case 37:   /* h */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* green + delta */
						GreenLevel = WorkPalColors[ActPen]->RGB_Green >> 24L;
						if (GreenLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							GreenLevel = (GreenLevel > (MAXVALUE - DELTA)) ? MAXVALUE : GreenLevel + DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, GreenLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* green + 1 */
						GreenLevel = WorkPalColors[ActPen]->RGB_Green >> 24L;
						if (GreenLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							GreenLevel = (GreenLevel > (MAXVALUE - 1)) ? MAXVALUE : GreenLevel + 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, GreenLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Green = GreenLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				case 52:   /* v */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* blue - delta */
						BlueLevel = WorkPalColors[ActPen]->RGB_Blue >> 24L;
						if (BlueLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							BlueLevel = (BlueLevel < (MINVALUE + DELTA)) ? MINVALUE : BlueLevel - DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, BlueLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* blue - 1 */
						if (BlueLevel > MINVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							BlueLevel = (BlueLevel < (MINVALUE + 1)) ? MINVALUE : BlueLevel - 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, BlueLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				case 54:   /* n */
					if (ie->ie_Qualifier & SHIFT_QUAL) {	/* blue + delta */
						BlueLevel = WorkPalColors[ActPen]->RGB_Blue >> 24L;
						if (BlueLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							BlueLevel = (BlueLevel > (MAXVALUE - DELTA)) ? MAXVALUE : BlueLevel + DELTA;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, BlueLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					else {											/* blue + 1 */
						BlueLevel = WorkPalColors[ActPen]->RGB_Blue >> 24L;
						if (BlueLevel < MAXVALUE) {
							GetRGB32(ViewPortAddress(Win)->ColorMap, 0L, NumColors, (ULONG *) UndoPalColors);
							BlueLevel = (BlueLevel > (MAXVALUE - 1)) ? MAXVALUE : BlueLevel + 1;
							SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
												SLIDER_Level, BlueLevel, TAG_DONE);
							WorkPalColors[ActPen]->RGB_Blue = BlueLevel << 24L;
							LoadRGB32(ViewPortAddress (Win), (APTR) WorkPal);
							}
						}
					break;
				}
			break;
			}

#ifndef NDEBUG
		default:
			printf("unknown result: %lX\nunknown class: %lX\n", result, result & WMHI_CLASSMASK);
			DisplayBeep(NULL);
			break;
#endif /*NDEBUG*/
		}
	}
return(rc);
}

/* Copy: Copy the color-values of an desired pen to a RGB-structure.

		SYNOPSIS: static void = Copy
						(
						struct Window *Win;
						ULONG				PenNumber;
						struct RGB	  *RGBColor;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						PenNumber:
							Number of the pen to copy.

						RGBColor:
							Pointer to a RGB-structure to store th color-values.

		RETURNS:		- 
*/

static void Copy(struct Window *Win, ULONG PenNumber, struct RGB *RGBColor)
{
GetRGB32 (ViewPortAddress(Win)->ColorMap, PenNumber, 1L, (ULONG *) RGBColor);
}

/* Paste: store the color-values of a RGB-structure to a pen of a palette.

		SYNOPSIS: static void = Paste
						(
						struct Window	  *Win;
						const ULONG			PenNumber;
						struct RGB		  *RGBColor;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						PenNumber:
							Number of the pen to copy.

						RGBColor:
							Pointer to a RGB-structure, which contains the color-values.

						Palette:
							Pointer to a loadrgb-structure to edit.

		RETURNS:		- 
*/

static void Paste(struct Window *Win, const ULONG PenNumber, struct RGB *RGBColor, struct loadrgb *Palette)
{
struct RGB (*PalColors) [1] = (struct RGB (*) [1]) (((ULONG) *(&Palette)) + sizeof(struct loadrgb_head));

PalColors[PenNumber]->RGB_Red = RGBColor->RGB_Red;
PalColors[PenNumber]->RGB_Green = RGBColor->RGB_Green;
PalColors[PenNumber]->RGB_Blue = RGBColor->RGB_Blue;
LoadRGB32 (ViewPortAddress(Win), (ULONG *) Palette);
}

/* Swap: Swap two colors of a palette.

		SYNOPSIS: static void = Swap
						(
						struct Window	  *Win;
						const ULONG			Pen_1;
						const ULONG			Pen_2;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						Pen_1:
							Number of the first pen.

						Pen_2:
							Number of the second pen.

						Palette:
							Pointer to a loadrgb-structure to edit.

		RETURNS:		- 
*/

static void Swap(struct Window *Win, const ULONG Pen_1, const ULONG Pen_2, struct loadrgb *Palette)
{
struct RGB TmpRGB1, TmpRGB2;

Copy (Win, Pen_1, &TmpRGB1);
Copy (Win, Pen_2, &TmpRGB2);
Paste (Win, Pen_1, &TmpRGB2, Palette);
Paste (Win, Pen_2, &TmpRGB1, Palette);
}

/*	Spread(): Create a range of colors between two pens.

		SYNOPSIS: static BOOL res = Spread
						(
						struct Window	  *Win;
						const ULONG			OldPen;
						const ULONG			NewPen;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						OldPen:
							Number of the old pen.

						NewPen:
							Number of the new Pen.

						Palette:
							Pointer to a loadrgb-structure of the palette to edit.

		RETURNS:		res: 
							TRUE, if spread failed.
*/

static BOOL Spread(struct Window *Win, const ULONG OldPen, const ULONG NewPen, struct loadrgb *Palette)
{
struct RGB (*PalColors) [1] = (struct RGB (*) [1]) (((ULONG) *(&Palette)) + sizeof(struct loadrgb_head));
const ULONG StartPen = MIN (OldPen, NewPen), EndPen = MAX (OldPen, NewPen);
const ULONG  Range = EndPen - StartPen;
LONG RedStep, GreenStep, BlueStep;
ULONG Index, RLevel, GLevel, BLevel;

if (Range < 2L) return(TRUE);

RLevel = PalColors[StartPen]->RGB_Red >> 8L;
GLevel = PalColors[StartPen]->RGB_Green >> 8L;
BLevel = PalColors[StartPen]->RGB_Blue >> 8L;

RedStep = (LONG) PalColors[EndPen]->RGB_Red >> 8L;
GreenStep = (LONG) PalColors[EndPen]->RGB_Green >> 8L;
BlueStep = (LONG) PalColors[EndPen]->RGB_Blue >> 8L;

RedStep    -= (LONG) RLevel;
GreenStep  -= (LONG) GLevel;
BlueStep   -= (LONG) BLevel;

RedStep    /= (LONG) Range;
GreenStep  /= (LONG) Range;
BlueStep   /= (LONG) Range;

for (Index = (StartPen + 1L); Index < EndPen; Index++) {
	RLevel += RedStep;
	GLevel += GreenStep;
	BLevel += BlueStep;

	PalColors[Index]->RGB_Red = RLevel << 8L;
	PalColors[Index]->RGB_Green = GLevel << 8L;
	PalColors[Index]->RGB_Blue = BLevel << 8L;
	}

LoadRGB32 (ViewPortAddress (Win), (APTR) Palette);

return(FALSE);
}

/*	InvertPalette(): Invert the colors of a palette.

		SYNOPSIS: static void = InvertPalette
						(
						struct Window	  *Win;
						ULONG					StartPen;
						ULONG					EndPen;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						StartPen:
							Number of the first pen.

						EndPen:
							Number of the last Pen.

						Palette:
							Pointer to a loadrgb-structure of the palette to edit.

		RETURNS:		-
*/

static void InvertPalette(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette)
{
while (StartPen < EndPen) Swap(Win, StartPen++, EndPen--, Palette);
}

/*	Shl(): Shift palette-colors to left.

		SYNOPSIS: static void = Shl
						(
						struct Window	  *Win;
						ULONG					StartPen;
						ULONG					EndPen;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						StartPen:
							Number of the first pen.

						EndPen:
							Number of the last Pen.

						Palette:
							Pointer to a loadrgb-structure of the palette to edit.

		RETURNS:		-
*/

static void Shl(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette)
{
while (StartPen < EndPen) Swap(Win, StartPen, StartPen + 1, Palette), StartPen++;
}

/*	Shr(): Shift palette-colors to right.

		SYNOPSIS: static void = Shr
						(
						struct Window	  *Win;
						ULONG					StartPen;
						ULONG					EndPen;
						struct loadrgb	  *Palette;
						);

		INPUTS:		Win:
							Pointer to a window-structure.

						StartPen:
							Number of the first pen.

						EndPen:
							Number of the last Pen.

						Palette:
							Pointer to a loadrgb-structure of the palette to edit.

		RETURNS:		res: -
*/

static void Shr(struct Window *Win, ULONG StartPen, ULONG EndPen, struct loadrgb *Palette)
{
while (EndPen > StartPen) Swap(Win, EndPen, EndPen - 1, Palette), EndPen--;
}

/*	UpdateSliders(): Update slider-positions and integer-values.

		SYNOPSIS: static void = UpdateSliders
						(
						ULONG					Pen;
						struct loadrgb   *Palette;
						);

		INPUTS:		Pen:
							Number of desired pen.

						Palette:
							Pointer to a loadrgb-structure of the palette to use.

		RETURNS:		-
*/

static void UpdateSliders(ULONG Pen, struct loadrgb *Palette)
{
struct RGB (*PalColors) [1] = (struct RGB (*) [1]) (((ULONG) *(&Palette)) + sizeof(struct loadrgb_head));

RedLevel = (PalColors[Pen]->RGB_Red >> 24L);
GreenLevel = (PalColors[Pen]->RGB_Green >> 24L);
BlueLevel = (PalColors[Pen]->RGB_Blue >> 24L);

SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Red], pal_rwd->RWD_IWindow, NULL,
					SLIDER_Level, RedLevel, TAG_DONE);
SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Green], pal_rwd->RWD_IWindow, NULL,
					SLIDER_Level, GreenLevel, TAG_DONE);
SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_SLIDER_Blue], pal_rwd->RWD_IWindow, NULL,
					SLIDER_Level, BlueLevel, TAG_DONE);

#ifndef INTERCONNECTION
SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_RedValue], pal_rwd->RWD_IWindow, NULL,
					INTEGER_Number, RedLevel, TAG_DONE);
SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_GreenValue], pal_rwd->RWD_IWindow, NULL,
					INTEGER_Number, GreenLevel, TAG_DONE);
SetGadgetAttrs(pal_rwd->RWD_GadgetArray[Pal_INTEGER_BlueValue], pal_rwd->RWD_IWindow, NULL,
					INTEGER_Number, BlueLevel, TAG_DONE);
#endif /*INTERCONNECTION*/
}
