/*
**  Colors.c  Version 39.24  (28. August 1993)
**
**  Ein Programm zum ändern der Farben des Bildschirms im Vordergrund
**  unter Amiga-OS 2.04 und höher, mit Unterstützung des AGA Chipsets
**  und der Locale-Library.
**
**  (c) Copyright 1993 Ralf Seyfarth
**	Alle Rechte vorbehalten
**  
**  Dieses Programm ist FREEWARE, es darf frei weitergegeben werden,
**  solange alle Dateien im original Zustand enthalten sind.
**
**  Aufruf für DICE (2.07.56R) :
**
**  DCC Colors.c -o Colors -3.0 -mi -ms -r
*/


#define VERSIONS_STRING  "$VER: Colors 39.24 (28.8.93)"

/* alte Intuitions-Bezeichner werden nicht gebraucht */

#define INTUITION_IOBSOLETE_H

/* benötigte Include-Files */

#include <dos/dos.h>
#include <dos/dosextens.h>
#include <dos/rdargs.h>
#include <graphics/gfxbase.h>
#include <intuition/gadgetclass.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <libraries/gadtools.h>
#include <libraries/locale.h>
#include <workbench/icon.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>

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

#define   GfxBase_DECLARED
#define   IntuitionBase_DECLARED
#define   LocaleBase_DECLARED

#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/gadtools.h>
#include <proto/graphics.h>
#include <proto/icon.h>
#include <proto/intuition.h>
#include <proto/locale.h>

#include "Colors.h"

/* einige nützliche Definitionen */

#define PALETTE_ID     1		/* Gadgets ID's */
#define RED_ID         2
#define GREEN_ID       3
#define BLUE_ID        4
#define UNDO_ID        5
#define RESET_ID       6
#define USE_ID         7
#define CANCEL_ID      8

#define DELAY_TIME     150L		/* 3 Sekunden Verzögerung */
#define TEMPLATE_WB   "DELAY"
#define TEMPLATE_CLI  "DELAY/S"
#define TOPAZ_NAME    "topaz.font"

/* Funktions-Prototypen */

VOID   Setup(VOID);
VOID   HandleEvent(VOID);
VOID   SetColor(VOID);
VOID   SetSliders(VOID);
VOID   ResetColors(VOID);
VOID   ConvertRGB4(UWORD);
VOID   ConvertRGB32(VOID);
ULONG  RGB8to32(UWORD);
UBYTE *LocStrCat(UBYTE);
VOID   SysConfig(VOID);

/* IntuitionBase und GfxBase werden vom Compiler zur Verfügung gestellt */

IMPORT struct IntuitionBase *IntuitionBase;
IMPORT struct GfxBase       *GfxBase;

/* globale Variablen */

struct LocaleBase *LocaleBase;
struct Screen     *Screen;
struct Window     *Window;
struct ViewPort   *ViewPort;
struct Gadget     *RedSlider,
		  *GreenSlider,
		  *BlueSlider;

/* Struktur für Locale-Strings */

STATIC const struct LocText LocText[] =
{
   { MSG_WTITLE_ID, MSG_WTITLE_STR },
   { MSG_RED_ID   , MSG_RED_STR    },
   { MSG_GREEN_ID , MSG_GREEN_STR  },
   { MSG_BLUE_ID  , MSG_BLUE_STR   },
   { MSG_UNDO_ID  , MSG_UNDO_STR   },
   { MSG_RESET_ID , MSG_RESET_STR  },
   { MSG_USE_ID   , MSG_USE_STR    },
   { MSG_CANCEL_ID, MSG_CANCEL_STR }
};

STATIC const UBYTE Version[] = VERSIONS_STRING;

BOOL  AGA;
UBYTE LocStr[3][16];
UWORD Red,
      Green,
      Blue,
      ActColor,
      RGB4[32];
LONG  Count,
      DELAY;
ULONG RGB32[769];


/* CLI-Einsprungspunkt */

