/* **************************************************************************

Programma .... Icon Arranger
Versione ..... 1.9 - 19 settembre 1989
Autore ....... Flavio Stanchina. Loc. Montevaccino 39. 38040 Trento TN
Scopo ........ Manipolazione icone del Workbench
Sintassi ..... Chiamata da Shell/Workbench con interfaccia Intuition
Hardware ..... Amiga 500/2500, Kickstart e Workbench V1.2/1.3
Software ..... Lattice C V5.0, 5.02, 5.04, 5.05.

************************************************************************** */

#include "exec/types.h"
#include "exec/memory.h"
#include "intuition/intuition.h"
#include "graphics/gfxmacros.h"
#include "workbench/workbench.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"

/***** I file di prototipi del Lattice *****/
#include "proto/exec.h"
#include "proto/dos.h"
#include "proto/intuition.h"
#include "proto/graphics.h"
#include "proto/icon.h"

/***** I #define per eseguire modifiche velocemente e senza errori *****/
#define BUFLEN 40	/* lunghezza buffer per filename \0 incluso */
#define XYBUFLEN 5	/* lunghezza buffer per x/y */
#define PENBUFLEN 3	/* lung. buffer per penne */
#define WIDTH 372	/* dimensioni della finestra */
#define HEIGHT 107

/***** Dimensioni massime ******/
#define MAXXSIZE IA_win->WScreen->Width
#define MAXYSIZE IA_win->WScreen->Height

/***** Alcune stringhe usate piu` volte *****/
char wpor[] = "Window position out of range";
char wsor[] = "Window size out of range";
char por[]  = "Pen out of range -1 to 3";

/***** Le ID dei gadget *****/
/* A causa di un altro uso di GadgetID in alcuni gadget, in realta` tutte
   queste costanti verranno messe nel campo dei dati utente. Essendo un
   APTR si rendera` necessario un po` di casting, del resto il C e` fatto
   apposta per poter usare trucchetti simili. */

#define SAVE	0
#define LOAD1	1
#define LOAD2	2
#define IMAGE1	3
#define IMAGE2	4

/* I gadget di tipo usano tutti la stessa id. */
#define TYPE	5

/* Idem per i gadget di highlight. */
#define HIGH	6

#define BOTTOM	7
#define SHOW	8
#define SWAP	9
#define UNLOAD	10

#define XPOS	11
#define YPOS	12
#define XWPOS	13
#define YWPOS	14
#define XWSIZE	15
#define YWSIZE	16

#define DETPEN	17
#define BLKPEN	18


/***** Le librerie usate dal programma *****/
struct DosLibrary *DOSBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *IconBase;

/***** Le strutture usate per manipolare le icone *****/
/* I valori in esadecimale sono uguali a quelli di un Disk.info standard.
   Sono stati inseriti per evitare guai se l' utente carica un' icona di
   tipo tool o project, che non ha la struttura drawerdata, e la salva
   come disk, drawer o garbage. */
struct DrawerData drawer = {
	{ /* dd_NewWindow */
		160, 50, 320, 100,
		-1, -1,	0, 0x0200027F,
		NULL, NULL, NULL, NULL,	NULL,
		90, 40, -1, -1,
		WBENCHSCREEN
	}, 0, 0
};
struct DiskObject diskobj = {
	WB_DISKMAGIC,
	WB_DISKVERSION,
	{ /* Gadget */
		NULL, 0, 0, 0, 1,
		0x0004, 0x0003, 0x0001,
		NULL, NULL, NULL,
		0, 0, 0, 0
	},
	WBDISK, NULL, NULL,
	0, 0, &drawer,
	NULL, NULL
};
/* Per le icone contenenti le due immagini */
struct DiskObject *diskobj1, *diskobj2;

/***** Strutture per garantire l' uso del topaz 8 ed evitare guai *****/
char topaz[] = "topaz.font";
struct TextAttr topaz8	= { topaz, TOPAZ_EIGHTY, 0, 0 };
struct TextAttr topaz8b	= { topaz, TOPAZ_EIGHTY, FSF_BOLD, 0 };

/*************** I gadget ***************/

/* I gadget che determinano il colore della window aperta dall' icona */

/* Prima di tutto i dati delle immagini. Devono essere in CHIP RAM. Col
   Lattice 5.0 la keyword "chip" risolve il problema. Con altri compi-
   latori dovete usare un' opzione per mettere i dati in CHIP (ad es.
   -ad con Lattice 4.0) o aggiungere del codice che ce li trasferisca.
   Cio` vale per tutte le Image contenute in questo file. Questo e` un
   esempio di come trasferire i dati in chip ram:

   USHORT *chipdata, data[] = { 0x0123, 0xABCD... };
   struct Image image = {...};
   void main()
   {
	chipdata = AllocMem(sizeof(data), MEMF_CHIP);
	if(chipdata == NULL) return;
	CopyMem(data, chipdata, sizeof(data));
	image.ImageData = chipdata;
	...
	...
	if(chipdata) FreeMem(chipdata, sizeof(data));
   }
*****/

USHORT chip image_data[] = {
	0xFFFF,	0xFFFF,	0xFFF0,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xC000,	0x0000,	0x0030,
	0xFFFF,	0xFFFF,	0xFFF0
};
struct Image xy_image = {
	-2, -1,		/* LeftEdge, TopEdge (relativi al gadget) */
	44, 10, 2,	/* Width, Height, Depth */
	image_data,	/* puntatore ad ImageData */
	0x1, 0x0	/* PlanePick, PlaneOnOff */
};

