/******************************************************************
** charmap.c : Affiche la table ascii d'une police de caractère  **
**             Écrit (en partie) par T.Pierron                   **
**             15-03-1999                                        **
**---------------------------------------------------------------**
** Special Requirements: WorkBench 2.0, version 36 or above      **
******************************************************************/

#include <Intuition/Intuition.H>
#include <Intuition/IntuitionBase.H>
#include <Graphics/RastPort.H>
#include <Graphics/Text.H>
#include <Libraries/Gadtools.H>
#include <Intuition/Screens.H>

/* Some constant definitions */
#define	MIN_VERSION			36L
#define	CHARMAP_VERSION	"1.1"

/* Libraries we'll need to open */
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase       = NULL;
struct Library *GadToolsBase  = NULL;
struct Library *AslBase       = NULL;
struct Library *DiskfontBase  = NULL;
struct Library *CxBase			= NULL;
struct Library *IconBase		= NULL;

/* Graphics area: */
struct RastPort *RP,RPT;
struct TextFont *font,*newfont=0;

struct Menu   *menu   = NULL;				/* Menu attached to the window */
struct Screen *screen = NULL;				/* Screen where window will be opened */
struct Window *window = NULL;				/* Main window ptr */
struct Gadget *glist  = NULL;  		   /* Gadget list pointer */
struct Gadget *gad;							/* our running Gadget pointer */
void   *vi = NULL;							/* VisualInfo pointer */

WORD  ZoomData[4];							/* Position of iconified window */
WORD  xdeb,ydeb,xfin,yfin,X,Y,I;			/* Position of ASCII table */
UBYTE CharWid[256],Char[]=" ";			/* Data of ASCII table */
UBYTE MaxWid,Font_height;					/* Font information */

/* For the "version" command: */
const UBYTE VERSION[]=
	"$VER:CharMap v" CHARMAP_VERSION " 20/9/1999\n"
	"Affiche l'ensemble des caractères d'une police ASCII";

/* Tag list for openning the main window: */
ULONG WinTags[] = {
	WA_Zoom,(ULONG)ZoomData,
	WA_NewLookMenus,TRUE,
	TAG_DONE
};

/* For our string gadget: */
UBYTE Buffer[50];
ULONG StrTags[] = {
	GTST_String,(ULONG) Buffer,
	GTST_MaxChars,sizeof(Buffer),
	TAG_DONE
};

/* Set the color of the menu: */
ULONG MenuTags[] = {
	GTMN_FrontPen, 1,
	TAG_DONE
};

ULONG BoxTags[] = {
	GT_VisualInfo,0,
	TAG_DONE,FALSE,
	TAG_DONE
};

/* Our gadtools gadgets will use this font: */
struct TextAttr topaz80={ "topaz.font",8,FS_NORMAL,FPF_ROMFONT };

/* here we declare the information for our new window - notice that GadTools
 * provides some constants which describe which IDCMP events the Window will
 * need to handle the GadTools Gadgets properly. Just OR them into your
 * normal IDCMPFlags field.
 */

ULONG sigwin;
struct NewWindow new_window = {
	50, 20, 510, 150,
	-1, -1,						/* DetailPen, BlockPen */
	CLOSEWINDOW | REFRESHWINDOW | MOUSEBUTTONS | MOUSEMOVE | VANILLAKEY | MENUPICK | MENUVERIFY,
	ACTIVATE | WINDOWDRAG | WINDOWDEPTH | WINDOWCLOSE | SMART_REFRESH | REPORTMOUSE,
	NULL,							/* FirstGadget */
	NULL,							/* CheckMark */
	"Table ASCII Latin 1",
	NULL,							/* Screen */
	NULL,							/* BitMap */
	0, 0, 0, 0,					/* min/max sizes */
	CUSTOMSCREEN
};

/**********************************************************
*****					MENU DATA MANAGMENT:						*****
**********************************************************/

/* NewMenu menu declaration */
struct NewMenu newmenu[] =
{
   {NM_TITLE, "Projet",         0 , 0, 0, 0},
   {  NM_ITEM, "Police d'éran","S", CHECKIT|CHECKED, ~1, (APTR) 11},
   {  NM_ITEM, "Police texte", "T", CHECKIT, ~2, (APTR)12},
   {  NM_ITEM, "Choisir...",   "F", CHECKIT, ~4, (APTR)13},
   {  NM_ITEM, (STRPTR) NM_BARLABEL,  0 , 0,  0, 0},
   {  NM_ITEM, "Effacer le texte","Del", NM_COMMANDSTRING, 0, (APTR)14},
   {  NM_ITEM, "Écran suivant","J", 0, 0, (APTR)15},
   {  NM_ITEM, "A propos...",  "?", 0, 0, (APTR)16},
   {  NM_ITEM, (STRPTR) NM_BARLABEL,  0 , 0,  0, 0},
	{  NM_ITEM, "Iconifier",    "I", 0, 0, (APTR)17},
	{  NM_ITEM, "Cacher",       "H", 0, 0, (APTR)18},
   {  NM_ITEM, "Quitter",      "Q", 0, 0, (APTR)19},