VOID
main(VOID)
{
    struct RDArgs *RDArgs;

    SysConfig();			/* Systemkonfiguration feststellen */

    /* Argumente einlesen */

    if (!(RDArgs = ReadArgs(TEMPLATE_CLI, &DELAY, NULL)))
    {
	PrintFault(IoErr(), NULL);	/* Fehlertext ausgeben */
	exit(RETURN_FAIL);		/* Programm beenden    */
    }

    FreeArgs(RDArgs);			/* Argumente freigeben */
    Setup();				/* Hauptprogramm       */
}


/* Workbench-Einsprungspunkt */

VOID
wbmain(struct WBStartup *WBMsg)
{
    BPTR OldCDir;

    SysConfig();			/* Systemkonfiguration feststellen */

    /* neuen Pfad setzen */

    if (OldCDir = CurrentDir(WBMsg->sm_ArgList[0].wa_Lock))
    {
	struct DiskObject *DObj;

	/* DiskObject anfordern */

	if (DObj = GetDiskObject(WBMsg->sm_ArgList[0].wa_Name))
	{
	    /* ToolType suchen */

	    if (FindToolType(DObj->do_ToolTypes, TEMPLATE_WB))
		DELAY = TRUE;

	    FreeDiskObject(DObj);	/* DiskObject freigeben */
	}

	CurrentDir(OldCDir);		/* alten Pfad wiederherstellen */
    }

    Setup();				/* Hauptprogramm */
}


/* Hauptprogramm */