char blk_buf[PENBUFLEN] = "-1";
char det_buf[PENBUFLEN] = "-1";

struct IntuiText blk_text = {
	1, 0,	/* Frontpen, Backpen */
	JAM1,	/* Drawmode */
	-14, 0,	/* Offset (relativi al gadget) */
	&topaz8b,/* TextAttr */
	"B",	/* Testo */
	NULL	/* Prossimo testo */
};
struct StringInfo blk_info = {
	blk_buf, /* Buffer */
	NULL,	/* Undo buffer */
	0,	/* Posizione cursore nel buffer */
	PENBUFLEN, /* Numero max. di caratteri nel buffer (\0 compreso) */
	0,	/* Posizione del primo carattere visualizzato */
	/* Le prossime 6 variabili vengono mantenute da Intuition */
	0,	/* Posizione nel buffer di undo */
	2,	/* Numero di caratteri nel buffer */
	0,	/* Numero di caratteri visibili nel gadget */
	0, 0,	/* Posizione del gadget */
	NULL,	/* Rastport del gadget */
	-1,	/* Valore iniziale per LongInt */
	NULL	/* Keymap alternativa */
};
struct Gadget blk_gad = {
	NULL,		/* Prossimo gadget (questo e` l' ultimo) */
	324, 71,	/* Posizione */
	40, 8,		/* Dimensioni HitBox */
	GADGIMAGE | GADGHCOMP, /* Flags */
	RELVERIFY | STRINGRIGHT | LONGINT, /* Flags attivazione */
	STRGADGET,	/* Tipo */
	(APTR)&xy_image,/* GadgetRender */
	NULL,		/* SelectRender */
	&blk_text,	/* GadgetText */
	0,		/* MutualExclude */
	(APTR)&blk_info,/* Informazioni speciali (StringInfo) */
	0,		/* Identificazione */
	(APTR)BLKPEN	/* Dati utente */
};

struct IntuiText det_text = { 1, 0, JAM1, -62, 0, &topaz8b, "Pens: D" };
struct StringInfo det_info = {
	det_buf, NULL, 0,
	PENBUFLEN,
	0, 0, 2, 0, 0, 0,
	NULL, -1, NULL
};
struct Gadget det_gad = {
	&blk_gad, 264, 71, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &det_text,
	0, (APTR)&det_info, 0, (APTR)DETPEN
};

/* IText per i vari gadget di x/y presenti */
struct IntuiText x_text = { 1, 0, JAM1, -14, 0, &topaz8b, "X", NULL };
struct IntuiText y_text = { 1, 0, JAM1, -14, 0, &topaz8b, "Y", NULL };

/* Gadget che determinano le varie x e y dell' icona. Nell' ordine:
   dimensioni della window aperta dall' icona;
   posizione della window;
   posizione dell' icona.
*/
char winysize_buf[XYBUFLEN] = "100";
char winxsize_buf[XYBUFLEN] = "320";
struct StringInfo winysize_info = {
	winysize_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 3, 0, 0, 0,
	NULL, 100, NULL
};
struct Gadget winysize_gad = {
	&det_gad, 324, 59, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &y_text,
	0, (APTR)&winysize_info, 0, (APTR)YWSIZE
};
struct StringInfo winxsize_info = {
	winxsize_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 3, 0, 0, 0,
	NULL, 320, NULL
};
struct Gadget winxsize_gad = {
	&winysize_gad, 324, 50, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &x_text,
	0, (APTR)&winxsize_info, 0, (APTR)XWSIZE
};

char winy_buf[XYBUFLEN] = "50";
char winx_buf[XYBUFLEN] = "160";
struct StringInfo winy_info = {
	winy_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 2, 0, 0, 0,
	NULL, 50, NULL
};
struct Gadget winy_gad = {
	&winxsize_gad, 264, 59, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &y_text,
	0, (APTR)&winy_info, 0, (APTR)YWPOS
};
struct StringInfo winx_info = {
	winx_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 3, 0, 0, 0,
	NULL, 160, NULL
};
struct Gadget winx_gad = {
	&winy_gad, 264, 50, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &x_text,
	0, (APTR)&winx_info, 0, (APTR)XWPOS
};

char icony_buf[XYBUFLEN] = "0";
char iconx_buf[XYBUFLEN] = "0";
struct StringInfo icony_info = {
	icony_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 1, 0, 0, 0,
	NULL, 0, NULL
};
struct Gadget icony_gad = {
	&winx_gad, 204, 59, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &y_text,
	0, (APTR)&icony_info, 0, (APTR)YPOS
};
struct StringInfo iconx_info = {
	iconx_buf, NULL, 0,
	XYBUFLEN,
	0, 0, 1, 0, 0, 0,
	NULL, 0, NULL
};
struct Gadget iconx_gad = {
	&icony_gad, 204, 50, 40, 8,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | STRINGRIGHT | LONGINT,
	STRGADGET,
	(APTR)&xy_image, NULL, &x_text,
	0, (APTR)&iconx_info, 0, (APTR)XPOS
};

/* I gadget per inserire il bottom border e per mostrare le immagini */
USHORT chip big_image_data[] = {
	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xC000,	0x0000,	0x0000,	0x0003,
	0xC000,	0x0000,	0x0000,	0x0003,	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF
};
struct Image big_image = { -2, -1, 64, 20, 2, big_image_data, 0x1, 0x0 };