   {NM_END, 0, 0, 0, 0, 0},
},*checked=&newmenu[1];

/* function prototypes */
BYTE setup();										/* Open window, ressources, font... */
void cleanup(UBYTE *,WORD);					/* Quit properly */
void create_gadgets(void);						/* Create the gadget using gadtools lib */
void handle_input(void);						/* Handle intuition events */
void Init_helpwin();								/* Alloc memory for help window */
void Open_helpwin(UBYTE, WORD, WORD);		/* Show the help window */
void Free_helpwin();								/* Free all allocated memory */
void Close_helpwin();							/* Cleanup the display */
void Open_std_libraries();						/* Open necessary libraries */

/**** Yes that's all :-) ****/
int main(int argc, char *argv[])
{
	extern BOOL PopWin;									/* True if the window is poped up at start */

	if( (CxBase   = (void *) OpenLibrary("commodities.library", 37L)) &&
		 (IconBase = (void *) OpenLibrary("icon.library",        36L)) )
		/* If the icon and commodities library are present, and the	**
		** programm failed to init as a commodity, it's probably		**
		** because it is already running, and user want to quit:		*/
	{	if( Init_commodity(argc,argv)==FALSE )
			cleanup(0,0);
	} else
		newmenu[10].nm_Flags |= NM_ITEMDISABLED;	/* If no commo., can't hide the interface */

	/* Openning things for the first time: */
	Open_std_libraries();
   if(PopWin) setup();

   handle_input();
}


/**** Simple requester to show copyright info: ****/
void about_app()
{
	static struct EasyStruct Request=
		{ sizeof(struct EasyStruct),0,
		  "A propos",
		  "CharMap v" CHARMAP_VERSION "\n© 1999 T.Pierron\nLogiciel libre sous licence GPL\nLivré sans aucunne garantie!",
		  "Continuer"};

	EasyRequestArgs( window, &Request, 0, 0 );
}