VOID
Setup(VOID)
{
    struct Gadget    *OldGadget,
		     *GList;
    struct TextFont  *Font;
    struct DrawInfo  *DrawInfo;
    struct NewGadget  NewGadget;

    /* Font für Gadgets */

    STATIC struct TextAttr FontAttr = { TOPAZ_NAME, TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT };

    /* Fenster Tag-Liste */

    STATIC struct TagItem WindowTagList[] =
    {
       { WA_CustomScreen, NULL },
       { WA_Width       , 0    },
       { WA_Height      , 0    },
       { WA_Left        , 0    },
       { WA_Top         , 0    },
       { WA_Title       , NULL },
       { WA_ScreenTitle , NULL },
       { WA_Zoom        , NULL },
       { WA_IDCMP       , PALETTEIDCMP	     |
			  SLIDERIDCMP	     |
			  BUTTONIDCMP	     |
			  IDCMP_CLOSEWINDOW  |
			  IDCMP_REFRESHWINDOW },
       { WA_Activate    , TRUE },
       { WA_DragBar     , TRUE },
       { WA_CloseGadget , TRUE },
       { WA_DepthGadget , TRUE },
       { WA_RMBTrap     , TRUE },
       { TAG_END        , NULL }
    };

    APTR  VisualInfo;
    UWORD Top,
	  LeRi,
	  Depth,
	  FSize,
	  Offset = 0,
	  ZPos[4];
    LONG  ECode  = RETURN_FAIL;


    if (DELAY)            			/* warten */
	Delay(DELAY_TIME);

    Screen   =  IntuitionBase->FirstScreen;	/* Screen im Vordergrund */
    ViewPort = &Screen->ViewPort;		/* ViewPort sichern	 */

    if (DrawInfo = GetScreenDrawInfo(Screen))	/* ScreenDrawInfo anfordern */
    {
	Depth = DrawInfo->dri_Depth;		/* Anzahl der BitPlanes */

	/* EHB, HAM und HAM8 Modus beachten */

	if ((ViewPort->Modes & EXTRA_HALFBRITE) == EXTRA_HALFBRITE)
	    Depth = 5;
	else
	    if ((ViewPort->Modes & HAM) == HAM)
		Depth = Depth == 8 ? 6 : 4;

	if (AGA)
	{
	    if (Depth > 8)			/* nur zur Sicherheit: AGA Chipset max. 8 BitPlanes */
		Depth = 8;

	    switch (Depth)			/* Höhe des Palette-Gadgets anpassen */
	    {
		    case 5 :
		    case 6 : Offset = 15;
			     break;

		    case 7 : Offset = 43;
			     break;

		    case 8 : Offset = 67;
	     }
	}
	else
	     if (Depth > 5)			/* nur zur Sicherheit: Orig. u. ECS Chipset max. 5 BitPlanes */
		 Depth = 5;

	Count = 1 << Depth;			/* Anzahl der Farben */

	if (Font = OpenFont(&FontAttr))		/* Font für Gadgets öffnen */
	{
	    FSize = Screen->Font->ta_YSize;	/* Font-Höhe für Titelzeile holen */
	    Top   = Screen->WBorTop;
	    LeRi  = Screen->WBorLeft + Screen->WBorRight;

	    if (VisualInfo = GetVisualInfo(Screen, TAG_DONE))	/* VisualInfo anfordern */
	    {
		/* Angaben für Fenster Tag-Liste eintragen */

		WindowTagList[0].ti_Data = Screen;
		WindowTagList[1].ti_Data = LeRi + 221;
		WindowTagList[2].ti_Data = Screen->WBorBottom + Top + FSize + Offset + 88;
		WindowTagList[3].ti_Data = ZPos[0] = (Screen->Width  - WindowTagList[1].ti_Data) / 2;
		WindowTagList[4].ti_Data = ZPos[1] = (Screen->Height - WindowTagList[2].ti_Data) / 2;
		WindowTagList[5].ti_Data = LocText[0].lt_Str;
		WindowTagList[6].ti_Data = Screen->Title;
		WindowTagList[7].ti_Data = ZPos;

		/* Angaben für Zoom-Gadget eintragen */

		ZPos[2] = TextLength(&Screen->RastPort, LocText[0].lt_Str, strlen(LocText[0].lt_Str)) + 88;
		ZPos[3] = Top + Screen->RastPort.TxHeight + 1;

		/* Kontext für Gadgets erzeugen */

		if (OldGadget = CreateContext(&GList))
		{
		    /* Angaben für Palette-Gadget eintragen */

		    NewGadget.ng_LeftEdge   =  LeRi / 2 + 4;
		    NewGadget.ng_TopEdge    =  Top + FSize + 3;
		    NewGadget.ng_Width      =  213;
		    NewGadget.ng_Height     =  Offset + 16;
		    NewGadget.ng_GadgetText =  NULL;
		    NewGadget.ng_Flags      =  0;
		    NewGadget.ng_TextAttr   = &FontAttr;
		    NewGadget.ng_VisualInfo =  VisualInfo;
		    NewGadget.ng_GadgetID   =  PALETTE_ID;

		    /* Palette-Gadget erzeugen */

		    if (OldGadget = CreateGadget(PALETTE_KIND,
						 OldGadget,
						 &NewGadget,
						 GTPA_Depth, Depth,
						 GTPA_Color, 0,
						 GTPA_IndicatorWidth, 53,
						 TAG_DONE))
		    {
			/* Angaben für Button-Gadget "Undo" eintragen */

			NewGadget.ng_TopEdge   += Offset + 57;
			NewGadget.ng_Width      = 105;
			NewGadget.ng_Height     = 12;
			NewGadget.ng_GadgetText = LocText[4].lt_Str;
			NewGadget.ng_Flags      = PLACETEXT_IN;
			NewGadget.ng_GadgetID   = UNDO_ID;

			/* Button-Gadget "Undo" erzeugen */

			if (OldGadget = CreateGadget(BUTTON_KIND, OldGadget, &NewGadget, TAG_DONE))
			{
			    /* Angaben für Button-Gadget "Reset" eintragen */

			    NewGadget.ng_LeftEdge   = 116;
			    NewGadget.ng_GadgetText = LocText[5].lt_Str;
			    NewGadget.ng_GadgetID   = RESET_ID;

			    /* Button-Gadget "Reset" erzeugen */

			    if (OldGadget = CreateGadget(BUTTON_KIND, OldGadget, &NewGadget, TAG_DONE))
			    {
				/* Angaben für Button-Gadget "Use" eintragen */

				NewGadget.ng_TopEdge    += 14;
				NewGadget.ng_LeftEdge    = LeRi / 2 + 4;
				NewGadget.ng_GadgetText  = LocText[6].lt_Str;
				NewGadget.ng_GadgetID    = USE_ID;

				/* Button-Gadget "Use" erzeugen */

				if (OldGadget = CreateGadget(BUTTON_KIND, OldGadget, &NewGadget, TAG_DONE))
				{
				    /* Angaben für Button-Gadget "Cancel" eintragen */

				    NewGadget.ng_LeftEdge    = 116;
				    NewGadget.ng_GadgetText  = LocText[7].lt_Str;
				    NewGadget.ng_GadgetID    = CANCEL_ID;

				    /* Button-Gadget "Cancel" erzeugen */

				    if (OldGadget = CreateGadget(BUTTON_KIND, OldGadget, &NewGadget, TAG_DONE))
				    {
					/* Angaben für Slider-Gadget "Red" eintragen */

					NewGadget.ng_Width       = 122;
					NewGadget.ng_Height      = 11;
					NewGadget.ng_LeftEdge    = LeRi / 2 + 95;
					NewGadget.ng_TopEdge    -= 53;
    					NewGadget.ng_GadgetText  = LocStrCat(0);
					NewGadget.ng_Flags       = PLACETEXT_LEFT | NG_HIGHLABEL;
					NewGadget.ng_GadgetID    = RED_ID;

					/* Slider-Gadget "Red" erzeugen */

					if (RedSlider = OldGadget = CreateGadget(SLIDER_KIND,
										 OldGadget,
										 &NewGadget,
										 GTSL_Max, AGA ? 255 : 15,
										 GTSL_MaxLevelLen, 3,
										 GTSL_LevelFormat, "%3ld",
										 TAG_DONE))
					{
					    /* Angaben für Slider-Gadget "Green" eintragen */

					    NewGadget.ng_TopEdge    += 13;
					    NewGadget.ng_GadgetText  = LocStrCat(1);
					    NewGadget.ng_GadgetID    = GREEN_ID;

					    /* Slider-Gadget "Green" erzeugen */

					    if (GreenSlider = OldGadget = CreateGadget(SLIDER_KIND,
										       OldGadget,
										       &NewGadget,
										       GTSL_Max, AGA ? 255 : 15,
										       GTSL_MaxLevelLen, 3,
										       GTSL_LevelFormat, "%3ld",
										       TAG_DONE))
					    {
						/* Angaben für Slider-Gadget "Blue" eintragen */

						NewGadget.ng_TopEdge    += 13;
						NewGadget.ng_GadgetText  = LocStrCat(2);
						NewGadget.ng_GadgetID    = BLUE_ID;

						/* Slider-Gadget "Blue" erzeugen */

						if (BlueSlider = CreateGadget(SLIDER_KIND,
									      OldGadget,
									      &NewGadget,
									      GTSL_Max, AGA ? 255 : 15,
									      GTSL_MaxLevelLen, 3,
									      GTSL_LevelFormat, "%3ld",
									      TAG_DONE))
						{
						    /* Fenster öffnen */

						    if (Window = OpenWindowTagList(NULL, WindowTagList))
						    {
							UWORD i;

							/* Gadgets ans Fenster anhängen */

							AddGList(Window, GList, -1, -1, NULL);

							/* Gadgets aktivieren */

							RefreshGList(GList, Window, NULL, -1);
							GT_RefreshWindow(Window, NULL);

							/* vorgegebene Farben sichern */

							if (AGA)
							{
							    RGB32[0] = Count << 16;

							    GetRGB32(ViewPort->ColorMap, 0, Count, &RGB32[1]);

							    ConvertRGB32();		/* RGB-Werte für Farbe[0] */
							}
							else
							{
							    for (i = 0; i < Count; i++)
								 RGB4[i] = GetRGB4(ViewPort->ColorMap, i);

							    ConvertRGB4(RGB4[0]);	/* RGB-Werte für Farbe[0] */
							}

							SetSliders();			/* Slider-Gadgets setzen */
							HandleEvent();			/* Ereignis auswerten	 */
							CloseWindow(Window);		/* Fenster schließen	 */
							FreeGadgets(GList);		/* Gadgets freigeben	 */
							ECode = RETURN_OK;		/* Return-Kode setzen	 */
						    }
						}
					    }
					}
				    }
				}
			    }
			}
		    }
		}

                FreeVisualInfo(VisualInfo);		/* VisualInfo freigeben */
	    }

	    CloseFont(Font);				/* Font für Gadgets schließen */
	}

	FreeScreenDrawInfo(Screen, DrawInfo);		/* ScreenDrawInfo freigeben */
    }

    exit(ECode);					/* Programm beenden */
}