/* La scritta "Images" e` usata dai prossimi tre gadget. */
struct IntuiText images_text = { 1, 0, JAM1, 6, 9, &topaz8b, "Images" };

struct IntuiText unload1_text = { 1, 0, JAM1, 6, 1, &topaz8b, "Unload", &images_text };
struct Gadget unload_gad = {
	&iconx_gad, 304, 86, 60, 18,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY, BOOLGADGET,
	(APTR)&big_image, NULL, &unload1_text,
	0, NULL, 0, (APTR)UNLOAD
};

struct IntuiText swap1_text = { 1, 0, JAM1, 14, 1, &topaz8b, "Swap", &images_text };
struct Gadget swap_gad = {
	&unload_gad, 236, 86, 60, 18,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY, BOOLGADGET,
	(APTR)&big_image, NULL, &swap1_text,
	0, NULL, 0, (APTR)SWAP
};

struct IntuiText show1_text = {	1, 0, JAM1, 14, 1, &topaz8b, "Show", &images_text };
struct Gadget show_gad = {
	&swap_gad, 168, 86, 60, 18,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY, BOOLGADGET,
	(APTR)&big_image, NULL, &show1_text,
	0, NULL, 0, (APTR)SHOW
};

struct IntuiText bottom2_text = { 1, 0, JAM1, 6, 9, &topaz8b, "Border" };
struct IntuiText bottom1_text = { 1, 0, JAM1, 6, 1, &topaz8b, "Bottom", &bottom2_text };
struct Gadget bottom_gad = {
	&show_gad, 100, 86, 60, 18,
	GADGIMAGE | GADGHCOMP | SELECTED,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&big_image, NULL, &bottom1_text,
	0, NULL, 0, (APTR)BOTTOM
};

/* Immagine usata dai gadget per selezionare highlight e tipo */
USHORT chip TheImage_data[] = {
	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF,	0xFF00,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,
	0xC000,	0x0000,	0x0000,	0x0000,	0x0000,	0x0300,	
	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF,	0xFFFF,	0xFF00
};
struct Image TheImage = {
	-2, -1,
	88, 12, 2,
	TheImage_data,
	0x1, 0x0
};

/* I gadget per selezionare il tipo di highlight */
struct IntuiText inv_text  = { 1, 0, JAM1, 14, 1, &topaz8b, "Inverse" };
struct IntuiText back_text = { 1, 0, JAM1, 10, 1, &topaz8b, "Backfill" };
struct IntuiText doub_text = { 1, 0, JAM1,  6, 1, &topaz8b, "Dbl Image" };
struct Gadget high_gads[3] = { {
	&high_gads[1], 100, 50, 84, 10,
	GADGIMAGE | GADGHCOMP | SELECTED,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &inv_text,
	0, NULL, GADGIMAGE | GADGHCOMP, (APTR)HIGH
}, {
	&high_gads[2], 100, 61, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &back_text,
	0, NULL, GADGIMAGE | GADGBACKFILL, (APTR)HIGH
}, {
	&bottom_gad, 100, 72, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &doub_text,
	0, NULL, GADGIMAGE | GADGHIMAGE, (APTR)HIGH
} };

/* I gadget per selezionare il tipo dell' icona. */
struct IntuiText disk_text = { 1, 0, JAM1, 26, 1, &topaz8b, "Disk" };
struct IntuiText draw_text = { 1, 0, JAM1, 18, 1, &topaz8b, "Drawer" };
struct IntuiText tool_text = { 1, 0, JAM1, 26, 1, &topaz8b, "Tool" };
struct IntuiText proj_text = { 1, 0, JAM1, 14, 1, &topaz8b, "Project" };
struct IntuiText garb_text = { 1, 0, JAM1, 14, 1, &topaz8b, "Garbage" };
struct Gadget type_gads[5] = { {
	&type_gads[1], 8, 50, 84, 10,
	GADGIMAGE | GADGHCOMP | SELECTED,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &disk_text,
	0, NULL, WBDISK, (APTR)TYPE
}, {
	&type_gads[2], 8, 61, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &draw_text,
	0, NULL, WBDRAWER, (APTR)TYPE
}, {
	&type_gads[3], 8, 72, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &tool_text,
	0, NULL, WBTOOL, (APTR)TYPE
}, {
	&type_gads[4], 8, 83, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &proj_text,
	0, NULL, WBPROJECT, (APTR)TYPE
}, {
	&high_gads[0], 8, 94, 84, 10,
	GADGIMAGE | GADGHCOMP,
	RELVERIFY | TOGGLESELECT, BOOLGADGET,
	(APTR)&TheImage, NULL, &garb_text,
	0, NULL, WBGARBAGE, (APTR)TYPE
} };

