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

#include <z_stdio.hpp>
#include <z_stdlib.hpp>
#include <z_string.hpp>
#include <z_scrdsp.hpp>
#include <z_win.hpp>
#include <z_utils.hpp>

#if defined(ZAF_MSDOS)
#	include <math.h>
#	if defined(__BORLANDC__) && defined(DOSX286)
#		include <phapi.h>
#	endif
#	include <dos.h>
#elif defined(ZAF_VXWORKS)
#	include <math.h>
#elif defined(ZAF_PSOS) && defined(__CADUL__)
#	include <mathcu.h>
#endif

#define ZAF_SCREEN_DISPLAY_INFO
#include "gbl_def.cpp"

bool _devicePainting = false;

#if defined(ZAF_GRAPHICS_MODE)

static bool colorUsedTable[ZAF_MAXCOLORS];

UGL_RGB defaultColorTable[] =
{
	UGL_MAKE_RGB(0, 0, 0),
	UGL_MAKE_RGB(0, 0, 128),
	UGL_MAKE_RGB(0, 128, 0),
	UGL_MAKE_RGB(0, 128, 128),
	UGL_MAKE_RGB(128, 0, 0),
	UGL_MAKE_RGB(128, 0, 128),
	UGL_MAKE_RGB(128, 0, 0),
	UGL_MAKE_RGB(192, 192, 192),
	UGL_MAKE_RGB(128, 128, 128),
	UGL_MAKE_RGB(0, 0, 255),
	UGL_MAKE_RGB(0, 255, 0),
	UGL_MAKE_RGB(0, 255, 255),
	UGL_MAKE_RGB(255, 0, 0),
	UGL_MAKE_RGB(255, 0, 255),
	UGL_MAKE_RGB(255, 255, 0),
	UGL_MAKE_RGB(255, 255, 255)
};