/* Ereignis auswerten */

VOID
HandleEvent(VOID)
{
    struct IntuiMessage *IMsg;
    struct Gadget       *IAddr;
 
    UWORD Code;
    ULONG Class;

    FOREVER
    {
	   /* Message anfordern */

	   if (!(IMsg = GT_GetIMsg(Window->UserPort)))
	   {
	       WaitPort(Window->UserPort);		/* auf Message warten */
	       continue;
	   }

	   /* Informationen sichern */

	   Class = IMsg->Class;
	   Code  = IMsg->Code;
	   IAddr = IMsg->IAddress;

	   GT_ReplyIMsg(IMsg);				/* Empfang der Message bestätigen */

	   /* Message auswerten */

	   if (Class == IDCMP_GADGETUP || Class == IDCMP_GADGETDOWN || Class == IDCMP_MOUSEMOVE)
	   {
	       switch (IAddr->GadgetID)
	       {
		       /* Palette-Gadget wurde gewählt */

		       case PALETTE_ID : ActColor = Code;	/* ausgewählte Farbe */

					 /* RGB-Werte für ausgewählte Farbe holen */

					 if (AGA)
					 {
					     ULONG ColVec[3];

					     GetRGB32(ViewPort->ColorMap, ActColor, 1, ColVec);

					     Red   = (UBYTE) ColVec[0];
					     Green = (UBYTE) ColVec[1];
					     Blue  = (UBYTE) ColVec[2];
					 }
					 else
					     ConvertRGB4(GetRGB4(ViewPort->ColorMap, ActColor));

					 SetSliders();		/* Slider-Gadgets setzen */
					 break;

		       /* Button-Gadget "Undo" wurde betätigt */

		       case UNDO_ID    : if (AGA)		/* RGB-Werte für aktuelle Farbe */
					     ConvertRGB32();
					 else
					     ConvertRGB4(RGB4[ActColor]);

					 SetColor();		/* Farbe auf Vorgabe zurücksetzen */
					 SetSliders();		/* Slider-Gadgets setzen	  */
					 break;

		       /* Button-Gadget "Reset" wurde betätigt */

		       case RESET_ID   : ResetColors();		/* Farben auf Vorgaben zurücksetzen */

					 if (AGA)
					     ConvertRGB32();	/* RGB-Werte für aktuelle Farbe */
					 else
					     ConvertRGB4(RGB4[ActColor]);

					 SetSliders();		/* Slider-Gadgets setzen */
					 break;

		       /* Button-Gadget "Use" wurde betätigt */

		       case USE_ID     : return;		/* Programm beenden */

		       /* Button-Gadget "Cancel" wurde betätigt */

		       case CANCEL_ID  : ResetColors();		/* Farben auf Vorgaben zurücksetzen */
					 return;		/* Programm beenden		    */

		       /* Slider-Gadget "Red" wurde bewegt */

		       case RED_ID     : Red   = Code;		/* neuer Rotwert     */
					 SetColor();		/* neue Farbe setzen */
					 break;

		       /* Slider-Gadget "Green" wurde bewegt */

		       case GREEN_ID   : Green = Code;		/* neuer Grünwert    */
					 SetColor();		/* neue Farbe setzen */
					 break;

		       /* Slider-Gadget "Blue" wurde bewegt */

	 	       case BLUE_ID    : Blue  = Code;		/* neuer Blauwert    */
					 SetColor();		/* neue Farbe setzen */
	       }
	   }
	   else
	   {
	       switch (Class)
	       {
		       /* Close-Gadget wurde betätigt */

		       case IDCMP_CLOSEWINDOW   : ResetColors();	/* Farben auf Vorgaben zurücksetzen */
						  return;		/* Programm beenden		    */

		       /* Fenster benötigt Refresh */

		       case IDCMP_REFRESHWINDOW : GT_BeginRefresh(Window);
						  GT_EndRefresh(Window, TRUE);
		}
	   }
    }
}