/* Gadget per selezionare prima o seconda immagine. */
USHORT chip first_data[] = {
	0xC0E0,	0x00C0,	0xC1E0,	0x01C0,	0xC0E1,	0xFBF0,	0xC0E3,	0x81C0,
	0xC0E1,	0xF1C0,	0xC0E0,	0x39F0,	0xC3FB,	0xF0E0,	0xC000,	0x0000
};
struct Image first_image = { -2, 0, 32, 8, 2, first_data, 0x1, 0x0 };
USHORT chip second_data[] = {
	0xC3E0,	0x00F0,	0xC770,	0x0070,	0xC077,	0xE3F0,	0xC1E7,	0x7770,
	0xC387,	0x7770,	0xC777,	0x7770,	0xC7F7,	0x73F8,	0xC000,	0x0000
};
struct Image second_image = { -2, 0, 32, 8, 2, second_data, 0x1, 0x0 };
struct Gadget file2_image_gad = {
	type_gads, 334, 30, 30, 8,
	GADGIMAGE | GADGHIMAGE,
	TOGGLESELECT | RELVERIFY, BOOLGADGET,
	(APTR)&first_image, (APTR)&second_image, NULL,
	0, NULL, 0, (APTR)IMAGE2
};

struct Gadget file1_image_gad = {
	&file2_image_gad, 334, 21, 30, 8,
	GADGIMAGE | GADGHIMAGE,
	TOGGLESELECT | RELVERIFY, BOOLGADGET,
	(APTR)&first_image, (APTR)&second_image, NULL,
	0, NULL, 0, (APTR)IMAGE1
};

/***** Gadget per i filename *****/
/* Il bordo per i gadget dei filename. E` fatto in modo di essere largo
   due pixel ai lati e uno sopra e sotto. */

USHORT files_vects[] = { 0,0, 0,9, 291,9, 291,0, 290,8, 290,0, 1,0, 1,8 };
struct Border files_bor = {
	-2, -1,		/* Offset */
	1, 0,		/* Penne */
	JAM1,		/* DrawMode */
	8,		/* Numero di vettori */
	files_vects,	/* puntatore all' array di vettori */
	NULL		/* Next Border */
};

struct IntuiText loadfile2_text = { 1, 3, JAM1, -71, 0, &topaz8b, "2nd icon" };
char loadfile2_buf[BUFLEN];
struct StringInfo loadfile2_info = {
	loadfile2_buf, NULL, 0,
	BUFLEN,
	0, 0, 0, 0, 0, 0,
	NULL, 0, NULL
};
struct Gadget loadfile2_gad = {
	&file1_image_gad, 76, 30, 256, 8,
	GADGHCOMP, RELVERIFY, STRGADGET,
	(APTR)&files_bor, NULL, &loadfile2_text,
	0, (APTR)&loadfile2_info, 0, (APTR)LOAD2
};

struct IntuiText loadfile1_text = { 1, 3, JAM1, -71, 0, &topaz8b, "1st icon" };
char loadfile1_buf[BUFLEN];
struct StringInfo loadfile1_info = {
	loadfile1_buf,
	NULL, 0,
	BUFLEN,
	0, 0, 0, 0, 0, 0,
	NULL, 0, NULL
};
struct Gadget loadfile1_gad = {
	&loadfile2_gad, 76, 21, 256, 8,
	GADGHCOMP, RELVERIFY, STRGADGET,
	(APTR)&files_bor, NULL, &loadfile1_text,
	0, (APTR)&loadfile1_info, 0, (APTR)LOAD1
};

/* Il gadget per il file da salvare. */
struct IntuiText file_text = { 1, 3, JAM1, -67, 0, &topaz8b, "Save to" };
char file_buf[BUFLEN];
struct StringInfo file_info = {
	file_buf, NULL, 0,
	BUFLEN,
	0, 0, 0, 0, 0, 0,
	NULL, 0, NULL
};
struct Gadget file_gad = {
	&loadfile1_gad, 76, 12, 288, 8,
	GADGHCOMP, RELVERIFY, STRGADGET,
	(APTR)&files_bor, NULL, &file_text,
	0, (APTR)&file_info, 0, (APTR)SAVE
};

/***** I nomi dei gadget *****/
struct IntuiText wsiz_text = { 1, 0, JAM1, 324, 0, &topaz8b, "WSize" };
struct IntuiText wpos_text = { 1, 0, JAM1, 268, 0, &topaz8b, "WPos", &wsiz_text };
struct IntuiText pos_text  = { 1, 0, JAM1, 212, 0, &topaz8b, "Pos", &wpos_text };
struct IntuiText high_text = { 1, 0, JAM1, 106, 0, &topaz8b, "HighLight", &pos_text };
struct IntuiText type_text = { 1, 0, JAM1,  34, 0, &topaz8b, "Type", &high_text };

/*************** I dati per i menu ***************/
char itemname[] = "About Icon Arranger v1.9";
/* Con questo #define risparmiamo 18 bytes di dati (a cosa si puo` arriva-
   re per sembrare piu` bravi...). */
#define title &itemname[6]
struct IntuiText about_text = { 0, 1, JAM1, 4, 2, &topaz8, itemname };
struct MenuItem about_item = {
	NULL,		/* Prossimo Item */
	-10, 0,		/* Offset */
	200, 12,	/* Dimensioni */
	ITEMTEXT | ITEMENABLED | HIGHCOMP,  /* flags */
	0,		/* MutualExclude */
	(APTR)&about_text,	/* Render */
	NULL,		/* Select */
	0,		/* Tasto associato */
	NULL,		/* SubItem */
	MENUNULL	/* NextSelect */
};
struct Menu IA_menu = {
	NULL,		/* Prossimo menu */
	30, 0, 188, 0,	/* Left,0,Width,0 */
	MENUENABLED,	/* flags */
	"Icon Arranger menu",	/* Nome del menu */
	&about_item	/* Primo Item nella lista */
};