/**** Open the necessary things: ****/
void Open_std_libraries()
{
	static UBYTE NoWB[]="Nécessite WB Version 36 ou plus.";

	/* open ze libraries */
	if( !(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", MIN_VERSION)) )
		cleanup(NoWB,30);

	if( !(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",MIN_VERSION)) )
		cleanup(NoWB,30);

	if( !(GadToolsBase = (struct Library *)OpenLibrary("gadtools.library",MIN_VERSION)) )
		cleanup(NoWB,30);

	if( !(AslBase = (struct Library *)OpenLibrary("asl.library",MIN_VERSION)) )
		newmenu[3].nm_Flags |= NM_ITEMDISABLED;	/* No ASL, no font requester */

	if( !(DiskfontBase  = (struct Library *)OpenLibrary("diskfont.library",0)) )
		cleanup("Impossible d'ouvrir la diskfont.library!",30);

	/* For temporary font measurement: */
	InitRastPort( &RPT );
	/* get access to the WorkBench screen */
	screen = (struct Screen *) IntuitionBase->ActiveScreen;
	font = screen->RastPort.Font;
}

/**** Setup the window, return 1 if init failed: ****/
BYTE setup()
{
	/* get the screen's visual information data */
	if( !(vi = (void *) GetVisualInfoA( screen,NULL )) )
		cleanup("L'écran public par défaut est bloqué!",30);

	BoxTags[1]=(ULONG)vi;

	/* build the menu-strip */
	if( !(menu = (void *) CreateMenusA(newmenu, MenuTags)) )
      cleanup("Impossible de créer la barre de menu!",30);

   /* Compute the size of the menus: */
   if( !LayoutMenusA(menu, vi, NULL))
      cleanup("Erreur dans la mise en page des menus!",30);

	SetFont(&RPT,font);
	/* Read the size of the 256 characters of the current font: */
	{
		register WORD I;
		register UBYTE *W;
		for(I=0,W=CharWid,MaxWid=0;I<256;I++,W++) {
			*Char = (UBYTE) I;
			*W = TextLength(&RPT,Char,1);
			if(MaxWid < *W) MaxWid=*W;
		}
	}

	/* Setup some interesting variables: */
	MaxWid += 6;
	Font_height = font->tf_YSize+4;
	new_window.Width  = xfin = MaxWid*28+20;
	new_window.Height = Font_height*9+35;
	new_window.Screen = screen;
	new_window.LeftEdge = 50;
	if(xfin+50 > screen->Width)
		new_window.LeftEdge = screen->Width-xfin>>1;

	/* now open up a Window on the frontmost screen: */
	ZoomData[0] = new_window.Width;
	ZoomData[1] = new_window.Height;
	ZoomData[2] = TextLength(&screen->RastPort,new_window.Title,strlen(new_window.Title))+100;
	ZoomData[3] = screen->BarHeight+1;

	/* Does the window fit in the screen? */
	if( !(window = (void *) OpenWindowTagList(&new_window,WinTags)) )
		/* If ASL is avaible, show a requester to change the font: */
		if( avert("La taille de votre police est trop grande.") && AslBase )
			return TRUE;
		else cleanup(0,0);

	sigwin = 1 << window->UserPort->mp_SigBit;
   SetMenuStrip(window, menu);	/* Attach the menu to the window */
	Init_helpwin();					/* Init the help win, using width height of the current font: */
   create_gadgets();					/* Creates all gadgets */
   return FALSE;
}

/**** Desallocate all ressources: ****/
void cleanup(UBYTE *msg,WORD err)
{
	extern APTR FR;

	if (msg)			puts(msg);
	if (window)	{
		ClearMenuStrip(window);
		CloseWindow(window);
		window=NULL;
	}

	/* these two functions can take a NULL, but let's stay consistent */
	if (glist) FreeGadgets(glist);	glist=0;
	if (vi) FreeVisualInfo(vi);		vi=0;
	if (menu) FreeMenus(menu);			menu=0;
	Free_helpwin();

	if (err<0) return;
	Free_commodity();
	if (DiskfontBase)		CloseLibrary(DiskfontBase);
	if (FR)					FreeAslRequest(FR);
	if (IconBase)			CloseLibrary(IconBase);
	if (CxBase)				CloseLibrary(CxBase);
	if (AslBase)			CloseLibrary(AslBase);
	if (GadToolsBase)		CloseLibrary(GadToolsBase);
	if (IntuitionBase)	CloseLibrary(IntuitionBase);
	if (GfxBase)			CloseLibrary(GfxBase);
	exit(err);
}

/**** Draw the table of the 256 characters: ****/
void Draw_ASCIIChart()
{
	register WORD i,x,y;

	/* Initial bevel box, which will be copied 256 times: */
	DrawBevelBoxA(RP,xdeb,ydeb,MaxWid,Font_height,BoxTags);

	/* Exponential copy (very fast :-) */
	for(x=MaxWid,i=xdeb+x,y=28*x+xdeb; i<xfin; ) {
		ClipBlit(RP,xdeb,ydeb,RP,i,ydeb,x,Font_height,0xC0);
		i+=x; x<<=1; if(i+x>y) x=y-i;
	}

	for(x=Font_height,i=ydeb+x,y-=xdeb; i<yfin; i+=x,x<<=1)
		ClipBlit(RP,xdeb,ydeb,RP,xdeb,i,y,x,0xC0);

	/* Character in each box: */
	for(i=32,x=xdeb; i<256; i++,y+=Font_height)
	{
		if( (i&7)==0 ) { y=ydeb; x+=MaxWid; }
		*Char = i;
		Move(RP,x-(MaxWid+CharWid[i]>>1),y+font->tf_Baseline+2);
		Text(RP,Char,1);
	}
}

/**** Create the gadgets of the window: ****/
void create_gadgets()
{
	static struct NewGadget ng;	/* gadget positionning */
	UWORD top;							/* offset into Window under titlebar */

	top = window->BorderTop + 1;
	gad = (void *) CreateContext(&glist);

	/*	the NewGadget stucture is not modified by any Gadget creation call,
		so you'll only need to change information that actually needs to be
		changed */
	ng.ng_TextAttr = &topaz80;			/* Use Topaz to prevent strange font format */
	ng.ng_VisualInfo = vi;
	ng.ng_TopEdge = top+5;
	ng.ng_LeftEdge = 65;
	ng.ng_Width = window->Width - 75;
	ng.ng_Height = 14;
	ng.ng_GadgetText = "Test:";
	ng.ng_Flags = PLACETEXT_LEFT | NG_HIGHLABEL;
	gad = (void *) CreateGadget(STRING_KIND, gad, &ng, StrTags);

	/* Show the name of the font in the string gadget: */
	strcpy(((struct StringInfo *)gad->SpecialInfo)->Buffer,font->tf_Message.mn_Node.ln_Name);

	/*	Now we're ready to add the Gadget list. Quit if the final Gadget
		pointer is NULL - this means that one of the Gadget allocations failed.
		If it exists, add it to the window and refresh, then add the new
		GT_RefreshWindow() call. */

	if (!gad)
		cleanup("Impossible de créer l'interface!",30);

	AddGList(window, glist, (UWORD)-1, (UWORD)-1, NULL);
	RefreshGList(glist, window, NULL, (UWORD)-1);
	GT_RefreshWindow(window, NULL);
	RP=window->RPort;
	SetFont(RP,font); SetAPen(RP,1); SetDrMd(RP,JAM1);

	/* Create the ASCII table: */
	xdeb = 10;			xfin -= 10;
	ydeb = top+25;		yfin  = ydeb+Font_height*8;
	Draw_ASCIIChart();
}
