/*ScianIcons.c
  Eric Pepke
  March 22, 1990
  Does icon stuff in scian

  Added PostScript output to DrawIcon, 8/25/92, JEL
*/

#include "Scian.h"
#include "ScianTypes.h"
#include "ScianIcons.h"
#include "ScianColors.h"
#include "ScianArrays.h"
#include "ScianErrors.h"
#include "ScianLists.h"
#include "ScianIDs.h"
#include "ScianEvents.h"
#include "ScianControls.h"
#include "ScianScripts.h"
#include "ScianStyle.h"
#include "ScianDraw.h"
#include "ScianTextBoxes.h"
#include "ScianFontSystem.h"
#ifdef GRAPHICS
#include "ScianIconFonts.h"
#endif


ObjPtr iconClass = 0;
int iconXOff, iconYOff;		/*Offsets for icons on dragging*/

#define COLORICONXOFFSET	-5	/*X offset for color icon*/
#define COLORICONYOFFSET	0	/*Y offset for color icon*/

#define NRAINBOWCOLORS	5

int rainbowColor[NRAINBOWCOLORS] =
    {
	UIRED,
	UIYELLOW,
	UIGREEN,
	UICYAN,
	UIBLUE
    };


static ObjPtr ColorIconExtraDraw(object, x, y)
ObjPtr object;
int x, y;
/*Draws extra stuff for a color icon*/
{
#ifdef GRAPHICS
    short bx, by, ex, ey, k;

    bx = x + COLORICONXOFFSET;
    by = y + COLORICONYOFFSET;
    ex = x + ICONSIZE / 2;
    ey = by - (ex - bx) / 2;
    for (k = 0; k < NRAINBOWCOLORS; ++k)
    {
	SetUIColor(rainbowColor[k]);
	FillTri(bx, by, ex, ey, ex, ey + (ex - bx) / (NRAINBOWCOLORS - 1));
	ey += (ex - bx) / (NRAINBOWCOLORS - 1);
    }
#endif
}

#ifdef PROTO
void DrawIcon(int x, int y, int whichIcon, char *iconTitle, char *subTitle, int backColor, int flags)
#else
void DrawIcon(x, y, whichIcon, iconTitle, subTitle, backColor, flags)
int x, y, whichIcon;
char *iconTitle;
char *subTitle;
int backColor;
int flags;
#endif
/*Draw icon whichIcon with its center at x, y with title
  iconTitle.  If iconTitle is NIL, doesn't draw a title.  
  Draws the background of the color in UIcolor backColor.
  Flags tells what parts to draw.
*/
{
#ifdef GRAPHICS
    Icoord v[4][2];
    char s[2];
    int texty;
    int k;
    int iconFont, iconChar, iconIndex;

    s[1] = '\0';

    /*Get the icon font and character*/
    iconFont = iconFontLocationTable[whichIcon - 32][0];
    iconChar = iconFontLocationTable[whichIcon - 32][1];

    if (drawingMode == DRAW_SCREEN)
    {
	font(ICONBEGFONTS + iconFont);
    }
    else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    {
	RegisterFontUsed("icons");
	if ((iconIndex = RegisterIconUsed(whichIcon)) < 0) return;
	if (strcmp("icons", curFontName) != 0)
	{
	    fprintf(psFile,"/icons findfont 32 scalefont setfont\n");
	    strcpy(curFontName, "icons"); /* remember this */
	    curFontSize = 32;
	}
    }

    if (flags & DI_DRAWSHADOW)
    {
	SetUIColor(UISHADOW);
	if (drawingMode == DRAW_SCREEN)
	{
	    cmov2i(x - ICONSIZE / 2, y - ICONSIZE / 2 - ICONSHADOW);
	    s[0] = iconChar + 2;
	    charstr(s);
	}
	else if (drawingMode == DRAW_POSTSCRIPT && psFile)
	{
	    fprintf(psFile, "%f setgray\n", PSColor());
	    s[0] = 32 + 3*iconIndex + 2;
	    fprintf(psFile,"%d %d moveto (%s) show\n",
		x - ICONSIZE/2, y - ICONSIZE/2 - ICONSHADOW, show(s));
	}
    }

    for (k = 0; k >= 0; --k)
    {
	if (flags & DI_DRAWBACK)
	{
	    SetUIColor(k ? UIICONGREYBACK : backColor);
	    if (drawingMode == DRAW_SCREEN)
	    {
		cmov2i(x - ICONSIZE / 2 + k * 2, y - ICONSIZE / 2 + k * 2);
		s[0] = iconChar + 1;
		charstr(s);
	    }
            else if (drawingMode == DRAW_POSTSCRIPT && psFile)
    	    {
		fprintf(psFile, "%f setgray\n", PSColor());
		s[0] = 32 + 3*iconIndex + 1;
                fprintf(psFile,"%d %d moveto (%s) show\n",
                    x - ICONSIZE/2 + k*2, y - ICONSIZE/2 + k*2, show(s));
    	    }
	}

	if (flags & DI_DRAWFORE)
	{
	    if (flags & DI_GREY || k)
	    {
		SetUIColor(UIICONGREYFORE);
	    }
	    else
	    {
		SetUIColor(UIICONFORE);
	    }
	    if (drawingMode == DRAW_SCREEN)
	    {
		cmov2i(x - ICONSIZE / 2 + k * 2, y - ICONSIZE / 2 + k * 2);
		s[0] = iconChar;
		charstr(s);
	    }
            else if (drawingMode == DRAW_POSTSCRIPT && psFile)
            {
		fprintf(psFile, "%f setgray\n", PSColor());
		s[0] = 32 + 3*iconIndex;
                fprintf(psFile,"%d %d moveto (%s) show\n",
                    x - ICONSIZE/2 + k*2, y - ICONSIZE/2 + k*2, show(s));
            }
 	}
    }

    texty = y - ICONSIZE / 2 - (flags & DI_DRAWSHADOW ? ICONSHADOW : 0) - ICONTEXTOFFSET;
    if (iconTitle)
    {
	char *s, *s2;
	SetUIColor(UITEXT);
	SetupFont(ICONTEXTFONT, flags & DI_SMALLTEXT ? 10 : 12);

	s = iconTitle;
	s2 = tempStr;

	while (*s)
	{
	    if (*s == '\n')
	    {
		*s2 = 0;
		++s;
		s2 = tempStr;
		DrawAString(CENTERALIGN, x, 
		   texty,
		   tempStr);
		texty -= (flags & DI_SMALLTEXT ? 11 : 13);
	    }
	    else
	    {
		*s2 = *s;
		++s;
		++s2;
	    }
	}
	*s2 = 0;
	DrawAString(CENTERALIGN, x, 
		   texty,
		   tempStr);
    }   

    if (subTitle)
    {
	texty -= (flags & DI_SMALLTEXT ? 11 : 13);
	SetUIColor(UITEXT);
	SetupFont(ICONTEXTFONT, 10);
	DrawAString(CENTERALIGN, x, 
	           texty,
		   subTitle);
    }
#endif
}