/***** Gli IntuiText per il requester di informazioni *****/ 
struct IntuiText about_text4 = { 0, 1, JAM1, 13, 33, &topaz8,
	"Thanks to Lattice C 5.0 and Amiga!", NULL };
struct IntuiText about_text3 = { 0, 1, JAM1, 13, 23, &topaz8,
	"Shareware - Please read IA_Read_Me", &about_text4 };
struct IntuiText about_text2 = { 0, 1, JAM1, 13, 13, &topaz8,
	"Written by Flavio Stanchina", &about_text3 };
struct IntuiText about_text1 = { 0, 1, JAM1, 13, 3, &topaz8,
	"Icon Arranger v1.9 - 19 Sept. 1989", &about_text2 };

/***** IntuiText per il requester per la seconda immagine *****/
struct IntuiText ls_text = { 0, 0, JAM1, 13, 3, &topaz8, "Load second image ?" };
struct IntuiText ok_text = { 2, 0, JAM1,  2, 3, &topaz8, " Ok", NULL };
struct IntuiText no_text = { 2, 0, JAM1,  2, 3, &topaz8, " No", NULL };

/***** Le strutture per la finestra del programma e delle immagini *****/
struct Window *IA_win, *images_win;
struct NewWindow IA_newwin = {
	0, 11,		/* LeftEdge, TopEdge */
	WIDTH, HEIGHT,	/* Width, Height */
	-1, -1,		/* DetailPen, BlockPen */
	GADGETUP | CLOSEWINDOW | MENUPICK,	/* IDCMP FLAGS */
	ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | NOCAREREFRESH,	/* Flags */
	NULL,		/* FirstGadget */
	NULL,		/* CheckMark */
	title,		/* Titolo */
	NULL,		/* Screen */
	NULL,		/* BitMap */
	0, 0,		/* Dimensioni min. */
	0, 0,		/* Dimensioni max. */
	WBENCHSCREEN	/* Tipo di schermo */
};
struct NewWindow images_newwin = {
	6, 13, 0, 0, -1, -1,
	CLOSEWINDOW, WINDOWDRAG | WINDOWCLOSE | NOCAREREFRESH,
	NULL, NULL, "Images", NULL, NULL,
	0, 0, 0, 0, WBENCHSCREEN
};

/***** Prototipi delle funzioni. *****/
void gadget(struct Gadget *);
void win(BOOL);
void showimages(void);
void checksize(void);
void err(char *);
void strswap(char *, char *);
void refresh(struct Gadget *, long);

/*************** Inizio del codice **************/
void main(void)
{
	register struct IntuiMessage *msg;
	register ULONG class, addr, rp;
	register USHORT code;

	/* Apriamo le librerie che ci servono */
	/* Ci serve Intuition almeno 1.2 */
	IntuitionBase = OpenLibrary("intuition.library", 33);

	GfxBase = OpenLibrary("graphics.library", 0);

	if(!(IconBase = OpenLibrary("icon.library", 0))) goto end2;

	if(!(IA_win = OpenWindow(&IA_newwin))) goto end1;
	rp = (ULONG)IA_win->RPort;

	/* Coloriamo di nero lo sfondo della finestra,.. */
	SetAPen((struct RastPort *)rp, 2);
	RectFill((struct RastPort *)rp, 2, 10, WIDTH - 3, HEIGHT - 2);

	/* ..inseriamo i gadget,.. */
	AddGList(IA_win, &file_gad, 0, 25, NULL);
	refresh(&file_gad, 25);

	/* ..ne stampiamo i titoli */
	PrintIText((struct RastPort *)rp, &type_text, 0, 40);

	/* ..e 'accendiamo' il menu */
	SetMenuStrip(IA_win, &IA_menu);

	ActivateGadget(&loadfile1_gad, IA_win, NULL);
	
	FOREVER /* Aspettiamo un segnale ed agiamo */
	{
		Wait(1L << IA_win->UserPort->mp_SigBit);

		/* Leggiamo il messaggio.. */
		while(msg = (struct IntuiMessage *)GetMsg(IA_win->UserPort))
		{
			/* ..conserviamo quel che ci interessa e rispedia-
			   molo al mittente */
			class = msg->Class;
			code = msg->Code;
			addr = (ULONG)msg->IAddress;
			ReplyMsg((struct Message *)msg);

			SetWindowTitles(IA_win, title, title);
			/* Cosa e` successo ? */
			switch (class)
			{
				case MENUPICK:
				/* Siccome c'e` solo un menu cosi e` piu
				   veloce che usare gli switch */
				if(code != (short)-1)
					AutoRequest(IA_win, &about_text1,
					  &ok_text, &ok_text, 0, 0, 320, 76);
				break;

				case GADGETUP:
				gadget((struct Gadget *)addr);
				break;

				case CLOSEWINDOW: /* bye! */
				goto the_end;
			} /* switch */
		} /* while */
	} /* for */

the_end:
	while(msg = (struct IntuiMessage *)GetMsg(IA_win->UserPort))
		ReplyMsg((struct Message *)msg);

	if(diskobj1) FreeDiskObject(diskobj1);
	if(diskobj2) FreeDiskObject(diskobj2);
	CloseWindow(IA_win);
end1:	CloseLibrary(IconBase);
end2:	CloseLibrary(GfxBase);
	CloseLibrary(IntuitionBase);
} /* main */

