/*
 *
 *	DISCLAIMER:
 *
 *	This program is provided as a service to the programmer
 *	community to demonstrate one or more features of the Amiga
 *	personal computer.  These code samples may be freely used
 *	for commercial or noncommercial purposes.
 * 
 * 	Commodore Electronics, Ltd ("Commodore") makes no
 *	warranties, either expressed or implied, with respect
 *	to the program described herein, its quality, performance,
 *	merchantability, or fitness for any particular purpose.
 *	This program is provided "as is" and the entire risk
 *	as to its quality and performance is with the user.
 *	Should the program prove defective following its
 *	purchase, the user (and not the creator of the program,
 *	Commodore, their distributors or their retailers)
 *	assumes the entire cost of all necessary damages.  In 
 *	no event will Commodore be liable for direct, indirect,
 *	incidental or consequential damages resulting from any
 *	defect in the program even if it has been advised of the 
 *	possibility of such damages.  Some laws do not allow
 *	the exclusion or limitation of implied warranties or
 *	liabilities for incidental or consequential damages,
 *	so the above limitation or exclusion may not apply.
 *
 */

/* text.demo.c */

/* sample program that asks AvailFonts() to make a list of the fonts
 * that are available and makes a list of them, then opens a separate
 * window and prints a description of the various attributes that can
 * be applied to the fonts, in the font itself.  Notice that not all
 * fonts accept all attributes (garnet9 for example, won't underline)
 *
 * Also note, if you run this, that not all fonts are as easily readable
 * in the various bold and italicized modes.... this rendering is done
 * in a fixed manner by software and the fonts were not necessarily
 * designed to accept it.  It is always best to have a font that has
 * been designed with a bold or italic characteristic built-in rather
 * than try to bold-ize or italicize and existing plain font.
 *
 * Author: Rob Peck, 12/1/85
 *
 * This code may be freely utilized to create programs for the Amiga 
 */


#define AFTABLESIZE 2000

#include "exec/types.h"
#include "exec/io.h"
#include "exec/memory.h"

#include "graphics/gfx.h"
#include "hardware/dmabits.h"
#include "hardware/custom.h"
#include "hardware/blit.h"
#include "graphics/gfxmacros.h"
#include "graphics/copper.h"
#include "graphics/view.h"
#include "graphics/gels.h"
#include "graphics/regions.h"
#include "graphics/clip.h"
#include "exec/exec.h"
#include "graphics/text.h"
#include "graphics/gfxbase.h"
#include "devices/keymap.h"
#include "libraries/dos.h"
#include "graphics/text.h"
#include "libraries/diskfont.h"
#include "intuition/intuition.h"

struct AvailFonts *af;
struct AvailFontsHeader *afh;
extern int AvailFonts();

struct TextFont *tf;
struct TextAttr ta;

ULONG DosBase;
ULONG DiskfontBase;
ULONG IntuitionBase;
ULONG GfxBase;

struct NewWindow nw = {
        10, 10,        /* starting position (left,top) */
        620,40,        /* width, height */
        -1,-1,          /* detailpen, blockpen */
        0,		/* flags for idcmp */
  WINDOWDEPTH|WINDOWSIZING|WINDOWDRAG|SIMPLE_REFRESH|ACTIVATE|GIMMEZEROZERO,
			/* window gadget flags */
        0,              /* pointer to 1st user gadget */
        NULL,           /* pointer to user check */
        "Text Font Test", /* title */
        NULL,           /* pointer to window screen */
        NULL,           /* pointer to super bitmap */
        100,45,         /* min width, height */
        640,200,        /* max width, height */
        WBENCHSCREEN};

struct Window *w;
struct RastPort *rp;

SHORT text_styles[ ] = { FS_NORMAL, FSF_UNDERLINED, FSF_ITALIC, FSF_BOLD, 
			FSF_ITALIC | FSF_BOLD, FSF_BOLD | FSF_UNDERLINED,
			FSF_ITALIC | FSF_BOLD | FSF_UNDERLINED };
		
char *text[ ] = { " Normal Text", " Underlined", " Italicized", " Bold", 
		  " Bold Italics", " Bold Underlined", 
		  " Bold Italic Underlined" };
