//	Zinc Application Framework - M_PRINT.CPP
//	COPYRIGHT (C) 1990-1999.  All Rights Reserved.
//	Zinc Software Incorporated.  Pleasant Grove, Utah  USA

#include <stdlib.h> // system()
#include <unistd.h> // unlink()

#include <z_border.hpp>
#include <z_group.hpp>
#include <z_int1.hpp>
#include <z_print.hpp>
#include <z_prompt.hpp>
#include <z_real1.hpp>
#include <z_spin.hpp>
#include <z_sys.hpp>
#include <z_title.hpp>
#include <z_unistd.hpp>
#include <z_utils.hpp> // ZafMax()

#define ZAF_PRINTER_INFO
#include "gbl_def.cpp"

#define NINT(f,type) ((f>=0.)? (type)(f+0.5) : (type)(f-0.5))

// Data used for initializing the color table. (see constructor)
static unsigned long psColorTable[16] = 
{
	0x00000000, // 0 - ZAF_CLR_BLACK
	0x00000080, // 1 - ZAF_CLR_BLUE
	0x00008000, // 2 - ZAF_CLR_GREEN
	0x00008080, // 3 - ZAF_CLR_CYAN
	0x00800000, // 4 - ZAF_CLR_RED
	0x00800080, // 5 - ZAF_CLR_MAGENTA
	0x00808000, // 6 - ZAF_CLR_BROWN
	0x00C0C0C0, // 7 - ZAF_CLR_LIGHTGRAY
	0x00808080, // 8 - ZAF_CLR_DARKGRAY
	0x000000FF, // 9 - ZAF_CLR_LIGHTBLUE
	0x0000FF00, // 10 - ZAF_CLR_LIGHTGREEN
	0x0000FFFF, // 11 - ZAF_CLR_LIGHTCYAN
	0x00FF0000, // 12 - ZAF_CLR_LIGHTRED
	0x00FF00FF, // 13 - ZAF_CLR_LIGHTMAGENTA
	0x00FFFF00, // 14 - ZAF_CLR_YELLOW
	0x00FFFFFF  // 15 - ZAF_CLR_WHITE
};

ZafPrinter::ZafPrinter() :
	ZafDisplay(), printerType(ZAF_POSTSCRIPT_2_PRINTER)
{
	preSpace = 2;
	postSpace = 2;
	miniNumeratorX = 1;
	miniDenominatorX = 10;
	miniNumeratorY = 1;
	miniNumeratorY = 10;
	scaleNumerator = 1;
	scaleDenominator = 1;

	// Initialize Tables
	int index;

	// Initialize the colors to the default table.
	// We put them into a separate table that can be modified
	// as needed.
	for(index = 0; index < ZAF_MAXCOLORS; index++)
		colorTable[index] = 0xFFFFFFFF;
	for(index = 0; index < 16; index++)
		colorTable[index] = psColorTable[index];

	// Clear all of the font table entries
	for(index = 0; index < ZAF_MAXFONTS; index++)
	{
		fontTable[index].typeFace[0] = 0x00;
		fontTable[index].pointSize = 12;
	}

	// Allocate the default fonts for printing

	// ZAF_FNT_SMALL
	strcpy(fontTable[ZAF_FNT_SMALL].typeFace, "/Helvetica");
	fontTable[ZAF_FNT_SMALL].pointSize = 8;

	// ZAF_FNT_DIALOG
	strcpy(fontTable[ZAF_FNT_DIALOG].typeFace, "/Helvetica");
	fontTable[ZAF_FNT_DIALOG].pointSize = 12;

	// ZAF_FNT_APPLICATION
	strcpy(fontTable[ZAF_FNT_APPLICATION].typeFace, "/Helvetica-Bold");
	fontTable[ZAF_FNT_APPLICATION].pointSize = 12;

	// ZAF_FNT_SYSTEM
	strcpy(fontTable[ZAF_FNT_SYSTEM].typeFace, "/Helvetica");
	fontTable[ZAF_FNT_SYSTEM].pointSize = 12;

	// ZAF_FNT_FIXED
	strcpy(fontTable[ZAF_FNT_FIXED].typeFace, "/Courier");
	fontTable[ZAF_FNT_FIXED].pointSize = 12;

	// Empty out all of the Line Style entries
	for(index = 0; index < ZAF_MAXLINES; index++)
		lineTable[index][0] = 0x00;
	strcpy(lineTable[ZAF_LINE_SOLID], "[] 0 setdash");
	strcpy(lineTable[ZAF_LINE_DOTTED], "[2] 1 setdash");

	// Initialize the Pattern Table
	// We will start out with no patterns at first...
	for(index = 0; index < ZAF_MAXPATTERNS; index++)
		patternTable[index][0] = 0x00;

	// Initialize the mode table.  Technically, we only support 
	// copying (which is the default), so these can all be 
	// initialized to an empty string.
	for(index = 0; index < ZAF_MAXMODES; index++)
		modeTable[index][0] = 0x00;		

	// Initialize the dimensions
	// For now, we assume a 300 dot / inch printer... The user has
	// the option of modifying this via the printer dialog...
	coordinateType = ZAF_PIXEL;
	pixelsPerInchX = 300;				// Points / Inch also
	pixelsPerInchY = 300;				// Points / Inch also
	marginLeft = (int)ConvertXValue(500, ZAF_INCH_1000, ZAF_PIXEL);
	marginRight = (int)ConvertXValue(500, ZAF_INCH_1000, ZAF_PIXEL);
	marginTop = (int)ConvertYValue(500, ZAF_INCH_1000, ZAF_PIXEL);
	marginBottom = (int)ConvertYValue(500, ZAF_INCH_1000, ZAF_PIXEL);
	paperWidth = (int)ConvertXValue(8500, ZAF_INCH_1000, ZAF_PIXEL);
	paperHeight = (int)ConvertYValue(11000, ZAF_INCH_1000, ZAF_PIXEL);
	pageWidth = paperWidth - (marginLeft + marginRight);
	pageHeight = paperHeight - (marginTop + marginBottom);

	palette.lineStyle = ZAF_LINE_SOLID;
	palette.fillPattern = ZAF_PTN_SOLID_FILL;
	palette.colorForeground = ZAF_CLR_BLACK;
	palette.colorBackground = ZAF_CLR_WHITE;
	palette.monoForeground = ZAF_MONO_BLACK;
	palette.monoBackground = ZAF_MONO_WHITE;
	palette.font = ZAF_FNT_DIALOG;

	cellWidth = fontTable[palette.font].pointSize;
	cellHeight = fontTable[palette.font].pointSize;
	miniNumeratorX = 1;
	miniDenominatorX = 10;
	miniNumeratorY = 1;
	miniDenominatorY = 10;
	preSpace = 2;
	postSpace = 2;

	paperOrientation = ZAF_PORTRAIT_ORIENTATION;
}

ZafPrinter::~ZafPrinter(void)
{
}