#ifdef PROTO
void GenIconDef(FILE *outFile)
#else
void GenIconDef(outFile)
FILE *outFile;
#endif
/* output PostScript font definition for icons used in eps file */
{
#ifdef GRAPHICS
    int icon, c, i, j, k;

    if (!outFile || numIconsUsed < 1) return;
    
    /* generate font def header and Encoding array */
    fprintf(outFile, 
"%%%%BeginFont: icons\n\
/iconfont 10 dict def\n\
iconfont begin\n\
	/FontType 3 def\n\
	/FontMatrix [1 0 0 1 0 0] def\n\
	/FontBBox [0 0 32 32] def\n\
	/Encoding 256 array def\n\
	0 1 255 { Encoding exch /.notdef put } for\n\n");

    for (i=0, c=32; i<numIconsUsed; ++i)
    {
	fprintf(outFile, "\tEncoding %d /fore%02d put\n", c++, i);
	fprintf(outFile, "\tEncoding %d /back%02d put\n", c++, i);
	fprintf(outFile, "\tEncoding %d /shad%02d put\n", c++, i);
    }
    fprintf(outFile, 
"\n\
	/CharProcs %d dict def\n\
	CharProcs begin\n\
		/.notdef { } def        %%not defined\n\n",
	    3*numIconsUsed + 1);
		
    /* generate the CharProcs */
    for (i=0; i<numIconsUsed; ++i)
    {
	register unsigned short *p;
	int iconFont, iconChar;
	
	iconFont = iconFontLocationTable[iconsUsed[i] - 32][0];
	iconChar = iconFontLocationTable[iconsUsed[i] - 32][1];
	fprintf(outFile, "%%font %d, char %d\n", iconFont, iconChar);

	/* set up pointer = (rasters for this font) + (offset to this character) */
	p = (unsigned short *) iconFontParameters[iconFont].rasters + 64*(iconChar - 32);

	fprintf(outFile, "\t\t/fore%02d\n\t\t{<\n\t\t", i);
	for (k=0; k<4; ++k)
	{
	  for (j=0; j<16; ++j)
	    fprintf(outFile,"%04X",*p++);
	  fprintf(outFile,"\n\t\t");
	}
	fprintf(outFile, ">} def\n");
	
	fprintf(outFile, "\t\t/back%02d\n\t\t{<\n\t\t", i);
	for (k=0; k<4; ++k)
	{
	  for (j=0; j<16; ++j)
	    fprintf(outFile,"%04X",*p++);
	  fprintf(outFile,"\n\t\t");
	}
	fprintf(outFile, ">} def\n");
	
	fprintf(outFile, "\t\t/shad%02d\n\t\t{<\n\t\t", i);
	for (k=0; k<4; ++k)
	{
	  for (j=0; j<16; ++j)
	    fprintf(outFile,"%04X",*p++);
	  fprintf(outFile,"\n\t\t");
	}
	fprintf(outFile, ">} def\n\n");
    }

    /* generate font def trailer */
    fprintf(outFile, 
"	end %%CharProcs\n\
\n\
	/BuildChar\n\
	{\n\
		32 0 0 0 32 32 setcachedevice\n\
		exch begin		%%icon font dict\n\
		Encoding exch get	%%get icon index\n\
		CharProcs exch get	%%get icon name\n\
		end\n\
		32 32\n\
		true\n\
		[32 0 0 32 0 0]\n\
		5 -1 roll               %%get name back on top\n\
		exec			%%get bits\n\
		imagemask		%%draw it\n\
	} def\n\
\n\
end %%iconfont\n\
\n\
/icons iconfont definefont pop\n\
%%%%EndFont\n\n");

#endif
    return;    
}