char textlength[ ] = { 12, 11, 11, 5, 13, 16, 23 };

char *pointsize[] = { " 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9",
                   "10","11","12","13","14","15","16","17","18","19",
                   "20","21","22","23","24","25","26","27","28","29",
                   "30","31"};

char fontname[40];
char dummy[100]; 	/* provided for string length calculation */
char outst[100];	/* build something to give to Text, see note in 
			 * the program body about algorithmically
			 * generated styles 
			 */

main()
{
	UBYTE fonttypes;
	int j,k,m;
	SHORT afsize;
	SHORT style;
	SHORT sEnd;	/* numerical position of end of string terminator,
			 * and coincidently the length of the string. */

	if( (DosBase = OpenLibrary("dos.library", 0)) == NULL) exit(-1);
	if((DiskfontBase=OpenLibrary("diskfont.library",0))==NULL) exit(-4);
	if((IntuitionBase=OpenLibrary("intuition.library",0))==NULL) exit(-2);
	if((GfxBase=OpenLibrary("graphics.library",0))==NULL) exit(-3);
	
	tf=NULL;	/* no font currently selected */
	afsize = AFTABLESIZE;	/* show how large a buffer is available */
	fonttypes = 0xff;	/* show us all font types */
	
	afh = (struct AvailFontsHeader *) AllocMem(afsize, MEMF_CLEAR);
	if(afh == NULL) exit(-5);
	
	printf("\nSearching for Fonts\n");
	AvailFonts(afh, afsize, fonttypes);

	af = (struct AvailFonts *) &afh[1];  /* bypass header to get to the
					      * first of the availfonts */

	for (j = 0; j < afh->afh_NumEntries; j++)
    	{
	if((af->af_Attr.ta_Flags & FPF_REMOVED) ||
	   (af->af_Attr.ta_Flags & FPF_REVPATH) ||
                    ((af->af_Type&AFF_MEMORY)&&
			(af->af_Attr.ta_Flags&FPF_DISKFONT)))
			;	/* do nothing if font is removed, or if
				 * font designed to be rendered rt->left
				 * (simple example writes left to right)
				 * or if font both on disk and in ram, 
				 * don't list it twice. */

	/* AvailFonts performs an AddFont to the system list;
	 * if run twice, you get two entries, one of "af_Type 1" saying
	 * that the font is memory resident, and the other of "af_Type 2"
	 * saying the font is disk-based.  The third part of the 
	 * if-statement lets you tell them apart if you are scanning
	 * the list for unique elements;  it says "if its in memory and
	 * it is from disk, then don't list it because you'll find another
	 * entry in the table that says it is not in memory, but is on disk.
	 * (Another task might have been using the font as well, creating
	 * the same effect).
	 */

	else
	   {
		printf("\nFont name found was: %ls",af->af_Attr.ta_Name);
		printf("  and its point size is: %ld",af->af_Attr.ta_YSize);
		/* Style parameter is in af->af_Attr.ta_Style,
		 * Flags parameter is in af->af_Attr.ta_Flags.
		 */		
	   }
	af++;
        }
	/* now that we've listed the fonts, lets look at them */

	w = (struct Window *)OpenWindow(&nw);
	rp = w->RPort;

    for(m=0; m<2; m++)	/* do normal video, then inverse video */
     {

	af = (struct AvailFonts *)&afh[1]; /* reset value of af to original */
	SetAPen(rp,1);		

	if(m == 0)SetDrMd(rp,JAM1);
	else SetDrMd(rp,JAM1+INVERSVID);

	/* now print a line that says what font and what style it is */

	for (j=0; j < afh->afh_NumEntries; j++)
	{
	CStringAppend(&fontname[0],af->af_Attr.ta_Name);  
			/* copy name into build-name area */
			/* already has ".font" onto end of it */
	
	ta.ta_Name = &fontname[0];
	ta.ta_YSize = af->af_Attr.ta_YSize;	/* ask for this size */
	ta.ta_Style = af->af_Attr.ta_Style;	/* ask for designed style */
	ta.ta_Flags = FPF_ROMFONT|FPF_DISKFONT|FPF_PROPORTIONAL|FPF_DESIGNED;
		/* accept it from anywhere it exists */
	style = ta.ta_Style;

	if(!((af->af_Attr.ta_Flags & FPF_REMOVED) ||
	   (af->af_Attr.ta_Flags & FPF_REVPATH) ||
           ((af->af_Type&AFF_MEMORY)&&
	   (af->af_Attr.ta_Flags&FPF_DISKFONT))))

	   /* this is an IF-NOT, the reverse of the earlier if-test on
	    * these same parameters 
	    */
           {
		tf = (struct TextFont *) OpenDiskFont(&ta);
	
        	if (tf != 0) 
	    	{ 
            	SetFont(w->RPort, tf);
	    	for(k=0; k<7; k++)
		    {
		    style = text_styles[k];
                    SetSoftStyle(w->RPort,style,255);
		    SetRast(rp,0);	/* erase any previous text */
		    Move(rp,10,20);	/* move down a bit from the top */
		    sEnd = CStringAppend(&outst[0],af->af_Attr.ta_Name);
		    sEnd = sEnd + CStringAppend(&outst[sEnd],"  ");
		    sEnd = sEnd + CStringAppend(&outst[sEnd],
					     pointsize[af->af_Attr.ta_YSize]);
		    sEnd = sEnd + CStringAppend(&outst[sEnd]," Points, ");
		    CStringAppend(&outst[sEnd],text[k]);
		    Text(rp,&outst[0],CStringAppend(&dummy[0],&outst[0]));

		    /* Have to build the string before sending it out to
		     * text IF ALGORITHMICALLY GENERATING THE STYLE since 
		     * the kerning and spacing tables are based on the
		     * vanilla text, and not the algorithmically generated
		     * style.  If you send characters out individually,
		     * it is possible that the enclosing rectangle of
	 	     * a later character will chop off the trailing edge
		     * of a preceding character 
		     */

		    /* ************************************************** 
		    This alternate method, when in INVERSVID, exhibits the
		    problem described above.
 
		    Text(rp,af->af_Attr.ta_Name,STRLEN(af->af_Attr.ta_Name));
		    Text(rp,"  ",2);
		    Text(rp,pointsize[af->af_Attr.ta_YSize],2);
		    Text(rp," Points, ",9);
	
		    Text(rp,text[k],textlength[k]);  
		    **************************************************  */ 

		    Delay(40);	/* use the DOS time delay function 
			  	 * specifies 60ths of a second */
		    }
            	CloseFont(tf); /* close the old one */
	
       /* NOTE: 
	*     Even though you close a font, it doesn't get unloaded
	*     Memory unless a font with a different name is specified
	*     for loading.  In this case, any font (except the topaz
	*     set) which has been closed can have its memory area
	*     freed and it will no longer be accessible.  If you close
	*     a font to go to a different point-size, it will NOT cause
	*     a disk-access.  
	*
	*  ALSO NOTE:   
	*      Loading a font loads ALL of the point
	*      sizes contained in that font's directory!!!!
	*/

            }	/* end of if-tf-ne-0 */
	  }	/* end of if-(in memory but from disk) */
	af++;
	}	/* Do next font now */
     }		/* end of for-loop, controlled by m */
 
	FreeMem(afh,AFTABLESIZE);
	CloseWindow(w);
	CloseLibrary(IntuitionBase);   
	CloseLibrary(DosBase);  
	CloseLibrary(DiskfontBase);   
	CloseLibrary(GfxBase);   

}

/* copy a string and return the number of characters added to 
 * a string.  Effectively returns the length of the string if
 * not adding anything */

int CStringAppend(dest, source)	
char *dest;
char *source;
{
    int i=0; 
    char *s = source; 
    char *d = dest; 
    while (( i <79 )&&( *d = *s )) { d++; s++; i++; } 
	/* if find a NULL in source, end the copy, but the NULL itself
	 * gets copied over to the destination.  If no NULL, then 79
	 * characters get copied, then a terminating NULL is added */
    if(i < 79) return(i);
    else {*d = 0; return(i);	}
	/* value returned is the position of the terminating NULL
	 * to allow other strings to be appended simply using the
	 * next append command in sequence */

}