/* GADGETUP ricevuto. Questa routine esegue l' azione appropriata */
void gadget(struct Gadget *gad)
{
	register short i;

	switch((short)gad->UserData)
	{
	/* Salviamo l' icona? */
		case SAVE:
		if(!*file_buf)
		{
			err("No name specified");
			break;
		}

		/* Controlla se esistono le immagini */
		if(diskobj.do_Gadget.GadgetRender &&
			((diskobj.do_Gadget.Flags & GADGHIMAGE) ?
			diskobj.do_Gadget.SelectRender : TRUE))
		{
			if(!(PutDiskObject(file_buf, &diskobj)))
				err("Error writing icon file!!");
		}
		else err("Must load the icon(s)");
		break;

	/* Carichiamo la prima immagine? */
		case LOAD1:
		/* Se ne avevamo gia caricata una, liberiamola */
		if(diskobj1)
		{
			FreeDiskObject(diskobj1);
			diskobj.do_Gadget.GadgetRender =
				(APTR)(diskobj1 = NULL);
		}

		if(!*loadfile1_buf)
		{
			err("Can't load NULL for 1st icon!");
			break;
		}

		if(!(diskobj1 = GetDiskObject(loadfile1_buf)))
		{
			err("Can't open 1st icon");
			break;
		}

		/* Simuliamo un click sul gadget per cambiare immagine.
		   Cosi` settiamo opportunamente il puntatore a Gadget-
		   Render in accordo con il gadget primo/secondo, ris-
		   parmiando pero` un bel po` di codice. */
		gadget(&file1_image_gad);

		diskobj.do_Gadget.Width =
		  ((struct Image *)diskobj.do_Gadget.GadgetRender)->Width;
		diskobj.do_Gadget.Height =
		  ((struct Image *)diskobj.do_Gadget.GadgetRender)->Height;

		/* Se l' utente vuole il bottom border, aumentiamo l'
		  altezza del gadget. */
		if(bottom_gad.Flags & SELECTED) diskobj.do_Gadget.Height++;

		/* Settiamo il tipo di icona uguale a quello di diskobj1.
		   Per fare questo usiamo un trucchetto: inganniamo gad-
		   get() facendole credere che sia stato selezionato un
		   gadget di tipo. Altrimenti avremmo dovuto inserire
		   molto piu` codice. */
		i = diskobj1->do_Type - 1;
		gadget(&type_gads[i]);

		/* Settiamo il tipo di highlight uguale a quello di
		   diskobj1. Vedi sopra. */
		i = diskobj1->do_Gadget.Flags & 3;
		gadget(&high_gads[i]);

		/* Se la prima icona ha la doppia immagine chiediamo se
		   dobbiamo ricaricarla anche per la seconda, cambiando
		   lo stato del gadget file2_image_gad. */
		if((diskobj1->do_Gadget.Flags & GADGHIMAGE) &&
		  AutoRequest(IA_win, &ls_text, &ok_text, &no_text,
		    0, 0, 200, 46))
		{
			diskobj.do_Gadget.GadgetRender =
			  diskobj1->do_Gadget.GadgetRender;
			strcpy(loadfile2_buf, loadfile1_buf);
			file1_image_gad.Flags &= ~SELECTED;
			file2_image_gad.Flags |= SELECTED;
			refresh(&loadfile1_gad, 4);
			gadget(&loadfile2_gad);
		}

		/* Controlliamo che le due immagini abbiano le stesse
		   dimensioni. */
		checksize();
		break;
	
	/* ..o la seconda? */
		case LOAD2:
		if(diskobj2)
		{
			FreeDiskObject(diskobj2);
			diskobj.do_Gadget.SelectRender =
				(APTR)(diskobj2 = NULL);
		}

		if(!*loadfile2_buf)
		{
			err("Can't load NULL for 2nd icon!");
			break;
		}

		if(!(diskobj2 = GetDiskObject(loadfile2_buf)))
		{
			err("Can't open 2nd icon");
			break;
		}

		/* Questa chiamata a gadget() setta opportunamente il
		   SelectRender della nostra icona. */
		gadget(&file2_image_gad);

		/* Controlliamo che le due immagini abbiano le stesse
		   dimensioni. */
		checksize();
		break;

	/* L' utente vuole cambiare l' immagine che viene presa dalla prima
	   icona. Puo` scegliere tra la prima immagine e la seconda, ovvia-
	   mente solo se l' icona ha la doppia immagine. */
		case IMAGE1:
		if(!diskobj1)
		{
			err("1st icon not loaded");
			break;
		}

		if(file1_image_gad.Flags & SELECTED)
		{
			if(diskobj1->do_Gadget.Flags & GADGHIMAGE)
			{
				diskobj.do_Gadget.GadgetRender =
				  diskobj1->do_Gadget.SelectRender;
			}
			else
			{
				err("1st icon isn't a double image one");
				file1_image_gad.Flags &= ~SELECTED;
				refresh(&file1_image_gad, 1);
			}
		}
		else
		{
			diskobj.do_Gadget.GadgetRender =
			    diskobj1->do_Gadget.GadgetRender;
		}
		break;

	/* L' utente vuole cambiare l' immagine che viene presa dalla
	   seconda icona. */
		case IMAGE2:
		if(!diskobj2)
		{
			err("2nd icon not loaded");
			break;
		}

		if(file2_image_gad.Flags & SELECTED)
		{
			if(diskobj2->do_Gadget.Flags & GADGHIMAGE)
			{
				diskobj.do_Gadget.SelectRender =
				  diskobj2->do_Gadget.SelectRender;
			}
			else
			{
				err("2nd icon isn't a double image one");
				file2_image_gad.Flags &= ~SELECTED;
				refresh(&file2_image_gad, 1);
			}
		}
		else
		{
			diskobj.do_Gadget.SelectRender =
			  diskobj2->do_Gadget.GadgetRender;
		}
		break;

	/* Cambiamo il tipo dell' icona. Per fare cio` ho usato un truc-
	   chetto: il membro GadgetID dei gadget e` settato ai vari tipi di
	   icona, cosi` non devo controllare esplicitamente quale gadget e`
	   stato selezionato e risparmio tempo e codice. */
		case TYPE:
		/* Deseleziona tutti i gadget poi seleziona quello
		   interessato */
		i = 5;
		while(i--) type_gads[i].Flags &= ~SELECTED;
		gad->Flags |= SELECTED;
		refresh(type_gads, 5);

		diskobj.do_Type = gad->GadgetID;

		/* win() abilita o meno i gadget per variare posizione e
		   dimensioni della window associata all' icona. */
		if(diskobj.do_Type == WBTOOL || diskobj.do_Type == WBPROJECT)
			win(FALSE); /* Spegne i gadget. */
		else	win(TRUE); /* Accende i gadget. */
		break;

	/* Cambiamo il tipo di Highlight. Stesso trucco di prima. */
		case HIGH:
		i = 3;
		while(i--) high_gads[i].Flags &= ~SELECTED;
		gad->Flags |= SELECTED;
		refresh(high_gads, 3);

		diskobj.do_Gadget.Flags = gad->GadgetID;
		break;

	/* Inseriamo o togliamo il bottom border. */
		case BOTTOM:
		if(bottom_gad.Flags & SELECTED) diskobj.do_Gadget.Height++;
		else diskobj.do_Gadget.Height--;
		break;

	/* Mostriamo le immagini. */
		case SHOW:
		showimages();
		break;

	/* Scambiamo le due icone. */
		case SWAP:
		{
			register void *temp;

			/* Scambia diskobj. */
			temp = diskobj1;
			diskobj1 = diskobj2;
			diskobj2 = temp;

			/* Scambia render. */
			temp = diskobj.do_Gadget.GadgetRender;
			diskobj.do_Gadget.GadgetRender =
				diskobj.do_Gadget.SelectRender;
			diskobj.do_Gadget.SelectRender = temp;

			/* Scambia selezione gadget 1st/2nd */
			i = file1_image_gad.Flags;
			file1_image_gad.Flags = file2_image_gad.Flags;
			file2_image_gad.Flags = i;

			/* Scambia buffer. */
			strswap(loadfile1_buf, loadfile2_buf);
			refresh(&loadfile1_gad, 4);
		}
		break;

	/* Eliminiamo le icone. */
		case UNLOAD:
		if(diskobj1) FreeDiskObject(diskobj1);
		if(diskobj2) FreeDiskObject(diskobj2);
		diskobj.do_Gadget.GadgetRender =
			diskobj.do_Gadget.SelectRender =
			(APTR)(diskobj1 = diskobj2 = NULL);
		*loadfile1_buf = '\0';
		*loadfile2_buf = '\0';
		file1_image_gad.Flags &= ~SELECTED;
		file2_image_gad.Flags &= ~SELECTED;
		refresh(&loadfile1_gad, 4);
		break;

	/* Cambiamo posizione all, icona. */
		case XPOS:
		diskobj.do_CurrentX = iconx_info.LongInt;
		break;

		case YPOS:
		diskobj.do_CurrentY = icony_info.LongInt;
		break;

	/* Cambiamo posizione alla window. */
		case XWPOS:
		if(winx_info.LongInt >= 0 &&
		  winx_info.LongInt <= MAXXSIZE - 90)
			drawer.dd_NewWindow.TopEdge = winx_info.LongInt;
		else err(wpor);
		break;

		case YWPOS:
		if(winy_info.LongInt >= 0 &&
		  winy_info.LongInt <= MAXYSIZE - 40)
			drawer.dd_NewWindow.LeftEdge = winx_info.LongInt;
		else err(wpor);
		break;

	/* Cambiamo dimensioni alla window. */
		case XWSIZE:
		if(winxsize_info.LongInt >= 90 &&
		  winxsize_info.LongInt <= MAXXSIZE)
			drawer.dd_NewWindow.Width = winxsize_info.LongInt;
		else err(wsor);
		break;

		case YWSIZE:
		if(winysize_info.LongInt >= 40 &&
		  winysize_info.LongInt <= MAXYSIZE)
			drawer.dd_NewWindow.Height = winysize_info.LongInt;
		else err(wsor);
		break;

	/* Cambiamo i colori della window. */
		case DETPEN:
		if(det_info.LongInt >= -1 && det_info.LongInt <= 3)
			drawer.dd_NewWindow.DetailPen = det_info.LongInt;
		else err(por);
		break;

		case BLKPEN:
		if(blk_info.LongInt >= -1 && blk_info.LongInt <= 3)
			drawer.dd_NewWindow.BlockPen = blk_info.LongInt;
		else err(por);
		break;
	}
}