/* aktuelle Farbe setzen */

VOID
SetColor(VOID)
{
    if (AGA)
	SetRGB32(ViewPort, ActColor, RGB8to32(Red), RGB8to32(Green), RGB8to32(Blue));
    else
	SetRGB4(ViewPort, ActColor, Red, Green, Blue);
}


/* Slider-Gadgets setzen */

VOID
SetSliders(VOID)
{
    GT_SetGadgetAttrs(RedSlider,   Window, NULL, GTSL_Level, Red,   TAG_DONE);
    GT_SetGadgetAttrs(GreenSlider, Window, NULL, GTSL_Level, Green, TAG_DONE);
    GT_SetGadgetAttrs(BlueSlider,  Window, NULL, GTSL_Level, Blue,  TAG_DONE);
}


/* Farben auf Vorgaben zurücksetzen */

VOID
ResetColors(VOID)
{
    if (AGA)
	LoadRGB32(ViewPort, RGB32);
    else
	LoadRGB4(ViewPort, RGB4, Count);
}


/* 4 Bit RGB-Wert in Rot-, Grün- und Blauwert umwandeln */

VOID
ConvertRGB4(UWORD Color)
{
    Red   = Color >> 8 & 0x0F;
    Green = Color >> 4 & 0x0F;
    Blue  = Color      & 0x0F;
}