static struct ZafPattern
{
	int width;
	int height;
	unsigned char data[16];
} defaultPatternTable[] =
{
	{ 0, 0, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
	{ 64, 2, { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55 } }
};

static OSLineStyle ZAF_FARDATA _lineStyleData[] = 
{
	UGL_LINE_STYLE_SOLID,  // ZAF_LINE_SOLID	
	UGL_LINE_STYLE_DASHED  // ZAF_LINE_DOTTED
};

static OSMode ZAF_FARDATA _modeData[] =
{
//	zREPz, // ZAF_MODE_COPY
//	zXORz  // ZAF_MODE_XOR
	0,
	1
};

static OSMono ZAF_FARDATA _monoData[] =
{
	ZAF_MONO_BLACK,
	ZAF_MONO_DIM,
	ZAF_MONO_NORMAL,
	ZAF_MONO_HIGH
};

static ZafPaletteStruct ZAF_FARDATA __xorPalette =
{
	ZAF_LINE_SOLID, ZAF_PTN_SOLID_FILL, ZAF_CLR_WHITE, ZAF_CLR_BLACK, ZAF_MONO_NULL, ZAF_MONO_NORMAL, ZAF_FNT_DIALOG
};

static ZafPaletteStruct ZAF_FARDATA __markedTextPalette =
{
	ZAF_LINE_SOLID, ZAF_PTN_SOLID_FILL, ZAF_CLR_WHITE, ZAF_CLR_BLUE, ZAF_MONO_NULL, ZAF_MONO_NORMAL, ZAF_FNT_DIALOG
};

ZafPaletteStruct *ZafScreenDisplay::markPalette = &__markedTextPalette;
ZafPaletteStruct *ZafScreenDisplay::xorPalette = &__xorPalette;

// ----- ZafScreenDisplay ---------------------------------------------------

ZafScreenDisplay::ZafScreenDisplay(int &, char **) :
	ZafDisplay(), initialized(false)
{
	devID = uglInitialize(0, 0, 0, 0, 0);
	gc = uglGcCreate(devID);

	uglInfo(gc, UGL_INFO_DISPLAY_WIDTH, &columns);
	uglInfo(gc, UGL_INFO_DISPLAY_HEIGHT, &lines);

	// Initialize fonts.
	int i;
	for (i = 0; i < ZAF_MAXFONTS; i++)
		fontTable[i] = 0;
	fontTable[ZAF_FNT_SMALL] = uglFontCreate(devID, "Small", 6);
	fontTable[ZAF_FNT_DIALOG] = uglFontCreate(devID, "Dialog", 8);
	fontTable[ZAF_FNT_APPLICATION] = fontTable[ZAF_FNT_SYSTEM] = uglFontCreate(devID, "System", 10);
	fontTable[ZAF_FNT_FIXED] = uglFontCreate(devID, "Fixed", 10);


	// Initialize tables.
	for (i = 0; i < sizeof(_lineStyleData) / sizeof(OSLineStyle); i++)
		lineTable[i] = _lineStyleData[i];
	for (i = 0; i < sizeof(_modeData) / sizeof(OSMode); i++)
		modeTable[i] = _modeData[i];
	for (i = 0; i < sizeof(_monoData) / sizeof(OSMono); i++)
		monoTable[i] = _monoData[i];

	memset(patternTable, 0, ZAF_MAXPATTERNS * sizeof(OSFillPattern));
	for (i = 0; i < sizeof(defaultPatternTable) / sizeof(ZafPattern); i++)
		if (defaultPatternTable[i].width)
			patternTable[i] = uglBitmapCreateMono(gc, defaultPatternTable[i].width,
				defaultPatternTable[i].height, defaultPatternTable[i].width,
				defaultPatternTable[i].data);
		else
			patternTable[i] = ZAF_NULLH(UGL_BITMAP_ID);


	// Initialize the device image array.
	for (i = 0; i < ZAF_MAXIMAGES; i++)
	{
		cursorImage[i].cursorID = ZAF_NULLH(UGL_CURSOR_ID);
		cursorImage[i].movePending = false;
		cursorImage[i].newX = cursorImage[i].newY = 0;
		cursorImage[i].clip.left = cursorImage[i].clip.top =
			cursorImage[i].clip.right = cursorImage[i].clip.bottom = 0;
	}

	// Initialize the MetaWINDOW display variables.
	virtualCount = 0;
	stopDevice = 0;

	palette.lineStyle = ZAF_LINE_DEFAULT;
	palette.fillPattern = ZAF_PTN_DEFAULT;
	palette.colorForeground = ZAF_CLR_DEFAULT;
	palette.colorBackground = ZAF_CLR_DEFAULT;
	palette.monoForeground = ZAF_MONO_DEFAULT;
	palette.monoBackground = ZAF_MONO_DEFAULT;
	palette.font = ZAF_FNT_DEFAULT;

	masterClip.left = masterClip.top = 0;
	masterClip.right = columns - 1;
	masterClip.bottom = lines - 1;
	masterClip.coordinateType =	clipRegion.coordinateType = ZAF_PIXEL;
	SetClipRegion(masterClip);

	// Initialize the ZafCoordinateStruct statics.
	preSpace = 2;
	postSpace = 2;
	miniNumeratorX = miniNumeratorY = 1;
	miniDenominatorX = miniDenominatorY = 10;
	pixelsPerInchX = 60; //??? magic numbers.
	pixelsPerInchY = 60;

	// Initialize colorUsedTable.  1st 32 colors are "in use" by default.
	for (i = 0; i < ZAF_MAXCOLORS; ++i)
		colorUsedTable[i] = i < ZAF_CLR_USER_FIRST ? true : false;

	// Initialize colorTable.
	for (i = 0; i < sizeof(defaultColorTable) / sizeof(UGL_RGB); i++)
		colorTable[i] = uglColorAlloc(gc, i, defaultColorTable[i]);


	// Set initial display information.
	SetForeground(ZAF_CLR_WHITE);
	SetBackground(ZAF_CLR_BLACK);
	SetMonoForeground(ZAF_MONO_NORMAL);
	SetMonoBackground(ZAF_MONO_BLACK);
	SetFillPattern(ZAF_PTN_SOLID_FILL);
	SetFont(ZAF_FNT_DIALOG);
	SetMode(ZAF_MODE_COPY);
	SetLineStyle(ZAF_LINE_SOLID);

	ZafRegionStruct sizeRegion = TextSize(ZAF_ITEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"));
	cellWidth = (sizeRegion.Width() + 19) / 39;
	cellHeight = (sizeRegion.Height() * 15 + 6) / 13 + 2 * ZAF_TEXT_MARGIN_SIZE +
		2 * ZAF_BORDER_SIZE + preSpace + postSpace;

	miniNumeratorX = 1;
	miniDenominatorX = 10;
	miniNumeratorY = 1;
	miniDenominatorY = 10;
	pixelsPerInchX = 72;
	pixelsPerInchY = 72;

	initialized = true;
}

ZafScreenDisplay::~ZafScreenDisplay(void)
{
	// Restore the display if it was initialized correctly.
	if (initialized)
	{
		for (int logicalFont = 0; logicalFont < ZAF_MAXFONTS; logicalFont++)
			DestroyFont(logicalFont);

		int i;
		for (i = 0; i < ZAF_MAXIMAGES; i++)
			if (cursorImage[i].cursorID)
			{
				UGL_BITMAP_ID bitmapID;
				uglCursorImageGet(gc, cursorImage[i].cursorID, &bitmapID, 0, 0);
				uglCursorDestroy(gc, cursorImage[i].cursorID);
				uglBitmapDestroy(gc, bitmapID);
			}

		for (i = 0; i < ZAF_MAXPATTERNS; i++)
			if (patternTable[i])
			{
				uglFillPatternSet(gc, 0);
				uglBitmapDestroy(gc, patternTable[i]);
			}

		uglGcDestroy(gc);
		uglDeinitialize(devID);
	}
}

// --- Bitmap ---------------------------------------------------------------

ZafError ZafScreenDisplay::Bitmap(ZafCoordinate column, ZafCoordinate line, ZafBitmapStruct &bitmap)
{
	int pixelColumn;
	int pixelLine;
	if (coordinateType == ZAF_PIXEL)
	{
		pixelColumn = int(column * scaleNumerator / scaleDenominator + originX);
		pixelLine = int(line * scaleNumerator / scaleDenominator + originY);
	}
	else
	{
		pixelColumn = (int)(ConvertXValue(column, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelLine = (int)(ConvertYValue(line, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	}

	if (!bitmap.array)
		return (ZAF_ERROR_VALUE_MISSING);
	if (!bitmap.handle)
		ConvertToOSBitmap(bitmap);
	
	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the bitmap on the display.
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglBitmapBlit(gc, bitmap.handle, 0, 0, bitmap.width - 1, bitmap.height - 1,
				ZAF_NULLH(UGL_BITMAP_ID), pixelColumn, pixelLine);
		}

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::ConvertToOSBitmap(ZafBitmapStruct &bitmap)
{
	if (!bitmap.array)
		return (ZAF_ERROR_INVALID_SOURCE);

	if (bitmap.handle && bitmap.StaticHandle())
		return (ZAF_ERROR_INVALID_TARGET);

	if (bitmap.handle)
		DestroyOSBitmap(bitmap);

	UGL_COLOR *bitmapData = new UGL_COLOR[bitmap.width * bitmap.height];
	unsigned char *maskData = new unsigned char[(bitmap.width * bitmap.height + 7) / 8];
	memset(maskData, 0xFF, (bitmap.width * bitmap.height + 7) / 8);
	unsigned char *maskPtr = maskData;
	unsigned char mask = 0x80;

	bool transparent = false;
	for (int index = 0; index < bitmap.height * bitmap.width; index++)
	{
		if (bitmap.array[index] == ZAF_CLR_BACKGROUND)
		{
			bitmapData[index] = 0;
			*maskPtr &= ~mask;
			transparent = true;
		}
		else
			bitmapData[index] = colorTable[bitmap.array[index]];

		mask >>= 1;
		if (mask == 0)
		{
			mask = 0x80;
			maskPtr++;
		}
	}


	if (transparent)
		bitmap.handle = uglBitmapCreate(gc, bitmap.width, bitmap.height,
			bitmap.width, bitmapData, bitmap.width, maskData);
	else
		bitmap.handle = uglBitmapCreate(gc, bitmap.width, bitmap.height,
			bitmap.width, bitmapData, 0, 0);

	delete []bitmapData;
	delete []maskData;

	if (bitmap.handle)
		return (ZAF_ERROR_NONE);
	else
		return (ZAF_ERROR_INVALID);
}

ZafError ZafScreenDisplay::ConvertToZafBitmap(ZafBitmapStruct &)
{
	return (ZAF_ERROR_INVALID);
}

ZafError ZafScreenDisplay::DestroyOSBitmap(ZafBitmapStruct &bitmap)
{
	uglBitmapDestroy(gc, bitmap.handle);
	bitmap.handle = ZAF_NULLH(UGL_BITMAP_ID);
	return (ZAF_ERROR_NONE);
}

// --- Icon -----------------------------------------------------------------

ZafError ZafScreenDisplay::Icon(ZafCoordinate column, ZafCoordinate line, ZafIconStruct &icon)
{
	int pixelColumn;
	int pixelLine;
	if (coordinateType == ZAF_PIXEL)
	{
		pixelColumn = int(column * scaleNumerator / scaleDenominator + originX);
		pixelLine = int(line * scaleNumerator / scaleDenominator + originY);
	}
	else
	{
		pixelColumn = (int)(ConvertXValue(column, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelLine = (int)(ConvertYValue(line, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	}

	if (!icon.array)
		return (ZAF_ERROR_VALUE_MISSING);
	if (!icon.handle)
		ConvertToOSIcon(icon);
	
	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the icon on the display.
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglBitmapBlit(gc, icon.handle, 0, 0, icon.width - 1, icon.height - 1,
				ZAF_NULLH(UGL_BITMAP_ID), pixelColumn, pixelLine);
		}

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::ConvertToOSIcon(ZafIconStruct &icon)
{
	if (!icon.array)
		return (ZAF_ERROR_INVALID_SOURCE);

	if (icon.handle && icon.StaticHandle())
		return (ZAF_ERROR_INVALID_TARGET);

	if (icon.handle)
		DestroyOSIcon(icon);

	ZafBitmapStruct bitmap;
	bitmap.width = icon.width;
	bitmap.height = icon.height;
	bitmap.array = icon.array;
	bitmap.staticArray = icon.staticArray;

	ZafError error = ConvertToOSBitmap(bitmap);
	if (error == ZAF_ERROR_NONE)
	{
		icon.handle = bitmap.handle;
		icon.mask = bitmap.mask;
	}

	return (error);
}

ZafError ZafScreenDisplay::ConvertToZafIcon(ZafIconStruct &)
{
	return (ZAF_ERROR_INVALID);
}

ZafError ZafScreenDisplay::DestroyOSIcon(ZafIconStruct &icon)
{
	uglBitmapDestroy(gc, icon.handle);
	icon.handle = ZAF_NULLH(UGL_BITMAP_ID);
	return (ZAF_ERROR_NONE);
}

// --- Mouse -----------------------------------------------------------------

ZafError ZafScreenDisplay::Mouse(ZafCoordinate, ZafCoordinate, ZafMouseStruct &)
{
	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::ConvertToOSMouse(ZafMouseStruct &)
{
	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::ConvertToZafMouse(ZafMouseStruct &)
{
	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::DestroyOSMouse(ZafMouseStruct &)
{
	return (ZAF_ERROR_NONE);
}

// --- Text -----------------------------------------------------------------

ZafError ZafScreenDisplay::Text(ZafCoordinate left, ZafCoordinate top,
	const ZafIChar *text, int length, int hotKeyIndex, bool fill)
{
	// Get the text size.
	ZafRegionStruct textSize = TextSize(text, length);

	// Draw the text (textSize.right and textSize.bottom are width & height).
	return (Text(left, top,
		left + textSize.right - 1, top + textSize.bottom - 1, text, length,
		ZAF_HZ_LEFT, ZAF_VT_TOP, hotKeyIndex, fill));
}

ZafError ZafScreenDisplay::Text(ZafCoordinate left, ZafCoordinate top, ZafCoordinate right, ZafCoordinate bottom,
	const ZafIChar *text, int length, ZafHzJustify hzJustify,
	ZafVtJustify vtJustify, int hotKeyIndex, bool fill)
{
	// Make sure we have a valid string.
	if (!text || !text[0])
		return (ZAF_ERROR_INVALID);

	int pixelLeft;
	int pixelTop;
	int pixelRight;
	int pixelBottom;

	if (coordinateType == ZAF_PIXEL)
	{
		pixelLeft = int(left * scaleNumerator / scaleDenominator + originX);
		pixelTop = int(top * scaleNumerator / scaleDenominator + originY);
		pixelRight = int(right * scaleNumerator / scaleDenominator + originX);
		pixelBottom = int(bottom * scaleNumerator / scaleDenominator + originY);
	}
	else
	{
		pixelLeft = (int)(ConvertXValue(left, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelTop = (int)(ConvertYValue(top, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelRight = (int)(ConvertXValue(right, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelBottom = (int)(ConvertYValue(bottom, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	}

	// Set up the fill line.
	static ZafIChar ZAF_FARDATA fillLine[256];
	if (length < 0)
		length = strlen(text);
	else if (length > 255)
		length = 255;
	strncpy(fillLine, text, length);
	fillLine[length] = '\0';

	int hotKeyLeft, hotKeyRight;
	if (hotKeyIndex >= 0)
	{
		ZafIChar hotKeyBuf[2];
		hotKeyBuf[0] = fillLine[hotKeyIndex];
		hotKeyBuf[1] =	fillLine[hotKeyIndex] = 0;
		hotKeyLeft = hotKeyIndex == 0 ? 0 : TextSize(fillLine).Width();
		fillLine[hotKeyIndex] = hotKeyBuf[0];
		hotKeyRight = hotKeyLeft + TextSize(hotKeyBuf).Width() - 1;
	}

	// Check for special characters.
	strrepc(fillLine, '\t', ' ');
	strrepc(fillLine, '\r', ' ');
	strrepc(fillLine, '\n', ' ');

	// Assign the rectangle to the region structure.
	ZafRegionStruct textSize = TextSize(text), cRegion = ClipRegion();
	int pixelWidth = (int)(ConvertXValue(textSize.Width(), coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
	int pixelHeight = (int)(ConvertYValue(textSize.Height(), coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);

	int leftText = pixelLeft;
	if (hzJustify == ZAF_HZ_RIGHT)
		leftText = pixelRight - pixelWidth;
	else if (hzJustify == ZAF_HZ_CENTER)
	{
		leftText += (pixelRight - pixelLeft - pixelWidth + 1) / 2;
		if (leftText < pixelLeft)
			leftText = pixelLeft;
	}

	// Adjust hotKey offsets.
	hotKeyLeft += leftText;
	hotKeyRight += leftText;

	int topText = pixelTop;
	if (vtJustify == ZAF_VT_BOTTOM)
		topText = pixelBottom - pixelHeight;
	else if (vtJustify == ZAF_VT_CENTER)
	{
		topText += (pixelBottom - pixelTop - pixelHeight + 1) / 2;
		if (topText < pixelTop)
			topText = pixelTop;
	}

	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	uglLineWidthSet(gc, 0);

	// Draw the text.
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			UGL_COLOR saveColor;

			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);

			if (fill)
				uglRectangle(gc, leftText, topText, leftText + pixelWidth - 1, topText + pixelHeight - 1);

			uglBackgroundColorGet(gc, &saveColor);
			uglBackgroundColorSet(gc, UGL_COLOR_TRANSPARENT);
			uglText(gc, leftText, topText, fillLine);
			uglBackgroundColorSet(gc, saveColor);

			if (hotKeyIndex >= 0)
			{
				uglLineWidthSet(gc, 1);
				uglLine(gc, hotKeyLeft, topText + pixelHeight, hotKeyRight, topText + pixelHeight);
			}
		}

	return (ZAF_ERROR_NONE);
}

ZafRegionStruct ZafScreenDisplay::TextSize(const ZafIChar *string, int)
{
	ZafRegionStruct size;
	size.Assign(1, 1, 0, 0, ZAF_PIXEL);

	if (!string || !string[0])
		return (size);

	size.right = uglTextWidth(gc, string);
	size.bottom = uglTextHeight(gc, string);

	// left and top stay 1 so that right and bottom contain the width & height.
	size.right = (int)(ConvertXValue(size.right, ZAF_PIXEL, coordinateType));
	size.bottom = (int)(ConvertYValue(size.bottom, ZAF_PIXEL, coordinateType));
	size.coordinateType = coordinateType;

	return (size);
}

// --- Primitives -----------------------------------------------------------

ZafError ZafScreenDisplay::Ellipse(ZafCoordinate left, ZafCoordinate top, ZafCoordinate right, ZafCoordinate bottom,
	float startAngle, float endAngle, int width, bool fill)
{
	int pixelLeft;
	int pixelTop;
	int pixelRight;
	int pixelBottom;
	int pixelWidth;

	if (coordinateType == ZAF_PIXEL)
	{
		pixelLeft = int(left * scaleNumerator / scaleDenominator + originX);
		pixelTop = int(top * scaleNumerator / scaleDenominator + originY);
		pixelRight = int(right * scaleNumerator / scaleDenominator + originX);
		pixelBottom = int(bottom * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax(int(width * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}
	else
	{
		pixelLeft = (int)(ConvertXValue(left, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelTop = (int)(ConvertYValue(top, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelRight = (int)(ConvertXValue(right, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelBottom = (int)(ConvertYValue(bottom, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax((int)(ConvertXValue(width, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}

	if (pixelRight < pixelLeft || pixelBottom < pixelTop)
		return (ZAF_ERROR_VALUE_MISSING);

	float angleSize = endAngle - startAngle;

	UGL_COLOR saveColor;
	if (!fill)
	{
		uglBackgroundColorGet(gc, &saveColor);
		uglBackgroundColorSet(gc, UGL_COLOR_TRANSPARENT);
	}

	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the ellipse on the display.
	uglLineWidthSet(gc, pixelWidth);
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);

			if (angleSize == 0.0 || angleSize == 360.0)
				uglEllipse(gc, pixelLeft, pixelTop, pixelRight, pixelBottom,
					0, 0, 0, 0);
			else
			{
				ZafCoordinate a = (pixelRight - pixelLeft + 1) / 2;
				ZafCoordinate b = (pixelBottom - pixelTop + 1) / 2;

				// Convert angles to radians;
				double rStartAngle = startAngle * 2 * 3.1415927 / 360.0;
				double rEndAngle = endAngle * 2 * 3.1415927 / 360.0;

				double r = a + b; // Make sure r is sufficiently large.
				ZafCoordinate startX = pixelLeft + a + (int)(r * cos(rStartAngle));
				ZafCoordinate startY = pixelTop + b - (int)(r *sin(rStartAngle));
				ZafCoordinate endX = pixelLeft + a + (int)(r * cos(rEndAngle));
				ZafCoordinate endY = pixelTop + b - (int)(r * sin(rEndAngle));

				uglEllipse(gc, pixelLeft, pixelTop, pixelRight, pixelBottom,
					(UGL_POS)startX, (UGL_POS)startY, (UGL_POS)endX, (UGL_POS)endY);
			}
		}

	if (!fill)
		uglBackgroundColorSet(gc, saveColor);

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::Line(ZafCoordinate x1, ZafCoordinate y1, ZafCoordinate x2, ZafCoordinate y2, int width)
{
	int pixelX1;
	int pixelY1;
	int pixelX2;
	int pixelY2;
	int pixelWidth;

	if (coordinateType == ZAF_PIXEL)
	{
		pixelX1 = int(x1 * scaleNumerator / scaleDenominator + originX);
		pixelY1 = int(y1 * scaleNumerator / scaleDenominator + originY);
		pixelX2 = int(x2 * scaleNumerator / scaleDenominator + originX);
		pixelY2 = int(y2 * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax(int(width * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}
	else
	{
		pixelX1 = (int)(ConvertXValue(x1, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelY1 = (int)(ConvertYValue(y1, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelX2 = (int)(ConvertXValue(x2, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelY2 = (int)(ConvertYValue(y2, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax((int)(ConvertXValue(width, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}

	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the line on the display.
	uglLineWidthSet(gc, pixelWidth);
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglLine(gc, pixelX1, pixelY1, pixelX2, pixelY2);
		}

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::Pixel(ZafCoordinate column, ZafCoordinate line, ZafLogicalColor color,
	ZafLogicalColor)
{
	int pixelColumn;
	int pixelLine;
	if (coordinateType == ZAF_PIXEL)
	{
		pixelColumn = int(column * scaleNumerator / scaleDenominator + originX);
		pixelLine = int(line * scaleNumerator / scaleDenominator + originY);
	}
	else
	{
		pixelColumn = (int)(ConvertXValue(column, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelLine = (int)(ConvertYValue(line, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	}

	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the pixel on the display.
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglPixelSet(gc, pixelColumn, pixelLine, colorTable[color]);
		}

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::Polygon(int numPoints, const ZafCoordinate *polygonPoints,
	int width, bool fill, bool close)
{
	int pixelWidth = (width > 0) ? ZafMax((int)(ConvertXValue(width, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator), 1) :
		(width == ZAF_HAIR_LINE ? 1 : 0);

	if (fill && !close && (polygonPoints[2 * numPoints - 2] != polygonPoints[0] ||
		polygonPoints[2 * numPoints - 1] != polygonPoints[1]))
			close = true;

	int realNumPoints = numPoints;
	if (close)
		++realNumPoints;

	// Create a list of UGL points.
	bool allocatedPoints = false;
	int *realPoints;
	if (!close && coordinateType == ZAF_PIXEL && sizeof(ZafCoordinate) ==
		sizeof(int))
		realPoints = (int *)polygonPoints;
	else
	{
		allocatedPoints = true;
		realPoints = new int[realNumPoints * 2];
		for (int p = 0; p < numPoints; ++p)
		{
			realPoints[2 * p] = (int)(ConvertXValue(polygonPoints[2 * p], coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
			realPoints[2 * p + 1] = (int)(ConvertYValue(polygonPoints[2 * p + 1], coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		}
	}

	if (close)
	{
		realPoints[2 * numPoints] = realPoints[0];
		realPoints[2 * numPoints + 1] = realPoints[1];
	}

	UGL_COLOR saveColor;
	if (!fill)
	{
		uglBackgroundColorGet(gc, &saveColor);
		uglBackgroundColorSet(gc, UGL_COLOR_TRANSPARENT);
	}

	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the polygon on the display.
	uglLineWidthSet(gc, pixelWidth);
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglPolygon(gc, realNumPoints, realPoints);
		}

	if (!fill)
		uglBackgroundColorSet(gc, saveColor);

	if (allocatedPoints)
		delete []realPoints;

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::Rectangle(ZafCoordinate left, ZafCoordinate top, ZafCoordinate right, ZafCoordinate bottom,
	int width, bool fill)
{
	int pixelLeft = (int)(ConvertXValue(left, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
	int pixelTop = (int)(ConvertYValue(top, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	int pixelRight = (int)(ConvertXValue(right, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
	int pixelBottom = (int)(ConvertYValue(bottom, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
	int pixelWidth = (width > 0) ? ZafMax((int)(ConvertXValue(width, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator), 1) :
		(width == ZAF_HAIR_LINE ? 1 : 0);

	if (coordinateType == ZAF_PIXEL)
	{
		pixelLeft = int(left * scaleNumerator / scaleDenominator + originX);
		pixelTop = int(top * scaleNumerator / scaleDenominator + originY);
		pixelRight = int(right * scaleNumerator / scaleDenominator + originX);
		pixelBottom = int(bottom * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax(int(width * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}
	else
	{
		pixelLeft = (int)(ConvertXValue(left, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelTop = (int)(ConvertYValue(top, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelRight = (int)(ConvertXValue(right, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originX);
		pixelBottom = (int)(ConvertYValue(bottom, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator + originY);
		pixelWidth = (width > 0) ? ZafMax((int)(ConvertXValue(width, coordinateType, ZAF_PIXEL) * scaleNumerator / scaleDenominator), 1) :
			(width == ZAF_HAIR_LINE ? 1 : 0);
	}

	UGL_COLOR saveColor;
	if (!fill)
	{
		uglBackgroundColorGet(gc, &saveColor);
		uglBackgroundColorSet(gc, UGL_COLOR_TRANSPARENT);
	}

	// Save the user's clip region so can restore it when done drawing.
	ZafRegionStruct clip, saveClip = ClipRegion();

	// Draw the rectangle on the display.
	uglLineWidthSet(gc, pixelWidth);
	for (ZafRegionElement *regionElement = drawRegionList.First(); regionElement; regionElement = regionElement->Next())
		if (regionElement->region.Overlap(saveClip, clip))
		{
			uglClipRectSet(gc, clip.left, clip.top, clip.right, clip.bottom);
			uglRectangle(gc, pixelLeft, pixelTop, pixelRight, pixelBottom);
		}

	if (!fill)
		uglBackgroundColorSet(gc, saveColor);

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::RectangleXORDiff(const ZafRegionStruct *oldRegion,
	const ZafRegionStruct *newRegion)
{
	// See if the regions match.
	if (oldRegion && newRegion &&
		oldRegion->left == newRegion->left && oldRegion->top == newRegion->top &&
		oldRegion->right == newRegion->right && oldRegion->bottom == newRegion->bottom)
		return (ZAF_ERROR_INVALID);

	ZafRegionStruct clip = ClipRegion();
	ZafPaletteStruct savePalette = Palette();

	// Hide the screen devices.
	ZafRegionStruct region;
/* START BLOCK COMMENT
	if (!RegionInitialize(region, &clip,
		ZafMin(oldRegion ? oldRegion->left : clip.left, newRegion ? newRegion->left : clip.left),
		ZafMin(oldRegion ? oldRegion->top : clip.top, newRegion ? newRegion->top : clip.top),
		ZafMax(oldRegion ? oldRegion->right : clip.right, newRegion ? newRegion->right : clip.right),
		ZafMax(oldRegion ? oldRegion->bottom : clip.bottom, newRegion ? newRegion->bottom : clip.bottom)))
		return (ZAF_ERROR_INVALID);
END BLOCK COMMENT */

//	UnvirtualizeRegion(region);

	region.left = region.top = 0;
	region.right = columns - 1;
	region.bottom = lines - 1;
	region.coordinateType = ZAF_PIXEL;
	BeginDraw(0, ID_ZAF_DIRECT, region, region);

	// Draw the XOR rectangles on the display.
	SetPalette(*xorPalette);
	SetMode(ZAF_MODE_XOR);

	if (oldRegion)
		ZafDisplay::Rectangle(*oldRegion);

	if (newRegion)
		ZafDisplay::Rectangle(*newRegion);

	EndDraw();

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::RegionCopy(const ZafRegionStruct &oldRegion,
	int newColumn, int newLine)
{

	uglBitmapBlit(gc, 0, oldRegion.left, oldRegion.top, oldRegion.right,
		oldRegion.bottom, 0, newColumn, newLine);

	return (ZAF_ERROR_NONE);
}

// --- Tables ---------------------------------------------------------------

ZafLogicalColor ZafScreenDisplay::AddColor(ZafLogicalColor index,
	ZafUInt8 red, ZafUInt8 green, ZafUInt8 blue)
{
	if (index != ZAF_CLR_NULL &&
		(index < 0 || index >= ZAF_MAXCOLORS))
		return (ZAF_CLR_NULL);

	int realIndex = index;
	if (realIndex == ZAF_CLR_NULL)
	{
		// Find next available color.
		int i = 0;
		while (colorUsedTable[i] && i < ZAF_MAXCOLORS)
			++i;
		if (i < ZAF_MAXCOLORS)
			realIndex = i;
		else
			return (ZAF_CLR_NULL);
	}

	// If that color is already in use, or the system doesn't support a color 
	// of that index, do nothing.
	int colorBits;
	uglInfo(gc, UGL_INFO_COLOR_BITS, &colorBits);

	if (colorUsedTable[realIndex] || (colorBits < 16 &&
		realIndex >= (1 << colorBits)))
		return (ZAF_CLR_NULL);

	colorTable[realIndex] = uglColorAlloc(gc, realIndex, UGL_MAKE_RGB(red, green, blue));
	colorUsedTable[realIndex] = true;

	return (realIndex);
}

ZafLogicalFont ZafScreenDisplay::AddFont(ZafLogicalFont index, char *fontFamily,
	int pointSize, ZafFontWeight, ZafFontSlant, ZafFontPitch)
{
	if (index != ZAF_FNT_NULL &&
		(index < 0 || index >= ZAF_MAXFONTS))
		return (ZAF_FNT_NULL);

	int realIndex = index;
	if (realIndex == ZAF_FNT_NULL)
	{
		// Find next available font.
		int i = 0;
		while (fontTable[i] && i < ZAF_MAXFONTS)
			++i;
		if (i < ZAF_MAXFONTS)
			realIndex = i;
		else
			return (ZAF_FNT_NULL);
	}

	fontTable[realIndex] = uglFontCreate(devID, fontFamily, pointSize);

	if (fontTable[realIndex])
		return (realIndex);
	else
		return (ZAF_FNT_NULL);
}

ZafError ZafScreenDisplay::DestroyColor(ZafLogicalColor index)
{
	if (index < 0 || index >= ZAF_MAXCOLORS)
		return (ZAF_ERROR_INVALID_INDEX);

	uglColorFree(gc, colorTable[index]);
	colorTable[index] = ZAF_CLR_NULL;
	colorUsedTable[index] = false;

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::DestroyFont(ZafLogicalFont index)
{
	if (index < 0 || index >= ZAF_MAXFONTS)
		return (ZAF_ERROR_INVALID_INDEX);

	fontTable[index] = 0;

	return (ZAF_ERROR_NONE);
}

ZafError ZafScreenDisplay::ColorInfo(ZafLogicalColor index, ZafUInt8 &red, ZafUInt8 &green, ZafUInt8 &blue)
{
	if (index < 0 || index >= ZAF_MAXCOLORS || !colorUsedTable[index])
		return (ZAF_ERROR_INVALID_INDEX);

	// Return the color information.
	UGL_RGB rgbColor;
	uglColorGet(gc, colorTable[index], &rgbColor);

	red = UGL_RGB_RED(rgbColor);
	green = UGL_RGB_GREEN(rgbColor);
	blue = UGL_RGB_BLUE(rgbColor);

	return (ZAF_ERROR_NONE);
}

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

	ZafLogicalFont saveFont = SetFont(index);

	UGL_FONT_INFO fontInfo;
	uglInfo(gc, UGL_INFO_FONT_INFO, &fontInfo);

	SetFont(saveFont);

	if (fontFamily)
		strncpy(fontFamily, fontInfo.name, bufferSize);

	if (pointSize)
		*pointSize = fontInfo.maxAscent + fontInfo.maxDescent;

	if (weight)
		*weight = fontInfo.weight ? ZAF_FNT_WEIGHT_BOLD : ZAF_FNT_WEIGHT_NORMAL;

	if (slant)
		*slant = fontInfo.slant ? ZAF_FNT_SLANT_ITALIC : ZAF_FNT_SLANT_NORMAL;

	if (pitch)
		*pitch = ZAF_FNT_PITCH_DEFAULT; // Not yet implemented.

	if (averageCharWidth)
		*averageCharWidth = 0; // Not yet implemented.

	if (height)
		*height = fontInfo.maxAscent + fontInfo.maxDescent;

	if (leading)
		*leading = fontInfo.leading;

	return (ZAF_ERROR_NONE);
}

// --- Get ------------------------------------------------------------------

ZafLogicalColor ZafScreenDisplay::Background(void) const
{
	return (palette.colorBackground);
}

ZafLogicalColor ZafScreenDisplay::MonoBackground(void) const
{
	return (palette.monoBackground);
}

ZafRegionStruct ZafScreenDisplay::ClipRegion(void) const
{
	return (clipRegion);
}

ZafLogicalFont ZafScreenDisplay::Font(void) const
{
	return (palette.font);
}

ZafLogicalColor ZafScreenDisplay::Foreground(void) const
{
	return (palette.colorForeground);
}

ZafLogicalColor ZafScreenDisplay::MonoForeground(void) const
{
	return (palette.monoForeground);
}

ZafLogicalLineStyle ZafScreenDisplay::LineStyle(void) const
{
	return (palette.lineStyle);
}

ZafLogicalMode ZafScreenDisplay::Mode(void) const
{
	return (mode);
}

ZafPaletteStruct ZafScreenDisplay::Palette(void) const
{
	return (palette);
}

ZafLogicalFillPattern ZafScreenDisplay::FillPattern(void) const
{
	return (palette.fillPattern);
}

// --- Set ------------------------------------------------------------------

ZafLogicalColor ZafScreenDisplay::SetBackground(ZafLogicalColor color)
{
	if (color >= 0 && color < ZAF_MAXCOLORS)
	{
		palette.colorBackground = color;
		uglBackgroundColorSet(gc, colorTable[color]);
	}

	return(palette.colorBackground);
}

ZafRegionStruct ZafScreenDisplay::SetClipRegion(const ZafRegionStruct &region)
{
	// Check region against master clip region. Clipping must be within
	// the master clip region.
	ZafRegionStruct convertRegion = region.Region(ZAF_PIXEL);
	convertRegion.left = (int)((long)convertRegion.left * scaleNumerator / scaleDenominator + originX);
	convertRegion.top = (int)((long)convertRegion.top * scaleNumerator / scaleDenominator + originY);
	convertRegion.right = (int)((long)convertRegion.right * scaleNumerator / scaleDenominator + originX);
	convertRegion.bottom = (int)((long)convertRegion.bottom * scaleNumerator / scaleDenominator + originY);
	if (!convertRegion.Overlap(masterClip, clipRegion))
		clipRegion.left =
			clipRegion.top =
			clipRegion.right=
			clipRegion.bottom = -1;

	uglClipRectSet(gc, clipRegion.left, clipRegion.top, clipRegion.right,
		clipRegion.bottom);

	return (clipRegion);
}

ZafLogicalFillPattern ZafScreenDisplay::SetFillPattern(ZafLogicalFillPattern pattern)
{
	if (pattern >= 0 && pattern < ZAF_MAXPATTERNS)
	{
		palette.fillPattern = pattern;
		uglFillPatternSet(gc, patternTable[pattern]);
	}

	return(palette.fillPattern);
}

ZafLogicalFont ZafScreenDisplay::SetFont(ZafLogicalFont font)
{
	if (font != palette.font && font >= 0 && font < ZAF_MAXFONTS)
	{
		palette.font = font;
		uglFontSet(gc, fontTable[font]);
	}

	return(palette.font);
}

ZafLogicalColor ZafScreenDisplay::SetForeground(ZafLogicalColor color)
{
	if (color >= 0 && color < ZAF_MAXCOLORS)
	{
		palette.colorForeground = color;
		uglForegroundColorSet(gc, colorTable[color]);
	}

	return(palette.colorForeground);
}

ZafLogicalLineStyle ZafScreenDisplay::SetLineStyle(ZafLogicalLineStyle line)
{
	if (line >= 0 && line < ZAF_MAXLINES)
	{
		palette.lineStyle = line;
		uglLineStyleSet(gc, (UGL_LINE_STYLE)lineTable[line]);
	}

	return (palette.lineStyle);
}

ZafLogicalMode ZafScreenDisplay::SetMode(ZafLogicalMode tMode)
{
	if (tMode >= 0 && tMode < ZAF_MAXMODES)
	{
		mode = tMode;
		if (mode == ZAF_MODE_COPY)
			uglRasterModeSet(gc, UGL_RASTER_OP_COPY);
		else if (mode == ZAF_MODE_XOR)
			uglRasterModeSet(gc, UGL_RASTER_OP_XOR);
	}
	return (mode);
}

ZafLogicalColor ZafScreenDisplay::SetMonoBackground(ZafLogicalColor color)
{
	if (color != ZAF_MONO_NULL && color >= 0 && color < ZAF_MAXCOLORS)
	{
		palette.monoBackground = color;
	}

	return (palette.monoBackground);
}

ZafLogicalColor ZafScreenDisplay::SetMonoForeground(ZafLogicalColor color)
{
	if (color != ZAF_MONO_NULL && color >= 0 && color < ZAF_MAXCOLORS)
	{
		palette.monoBackground = color;
	}

	return (palette.monoBackground);
}

ZafPaletteStruct ZafScreenDisplay::SetPalette(ZafPaletteStruct palette)
{
	SetLineStyle(palette.lineStyle);
	SetFillPattern(palette.fillPattern);
	SetForeground(palette.colorForeground);
	SetBackground(palette.colorBackground);
	SetMonoForeground(palette.monoForeground);
	SetMonoBackground(palette.monoBackground);
	SetFont(palette.font);

	return (palette);
}

// --- Draw Setup -----------------------------------------------------------

ZafError ZafScreenDisplay::BeginDraw(OSDisplayContext, OSDrawContext dc,
	const ZafRegionStruct &draw, const ZafRegionStruct &clip)
{
	ZafError retVal = ZAF_ERROR_NONE;

	if (--virtualCount == -1)
	{
 		stopDevice++;

//??? Why?... compatibility with i_metdsp.
		if (dc == ID_ZAF_SCREEN)
		{
			viewPort.left = viewPort.top = 0;
			viewPort.right = columns - 1;
			viewPort.bottom = lines - 1;
		}
		else
			viewPort = draw;

/* START BLOCK COMMENT
**			masterClip.left = -viewPort.left;
**			masterClip.top = -viewPort.top;
**			masterClip.right = columns - viewPort.left - 1;
**			masterClip.bottom = lines - viewPort.top - 1;
**			masterClip.coordinateType = viewPort.coordinateType;
**			clipRegion = masterClip;
END BLOCK COMMENT */

/* START BLOCK COMMENT
**			drawRegionList.Destroy();
**			drawRegionList.Allocate(0, masterClip);
END BLOCK COMMENT */

		masterClip.left = clip.left - viewPort.left;
		masterClip.top = clip.top - viewPort.top;
		masterClip.right = clip.right - viewPort.left;
		masterClip.bottom = clip.bottom - viewPort.top;
		clipRegion = masterClip;

		uglViewPortSet(gc, viewPort.left, viewPort.top, viewPort.right, viewPort.bottom);
		uglClipRectSet(gc, masterClip.left, masterClip.top, masterClip.right, masterClip.bottom);
		uglBatchStart(gc);

/* START BLOCK COMMENT
**			drawRegionList.Destroy();
END BLOCK COMMENT */

//		if (dc != ID_ZAF_DIRECT && dc != ID_ZAF_SCREEN)
		{
			// Set the draw regions.
			if (dc != ID_ZAF_DIRECT && dc != ID_ZAF_SCREEN)
			{
				for (ZafRegionElement *element = drawRegionList.First(); element;
					element = element->Next())
				{
					element->region.VtShift(-viewPort.top);
					element->region.HzShift(-viewPort.left);
				}
			}

			if (!drawRegionList.First())
			{
				drawRegionList.Allocate(0, masterClip);
				destroyDrawList = true;
				retVal = ZAF_ERROR_VALUE_MISSING;
			}
		}
	}

	return (retVal);
}

ZafError ZafScreenDisplay::EndDraw(void)
{
	if (++virtualCount == 0)
	{
		masterClip.left = -viewPort.left;
		masterClip.top = -viewPort.top;
		masterClip.right = columns - viewPort.left - 1;
		masterClip.bottom = lines - viewPort.top - 1;
		clipRegion = masterClip;

		// Restore display.
		coordinateType = ZAF_PIXEL;
		SetMode(ZAF_MODE_COPY);
		originX = originY = 0;
		scaleNumerator = scaleDenominator = 1;

		uglBatchEnd(gc);

		stopDevice--;

		bool finished;
		do
		{
			finished = true;
			for (int i = 0; i < ZAF_MAXIMAGES; i++)
			{
				if (cursorImage[i].movePending)
				{
					DeviceMove((ZafDeviceImageType)i, cursorImage[i].newX,
						cursorImage[i].newY, cursorImage[i].clip);
					cursorImage[i].movePending = false;
					finished = false;
				}
			}
		} while (!finished);


		if (destroyDrawList)
			drawRegionList.Destroy();
		else
		{
			for (ZafRegionElement *element = drawRegionList.First(); element;
				element = element->Next())
			{
				element->region.VtShift(viewPort.top);
				element->region.HzShift(viewPort.left);
			}
		}

/* START BLOCK COMMENT
**			for (ZafRegionElement *element = drawRegionList.First(); element;
**				element = element->Next())
**			{
**				element->region.VtShift(viewPort.top);
**				element->region.HzShift(viewPort.left);
**			}
END BLOCK COMMENT */
	}
	else if (virtualCount > 0)
		virtualCount = 0;

	return (ZAF_ERROR_NONE);
}


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

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

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

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

OSDisplayContext ZafScreenDisplay::SetDisplayContext(OSDisplayContext)
{
  	// Meaningless on MSDOS.
	return (0);
}

OSDrawContext ZafScreenDisplay::SetDrawContext(OSDrawContext)
{
	// Meaningless on MSDOS.
	return (0);
}

// --- Devices --------------------------------------------------------------

int ZafScreenDisplay::DeviceMove(ZafDeviceImageType imageType, int newColumn,
	int newLine, ZafRegionStruct &clip)
{
	if (stopDevice++ == 0)
	{
		if (cursorImage[imageType].cursorID)
		{
			ZafRegionStruct cursorRegion;
			cursorRegion.coordinateType = ZAF_PIXEL;
			cursorRegion.left = newColumn;
			cursorRegion.top = newLine;
			cursorRegion.right = cursorRegion.left +
				cursorImage[imageType].cursorID->width - 1;
			cursorRegion.bottom = cursorRegion.top +
				cursorImage[imageType].cursorID->height - 1;

			if (newColumn >= columns || newLine >= lines ||
				(imageType == ZAF_IMT_CURSOR_IMAGE &&
				 !cursorRegion.Encompassed(clip)))
				uglCursorOff(gc, cursorImage[imageType].cursorID);
			else
			{
				uglCursorOn(gc, cursorImage[imageType].cursorID);
				uglCursorMove(gc, cursorImage[imageType].cursorID,
					newColumn, newLine);
			}
		}
	}
	else
	{
		cursorImage[imageType].newX = newColumn;
		cursorImage[imageType].newY = newLine;
		cursorImage[imageType].clip = clip;
		cursorImage[imageType].movePending = true;
	}


	stopDevice--;

	return (true);
}

int ZafScreenDisplay::DeviceSet(ZafDeviceImageType imageType, int column,
	int line, int width, int height, ZafLogicalColor *image,
	ZafRegionStruct &clip)
{
	stopDevice++;

	UGL_COLOR *bitmapData = new UGL_COLOR[width * height];
	unsigned char *maskData = new unsigned char[(width * height + 7) / 8];
	memset(maskData, 0xFF, (width * height + 7) / 8);
	unsigned char *maskPtr = maskData;
	unsigned char mask = 0x80;

	for (int index = 0; index < height * width; index++)
	{
		if (image[index] == ZAF_CLR_BACKGROUND)
		{
			bitmapData[index] = 0;
			*maskPtr &= ~mask;
		}
		else
			bitmapData[index] = colorTable[image[index]];

		mask >>= 1;
		if (mask == 0)
		{
			mask = 0x80;
			maskPtr++;
		}
	}

	UGL_BITMAP_ID cursorBitmap = uglBitmapCreate(gc,
		width, height, width, bitmapData, width, maskData);

	delete []bitmapData;
	delete []maskData;

	if (cursorImage[imageType].cursorID)
	{
		UGL_BITMAP_ID oldBitmap;
		uglCursorImageGet(gc, cursorImage[imageType].cursorID,
			&oldBitmap, 0, 0);

		uglCursorMove(gc, cursorImage[imageType].cursorID,
			column, line);
		uglCursorImageSet(gc, cursorImage[imageType].cursorID,
			cursorBitmap, 0, 0);

		uglBitmapDestroy(gc, oldBitmap);
	}
	else
		cursorImage[imageType].cursorID = uglCursorCreate(gc, cursorBitmap,
			0, 0, column, line);

	ZafRegionStruct cursorRegion;
	cursorRegion.coordinateType = ZAF_PIXEL;
	cursorRegion.left = column;
	cursorRegion.top = line;
	cursorRegion.right = cursorRegion.left +
		cursorImage[imageType].cursorID->width - 1;
	cursorRegion.bottom = cursorRegion.top +
		cursorImage[imageType].cursorID->height - 1;

	if (imageType != ZAF_IMT_CURSOR_IMAGE || cursorRegion.Encompassed(clip))
		uglCursorOn(gc, cursorImage[imageType].cursorID);

	stopDevice--;

	return (true);
}

#endif // ZAF_GRAPHICS_MODE