#ifdef PROTO
void DrawIconGhost(ObjPtr icon, int xDisp, int yDisp)
#else
void DrawIconGhost(icon, xDisp, yDisp)
ObjPtr icon;
int xDisp, yDisp;
#endif
/*Draw a ghost of icon icon, displacint its center by xDisp, yDisp.*/
{
#ifdef GRAPHICS
    Icoord v[4][2];
    char s[2];
    ObjPtr theName, whichIconInt, theLoc;
    int x, y;
    real loc[2];
    int whichIcon;
    char *name;
    int iconFont, iconChar;

    theName = GetVar(icon, NAME);
    if (IsString(theName))
    {
	name = GetString(theName);
    }
    else
    {
	name = 0;
    }
    whichIconInt = GetVar(icon, WHICHICON);
    if (whichIconInt && IsInt(whichIconInt))
    {
	whichIcon = GetInt(whichIconInt);
    }
    else
    {
	return;
    }
    theLoc = GetFixedArrayVar("DrawIconGhost", icon, ICONLOC, 1, 2L);
    if (!theLoc)
    {
	return;
    }
    Array2CArray(loc, theLoc);
    x = loc[0] + xDisp;
    y = loc[1] + yDisp;

    iconFont = iconFontLocationTable[whichIcon - 32][0];
    iconChar = iconFontLocationTable[whichIcon - 32][1];
    font(ICONBEGFONTS + iconFont);

    s[1] = 0;
    s[0] = iconChar;

    cmov2i(x - ICONSIZE / 2, y - ICONSIZE / 2);
    charstr(s); 

    if (name)
    {
	SetupFont(ICONTEXTFONT, 12);
	DrawAString(CENTERALIGN, x, 
		   y - ICONSIZE / 2 - ICONSHADOW - ICONTEXTOFFSET,
		   name);
    }
#endif
}

ObjPtr IconBoundsInvalid(icon, changeCount)
ObjPtr icon;
unsigned long changeCount;
/*Returns invalid bounds of icon*/
{
    ObjPtr var;

    MakeVar(icon, APPEARANCE);

    if (GetVarChangeCount(icon, CHANGEDBOUNDS) > changeCount)
    {
	real loc[2], bounds[4];

	/*DIKEO do differently, using ImInvalidRect*/
	var = GetVar(icon, ICONLOC);
	if (!var)
	{
	    return ObjTrue;
	}
	Array2CArray(loc, var);
	/*KLUGE bigger for IBM.*/
	bounds[0] = loc[0] - ICONSIZE / 2 - 1 - ICONINVALEXTRA;
	bounds[1] = loc[0] + ICONSIZE / 2 + 1;
	bounds[2] = loc[1] - ICONSIZE / 2 - ICONSHADOW - 1 - ICONTEXTOFFSET;
	bounds[3] = loc[1] + ICONSIZE / 2 + 1 + ICONINVALEXTRA;

	var = NewRealArray(1, 4L);
	CArray2Array(var, bounds);
	return var;
    }
    else
    {
	return NULLOBJ;
    }
}