/* Attiva i gadget specifici per la window. */
void win(BOOL a)
{
	register short i;
	register struct Gadget *x = &winx_gad;

	i = 6;

	while(i--)
	{
		if(a)	x->Flags &= ~GADGDISABLED;
		else	x->Flags |= GADGDISABLED;
		x = x->NextGadget;
	}

	refresh(&winx_gad, 6);
	return;
}

/* Mostra le immagini in una finestra */
void showimages( void )
{
	register struct IntuiMessage *msg;
	register struct RastPort *rp;
	register long x, y, w, h, buf;
	struct TmpRas tmpras;

	/* Controlla la presenza della/e immagine/i. */
	if(!diskobj1 || (diskobj.do_Gadget.Flags & GADGHIMAGE) ?
		!diskobj2 : FALSE)
	{
		err("Icon(s) not loaded");
		return;
	}
	checksize();

	/* Calcola larghezza ed altezza della finestra in modo che ci entri
	   l' immagine piu` grande. I numeri che vengono aggiunti sono per
	   evitare di finire sui bordi. Notate che se le due immagini sono
	   di diverse dimensioni possono verificarsi malfunzionamenti. */

	w = ((struct Image *)diskobj.do_Gadget.GadgetRender)->Width;
	h = ((struct Image *)diskobj.do_Gadget.GadgetRender)->Height;
	x = 4; y = 11;

	if(diskobj.do_Gadget.Flags & GADGHIMAGE)
	{
		w = max(w, ((struct Image *)
			diskobj.do_Gadget.SelectRender)->Width);
		h = max(h, ((struct Image *)
			diskobj.do_Gadget.SelectRender)->Height);
	}
	images_newwin.Width = 4 + w + 4;
	images_newwin.Height = 11 + h + 2;

	if(!(images_win = OpenWindow(&images_newwin)))
	{
		err("Can't open window to show icons");
		return;
	}
	rp = images_win->RPort;

	/* Se GADGBACKFILL alloca raster per riempire. */
	if(diskobj.do_Gadget.Flags & GADGBACKFILL)
	{
		if(RASSIZE(images_newwin.Width, images_newwin.Height) >
			RASSIZE(256, 256))
		{
			err("Icon too big, can't show");
			goto end1;
		}
		x = 3; y = 10; w += 2; h += 2;
		if(!(buf = (long)AllocMem(RASSIZE(256, 256), MEMF_CHIP)))
		{
			err("Can't alloc TmpRas for Flood().");
			goto end1;
		}
		/* Lega la memoria al TmpRas del RastPort. */
		rp->TmpRas = InitTmpRas(&tmpras, (PLANEPTR)buf, RASSIZE(256, 256));
	}

	/* Disegna le immagini finche` l' utente non si rompe */
	FOREVER
	{
		DrawImage(rp, (struct Image *)
		 	diskobj.do_Gadget.GadgetRender, 4, 11);
		Delay(25); /* Mezzo secondo */

		if(diskobj.do_Gadget.Flags & GADGHIMAGE)
		{
			/* Disegna la seconda immagine */
			DrawImage(rp, (struct Image *)
				diskobj.do_Gadget.SelectRender, 4, 11);
		}
		else
		{
			/* Inverte l' immagine */
			ClipBlit(rp, x, y, rp, x, y, w, h, 0x50);

			if(diskobj.do_Gadget.Flags & GADGBACKFILL)
			{
				/* Come pattern vengono usati i dati per un
				   gadget. Infatti le prime word sono tutte
				   pari a 0xFFFF. */

				SetAfPt(rp, TheImage_data, 2);
				SetAPen(rp, 0);
				SetBPen(rp, 0);
				SetDrMd(rp, JAM2);
				Flood(rp, 1, 3, 10);
			}
		}

		Delay(24);

		if(msg = (struct IntuiMessage *)GetMsg(images_win->UserPort))
		{
			do ReplyMsg((struct Message *)msg);
			while(msg = (struct IntuiMessage *)
				GetMsg(images_win->UserPort));
			goto end0;
		}
	}
end0:	if(diskobj.do_Gadget.Flags & GADGBACKFILL)
		FreeMem((void *)buf, RASSIZE(256, 256));
end1:	CloseWindow(images_win);
	return;
}