ZafError ZafPrinter::ColorInfo(ZafLogicalColor index, ZafUInt8 &red, ZafUInt8 &green, ZafUInt8 &blue)
{
	if (index >= ZAF_MAXCOLORS)
		return (ZAF_ERROR_INVALID_INDEX);

	// Return the color information.
	red = (ZafUInt8)(colorTable[index] >> 16);
	green = (ZafUInt8)((colorTable[index] & 0x0000FF00L) >> 8);
	blue = (ZafUInt8)(colorTable[index] & 0x000000FFL);

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::FontInfo(ZafLogicalFont index, char *fontFamily,
	int bufferSize, int *pointSize, ZafFontWeight *weight,
	ZafFontSlant *slant, ZafFontPitch *, ZafCoordinate *, ZafCoordinate *,
	ZafCoordinate *)
{
	if (index < 0 || index >= ZAF_MAXFONTS || !fontTable[index].typeFace[0])
		return (ZAF_ERROR_INVALID_INDEX);

	// Return the font information.
	if (fontFamily)
		strncpy(fontFamily, fontTable[index].typeFace, bufferSize);
	if (pointSize)
		*pointSize = fontTable[index].pointSize;
	if (weight)
		*weight = ZAF_FNT_WEIGHT_NORMAL;
	if (slant)
		*slant = ZAF_FNT_SLANT_NORMAL;

	return (ZAF_ERROR_NONE);
}

//??? Add in the use of the xscale and yscale
void ZafPrinter::EmitForeground()
{
	unsigned long color = colorTable[palette.colorForeground];
	fprintf(outfile, "%4.3f %4.3f %4.3f rgb\n",
		((color & 0x00FF0000)>>16)/255., 
		((color & 0x0000FF00)>>8)/255., 
		((color & 0x000000FF))/255.);
}

void ZafPrinter::EmitBackground()
{
	unsigned long color = colorTable[palette.colorBackground];
	fprintf(outfile, "%4.3f %4.3f %4.3f rgb\n",
		((color & 0x00FF0000)>>16)/255., 
		((color & 0x0000FF00)>>8)/255., 
		((color & 0x000000FF))/255.);
}

void ZafPrinter::EmitLineAttributes(int width)
{
	if (lineTable[palette.lineStyle][0] != 0x00)
		fprintf(outfile, "%s\n", lineTable[palette.lineStyle]);
	fprintf(outfile, "%ld lw\n", width == -1 ? 0 : 
		ConvertXValue(width, coordinateType, ZAF_PIXEL));
}

void ZafPrinter::EmitImage(ZafCoordinate x, ZafCoordinate y, 
		double /* xscale */, double /* yscale */, int width, int height,
		ZafLogicalColor *array)
{
	int i, n;
	unsigned long color;

#define PSLINESIZE 70  // Limits width of hex line output 

	x = ConvertXValue(x, coordinateType, ZAF_PIXEL);
	y = ConvertYValue(y, coordinateType, ZAF_PIXEL);

	fprintf(outfile, "%ld %ld %d %d %d %d ColorImage\n",
		x, y, 100, 100, width, height);

	// Emit image as hex stream of RGB triplets.
	for(i = 0, n = 0; i < width * height; i++)
	{
		color = colorTable[array[i]];
		fprintf(outfile, "%02X%02X%02X", 
			(unsigned int)((color & 0x00FF0000)>>16), 
			(unsigned int)((color & 0x0000FF00)>>8), 
			(unsigned int)((color & 0x000000FF)));
		if (++n == (PSLINESIZE/6))   // 6 chars per RGB triplet
		{
			fprintf(outfile, "\n");  // Wrap line
			n = 0;
		}
	}
	fprintf(outfile, "\ngr\n");
}

ZafError ZafPrinter::Bitmap(ZafCoordinate column, ZafCoordinate line, 
	ZafBitmapStruct &bitmap)
{
	EmitImage(column, line, 100, 100, 
		bitmap.width, bitmap.height, bitmap.array);

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::Icon(ZafCoordinate column, ZafCoordinate line, 
	ZafIconStruct &icon)
{
	EmitImage(column, line, 100, 100, 
		icon.width, icon.height, icon.array);

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::Mouse(ZafCoordinate /* column */, ZafCoordinate /* line */,
	ZafMouseStruct &/*mouse*/)
{
	return (ZAF_ERROR_UNKNOWN);
}

//??? Use the length parameter and the hotKeyIndex parameter
ZafError ZafPrinter::Text(ZafCoordinate left, ZafCoordinate top, 
	ZafCoordinate right, ZafCoordinate bottom, const ZafIChar *text, 
	int /* length */, ZafHzJustify hzJustify, ZafVtJustify vtJustify,
	int /* hotKeyIndex */, bool fill)
{
	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);
	bottom = ConvertYValue(bottom, coordinateType, ZAF_PIXEL);
	if (fill)
	{
		EmitBackground();
		fprintf(outfile, "%ld %ld %ld %ld rectfill\n",
			left, top,
			(right-left+1), (bottom-top+1));
	}
	EmitForeground();
	fprintf( outfile, "%s %ld %ld %ld %ld %ld %d %d (%s) JustifyText\n", 
		fontTable[palette.font].typeFace, 
		ConvertYValue(fontTable[palette.font].pointSize, 
		ZAF_POINTS, ZAF_PIXEL),
		left, top, right, bottom, 
		(int)(hzJustify == ZAF_HZ_LEFT ? -1 : ZAF_HZ_CENTER ? 0 : 1),
		(int)(vtJustify == ZAF_VT_TOP ? -1 : ZAF_VT_CENTER ? 0 : 1),
		text);
	return (ZAF_ERROR_NONE);
}

//??? Use hotKeyIndex
ZafError ZafPrinter::Text(ZafCoordinate left, ZafCoordinate top, 
	const ZafIChar *text, int length, int /* hotKeyIndex */, 
	bool fill) 
{
	EmitForeground();
	EmitLineAttributes();
	fprintf(outfile, "%ld %ld %s %ld Text (", left, top, 
		fontTable[palette.font].typeFace, 
		ConvertYValue(fontTable[palette.font].pointSize, 
		ZAF_POINTS, ZAF_PIXEL));

	ZafIChar fillLine[256];

	if (length < 0)
		length = strlen(text);	
	else if (length > 255)
		length = 255;
	
	strncpy(fillLine, text, length);
	fillLine[length] = 0x00;

	ZafIChar *tmpStr = fillLine;
	for (ZafIChar *ptr = tmpStr; *ptr; ptr++)
	{
		if (*ptr == '(')
			fprintf(outfile, "\\050");
		else if (*ptr == ')')
			fprintf(outfile, "\\051");
		else 
			fprintf(outfile, "%c", *ptr);
	}

	fprintf(outfile, ") show\n");
		
	if (fill)
		Rectangle(left - preSpace, top - preSpace, 
			left+strlen(text)*fontTable[palette.font].pointSize + postSpace, 
			fontTable[palette.font].pointSize + postSpace, 0, true);
	return (ZAF_ERROR_NONE);
}

ZafRegionStruct ZafPrinter::TextSize(const ZafIChar *text, int length)
{
	ZafRegionStruct region;
	// Following line is needed to remove a warning on broken compilers.
	region.top = 0;
	region.Assign(0, 0, 0, 0, ZAF_POINTS);
	int textLines = 0;
	int width = 0;

	// Check for a valid string.
	if (!text || !text[0])
		return (region);
	if (length < 0)
	{
		int size = 0; 
		int column = 0;  
		int tabWidth = 4;
		length = 0;
		int strLength = strlen(text);
		const ZafIChar *beginText = text;
		const ZafIChar *endText = text;
		for ( ; *endText && strLength > 0; endText++, strLength--)
			if (*endText == '\t')
			{
				// Compute up to the tab character.
				size = (int)(endText - beginText);
				width = size ? size : 0;

				beginText = &endText[1];

				column += width;
				column = column / tabWidth + 1;
				column = column * tabWidth;
			}
			else if (*endText == '\n' || *endText == '\r')
			{
				// Compute up to the newline character.
				size = (int)(endText - beginText);
				width = size ? size : 0;
				
				if (*endText == '\r' && endText[1] == '\n')
					endText++;
				beginText = &endText[1];

				// Increment the line, reset the column and check for longer lenght.
				if (length < column + width)
					length = column + width;
				textLines++;
				column = 0;
			}

		// Finish calculations for the last line.
		size = (int)(endText - beginText);
		width = size ? size : 0;

		if (length < column + width)
			length = column + width;
		textLines++;
	}

	region.right = fontTable[palette.font].pointSize * length;
	region.bottom = fontTable[palette.font].pointSize * textLines;

	return (region);
}

ZafError ZafPrinter::Ellipse(ZafCoordinate left, ZafCoordinate top, 
	ZafCoordinate right, ZafCoordinate bottom,
	float startAngle, float endAngle, int width, bool fill)
{
	if (width == 0 && fill == false)
		return (ZAF_ERROR_NONE);

	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);
	bottom =   ConvertYValue(bottom, coordinateType, ZAF_PIXEL);

	// If filling, use operator which draws outlines from origin.
	if (fill && (endAngle - startAngle) < 360.0)
	{
		fprintf(outfile, "%ld %ld %ld %ld %d %d Pie\n",
			left + (right-left)/2, top + (bottom-top)/2,
			(right-left+1) / 2, (bottom-top+1) / 2,
			(int)(360.0 - endAngle), (int)(360.0 - startAngle));
	}
	else 
		fprintf(outfile, "%ld %ld %ld %ld %d %d Arc\n",
			left + (right-left)/2, top + (bottom-top)/2,
			(right-left+1) / 2, (bottom-top+1) / 2,
			(int)(360.0 - endAngle), (int)(360.0 - startAngle));

	if (fill)
	{
		EmitBackground();
		fprintf(outfile, "Fill\n");
	}
	if (width)
	{
		EmitForeground();
		EmitLineAttributes(width);
		fprintf(outfile, "stroke\n");
	}
	else
		fprintf(outfile, "newpath\n"); // Clear path if no outline
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::Line(ZafCoordinate column1, ZafCoordinate line1, 
	ZafCoordinate column2, ZafCoordinate line2, int width)
{
	if (width == 0)
		return (ZAF_ERROR_NONE);

	column1 = ConvertXValue(column1, coordinateType, ZAF_PIXEL);
	line1 = ConvertYValue(line1, coordinateType, ZAF_PIXEL);
	column2 = ConvertXValue(column2, coordinateType, ZAF_PIXEL);
	line2 = ConvertYValue(line2, coordinateType, ZAF_PIXEL);
	EmitForeground();
	EmitLineAttributes(width);
	fprintf(outfile, "%ld %ld %ld %ld Line\n", 
		column1, line1, column2, line2);
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::Polygon(int numPoints, const ZafCoordinate *polygonPoints,
	int width, bool fill, bool close)
{
	int i;

	if (width == 0 && fill == false)
		return (ZAF_ERROR_NONE);

	// Output line segments
	fprintf(outfile, "%ld %ld m\n", 
		ConvertXValue(polygonPoints[0], coordinateType, ZAF_PIXEL),
		ConvertYValue(polygonPoints[1], coordinateType, ZAF_PIXEL));

	for(i = 2; i < numPoints * 2; i += 2)
		fprintf(outfile, "%ld %ld l\n", 
			ConvertXValue(polygonPoints[i], coordinateType, ZAF_PIXEL),
			ConvertYValue(polygonPoints[i+1], coordinateType, ZAF_PIXEL));

	if (close)
		fprintf(outfile, "closepath\n");
	if (fill) 
	{
		EmitBackground();
		fprintf(outfile, "Fill\n");
	}
	if (width)
	{
		EmitForeground();
		EmitLineAttributes(width);
		fprintf(outfile, "stroke\n");
	}
	else
		fprintf(outfile, "newpath\n"); // Clear path if no outline

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::Rectangle(ZafCoordinate left, ZafCoordinate top, 
	ZafCoordinate right, ZafCoordinate bottom, int width, bool fill)
{
	if (width == 0 && fill == false)
		return (ZAF_ERROR_NONE);

	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);
	bottom = ConvertYValue(bottom, coordinateType, ZAF_PIXEL);
	if (fill)
	{
		EmitBackground();
		fprintf(outfile, "%ld %ld %ld %ld rectfill\n",
			left, top,
			(right-left+1), (bottom-top+1));
	}
	if (width)
	{
		EmitForeground();
		EmitLineAttributes(width);
		fprintf(outfile, "%ld %ld %ld %ld rectstroke\n",
			left, top,
			(right-left+1), (bottom-top+1));
	}
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::RegionCopy(const ZafRegionStruct &, int, int)
{
	// Unimplemented.
	return (ZAF_ERROR_UNKNOWN);
}

ZafError ZafPrinter::RectangleXORDiff(const ZafRegionStruct *,
	const ZafRegionStruct *)
{
	// Unimplemented.
	return (ZAF_ERROR_UNKNOWN);
}

//??? Finish.  For now, my code only works
// with the top-left justification...  NOTABLE more work would have to be
// done to handle anything additional...
ZafCoordinate ZafPrinter::TextBlock(ZafCoordinate left, ZafCoordinate top,
	ZafCoordinate right, ZafCoordinate bottom,
	int &charactersPrinted, const ZafIChar *text, int length,
	ZafHzJustify , ZafVtJustify , bool fill)
{
	//??? unfinished
	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	bottom = ConvertYValue(bottom, coordinateType, ZAF_PIXEL);

	if (fill)
		Rectangle(left, top, right, bottom, true);
	fprintf(outfile, "%ld %ld %s %ld Text\n", left, top, 
		fontTable[palette.font].typeFace, 
		ConvertYValue(fontTable[palette.font].pointSize, 
			ZAF_POINTS, ZAF_PIXEL));
	fprintf(outfile, "/yline %ld def\n", top);
	fprintf(outfile, "(%s) %ld\n", text, right - left);
	fprintf(outfile, "{ %ld yline moveto show /yline yline %ld add def} \n",
		left, 
		ConvertYValue(fontTable[palette.font].pointSize, 
			ZAF_POINTS, ZAF_PIXEL) + postSpace);
	fprintf(outfile, "BreakIntoLines\n");
	if (length == -1)
		charactersPrinted = strlen(text);
	else
		charactersPrinted = length;
	return (ZAF_ERROR_NONE);
}

//??? Actually implement the 'mono' portion
ZafError ZafPrinter::Pixel(ZafCoordinate column, ZafCoordinate line,
	ZafLogicalColor color, ZafLogicalColor /* mono */)
{
	column = ConvertXValue(column, coordinateType, ZAF_PIXEL);
	line = ConvertYValue(line, coordinateType, ZAF_PIXEL);

	unsigned long out_color = colorTable[color];
	fprintf(outfile, "%4.3f %4.3f %4.3f rgb\n",
		((out_color & 0x00FF0000)>>16)/255.,
		((out_color & 0x0000FF00)>>8)/255.,
		((out_color & 0x000000FF))/255.);

	fprintf(outfile, "%ld %ld %ld %ld L\n", column, line, column, line);
	return (ZAF_ERROR_NONE);
}


ZafCoordinate ZafPrinter::TextLine(ZafCoordinate left, ZafCoordinate top, 
	ZafCoordinate right, const ZafIChar *text, 
	int /* length */, ZafHzJustify hzJustify, bool fill)
{
	left = ConvertXValue(left, coordinateType, ZAF_PIXEL);
	top = ConvertYValue(top, coordinateType, ZAF_PIXEL);
	right = ConvertXValue(right, coordinateType, ZAF_PIXEL);

	ZafCoordinate bottom = top +
		ConvertYValue(fontTable[palette.font].pointSize, ZAF_POINTS, ZAF_PIXEL);

	if (fill)
	{
		EmitBackground();
		fprintf(outfile, "%ld %ld %ld %ld rectfill\n",
			left, top,
			(right-left+1), (bottom-top+1) );
	}

	EmitForeground();

	fprintf(outfile, "%s %ld %ld %ld %ld %ld %d %d (%s) JustifyText\n",
		fontTable[palette.font].typeFace,
		ConvertYValue(fontTable[palette.font].pointSize,
		ZAF_POINTS, ZAF_PIXEL),
		left, top, right, bottom,
		(int)(hzJustify == ZAF_HZ_LEFT ? -1 : hzJustify == ZAF_HZ_CENTER ? 0 : 1),
		-1, text);
	
	return (ConvertYValue(bottom, ZAF_PIXEL, coordinateType));
}

ZafLogicalColor ZafPrinter::AddColor(ZafLogicalColor index, 
	ZafUInt8 red, ZafUInt8 green, ZafUInt8 blue)
{
	// Check for a valid entry.
	if (index >= ZAF_MAXCOLORS)
	{
		// Find the first null entry.
		for (index = ZAF_CLR_USER_FIRST; index < ZAF_MAXCOLORS; index++)
		if (colorTable[index] == 0xFFFFFFFF)
			break;
	}
	if (index >= ZAF_MAXCOLORS)
		return (ZAF_CLR_NULL);

	// Allocate the color entry.
	colorTable[index] = (unsigned long)red << 16;
	colorTable[index] += (unsigned long)green << 8;
	colorTable[index] += (unsigned long)blue;
	return (index);
}

ZafLogicalFont ZafPrinter::AddFont(ZafLogicalFont index, char *fontFamily, 
	int pointSize, ZafFontWeight weight, ZafFontSlant slant, ZafFontPitch )
{
	// Check for a valid entry.
	if (index < 0)
	{
		// Find the first null entry.
		for (index = 0; index < ZAF_MAXFONTS; index++)
			if (fontTable[index].typeFace[0] == 0x00)
				break;
	}
	if (index >= ZAF_MAXFONTS)
		return (ZAF_FNT_NULL);

	// Determine the weight.
	ZafIChar *sWeight =
		(weight == ZAF_FNT_WEIGHT_BOLD) ? ZAF_ITEXT("Bold") : ZAF_ITEXT("");
	ZafIChar *sSlant =
		(slant == ZAF_FNT_SLANT_ITALIC) ? ZAF_ITEXT("Oblique") : ZAF_ITEXT("");

	char fontName[256];

	if(sWeight[0] || sSlant[0])	
		sprintf(fontName, "/%s-%s%s", fontFamily, sWeight, sSlant);
	else
		sprintf(fontName, "/%s", fontFamily);
	
	strcpy(fontTable[index].typeFace, fontName);
	fontTable[index].pointSize = pointSize;

	return (index);
}

ZafError ZafPrinter::DestroyColor(ZafLogicalColor color)
{
	// Make sure the entry is valid.
	int index = (int)color;
	if (index < 0 || index >= ZAF_MAXCOLORS)
		return (ZAF_ERROR_OUT_OF_RANGE);

	// Remove the color entry.
	colorTable[color] = 0;

	// Return success.
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::DestroyFont(ZafLogicalFont font)
{
	int index = (int)font;
	if (index < 0 || index >= ZAF_MAXFONTS)
		return (ZAF_ERROR_OUT_OF_RANGE);

	fontTable[index].typeFace[0] = 0x00;
	fontTable[index].pointSize = 12; 
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::BeginDraw(OSDisplayContext ,
	OSDrawContext , const ZafRegionStruct &,
	const ZafRegionStruct &)
{
	return (ZAF_ERROR_UNKNOWN);
}

ZafError ZafPrinter::EndDraw(void)
{
	return (ZAF_ERROR_UNKNOWN);
}

OSDisplayContext ZafPrinter::DisplayContext(void) const
{
	return (ZAF_NULLH(OSDisplayContext));
}

OSDisplayContext ZafPrinter::SetDisplayContext(OSDisplayContext)
{
	return (0);
}

OSDisplayContext ZafPrinter::RestoreDisplayContext(void)
{
	return (ZAF_NULLH(OSDisplayContext));
}

OSDrawContext ZafPrinter::DrawContext(void) const
{
	return (ZAF_NULLH(OSDrawContext));
}

OSDrawContext ZafPrinter::SetDrawContext(OSDrawContext)
{
	return (0);
}

OSDrawContext ZafPrinter::RestoreDrawContext(void)
{
	return (ZAF_NULLH(OSDrawContext));
}

ZafCoordinate ZafPrinter::PageWidth(void) const
{
	return (ConvertXValue(pageWidth, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PageHeight(void) const
{
	return (ConvertYValue(pageHeight, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PaperWidth(void) const
{
	return (ConvertXValue(paperWidth, ZAF_PIXEL, coordinateType));
}

ZafCoordinate ZafPrinter::PaperHeight(void) const
{
	return (ConvertYValue(paperHeight, ZAF_PIXEL, coordinateType));
}

void ZafPrinter::Margins(ZafCoordinate &leftMargin, ZafCoordinate &topMargin,
	ZafCoordinate &rightMargin, ZafCoordinate &bottomMargin) const
{
	leftMargin = ConvertXValue(marginLeft, ZAF_PIXEL, coordinateType);
	topMargin = ConvertYValue(marginTop, ZAF_PIXEL, coordinateType);
	rightMargin = ConvertXValue(marginRight, ZAF_PIXEL, coordinateType);
	bottomMargin = ConvertYValue(marginBottom, ZAF_PIXEL, coordinateType);
}

ZafPrinterType ZafPrinter::SetPrinterType(ZafPrinterType )
{
	printerType = ZAF_POSTSCRIPT_2_PRINTER;
	return (printerType);
}

// XXX Needs work!!!!
ZafPaperOrientation ZafPrinter::SetPaperOrientation(
	ZafPaperOrientation setPaperOrientation)
{
	if (setPaperOrientation != paperOrientation)
	{
		paperOrientation = setPaperOrientation;

		int temp = paperHeight;
		paperHeight = paperWidth;
		paperWidth = temp;

		pageWidth = paperWidth - marginLeft - marginRight;
		pageHeight = paperHeight - marginTop - marginBottom;
	}

	return (paperOrientation);
}

ZafCoordinate ZafPrinter::SetPaperWidth(ZafCoordinate setPaperWidth)
{
	paperWidth = (int)ConvertXValue(setPaperWidth, coordinateType, ZAF_PIXEL);
	pageWidth = paperWidth - marginLeft - marginRight;

	return (PaperWidth());
}

ZafCoordinate ZafPrinter::SetPaperHeight(ZafCoordinate setPaperHeight)
{
	paperHeight = (int)ConvertYValue(setPaperHeight, coordinateType, ZAF_PIXEL);
	pageHeight = paperHeight - marginTop - marginBottom;

	return (PaperHeight());
}

ZafCoordinate ZafPrinter::SetPageWidth(ZafCoordinate setPageWidth)
{
	pageWidth = (int)ConvertXValue(setPageWidth, coordinateType, ZAF_PIXEL);
	marginRight = ZafMax(paperWidth - marginLeft - pageWidth, 0);

	return (PageWidth());
}

ZafCoordinate ZafPrinter::SetPageHeight(ZafCoordinate setPageHeight)
{
	pageHeight = (int)ConvertYValue(setPageHeight, coordinateType, ZAF_PIXEL);
	marginBottom = ZafMax(paperHeight - marginTop - pageHeight, 0);

	return (PageHeight());
}

void ZafPrinter::SetMargins(ZafCoordinate leftMargin, ZafCoordinate topMargin,
	ZafCoordinate rightMargin, ZafCoordinate bottomMargin)
{
	marginLeft = (int)ConvertXValue(leftMargin, coordinateType, ZAF_PIXEL);
	marginTop = (int)ConvertYValue(topMargin, coordinateType, ZAF_PIXEL);
	marginRight = (int)ConvertXValue(rightMargin, coordinateType, ZAF_PIXEL);
	marginBottom = (int)ConvertYValue(bottomMargin, coordinateType, ZAF_PIXEL);

	pageWidth = paperWidth - marginLeft - marginRight;
	pageHeight = paperHeight - marginTop - marginBottom;
}

ZafError ZafPrinter::AbortJob(void)
{
	fclose(outfile);
	unlink(printfileName);
	outfile = NULL;

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::BeginJob(ZafIChar *jobName)
{
	// if jobName is null then create a file name.
	if (!jobName)
	{
		jobName = tmpnam(ZAF_NULLP(ZafIChar));
		sprintf(printfileName, ZAF_ITEXT("%s"), jobName);
	}
	else
		sprintf(printfileName, ZAF_ITEXT("/tmp/%s"), jobName);
#if defined(__linux__)
	strcpy(printCommand, ZAF_ITEXT("lpr %s"));
#else
	strcpy(printCommand, ZAF_ITEXT("lp -c %s"));
#endif
	outfile = fopen(printfileName, ZAF_ITEXT("w"));
	if (outfile == NULL)
		return (ZAF_ERROR_OUTPUT_FAILED);

	/* HEADER */
	fprintf(outfile, "%%!PS-Adobe-3.0\n");
	fprintf(outfile, "%%%%Creator: Zinc\n");
	fprintf(outfile, "%%%%Pages: 1 1\n");
	fprintf(outfile, "%%%%Title: %s\n", jobName);
	fprintf(outfile, "%%%%DocumentData: Clean7Bit\n");
	fprintf(outfile, "%%%%Orientation: %s\n", 
		paperOrientation == ZAF_LANDSCAPE_ORIENTATION ? 
		"Landscape" : "Portrait");
	fprintf(outfile, "%%%%EndComments\n");

	fprintf(outfile, "%%%%BeginProlog\n");

	/* OPERATOR ABBREVIATIONS */
	fprintf(outfile, "  %% Operator Abbreviations\n");
	fprintf(outfile, "  /m {moveto} bind def\n");
	fprintf(outfile, "  /l {lineto} bind def\n");
	fprintf(outfile, "  /Line {moveto lineto stroke} bind def\n");
	fprintf(outfile, "  /Fill {gs fill gr} bind def\n");
	fprintf(outfile, "  /lw {setlinewidth} bind def\n");
	fprintf(outfile, "  /Text { %%args: x, y, fontName, size\n"
        	"/size exch def newpath findfont [size 0 0 size neg 0 size] "
		"makefont setfont moveto\n } def\n\n");

	fprintf(outfile, "  /gs {gsave} bind def\n");
	fprintf(outfile, "  /gr {grestore} bind def\n");
	fprintf(outfile, "  /rgb {setrgbcolor} bind def\n");
	fprintf(outfile, "  /savematrix {matrix currentmatrix} bind def\n");
	fprintf(outfile, "  /resetmatrix {setmatrix} bind def\n");

	/* PROCEDURE DEFINITIONS */
	fprintf(outfile, "  %% Procedures\n");
	fprintf(outfile, "%% origin_x origin_y xradius yradius start_angle end_angle\n");
	fprintf(outfile, "/Pie {\n");
	fprintf(outfile, "    /end_angle exch def\n");
	fprintf(outfile, "    /start_angle exch def\n");
	fprintf(outfile, "    /yradius exch def\n");
	fprintf(outfile, "    /xradius exch def\n");
	fprintf(outfile, "    /origin_y exch def\n");
	fprintf(outfile, "    /origin_x exch def\n");
	fprintf(outfile, "    savematrix origin_x origin_y translate\n");
	fprintf(outfile, "    newpath 0 0 moveto xradius yradius scale\n");
	fprintf(outfile, "    0 0 1 start_angle end_angle arc\n");
	fprintf(outfile, "    closepath resetmatrix\n");
	fprintf(outfile, "} bind def\n");
	fprintf(outfile, "%% origin_x origin_y xradius yradius start_angle end_angle\n");

	fprintf(outfile, "/Arc {\n");
	fprintf(outfile, "    /end_angle exch def\n");
	fprintf(outfile, "    /start_angle exch def\n");
	fprintf(outfile, "    /yradius exch def\n");
	fprintf(outfile, "    /xradius exch def\n");
	fprintf(outfile, "    /origin_y exch def\n");
	fprintf(outfile, "    /origin_x exch def\n");
	fprintf(outfile, "    savematrix origin_x origin_y translate\n");
	fprintf(outfile, "    xradius yradius scale\n");
	fprintf(outfile, "    0 0 1 start_angle end_angle arc\n");
	fprintf(outfile, "    resetmatrix\n");
	fprintf(outfile, "} bind def\n");
	fprintf(outfile, "  %% x y xscale yscale width height ColorImage\n"
		"  %%  (must be followed by gr)\n");
	fprintf(outfile, "/ColorImage {\n"
		"   /height exch def\n"
		"	/width exch def\n"
		"	/yscale exch def\n"
		"	/xscale exch def\n"
		"	/y exch def\n"
		"	/x exch def\n"
		"	gs\n"
		"	x y translate xscale yscale scale\n"
#ifdef LEVEL2_DICTS_WORK
		"	<<\n"
		"	    /ImageType 1\n"
		"	    /Width width\n"
		"	    /Height height\n"
		"	    /BitsPerComponent 8\n"
		"	    /Decode [0 1 0 1 0 1]\n"
		"	    /ImageMatrix [width 0 0 height 0 0]\n"
		"	    /DataSource currentfile /ASCIIHexDecode filter\n"
		"	>> image\n" 
#else
                "       /linestr width 3 mul string def\n"
		"       width width 8\n"
		"       [width 0 0 height 0 0]\n"
		"       {currentfile linestr readhexstring pop}\n"
		"       false 3 colorimage\n"
#endif
		"} def\n");

	fprintf(outfile, "/JustifyText {\n"
		"/text exch def\n"
		"/vtjust exch def\n"
		"/hzjust exch def\n"
		"/bottom exch def\n"
		"/right exch def\n"
		"/top exch def\n"
		"/left exch def\n"
		"/fontsize exch def\n"
		"/fontname exch def\n"
		"fontname [fontsize 0 0 fontsize neg 0 fontsize] selectfont\n"
		"text stringwidth 2 div\n"
		"hzjust -1 eq {  %% Left\n"
		"	left /x exch def\n"
		"} if\n"
		"hzjust 0 eq {   %% Horizontal Center\n"
		"	right left sub text stringwidth pop sub 2 div /x exch def\n"
		"} if\n"
		"hzjust 1 eq {  %% Right\n"
		"	right text stringwidth pop sub /x exch def\n"
		"} if\n"
		"vtjust -1 eq {  %% Top\n"
		"	top /y exch def\n"
		"} if\n"
		"    vtjust 0 eq {   %% Vertical Center\n"
		"bottom top sub text stringwidth exch pop sub 2 div /y exch def\n"
		"} if\n"
		"vtjust 1 eq {   %% Bottom\n"
		"	bottom fontsize sub /y exch def\n"
		"} if\n"
		"x y moveto text show\n"
	"} def\n");

	fprintf(outfile, "/wordbreak ( ) def\n");
	fprintf(outfile, "/BreakIntoLines {\n");
	fprintf(outfile, "  /proc exch def /linewidth exch def \n");
	fprintf(outfile, "  /textstring exch def \n");
	fprintf(outfile, "  /breakwidth wordbreak stringwidth pop def\n");
	fprintf(outfile, "  /curwidth 0 def /lastwordbreak 0 def\n");
	fprintf(outfile, "  /startchar 0 def /restoftext textstring def\n");
	fprintf(outfile, "  { restoftext wordbreak search \n");
	fprintf(outfile, "    { /nextword exch def pop\n");
	fprintf(outfile, "      /restoftext exch def\n");
	fprintf(outfile, "      /wordwidth nextword stringwidth pop def\n");
	fprintf(outfile, "      curwidth wordwidth add linewidth gt\n");
	fprintf(outfile, "      { textstring startchar\n");
	fprintf(outfile, "        lastwordbreak startchar sub\n");
	fprintf(outfile, "        getinterval proc\n");
	fprintf(outfile, "        /startchar lastwordbreak def\n");
	fprintf(outfile, "        /curwidth wordwidth breakwidth add def }\n");
	fprintf(outfile, "      { /curwidth curwidth wordwidth add\n");
	fprintf(outfile, "        breakwidth add def\n");
	fprintf(outfile, "      } ifelse\n");
	fprintf(outfile, "    /lastwordbreak lastwordbreak\n");
	fprintf(outfile, "      nextword length add 1 add def\n");
	fprintf(outfile, "    }\n");
	fprintf(outfile, "    { pop exit }\n");
	fprintf(outfile, "    ifelse\n");
	fprintf(outfile, "  } loop\n");
	fprintf(outfile, "  /lastchar textstring length def\n");
	fprintf(outfile, "  textstring startchar lastchar startchar sub\n");
	fprintf(outfile, "    getinterval proc\n");
	fprintf(outfile, " } def\n");

	fprintf(outfile, "%%%%EndProlog\n");

	/* DOCUMENT SETUP */
	fprintf(outfile, "%%%%BeginSetup\n");
	fprintf(outfile, "%%%%EndSetup\n");

	/* PAGE SETUP */
	fprintf(outfile, "%%%%Page: 1\n");
	fprintf(outfile, "%%%%BeginPageSetup\n");
	fprintf(outfile, "%%%%EndPageSetup\n");

	if (paperOrientation == ZAF_LANDSCAPE_ORIENTATION) 
	{
		fprintf(outfile, "%% Use a screen-similar coordinate system\n");
		fprintf(outfile, "[%g 0 0 -%g 0 %ld] concat\n",
	    		72. / pixelsPerInchX,
	    		72. / pixelsPerInchY,
	    		ConvertXValue(paperWidth, ZAF_PIXEL, ZAF_POINTS));
		fprintf(outfile, "%% origin is top left corner (Landscape)\n");
		fprintf(outfile, "90 rotate\n");
		fprintf(outfile, "%d %d translate\n", 0, -paperHeight);
	} 
	else 
	{
		fprintf(outfile, "%% Use a screen-similar coordinate system\n");
		fprintf(outfile, "[%g 0 0 -%g 0 %ld] concat\n",
			72. / pixelsPerInchX,
			72. / pixelsPerInchY,
			ConvertYValue(paperHeight, ZAF_PIXEL, ZAF_POINTS));
		fprintf(outfile, "%% origin is bottom left corner (Portrait)\n");
	}
	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::BeginPage(void)
{
	fprintf(outfile, "gs\n");
	fprintf(outfile, "%d %d translate\n", marginLeft, marginRight);
	fprintf(outfile, "%g %g scale\n", 1.0, 1.0);
	fprintf(outfile, "%d %d %d %d rectclip\n",
		0, 0,
		pageWidth, pageHeight);

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::EndJob(void)
{
	fprintf(outfile, "%%%%Trailer\n");
	fprintf(outfile, "%%%%EOF");
	fclose(outfile);
	outfile = NULL;

	ZafIChar outCommand[1024];
	sprintf(outCommand, printCommand, printfileName);
#if defined(ZAF_UNICODE)
	char sysOutCommand[1024];
	zafCodeSet->UnicodeToIso(outCommand, sysOutCommand);
	if (system(sysOutCommand) != 0)
		return (ZAF_ERROR_OUTPUT_FAILED);
#else
	if (system(outCommand) != 0)
		return (ZAF_ERROR_OUTPUT_FAILED);
#endif

	unlink(printfileName);

	return (ZAF_ERROR_NONE);
}

ZafError ZafPrinter::EndPage(void)
{
	fprintf(outfile, "showpage gr  %% restore to original state\n");
	fprintf(outfile, "%%%%PageTrailer\n");

	return (ZAF_ERROR_NONE);
}

ZafRegionStruct ZafPrinter::SetClipRegion(const ZafRegionStruct &region)
{
	ZafRegionStruct pixelRegion;
	pixelRegion.coordinateType = ZAF_PIXEL;
	pixelRegion.left = (int)ConvertXValue(region.left, coordinateType, 
		ZAF_PIXEL) + marginLeft;
	pixelRegion.top = (int)ConvertYValue(region.top, coordinateType, 
		ZAF_PIXEL) + marginTop;
	pixelRegion.right = (int)ConvertXValue(region.right, coordinateType, 
		ZAF_PIXEL) + marginLeft;
	pixelRegion.bottom = (int)ConvertYValue(region.bottom, coordinateType, 
		ZAF_PIXEL) + marginTop;

	// XXX Make sure clip region is valid (within page)

	ZafCoordinateType oldCoordinateType = SetCoordinateType(ZAF_PIXEL);
	ZafDisplay::SetClipRegion(pixelRegion);
	SetCoordinateType(oldCoordinateType);

	fprintf(outfile, "0 0 translate\n");
	fprintf(outfile, "%g %g scale\n", 1.0, 1.0);
	fprintf(outfile, "%d %d %d %d rectclip\n", 
		clipRegion.left, clipRegion.top,
		clipRegion.Width(), clipRegion.Height());

	ZafRegionStruct oldClipRegion = clipRegion;
	clipRegion = region;
	return (oldClipRegion);
}

bool ZafPrinter::JobSetup(ZafPrintJobStruct &printJob)
{
	ZafPrintDialog printDialog(0, 0, this, &printJob);
	return ((printDialog.Control() == S_DLG_OK) ? true : false);
}

bool ZafPrinter::PrintSetup(void)
{
	ZafPrintSetupDialog setupDialog(10, 3, this);
	return ((setupDialog.Control() == S_DLG_OK) ? true : false);
}

ZafPrintSetupDialog::ZafPrintSetupDialog(int left, int top,
	ZafPrinter *setPrinter) :
	ZafDialogWindow(left, top, 45, 8), printer(setPrinter)
{
	Add(new ZafBorder);
	Add(new ZafSystemButton(ZAF_NATIVE_SYSTEM_BUTTON));
	Add(new ZafTitle(ZAF_ITEXT("Printer Properties")));

	ZafIChar tString[128];

	ZafButton *tButton = NULL;
	ZafGroup *setupGroup = new ZafGroup(1, 0, 43, 5, ZAF_ITEXT("Printer Properties"));
	ZafGroup *orientationGroup = new ZafGroup(1, 5, 43, 2, ZAF_ITEXT("Paper Orientation"));

	sprintf(tString, ZAF_ITEXT("Printer:"));
	ZafPrompt *tPrompt = new ZafPrompt(2, 0, 20, tString);
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	setupGroup->Add(tPrompt);

	sprintf(tString, ZAF_ITEXT("<default>"));
	tPrompt = new ZafPrompt(22, 0, 10, tString);
	tPrompt->SetHzJustify(ZAF_HZ_LEFT);
	setupGroup->Add(tPrompt);

	tPrompt = new ZafPrompt(2, 1, 20, ZAF_ITEXT("Resolution (W x H):"));
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	setupGroup->Add(tPrompt);

	ZafInteger *tInteger = new ZafInteger(22, 1, 6, printer->pixelsPerInchX);
	tInteger->SetRange(ZAF_ITEXT("1..1200"));
	tInteger->SetStringID(ZAF_ITEXT("HZ_DPI"));
	setupGroup->Add(tInteger);

	tPrompt = new ZafPrompt(29, 1, 1, ZAF_ITEXT("x"));
	tPrompt->SetHzJustify(ZAF_HZ_CENTER);
	setupGroup->Add(tPrompt);

	tInteger = new ZafInteger(31, 1, 6, (long)printer->pixelsPerInchY);
	tInteger->SetRange(ZAF_ITEXT("1..1200"));
	tInteger->SetStringID(ZAF_ITEXT("VT_DPI"));
	setupGroup->Add(tInteger);

	tPrompt = new ZafPrompt(2, 2, 20, ZAF_ITEXT("Page Size (W x H in Inches):"));
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	setupGroup->Add(tPrompt);

	ZafReal *tReal = new ZafReal(22, 2, 6, printer->PaperWidth() / 1000.0);
	tReal->SetRange(ZAF_ITEXT("0.0..36.0"));
	tReal->SetStringID(ZAF_ITEXT("PAPER_WIDTH"));
	setupGroup->Add(tReal);

	tPrompt = new ZafPrompt(29, 2, 1, ZAF_ITEXT("x"));
	tPrompt->SetHzJustify(ZAF_HZ_CENTER);
	setupGroup->Add(tPrompt);

	tReal = new ZafReal(31, 2, 6, printer->PaperHeight() / 1000.0);
	tReal->SetRange(ZAF_ITEXT("0.0..36.0"));
	tReal->SetStringID(ZAF_ITEXT("PAPER_HEIGHT"));
	setupGroup->Add(tReal);

	Add(setupGroup);

	tButton = 
		new ZafButton(2, 0, 10, 1, ZAF_ITEXT("Portrait"), NULL, ZAF_RADIO_BUTTON);
	tButton->SetStringID(ZAF_ITEXT("PORTRAIT"));
	tButton->SetHzJustify(ZAF_HZ_LEFT);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetAllowToggling(true);
	tButton->SetSelectOnDownClick(true);
	tButton->SetSelectOnDoubleClick(false);
	if (printer->PaperOrientation() == ZAF_PORTRAIT_ORIENTATION)
		tButton->SetSelected(true);
	else
		tButton->SetSelected(false);
	orientationGroup->Add(tButton);
	
	tButton = 
		new ZafButton(22, 0, 12, 1, ZAF_ITEXT("Landscape"), NULL, ZAF_RADIO_BUTTON);
	tButton->SetStringID(ZAF_ITEXT("LANDSCAPE"));
	tButton->SetHzJustify(ZAF_HZ_LEFT);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetAllowToggling(true);
	tButton->SetSelectOnDownClick(true);
	tButton->SetSelectOnDoubleClick(false);
	if (printer->PaperOrientation() == ZAF_LANDSCAPE_ORIENTATION)
		tButton->SetSelected(true);
	else
		tButton->SetSelected(false);
	orientationGroup->Add(tButton);
	
	Add(orientationGroup);

	tButton = new ZafButton(45 - 24, 7, 9, 1, ZAF_ITEXT("OK"));
	tButton->SetHotKey('O', 0);
	tButton->SetHzJustify(ZAF_HZ_CENTER);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetSendMessageWhenSelected(true);
	tButton->SetValue(S_DLG_OK);
	Add(tButton);

	tButton = new ZafButton(45 - 12, 7, 9, 1, ZAF_ITEXT("Cancel"));
	tButton->SetHotKey('C', 0);
	tButton->SetHzJustify(ZAF_HZ_CENTER);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetSendMessageWhenSelected(true);
	tButton->SetValue(S_DLG_CANCEL);
	Add(tButton);
}

ZafEventType ZafPrintSetupDialog::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);
	switch (ccode)
	{
	case S_DLG_OK:
	{
		// Get the values and initialize the system appropriately.
		// Get the Resolution
		int HZ_DPI = 0, VT_DPI = 0;
		ZafInteger *intField = (ZafInteger *)GetObject(ZAF_ITEXT("HZ_DPI"));
		if (intField)
			HZ_DPI = (int)intField->IntegerData()->Value();
		intField = (ZafInteger *)GetObject(ZAF_ITEXT("VT_DPI"));
		if (intField)
			VT_DPI = (int)intField->IntegerData()->Value();

		// Get the Paper Size
		double tPaperWidth = 0.0, tPaperHeight = 0.0;
		ZafReal *floatField = (ZafReal *)GetObject(ZAF_ITEXT("PAPER_WIDTH"));
		if (floatField)
			tPaperWidth = floatField->RealData()->Value();

		floatField = (ZafReal *)GetObject(ZAF_ITEXT("PAPER_HEIGHT"));
		if (floatField)
			tPaperHeight = floatField->RealData()->Value();

		// Get the paper orientation
		ZafPaperOrientation tPaperOrientation = ZAF_PORTRAIT_ORIENTATION;
		ZafButton *orientationButton = 
			(ZafButton *)GetObject(ZAF_ITEXT("PORTRAIT"));
		if (orientationButton)
		{
			if (orientationButton->Selected())
				tPaperOrientation = ZAF_PORTRAIT_ORIENTATION;
			else
				tPaperOrientation = ZAF_LANDSCAPE_ORIENTATION;
		}
		long oldmarginLeft, oldmarginRight,
			oldmarginTop, oldmarginBottom;	
		printer->Margins(oldmarginLeft, oldmarginTop, oldmarginRight,
			oldmarginBottom);	
    		oldmarginLeft = printer->ConvertXValue(oldmarginLeft, 
			ZAF_PIXEL, ZAF_INCH_1000);
    		oldmarginRight = printer->ConvertXValue(oldmarginRight, 
			ZAF_PIXEL, ZAF_INCH_1000);
    		oldmarginTop = printer->ConvertYValue(oldmarginTop, 
			ZAF_PIXEL, ZAF_INCH_1000);
    		oldmarginBottom = printer->ConvertYValue(oldmarginBottom, 
			ZAF_PIXEL, ZAF_INCH_1000);

		printer->pixelsPerInchX = HZ_DPI;
		printer->pixelsPerInchY = VT_DPI;

		printer->SetMargins(
			printer->ConvertXValue(oldmarginLeft, ZAF_INCH_1000, ZAF_PIXEL),
			printer->ConvertYValue(oldmarginTop, ZAF_INCH_1000, ZAF_PIXEL),
			printer->ConvertXValue(oldmarginRight, ZAF_INCH_1000, ZAF_PIXEL),
			printer->ConvertYValue(oldmarginBottom, ZAF_INCH_1000, ZAF_PIXEL));

		printer->SetPaperWidth( 
			printer->ConvertXValue((int)(tPaperWidth * 1000), 
			ZAF_INCH_1000, printer->CoordinateType()));
		printer->SetPaperHeight( 
			printer->ConvertYValue((int)(tPaperHeight * 1000), 
			ZAF_INCH_1000, printer->CoordinateType()));

		printer->Margins(oldmarginLeft, oldmarginTop, oldmarginRight,
			oldmarginBottom);
		printer->SetPageWidth(printer->PaperWidth() - 
			(oldmarginLeft + oldmarginRight));
		printer->SetPageHeight(printer->PaperHeight() - 
			(oldmarginTop + oldmarginBottom));

		printer->SetPaperOrientation(tPaperOrientation);
		ZafDialogWindow::Event(event);
		}
		break;

	default:
		ccode = ZafDialogWindow::Event(event);
		break;
	}
	return (ccode);
}

ZafPrintDialog::ZafPrintDialog(int left, int top,
	ZafPrinter *setPrinter, ZafPrintJobStruct *setPrintJob) :
	ZafDialogWindow(left, top, 60, 8), printer(setPrinter),
	printJob(setPrintJob), allowModifyCollate(true), allowModifyCopies(true),
	allowModifyRange(true)
{
	ZafIChar tString[1024];

	Add(new ZafBorder);
	Add(new ZafSystemButton(ZAF_NATIVE_SYSTEM_BUTTON));
	Add(new ZafTitle(ZAF_ITEXT("Print Dialog")));

	ZafGroup *configGroup = new ZafGroup(1, 0, 57, 3, ZAF_ITEXT("Printer"));
	ZafGroup *rangeGroup = new ZafGroup(1, 3, 35, 3, ZAF_ITEXT("Print range"));
	ZafGroup *copiesGroup = new ZafGroup(36, 3, 22, 3, ZAF_ITEXT("Copies"));
	copiesGroup->SetSelectionType(ZAF_MULTIPLE_SELECTION);
	ZafButton *tButton = 
		new ZafButton(10, 1, 10, 1, ZAF_ITEXT("Collate"), NULL, ZAF_CHECK_BOX);
	if (printJob->collate == true)
		tButton->SetSelected(true);
	else	
		tButton->SetSelected(false);
	tButton->SetStringID(ZAF_ITEXT("COLLATE"));
	tButton->SetHzJustify(ZAF_HZ_RIGHT);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetAllowToggling(true);
	tButton->SetSelectOnDownClick(true);
	tButton->SetSelectOnDoubleClick(false);
	copiesGroup->Add(tButton);

	ZafPrompt *tPrompt = new ZafPrompt(2, 0, 10, ZAF_ITEXT("# of Copies"));
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	copiesGroup->Add(tPrompt);

	ZafInteger *tInteger = 
		new ZafInteger(13, 0, 7, 1);
	tInteger->SetRange(ZAF_ITEXT("1..99"));
	tInteger->SetStringID(ZAF_ITEXT("COPIES"));
	ZafSpinControl *tSpin = 
		new ZafSpinControl(13, 0, 7, new ZafIntegerData(1));
	tSpin->Add(tInteger);
	copiesGroup->Add(tSpin);

	tButton = 
		new ZafButton(2, 0, 10, 1, ZAF_ITEXT("All"), NULL, ZAF_RADIO_BUTTON);
	tButton->SetSelected(true);
	tButton->SetStringID(ZAF_ITEXT("PAGES_ALL"));
	tButton->SetHzJustify(ZAF_HZ_LEFT);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetAllowToggling(true);
	tButton->SetSelectOnDownClick(true);
	tButton->SetSelectOnDoubleClick(false);
	rangeGroup->Add(tButton);

	tButton = 
		new ZafButton(2, 1, 10, 1, ZAF_ITEXT("Pages"), NULL, ZAF_RADIO_BUTTON);
	tButton->SetSelected(false);
	tButton->SetStringID(ZAF_ITEXT("PAGES_RANGE"));
	tButton->SetHzJustify(ZAF_HZ_LEFT);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetAllowToggling(true);
	tButton->SetSelectOnDownClick(true);
	tButton->SetSelectOnDoubleClick(false);
	rangeGroup->Add(tButton);

	tPrompt = new ZafPrompt(12, 1, 4, ZAF_ITEXT("from"));
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	rangeGroup->Add(tPrompt);

	tInteger = new ZafInteger(16, 1, 5, printJob->startPage);
	sprintf(tString, ZAF_ITEXT("%d..%d"), printJob->minPage, printJob->maxPage);
	tInteger->SetRange(tString);
	tInteger->SetStringID(ZAF_ITEXT("FROM"));
	rangeGroup->Add(tInteger);

	tPrompt = new ZafPrompt(22, 1, 2, ZAF_ITEXT("to"));
	tPrompt->SetHzJustify(ZAF_HZ_RIGHT);
	rangeGroup->Add(tPrompt);

	tInteger = new ZafInteger(24, 1, 5, printJob->endPage);
	sprintf(tString, ZAF_ITEXT("%d..%d"), printJob->minPage, printJob->maxPage);
	tInteger->SetRange(tString);
	tInteger->SetStringID(ZAF_ITEXT("TO"));
	rangeGroup->Add(tInteger);


	sprintf(tString, ZAF_ITEXT("Printer Name: <default>"));
	tPrompt = new ZafPrompt(2, 0, 2, tString);
	tPrompt->SetHzJustify(ZAF_HZ_LEFT);
	configGroup->Add(tPrompt);

	sprintf(tString, ZAF_ITEXT("Printer Resolution: %d x %d dots / inch"),
		printer->pixelsPerInchX, printer->pixelsPerInchY);
	tPrompt = new ZafPrompt(2, 1, 2, tString);
	tPrompt->SetHzJustify(ZAF_HZ_LEFT);
	configGroup->Add(tPrompt);

	tButton = new ZafButton(56 - 15, 1, 14, 1, ZAF_ITEXT("Properties"));
	tButton->SetHzJustify(ZAF_HZ_CENTER);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetSendMessageWhenSelected(true);
	tButton->SetValue(S_PRINT_SETUP);
	configGroup->Add(tButton);

	Add(configGroup);
	Add(rangeGroup);
	Add(copiesGroup);

	tButton = new ZafButton(60 - 24, 7, 9, 1, ZAF_ITEXT("Print"));
	tButton->SetHotKey('P', 0);
	tButton->SetHzJustify(ZAF_HZ_CENTER);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetSendMessageWhenSelected(true);
	tButton->SetValue(S_DLG_OK);
	Add(tButton);

	tButton = new ZafButton(60 - 12, 7, 9, 1, ZAF_ITEXT("Cancel"));
	tButton->SetHotKey('C', 0);
	tButton->SetHzJustify(ZAF_HZ_CENTER);
	tButton->SetVtJustify(ZAF_VT_CENTER);
	tButton->SetSendMessageWhenSelected(true);
	tButton->SetValue(S_DLG_CANCEL);
	Add(tButton);
}

ZafDialogEvent ZafPrintDialog::Control(ZafQFlags flags)
{
	return (ZafDialogWindow::Control(flags));
}

ZafEventType ZafPrintDialog::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);
	switch (ccode)
	{
	case S_PRINT_SETUP:
		{
		ZafPrintSetupDialog setupDialog(10, 3, printer);
		setupDialog.Control();
		}
		break;

	case S_DLG_OK:
		{
		printJob->collate = false;
		ZafButton *collateButton = 
			(ZafButton *)GetObject(ZAF_ITEXT("COLLATE"));
		if (collateButton && collateButton->Selected())
			printJob->collate = true;

		printJob->copies = 1;
		ZafInteger *copiesField = 
			(ZafInteger *)GetObject(ZAF_ITEXT("COPIES"));
		if (copiesField)
			printJob->copies = (int)copiesField->IntegerData()->Value();

		printJob->startPage = printJob->minPage;
		printJob->endPage = printJob->maxPage;
		ZafButton *rangeButton = 
			(ZafButton *)GetObject(ZAF_ITEXT("PAGES_ALL"));	
		if (rangeButton && rangeButton->Selected() == false)
		{
			ZafInteger *intField = 
				(ZafInteger *)GetObject(ZAF_ITEXT("FROM"));
			if (intField)
				printJob->startPage = 
					(int)intField->IntegerData()->Value();
			intField = (ZafInteger *)GetObject("TO");
			if (intField)
				printJob->endPage = 
					(int)intField->IntegerData()->Value();
		}
		ccode = ZafDialogWindow::Event(event);
		}
		break;

	default:
		ccode = ZafDialogWindow::Event(event);
		break;
	}
	return (ccode);
}