ObjPtr DrawIconObj(object)
ObjPtr object;
/*Draws this icon thing*/
{
#ifdef GRAPHICS
    ObjPtr theLoc;
    ObjPtr theName;
    char *title, *subTitle;
    ObjPtr whichIconInt;
    real loc[2];
    int whichIcon;
    FuncTyp method;
    ObjPtr repObj;

    theLoc = GetFixedArrayVar("DrawIconObj", object, ICONLOC, 1, 2L);
    if (!theLoc)
    {
	return NULLOBJ;
    }

    MakeVar(object, NAME);
    theName = GetVar(object, NAME);
    if (theName && IsString(theName))
    {
	title = GetString(theName);
    }
    else
    {
	title = (char *) 0;
    }

    MakeVar(object, FORMAT);
    theName = GetVar(object, FORMAT);
    if (theName && IsString(theName))
    {
	subTitle = GetString(theName);
    }
    else
    {
	subTitle = (char *) 0;
    }

    whichIconInt = GetVar(object, WHICHICON);
    if (whichIconInt && IsInt(whichIconInt))
    {
	whichIcon = GetInt(whichIconInt);
    }
    else
    {
	whichIcon = ICONQUESTION;
    }

    Array2CArray(loc, theLoc);

    repObj = GetVar(object, REPOBJ);
    MakeVar(object, ICONGREYED);
    DrawIcon((int) loc[0], (int) loc[1], whichIcon, 
		title, subTitle, 
		IsSelected(repObj ? repObj : object) ? UIICONSELBACK : 
		    (GetPredicate(object, ICONGREYED) ? UIICONGREYBACK : UIICONBACK),
		GetPredicate(object, ICONGREYED) ?
		    DI_DRAWFORE | DI_DRAWBACK | DI_DRAWSHADOW | DI_GREY :
		    DI_DRAWFORE | DI_DRAWBACK | DI_DRAWSHADOW);

    method = GetMethod(object, ICONEXTRADRAW);
    if (method)
    {
	(*method)(object, (int) loc[0], (int) loc[1]);
    }
#endif
    return ObjTrue;
}

ObjPtr NewIcon(x, y, whichIcon, name)
int x, y;
int whichIcon;
char *name;
/*Makes and returns a new icon of type whichIcon and name name*/
{
    ObjPtr retVal;

    retVal = NewObject(iconClass, 0);
    if (whichIcon == ICONCOLOR)
    {
	SetMethod(retVal, ICONEXTRADRAW, ColorIconExtraDraw);
    }
    if (retVal)
    {
	real loc[2];
	ObjPtr locArray;
	
	loc[0] = x;
	loc[1] = y;
	locArray = NewRealArray(1, (long) 2);
	if (locArray)
	{
	    CArray2Array(locArray, loc);
	    SetVar(retVal, ICONLOC, locArray);
	}

	SetVar(retVal, WHICHICON, NewInt(whichIcon));

	if (name)
	{
	    SetVar(retVal, NAME, NewString(name));
	}
    }

    return retVal;
}

ObjPtr MakeIconGreyed(icon)
ObjPtr icon;
/*Makes an icon greyed or not*/
{
    ObjPtr repObj;
    repObj = GetVar(icon, REPOBJ);
    if (repObj)
    {
	SetVar(icon, ICONGREYED, GetVar(repObj, HIDDEN));
    }
    else
    {
	SetVar(icon, ICONGREYED, ObjFalse);
    }
}

static ObjPtr MakeIconAppearance(icon)
ObjPtr icon;
/*Dummy make for icon appearance*/
{
    SetVar(icon, APPEARANCE, ObjTrue);
    ImInvalid(icon);
    return ObjTrue;
}

void InitIcons()
/*Initializes the icon system*/
{
    int i;
#ifdef GRAPHICS
    for (i = 0; i < NICONFONTS; ++i)
    {
	defrasterfont(ICONBEGFONTS + i,
		iconFontParameters[i] . ht,
		iconFontParameters[i] . nc,
		iconFontParameters[i] . chars,
		iconFontParameters[i] . rs,
		(void *) iconFontParameters[i] . rasters);
	/*Have to use (void *) cast to make compatible both
	 with SGI and IBM*/
    }
#endif

    iconClass = NewObject(screenClass, 0);
    AddToReferenceList(iconClass);
    SetVar(iconClass, CLASSID, NewInt(CLASS_ICON));
    SetMethod(iconClass, DRAW, DrawIconObj);
    SetVar(iconClass, TYPESTRING, NewString("icon"));
    DeclareIndirectDependency(iconClass, ICONGREYED, REPOBJ, HIDDEN);
    SetMethod(iconClass, ICONGREYED, MakeIconGreyed);
    DeclareIndirectDependency(iconClass, APPEARANCE, REPOBJ, SELECTED);
    DeclareIndirectDependency(iconClass, APPEARANCE, REPOBJ, HIDDEN);
    SetMethod(iconClass, APPEARANCE, MakeIconAppearance);
    SetMethod(iconClass, BOUNDSINVALID, IconBoundsInvalid);
    SetVar(iconClass, REPOBJONLY, ObjTrue);
}

void KillIcons()
/*Kills the icons*/
{
    DeleteThing(iconClass);
}