/* Controlla che le due immagini abbiano le stesse dimensioni. Se cio`
   non fosse si presenterebbero malfunzionamenti quando l' icona viene
   selezionata da Workbench. */
void checksize( void )
{
	if(!(diskobj.do_Gadget.Flags & GADGHIMAGE) || !diskobj1 || !diskobj2)
		return;
	if(((struct Image *)diskobj.do_Gadget.GadgetRender)->Height !=
	   ((struct Image *)diskobj.do_Gadget.SelectRender)->Height ||
	   ((struct Image *)diskobj.do_Gadget.GadgetRender)->Width !=
	   ((struct Image *)diskobj.do_Gadget.SelectRender)->Width)
		err("Warning: icons not of the same size");
}

/* Stampa un messaggio nella title bar della finestra */
void err(char *s)
{
	SetWindowTitles(IA_win, s, title);
	DisplayBeep(IA_win->WScreen);
}

/* Scambia due stringhe. */
void strswap(char *s1, char *s2)
{
	register char chr;
	register short i = BUFLEN;

	while(i--)
	{
		chr   = *s1;
		*s1++ = *s2;
		*s2++ = chr;
	}
}

/* RefreshGList richiede molto codice. Facendo cosi` buona parte viene
   inserito una sola volta. */

void refresh(struct Gadget *gad, long num)
{
	RefreshGList(gad, IA_win, NULL, num);
}