/* 32 Bit RGB-Wert in Rot-, Grün- und Blauwert umwandeln */

VOID
ConvertRGB32(VOID)
{
    Red   = (UBYTE) RGB32[ActColor * 3 + 1];
    Green = (UBYTE) RGB32[ActColor * 3 + 2];
    Blue  = (UBYTE) RGB32[ActColor * 3 + 3];
}


/* 8 Bit RGB-Wert in 32 Bit RGB-Wert umwandeln */

ULONG
RGB8to32(UWORD Color)
{
    return(Color | Color << 8 | Color << 16 | Color << 24);
}


/* fügt ":   " oder ":    " an einen Locale-String an */

UBYTE *
LocStrCat(UBYTE i)
{
    return(strcat(strcpy(LocStr[i], LocText[i+1].lt_Str), AGA ? ":    " : ":   "));
}


/* Systemkonfiguration feststellen und Locale-Strings einlesen */

VOID
SysConfig(VOID)
{
    UWORD Version = IntuitionBase->LibNode.lib_Version;

    /* min. Amiga-OS 2.04 wird benötigt */

    if (Version < 37)
	exit(RETURN_FAIL);			/* Programm beenden */

    /* Locale-Library öffnen */

    if (LocaleBase = OpenLibrary(LOCALENAME, 38L))
    {
	struct Catalog *Catalog;

	/* Katalog öffnen */

	if (Catalog = OpenCatalogA(NULL, CATALOGNAME, TAG_DONE))
	{
	    UWORD i;

	    /* Locale-Strings holen */

	    for (i = 0; i < MSG_ENTRIES; i++)
        	 LocText[i].lt_Str = GetCatalogStr(Catalog, i, LocText[i].lt_Str);

	    CloseCatalog(Catalog);		/* Katalog schließen */
	}

	CloseLibrary(LocaleBase);		/* Locale-Library schließen */
    }

    /* AGA Chipset vorhanden u. aktiv ? */

    if (Version >= 39 && (GfxBase->ChipRevBits0 & SETCHIPREV_AA) == SETCHIPREV_AA)
	AGA = TRUE;
}
