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

#include <time.h>
#include <z_ctype.hpp>
#include <z_error.hpp>
#include <z_help.hpp>
#define USE_RAW_KEYS
#include <z_keymap.hpp>
#include <z_mouse2.hpp>	// For DM_VIEW.
#include <z_stdlib.hpp>
#include <z_string.hpp>
#include <z_utils.hpp>
#include <z_win.hpp>

static void ZafRubberBandRegion(ZafWindowObject *object,
	ZafRegionStruct *region1, ZafRegionStruct *region2);

// ----- ZafWindowObject ---------------------------------------------------

ZafRegionStruct ZafWindowObject::BeginDraw(void)
{
	// Start with screen region and pare it down.
	ZafRegionStruct clip, viewPort;
	clip.left = clip.top = 0;
	clip.right = display->columns - 1;
	clip.bottom = display->lines - 1;
#if defined(ZAF_GRAPHICS_MODE)
	clip.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
	clip.coordinateType = ZAF_CELL;
#endif

	// Start with the object's region, based at (0, 0), and translate it
	// based on its parents' regions.
	viewPort.left = viewPort.top = 0;
	viewPort.right = zafRegion.Width() - 1;
	viewPort.bottom = zafRegion.Height() - 1;
	viewPort.coordinateType = zafRegion.coordinateType;

	// Get the clip and virtual regions.
	GetClip(this, clip, viewPort);

	// Initialize the display class for drawing.
	ZafError dispError = display->BeginDraw(0, screenID, viewPort, clip);
	if (dispError != ZAF_ERROR_NONE)
	{
		display->EndDraw();
		ZafRegionList drawList;
		ZafRegionStruct tRegion = zafRegion;
		tRegion.VtShift(-tRegion.top);
		tRegion.HzShift(-tRegion.left);
		drawList.Allocate(screenID, tRegion);
		windowManager->GetDrawRegionList(this, drawList);
		
		ZafRegionStruct osRegion;
		if (parent)
		{
			if (regionType == ZAF_OUTSIDE_REGION)
			{
				osRegion = parent->zafRegion;
				osRegion.VtShift(-osRegion.top);
				osRegion.HzShift(-osRegion.left);
				osRegion = parent->ConvertToOSRegion(parent, &osRegion);
			}
			else
				osRegion = parent->ConvertToOSRegion(this, 0);
		}
		else
			osRegion = zafRegion;

		ZafRegionElement *damageElement;
		for (damageElement = drawList.First(); damageElement;
			damageElement = damageElement->Next())
		{
			damageElement->region.VtShift(osRegion.top);
			damageElement->region.HzShift(osRegion.left);
		}
		if (!drawList.First())
		{
			tRegion.Assign(-1000, -1000, 0, 0, zafRegion.coordinateType);
			drawList.Allocate(screenID, tRegion);
		}


		display->SetDrawRegions(&drawList);
		display->BeginDraw(0, screenID, viewPort, clip);
	}

	// Shift the region to be (0, 0)-based.
	return (ConvertToDrawRegion(this, &viewPort));
}

ZafRegionStruct ZafWindowObject::ConvertToDrawRegion(const ZafWindowObject *object, const ZafRegionStruct *tZafRegion) const
{
	// Start with the native zaf region.
	ZafRegionStruct convert = tZafRegion ? *tZafRegion : object->zafRegion;
	if (object == this)
	{
		// Shift the region to be (0, 0)-based for drawing.
		convert.right -= convert.left;
		convert.bottom -= convert.top;
		convert.left = convert.top = 0;
	}

	// Return the result.
	return (convert);
}

ZafPositionStruct ZafWindowObject::ConvertToObjectPosition(const ZafPositionStruct screenPosition) const
{
	ZafPositionStruct zafPosition = screenPosition;
	if (parent && windowManager->Index(this) == -1)
		zafPosition = parent->ConvertToZafPosition(this, &zafPosition);
	else
		zafPosition = windowManager->ConvertToZafPosition(this, &zafPosition);

	zafPosition.line -= zafRegion.top;
	zafPosition.column -= zafRegion.left;

	return (zafPosition);
}

ZafPositionStruct ZafWindowObject::ConvertToOSPosition(const ZafWindowObject *,
	const ZafPositionStruct *zafPosition) const
{
	ZafPositionStruct osPosition;

	if (zafPosition)
	{
		osPosition.column = zafPosition->column + zafRegion.left;
		osPosition.line = zafPosition->line + zafRegion.top;
		osPosition.coordinateType = zafPosition->coordinateType;
	}
	else
	{
		osPosition.column = osPosition.line = 0;
#if defined(ZAF_GRAPHICS_MODE)
		osPosition.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
		osPosition.coordinateType = ZAF_CELL;
#endif
	}

	if (parent)
		osPosition = parent->ConvertToOSPosition(this, &osPosition);

	return (osPosition);
}

ZafPositionStruct ZafWindowObject::ConvertToScreenPosition(const ZafPositionStruct objectPosition) const
{
	ZafPositionStruct osPosition;
/* START BLOCK COMMENT
**		if (parent)
**			osPosition = parent->ConvertToOSPosition(this, &objectPosition);
**		else
**			osPosition = windowManager->ConvertToOSPosition(this, &objectPosition);
END BLOCK COMMENT */
		osPosition = ConvertToOSPosition(0, &objectPosition);

	return (osPosition);
}

bool ZafWindowObject::ConvertToZafEvent(ZafEventStruct &event)
{
	event.converted = this;
	if (event.osEvent.type == E_MOUSE)
	{
		event.position.line = event.osEvent.position.line;
		event.position.column = event.osEvent.position.column;
		event.position = ConvertToObjectPosition(event.position);
	}

	return (event.converted ? true : false);
}

ZafPositionStruct ZafWindowObject::ConvertToZafPosition(const ZafWindowObject *,
	const ZafPositionStruct *osPosition) const
{
	ZafPositionStruct zafPosition;

	if (osPosition)
	{
		zafPosition.column = osPosition->column - zafRegion.left;
		zafPosition.line = osPosition->line - zafRegion.top;
		zafPosition.coordinateType = osPosition->coordinateType;
	}
	else
	{
		zafPosition.column = zafPosition.line = 0;
#if defined(ZAF_GRAPHICS_MODE)
		zafPosition.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
		zafPosition.coordinateType = ZAF_CELL;
#endif
	}

	if (parent)
		zafPosition = parent->ConvertToZafPosition(this, &zafPosition);

	return (zafPosition);
}

ZafEventType ZafWindowObject::DispatchMouseEvent(const ZafEventStruct &event)
{
	if (modifyMode)
		return (Modify(event));

	if (windowManager->MouseEventRoute() == this)
		return (Event(event));

	// LogicalEvent() must be called first to map the logical events (L_*) and
	// to convert the event to the context of this object.
	ZafEventType ccode = LogicalEvent(event);

	// An object being clicked on receives focus before processing
	// the selection event.
	if (ccode == L_BEGIN_SELECT)// && !Disabled() && !Noncurrent())
	{
		ZafWindowObject *root = RootObject();
		if (root != this && !root->Focus())
			root->SetFocus(true);
		SetFocus(true);
	}

	// Modify() is called from ZafWindowObject::Event().
	if (editMode && (ccode == L_BEGIN_SELECT || ccode == L_END_SELECT))
		return (ZafWindowObject::Event(event));

	if (ccode == L_VIEW && this != windowManager->mouseObject)
	{
		// Generate the N_MOUSE_ENTER and N_MOUSE_LEAVE messages.
		if (windowManager->mouseObject)
			windowManager->mouseObject->Event(N_MOUSE_LEAVE);
		if (Disabled())
			windowManager->mouseObject = ZAF_NULLP(ZafWindowObject);
		else
		{
			// Set the mouse object.
			windowManager->mouseObject = this;

			// Create a mouse enter event that contains event.position.
			ZafEventStruct enterEvent = event;
			enterEvent.type = N_MOUSE_ENTER;
			Event(enterEvent);
		}
	}

	// Dispatch all mouse events to the leaf-most object.
	if (Disabled())
		ccode = S_UNKNOWN;
	else
		ccode = Event(event);

	return (ccode);
}

ZafWindowObject *ZafWindowObject::FindMouseObject(const ZafEventStruct &)
{
	// If the object is disabled return a null pointer.
	if (Disabled() || !SystemObject())
		return (ZAF_NULLP(ZafWindowObject));
	return (this);
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafWindowObject::Draw(const ZafEventStruct &,
	ZafEventType ccode)
{
	return (ccode);
}

ZafEventType ZafWindowObject::DrawBackground(ZafRegionStruct &region, ZafEventType ccode)
{
//	if (ccode == S_REDISPLAY || ccode == S_REDISPLAY_REGION)
	{
		// Fill the background.
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, PaletteState()));
		display->Rectangle(region, 0, true);
	}

	return (ccode);
}

ZafEventType ZafWindowObject::DrawBorder(ZafRegionStruct &region,
	ZafEventType ccode)
{
	if (parent && parentDrawBorder)
		return (parent->DrawBorder(region, ccode));

	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct whiteShadow = lightShadow;
	ZafPaletteStruct blackShadow = darkShadow;

	// Copy the background colors to the foreground since display->Line() uses
	// the foreground color. The "shadow" palettes have different colors in
	// the foreground and background entries so they can generate two shades
	// of shadow.
	whiteShadow.colorForeground = whiteShadow.colorBackground;
	blackShadow.colorForeground = blackShadow.colorBackground;

	display->SetPalette(darkShadow);
	display->Line(region.left, region.top,	region.right - 1, region.top, 1);
	display->Line(region.left, region.top + 1, region.left, region.bottom - 1, 1);

	display->SetPalette(blackShadow);
	display->Line(region.left + 1, region.top + 1, region.right - 1, region.top + 1, 1);
	display->Line(region.left + 1, region.top + 1, region.left + 1, region.bottom - 1, 1);

	display->SetPalette(whiteShadow);
	display->Line(region.right, region.top, region.right, region.bottom, 1);
	display->Line(region.left, region.bottom, region.right, region.bottom, 1);

	display->SetPalette(lightShadow);
	display->Line(region.right - 1, region.top + 1, region.right - 1, region.bottom - 1, 1);
	display->Line(region.left + 1, region.bottom - 1, region.right - 1, region.bottom - 1, 1);

	region -= ZAF_BORDER_SIZE;
	return (ccode);
}

ZafEventType ZafWindowObject::DrawFocus(ZafRegionStruct &,
	ZafEventType ccode)
{
	if (!SystemObject())
	{
		ZafRegionStruct focusRegion = ConvertToDrawRegion(this, &zafRegion);
		return (parent->DrawFocus(focusRegion, ccode));
	}

	return (ccode);
}

ZafEventType ZafWindowObject::DrawShadow(ZafRegionStruct &region,
	int depth, ZafEventType ccode)
{
	// Make sure there is depth to the object
	if (!depth)
		return (ccode);

	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);
	ZafPaletteStruct whiteShadow = lightShadow;
	ZafPaletteStruct blackShadow = darkShadow;

	// Copy the background colors to the foreground since display->Line() uses
	// the foreground color. The "shadow" palettes have different colors in
	// the foreground and background entries so they can generate two shades
	// of shadow.
	whiteShadow.colorForeground = whiteShadow.colorBackground;
	blackShadow.colorForeground = blackShadow.colorBackground;

	// Draw the shadow.
	int absoluteDepth = ZafAbs(depth);
	int halfDepth = absoluteDepth / 2;
	for (int i = 0; i < absoluteDepth; i++)
	{
		if (depth > 0)
			display->SetPalette(i > halfDepth ? lightShadow : whiteShadow);
		else
			display->SetPalette(i > halfDepth ? blackShadow : darkShadow);
		display->Line(region.left, region.top,	region.right - 1, region.top, 1);
		display->Line(region.left, region.top + 1, region.left, region.bottom - 1, 1);

		if (depth > 0)
			display->SetPalette(i > halfDepth ? blackShadow : darkShadow);
		else
			display->SetPalette(i > halfDepth ? lightShadow : whiteShadow);
		display->Line(region.right, region.top, region.right, region.bottom, 1);
		display->Line(region.left, region.bottom, region.right, region.bottom, 1);

		--region;
	}

	return (ccode);
}
#endif

ZafEventType ZafWindowObject::DragDropEvent(const ZafEventStruct &event)
{
	ZafEventType ccode = event.type;

	switch (ccode)
	{
	case S_DRAG_DEFAULT:
		ccode = S_DRAG_MOVE;
		// Fall through to S_DRAG_MOVE.
	case S_DRAG_MOVE:
	case S_DRAG_COPY:
		if (!AcceptDrop() && windowManager->dragObject != this)
		{
			eventManager->SetDeviceImage(E_MOUSE, DM_CANCEL);
			ccode = S_ERROR;
		}
		else
			eventManager->SetDeviceImage(E_MOUSE, ccode == S_DRAG_MOVE ?
				DM_DRAG_MOVE : DM_DRAG_COPY);
		break;

	case S_DROP_DEFAULT:
		ccode = S_DROP_MOVE;
		// Fall through to S_DROP_MOVE.
	case S_DROP_MOVE:
	case S_DROP_COPY:
		if (Disabled() || !AcceptDrop() || windowManager->dragObject == this)
			return (S_ERROR);
		else
		{
			const ZafIChar *text = ZAF_NULLP(ZafIChar);
			ZafWindowObject *dragObject = windowManager->dragObject;

			text = dragObject->Text();
			if (text)
				SetText(text);
			if (ccode == S_DROP_MOVE)
				dragObject->SetText(ZafLanguageManager::blankString);
		}
		break;

	case S_BEGIN_DRAG:
		windowManager->CaptureMouse(this);
		windowManager->dragObject = this;
		break;

	case S_END_DRAG:
		windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
		windowManager->dragObject = ZAF_NULLP(ZafWindowObject);
		eventManager->SetDeviceImage(E_MOUSE, DM_VIEW);
		break;

	default:
		ccode = S_ERROR;
		break;
	}

	return (ccode);
}

void ZafWindowObject::EndDraw(void)
{
	display->EndDraw();
}

ZafEventType ZafWindowObject::Event(const ZafEventStruct &event)
{
	static ZafWindowObject *lastSelected = ZAF_NULLP(ZafWindowObject);

	ZafEventType ccode = LogicalEvent(event);

	if (ccode != L_BEGIN_SELECT && modifyMode)
		Modify(event);
//		return (Modify(event));

	ZafEventStruct tmpEvent;

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		{
		// Convert "zafRegion" to OS (pixel) coordinates.
		modifyMode = 0;
#if defined(ZAF_GRAPHICS_MODE)
		ConvertCoordinates(ZAF_PIXEL);//(parent && RegionType() != ZAF_AVAILABLE_REGION) ? false : true);
#elif defined(ZAF_TEXT_MODE)
		ConvertCoordinates(ZAF_CELL);
#endif
		oldRegion.left = oldRegion.top = oldRegion.right = oldRegion.bottom = -10000;
		oldRegion.coordinateType = zafRegion.coordinateType;

		ZafWindowObject *rootObject = this;
		while (rootObject->parent)
			rootObject = rootObject->parent;

		// Initialize numberID and screenID.
		if (!numberID)
		{
			if (parent)
			{
				numberID = rootObject->NumberID();
				rootObject->SetNumberID((ZafNumberID)(numberID + 1));
			}
			else
			{
				numberID = windowManager->NumberID();
				windowManager->SetNumberID((ZafNumberID)(numberID + 1));
			}
		}
		// Make sure the root object always has the largest numberID.
		else if (parent && numberID >= rootObject->NumberID())
			rootObject->SetNumberID((ZafNumberID)(numberID + 1));
		// Set the stringID.
		if (!stringID)
		{
			ZafIChar newStringID[ZAF_MAXNAMELEN];
			strcpy(newStringID, parent ? genericFieldID : ClassName());
			itoa(numberID, &newStringID[strlen(newStringID)], 10, 0);
			SetStringID(newStringID);
		}
		}
		break;

	case S_DEINITIALIZE:
		screenID = 0;
		focus = false;

		if (windowManager->mouseObject == this)
			windowManager->mouseObject = 0;
		if (windowManager->MouseEventRoute() == this)
			windowManager->CaptureMouse(0);
		if (windowManager->cursorObject == this)
			windowManager->cursorObject = 0;

		if (windowManager->dragObject == this)
			windowManager->dragObject = 0;
		if (windowManager->helpObject == this)
			windowManager->helpObject = 0;
		if (windowManager->focusObject == this)
			windowManager->focusObject = 0;
		if (windowManager->oldFocusObject == this)
			windowManager->oldFocusObject = 0;
		windowManager->OSValidateObject(this);
		break;

	case S_REGISTER_OBJECT:
		OSRegisterObject();
		break;

	case S_CREATE:
		{
		// Don't allow the object to be displayed until the creation
		// process is finished.
		bool saveVisible = visible;
		SetVisible(false);

		// Initialize member variables.
		Event(S_INITIALIZE);

		// Create the object with the OS.
		Event(S_REGISTER_OBJECT);

		// Allow the object to update its size/position (zafRegion).
		Event(S_COMPUTE_SIZE);

		// Size the object with the OS.
		OSSize();

		// Display the object on the screen (if visible).
		SetVisible(saveVisible);
		}
		break;

	// ----- Activation messages -----
	case S_CURRENT:
		focus = true;
		break;

	case S_NON_CURRENT:
		focus = false;
		break;

	case N_CURRENT:
	case N_NON_CURRENT:
		// Call the associated user function.
		ccode = (this->*memberUserFunction)(event, ccode);
		break;

	case S_SIZE_MODE:
	case S_MOVE_MODE:
		{
			tmpEvent = event;
			if (ccode != tmpEvent.type)
			{
				tmpEvent.type = ccode;
				tmpEvent.rawCode = 0;
			}
			Modify(tmpEvent);
		}
		break;

	case S_REDISPLAY_REGION:
	case S_REDISPLAY_DATA:
	case S_REDISPLAY:
		if (AutomaticUpdate() && Visible() && screenID)
		{
			ZafRegionStruct region;
			region.left = region.top = 0;
			region.right = zafRegion.Width() - 1;
			region.bottom = zafRegion.Height() - 1;
			region.coordinateType = zafRegion.coordinateType;

			if (ccode == S_REDISPLAY)
				OSInvalidateRegion(&region, false, false);
			else if (ccode == S_REDISPLAY_DATA)
				OSInvalidateRegion(&region, true, false);
			else if (ccode == S_REDISPLAY_REGION && region.Overlap(event.region))
			{
				region = event.region;
				OSInvalidateRegion(&region, false, true);
			}
		}
		break;

	case S_SET_FOCUS:
		{
		tmpEvent = event;
		tmpEvent.windowObject = this;
		eventManager->Put(tmpEvent);
		}
		break;

	// ----- Actions -----
	case L_VIEW:
		{
			if (!editMode)
				break;

			// Determine the type of modify operation.
			ZafRawCode sizeOperation = 0;
			if (event.position.column < ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_LEFT;
			else if (event.position.column >= zafRegion.Width() - ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_RIGHT;
			if (event.position.line < ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_TOP;
			else if (event.position.line >= zafRegion.Height() - ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_BOTTOM;

			// Set the mouse cursor image.
			if (sizeOperation & ZAF_SIZE_LEFT && sizeOperation & ZAF_SIZE_TOP)
				eventManager->SetDeviceImage(E_MOUSE, DM_TOP_LEFT_CORNER);
			else if (sizeOperation & ZAF_SIZE_RIGHT && sizeOperation & ZAF_SIZE_BOTTOM)
				eventManager->SetDeviceImage(E_MOUSE, DM_BOTTOM_RIGHT_CORNER);
			else if (sizeOperation & ZAF_SIZE_RIGHT && sizeOperation & ZAF_SIZE_TOP)
				eventManager->SetDeviceImage(E_MOUSE, DM_TOP_RIGHT_CORNER);
			else if (sizeOperation & ZAF_SIZE_LEFT && sizeOperation & ZAF_SIZE_BOTTOM)
				eventManager->SetDeviceImage(E_MOUSE, DM_BOTTOM_LEFT_CORNER);
			else if (sizeOperation & ZAF_SIZE_LEFT)
				eventManager->SetDeviceImage(E_MOUSE, DM_LEFT_SIDE);
			else if (sizeOperation & ZAF_SIZE_RIGHT)
				eventManager->SetDeviceImage(E_MOUSE, DM_RIGHT_SIDE);
			else if (sizeOperation & ZAF_SIZE_TOP)
				eventManager->SetDeviceImage(E_MOUSE, DM_TOP_SIDE);
			else if (sizeOperation & ZAF_SIZE_BOTTOM)
				eventManager->SetDeviceImage(E_MOUSE, DM_BOTTOM_SIDE);
			else
				eventManager->SetDeviceImage(E_MOUSE, DM_MOVE);
		}
		break;

	case L_DOUBLE_CLICK:
		ccode = (this->*memberUserFunction)(event, L_DOUBLE_CLICK);
		break;

	case L_BEGIN_SELECT:
		lastSelected = this;
		if (editMode)
		{
			// Modify (move / size) the object.
			Modify(event);

			tmpEvent = event;

			// Notify of active object.
			tmpEvent.type = D_SET_OBJECT;
			tmpEvent.rawCode = ClassID();
			tmpEvent.windowObject = this;
			Event(tmpEvent);

			// Notify of current position.
			tmpEvent.type = D_SET_POSITION;
			tmpEvent.rawCode = event.rawCode;
			tmpEvent.position = event.position;
			Event(tmpEvent);
		}
		else if (Draggable())
		{
			modifyRegion.left = event.position.column;
			modifyRegion.top = event.position.line;
		}
		break;

	case L_CONTINUE_SELECT:
//	case L_CONTINUE_COPY_DRAG:
//	case L_CONTINUE_LINK_DRAG:
		if (windowManager->dragObject)
		{
			if (acceptDrop || windowManager->dragObject == this)
			{
				tmpEvent = event;
				tmpEvent.type = S_DRAG_DEFAULT;

				// dragObject may not be draggable if it is in a combo box or tree.
				// Need to check its parent in these cases.
				ZafWindowObject *dragObject = windowManager->dragObject->Draggable() ?
					windowManager->dragObject : windowManager->dragObject->parent;
				if (ccode == L_CONTINUE_SELECT && dragObject->MoveDraggable())
					tmpEvent.type = S_DRAG_MOVE;
/* START BLOCK COMMENT
**					else if (ccode == L_CONTINUE_COPY_DRAG && dragObject->CopyDraggable())
**						tmpEvent.type = S_DRAG_COPY;
**					else if (ccode == L_CONTINUE_LINK_DRAG && dragObject->LinkDraggable())
**						tmpEvent.type = S_DRAG_LINK;
END BLOCK COMMENT */
				else if (dragObject->MoveDraggable())
					tmpEvent.type = S_DRAG_MOVE;
				else if (dragObject->CopyDraggable())
					tmpEvent.type = S_DRAG_COPY;
				else if (dragObject->LinkDraggable())
					tmpEvent.type = S_DRAG_LINK;

//				ccode = DragDropEvent(tmpEvent);
				ccode = windowManager->DispatchMouseEvent(tmpEvent);
				if (ccode == S_ERROR)
					eventManager->SetDeviceImage(E_MOUSE, DM_CANCEL);
			}
			else
			{
				eventManager->SetDeviceImage(E_MOUSE, DM_CANCEL);
				ccode = S_ERROR;
			}
		}
		else if (Draggable() && (ZafAbs(modifyRegion.left - event.position.column) >= 4 ||
			ZafAbs(modifyRegion.top - event.position.line) >= 4) && lastSelected == this)
			Event(S_BEGIN_DRAG);
		break;

	case L_END_SELECT:
		{
			ZafPositionStruct mousePosition = event.position;
			mousePosition.line += zafRegion.top;
			mousePosition.column += zafRegion.left;
			if (lastSelected != this && !windowManager->dragObject)
				break;


			if (windowManager->dragObject)
			{
//				if (acceptDrop && windowManager->dragObject != this)
				{
					tmpEvent = event;
					tmpEvent.type = S_DROP_DEFAULT;

					// dragObject may not be draggable if it is in a combo box or
					// tree.  Need to check its parent in these cases.
					ZafWindowObject *dragObject = windowManager->dragObject->Draggable() ?
						windowManager->dragObject : windowManager->dragObject->parent;

					if ((event.modifiers | (S_CTRL | S_SHIFT)) == event.modifiers
						&&	dragObject->LinkDraggable())
						tmpEvent.type = S_DROP_LINK;
					else if (event.modifiers & S_CTRL &&
						dragObject->CopyDraggable())
						tmpEvent.type = S_DROP_COPY;
					else if (event.modifiers & S_SHIFT &&
						dragObject->MoveDraggable())
						tmpEvent.type = S_DROP_MOVE;

					if (tmpEvent.type == S_DROP_DEFAULT)
					{
						if (dragObject->MoveDraggable())
							tmpEvent.type = S_DROP_MOVE;
						else if (dragObject->CopyDraggable())
							tmpEvent.type = S_DROP_COPY;
						else if (dragObject->LinkDraggable())
							tmpEvent.type = S_DROP_LINK;
					}

					ccode = windowManager->DispatchMouseEvent(tmpEvent);
					Event(S_END_DRAG);
				}
				lastSelected = ZAF_NULLP(ZafWindowObject);
				break;
			}
			lastSelected = this;
		}
		break;

	case N_MOUSE_ENTER:
		// If help tip, update the help tips device.
		if ((QuickTip() || HelpObjectTip()))
			eventManager->Event(event, E_HELPTIPS);
		eventManager->SetDeviceState(E_MOUSE, DM_VIEW);
		break;

	case N_MOUSE_LEAVE:
		// If help tip, update the help tips device.
		if ((QuickTip() || HelpObjectTip()))
			eventManager->Event(event, E_HELPTIPS);
		break;

	// ----- Scroll messages -----
	case N_VSCROLL:
	case N_HSCROLL:
	case S_VSCROLL:
	case S_HSCROLL:
	case S_VSCROLL_SET:
	case S_HSCROLL_SET:
	case S_VSCROLL_CHECK:
	case S_HSCROLL_CHECK:
	case S_VSCROLL_COMPUTE:
	case S_HSCROLL_COMPUTE:
		ccode = ScrollEvent(event);
		break;

	// ----- Position & size messages -----
	case S_SIZE:
		SetRegion(event.region);
		ConvertCoordinates(ZAF_PIXEL);
/* START BLOCK COMMENT
**			SetConvertedCoordinate(false);
**			ConvertRegion((parent && RegionType() != ZAF_AVAILABLE_REGION) ? false : true);
END BLOCK COMMENT */
		Event(S_COMPUTE_SIZE);
		OSSize();
		break;

	case N_MOVE:
	case N_SIZE:
		ccode = 0;
		break;

	case S_COMPUTE_SIZE:
		if (RegionType() != ZAF_INSIDE_REGION)
  			SetRegion(parent ? parent->MaxRegion(this) : windowManager->MaxRegion(this));
		break;

	// ----- Drag & Drop -----
	case S_DRAG_MOVE:
	case S_DRAG_COPY:
	case S_DRAG_LINK:
	case S_DROP_MOVE:
	case S_DROP_COPY:
	case S_DROP_LINK:
	case S_DRAG_DEFAULT:
	case S_DROP_DEFAULT:
	case S_BEGIN_DRAG:
	case S_END_DRAG:
		ccode = DragDropEvent(event);
		break;

	case S_DESTROY:
		// Remove focus before destruction to allow data to be saved.
		if (focus)
		{
			windowManager->focusObject = ZAF_NULLP(ZafWindowObject);
			NotifyFocus(ZAF_NULLP(ZafWindowObject), false);
		}

		// Deinitialize the object.
		Event(ZafEventStruct(S_DEINITIALIZE));
		break;

	// ----- Miscellaneous -----
	case S_HELP:
	case L_HELP:
		if (helpContext && zafHelpSystem)
			zafHelpSystem->DisplayHelp(helpContext);
		else
		{
			// Allow the parent to display a help context if it has one.
			ccode = S_UNKNOWN;
		}
		break;

	case E_MOUSE:
		if (!Draggable())
			break;

		// Begin select
		if (event.rawCode == (M_LEFT | M_LEFT_CHANGE))
		{
			lastSelected = this;
			modifyRegion.left = event.position.column;
			modifyRegion.top = event.position.line;
		}
		// End and Continue select
		else if (windowManager->dragObject == this)
		{
			// Determine the requested operation.
			tmpEvent = event;
			bool copy = false, link = false, move = false;
			if ((event.modifiers | (S_CTRL | S_SHIFT)) == event.modifiers)
				link = true;
			else if (event.modifiers & S_CTRL)
				copy = true;
			else if (event.modifiers & S_SHIFT)
				move = true;

			if (link && windowManager->dragObject->LinkDraggable())
				tmpEvent.type = (event.rawCode == M_LEFT) ? S_DRAG_LINK : S_DROP_LINK;
			else if (copy && windowManager->dragObject->CopyDraggable())
				tmpEvent.type = (event.rawCode == M_LEFT) ? S_DRAG_COPY : S_DROP_COPY;
			else if (move && windowManager->dragObject->MoveDraggable())
				tmpEvent.type = (event.rawCode == M_LEFT) ? S_DRAG_MOVE : S_DROP_MOVE;
			else
				tmpEvent.type = (event.rawCode == M_LEFT) ? S_DRAG_DEFAULT : S_DROP_DEFAULT;

			if (windowManager->DispatchMouseEvent(tmpEvent) == S_ERROR)
				eventManager->SetDeviceImage(E_MOUSE, DM_CANCEL);

			if (event.rawCode == M_LEFT_CHANGE)
				Event(S_END_DRAG);
		}
		else if (windowManager->dragObject) // Shouldn't get here!
			DragDropEvent(event);
		else if (lastSelected == this && (ZafAbs(modifyRegion.left - event.position.column) >= 4 ||
			ZafAbs(modifyRegion.top - event.position.line) >= 4) && event.rawCode == M_LEFT)
			Event(S_BEGIN_DRAG);
		break;

	// ----- Unknown or error messages -----
	default:
		ccode = S_UNKNOWN;
	}

	// Return the control code.
	return (ccode);
}

void ZafWindowObject::GetClip(ZafWindowObject *, ZafRegionStruct &clip,
	ZafRegionStruct &viewPort)
{
	// Let the parent adjust the regions first.
	if (parent)
		parent->GetClip(this, clip, viewPort);

	// Adjust the viewPort region.
	viewPort.left += zafRegion.left;
	viewPort.top += zafRegion.top;
	viewPort.right += zafRegion.left;
	viewPort.bottom += zafRegion.top;

	// Adjust the clip region.
	if (viewPort.left > clip.left)
		clip.left = viewPort.left;
	if (viewPort.top > clip.top)
		clip.top = viewPort.top;
	clip.right = ZafMin(clip.right, clip.left + zafRegion.Width() - 1);
	clip.bottom = ZafMin(clip.bottom, clip.top + zafRegion.Height() - 1);
}

void ZafWindowObject::OSGetExposedRegionList(ZafRegionList &regionList)
{
	for (ZafWindowObject *obj2 = Next(); obj2; obj2 = obj2->Next())
		if (zafRegion.Overlap(obj2->zafRegion))
			regionList.Split(0, obj2->zafRegion);
}

ZafRegionStruct ZafWindowObject::MaxRegion(ZafWindowObject *, ZafVtJustify, ZafHzJustify)
{
	// Default is the object's region.
	ZafRegionStruct region;
	region.left = region.top = 0;
	region.right = zafRegion.right - zafRegion.left;
	region.bottom = zafRegion.bottom - zafRegion.top;
	region.coordinateType = zafRegion.coordinateType;

	return (region);
}

ZafEventType ZafWindowObject::Modify(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);
	static ZafRawCode sizeOperation = 0;

	// Save the original mouse coordinates.
	static ZafPositionStruct originalPosition;

	switch (ccode)
	{
		case L_DOWN:
		case L_LEFT:
		case L_RIGHT:
		case L_UP:
			{
				if (modifyMode == S_SIZE_MODE)
				{
					switch (ccode)
					{
						case L_DOWN:
							lastRegion.bottom += Display()->cellHeight;
							break;

						case L_UP:
							lastRegion.bottom -= Display()->cellHeight;
							break;

						case L_LEFT:
							lastRegion.right -= Display()->cellWidth;
							break;

						case L_RIGHT:
							lastRegion.right += Display()->cellWidth;
							break;
					}
				}
				else
				{
					switch (ccode)
					{
						case L_DOWN:
							lastRegion.VtShift(Display()->cellHeight);
							break;

						case L_UP:
							lastRegion.VtShift(-Display()->cellHeight);
							break;

						case L_LEFT:
							lastRegion.HzShift(-Display()->cellWidth);
							break;

						case L_RIGHT:
							lastRegion.HzShift(Display()->cellWidth);
							break;
					}
				}

				// Make sure the window can't be sized too small.
				int minWindowWidth = 20 * display->cellWidth;
				int minWindowHeight = 4 * display->cellHeight;
				int minObjectWidth = display->cellWidth;
				int minObjectHeight = display->cellHeight;
				if (modifyMode == S_SIZE_MODE)
				{
					if ((!parent || IsA(ID_ZAF_MDI_WINDOW)) && lastRegion.Width() < minWindowWidth)
					{
						if (SizeLeft(sizeOperation))
							lastRegion.left = lastRegion.right - minWindowWidth + 1;
						else if (SizeRight(sizeOperation))
							lastRegion.right = lastRegion.left + minWindowWidth - 1;
					}
					else if (parent && lastRegion.Width() < minObjectWidth)
					{
						if (SizeLeft(sizeOperation))
							lastRegion.left = lastRegion.right - minObjectWidth + 1;
						else if (SizeRight(sizeOperation))
							lastRegion.right = lastRegion.left + minObjectWidth - 1;
					}

					if ((!parent || IsA(ID_ZAF_MDI_WINDOW)) && lastRegion.Height() < minWindowHeight)
					{
						if (SizeTop(sizeOperation))
							lastRegion.top = lastRegion.bottom - minWindowHeight + 1;
						else if (SizeBottom(sizeOperation))
							lastRegion.bottom = lastRegion.top + minWindowHeight - 1;
					}
					else if (parent && lastRegion.Height() < minObjectHeight)
					{
						if (SizeTop(sizeOperation))
							lastRegion.top = lastRegion.bottom - minObjectHeight + 1;
						else if (SizeBottom(sizeOperation))
							lastRegion.bottom = lastRegion.top + minObjectHeight - 1;
					}
				}

				zafRegion = modifyRegion = lastRegion;
				OSSize();
				windowManager->RepairDamage();
				ZafRubberBandRegion(this, 0, &modifyRegion);
			}
			break;

		case S_SIZE_MODE:
			{
				// Make sure all damage has been repaired so that the
				// rubber-band outline appears correctly.
				windowManager->RepairDamage();

				// Draw the initial xor rectangle.
				lastRegion = modifyRegion = zafRegion;

				originalPosition.line = event.osEvent.position.line;
				originalPosition.column = event.osEvent.position.column;
				originalPosition.coordinateType = event.position.coordinateType;

				ZafRubberBandRegion(this, 0, &modifyRegion);
				modifyMode = S_SIZE_MODE;
				if (!sizeOperation)
					sizeOperation = event.rawCode;
				if (!sizeOperation)
					sizeOperation = ZAF_SIZE_RIGHT | ZAF_SIZE_BOTTOM;
			}
			break;

		case S_MOVE_MODE:
			{
				// Make sure all damage has been repaired so that the
				// rubber-band outline appears correctly.
				windowManager->RepairDamage();

				lastRegion = modifyRegion = zafRegion;
#if 1

				originalPosition.line = event.osEvent.position.line;
				originalPosition.column = event.osEvent.position.column;
				originalPosition.coordinateType = event.position.coordinateType;

				eventManager->SetDeviceState(E_CURSOR, D_OFF);
				ZafRubberBandRegion(this, 0, &modifyRegion);

#else
				originalPosition.line = event.osEvent.position.line;
				originalPosition.column = event.osEvent.position.column;
				originalPosition.coordinateType = event.position.coordinateType;
#endif
				sizeOperation = ZAF_SIZE_LEFT | ZAF_SIZE_RIGHT | ZAF_SIZE_TOP | ZAF_SIZE_BOTTOM;
				modifyMode = S_MOVE_MODE;
			}
			break;

		case L_BEGIN_SELECT:
			if (modifyMode)
			{
				modifyMode = 0;
				ZafRubberBandRegion(this, &lastRegion, 0);
				windowManager->CaptureMouse(0);
				break;
			}
			windowManager->CaptureMouse(this);

			// Position coordinates are converted to 0,0 based.
			originalPosition.line = event.osEvent.position.line;
			originalPosition.column = event.osEvent.position.column;
			originalPosition.coordinateType = event.position.coordinateType;

			lastRegion = modifyRegion = zafRegion;
			sizeOperation = 0;

			// Determine the type of modify operation.
			if (event.position.column <= ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_LEFT;
			else if (event.position.column >= zafRegion.Width() - ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_RIGHT;
			if (event.position.line <= ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_TOP;
			else if (event.position.line >= zafRegion.Height() - ZAF_EDIT_MARGIN_SIZE)
				sizeOperation |= ZAF_SIZE_BOTTOM;

			// Setting all flags acts as a move operation.
			if (!sizeOperation)
			{
				sizeOperation = ZAF_SIZE_LEFT | ZAF_SIZE_RIGHT | ZAF_SIZE_TOP | ZAF_SIZE_BOTTOM;
				modifyMode = S_MOVE_MODE;
				eventManager->SetDeviceState(E_CURSOR, D_HIDE);
			}
			else
			{
				modifyMode = S_SIZE_MODE;
				ZafRubberBandRegion(this, 0, &modifyRegion);
			}
			break;

		case L_CONTINUE_SELECT:
			{
				ZafPositionStruct deltaPosition;
				deltaPosition.line  = event.osEvent.position.line;
				deltaPosition.column  = event.osEvent.position.column;
				deltaPosition.coordinateType = event.position.coordinateType;
				// Constrain the mouse.
				ZafRegionStruct clipRegion;
#if defined(ZAF_GRAPHICS_MODE)
				clipRegion.Assign(0, 0, display->columns, display->lines);
				clipRegion.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
				clipRegion.Assign(0, 0, display->columns - 1, display->lines - 1);
				clipRegion.coordinateType = ZAF_CELL;
#endif
				ZafRegionStruct viewPort = clipRegion;
				if (parent)
				{
					parent->GetClip(this, clipRegion, viewPort);
//					ZafPositionStruct osDeltaPosition = ConvertToOSPosition(this, &deltaPosition);
					ZafPositionStruct osDeltaPosition = deltaPosition;
					if (osDeltaPosition.line < clipRegion.top)
					{
						deltaPosition.line += clipRegion.top - osDeltaPosition.line;
						osDeltaPosition.line = clipRegion.top;
					}
					if (osDeltaPosition.line > clipRegion.bottom)
					{
						deltaPosition.line += clipRegion.bottom - osDeltaPosition.line;
						osDeltaPosition.line = clipRegion.bottom;
					}
					if (osDeltaPosition.column < clipRegion.left)
					{
						deltaPosition.column += clipRegion.left - osDeltaPosition.column;
						osDeltaPosition.column = clipRegion.left;
					}
					if (osDeltaPosition.column > clipRegion.right)
					{
						deltaPosition.column += clipRegion.right - osDeltaPosition.column;
						osDeltaPosition.column = clipRegion.right;
					}
					if (!SupportObject())
						eventManager->SetDevicePosition(E_MOUSE, osDeltaPosition.column,
							osDeltaPosition.line);
				}

				deltaPosition.column -= originalPosition.column;
				deltaPosition.line -= originalPosition.line;

				// Snap the position to the proper coordinates.
				if (editMode)
				{
					deltaPosition.ConvertCoordinates(coordinateType);
					deltaPosition.ConvertCoordinates(zafRegion.coordinateType);
				}

				// Compute the new moving/sizeing region.
				if (SizeLeft(sizeOperation))
					modifyRegion.left += deltaPosition.column;
				if (SizeTop(sizeOperation))
					modifyRegion.top += deltaPosition.line;
				if (SizeRight(sizeOperation))
					modifyRegion.right += deltaPosition.column;
				if (SizeBottom(sizeOperation))
					modifyRegion.bottom += deltaPosition.line;

				// Don't let the object be sized too small.
				int minWindowWidth = 20 * display->cellWidth;
				int minWindowHeight = 4 * display->cellHeight;
				int minObjectWidth = display->cellWidth;
				int minObjectHeight = display->cellHeight;
				if (modifyMode == S_SIZE_MODE)
				{
					if ((!parent || IsA(ID_ZAF_MDI_WINDOW)) && modifyRegion.Width() < minWindowWidth)
					{
						if (SizeLeft(sizeOperation))
						{
							modifyRegion.left = modifyRegion.right - minWindowWidth + 1;
							deltaPosition.column = modifyRegion.left - lastRegion.left;
						}
						else if (SizeRight(sizeOperation))
						{
							modifyRegion.right = modifyRegion.left + minWindowWidth - 1;
							deltaPosition.column = modifyRegion.right - lastRegion.right;
						}
					}
					else if (parent && modifyRegion.Width() < minObjectWidth)
					{
						if (SizeLeft(sizeOperation))
						{
							modifyRegion.left = modifyRegion.right - minObjectWidth + 1;
							deltaPosition.column = modifyRegion.left - lastRegion.left;
						}
						else if (SizeRight(sizeOperation))
						{
							modifyRegion.right = modifyRegion.left + minObjectWidth - 1;
							deltaPosition.column = modifyRegion.right - lastRegion.right;
						}
					}

					if ((!parent || IsA(ID_ZAF_MDI_WINDOW)) && modifyRegion.Height() < minWindowHeight)
					{
						if (SizeTop(sizeOperation))
						{
							modifyRegion.top = modifyRegion.bottom - minWindowHeight + 1;
							deltaPosition.line = modifyRegion.top - lastRegion.top;
						}
						else if (SizeBottom(sizeOperation))
						{
							modifyRegion.bottom = modifyRegion.top + minWindowHeight - 1;
							deltaPosition.line = modifyRegion.bottom - lastRegion.bottom;
						}
					}
					else if (parent && modifyRegion.Height() < minObjectHeight)
					{
						if (SizeTop(sizeOperation))
						{
							modifyRegion.top = modifyRegion.bottom - minObjectHeight + 1;
							deltaPosition.line = modifyRegion.top - lastRegion.top;
						}
						else if (SizeBottom(sizeOperation))
						{
							modifyRegion.bottom = modifyRegion.top + minObjectHeight - 1;
							deltaPosition.line = modifyRegion.bottom - lastRegion.bottom;
						}
					}
				}

				// Move the xor rectangle.
				if (modifyRegion != lastRegion)
				{
					originalPosition.column += deltaPosition.column;
					originalPosition.line += deltaPosition.line;
#if 0
					// Calculate OS Positions first.
					if (modifyMode == S_SIZE_MODE)
#endif
					{
						ZafRubberBandRegion(this, &lastRegion, &modifyRegion);
					}
#if 0
					else
					{
						// RegionCopy
						if (parent)
						{
							osLastRegion = lastRegion;
							parent->GetClip(this, clipRegion, osLastRegion);
							osModifyRegion = parent->ConvertToOSRegion(this, &modifyRegion);
						}
						else
						{
							osModifyRegion = modifyRegion;
							osLastRegion = lastRegion;
						}
						ZafRegionStruct copyRegion;
						clipRegion.Overlap(osLastRegion, copyRegion);
						if (osModifyRegion.bottom > clipRegion.bottom && deltaPosition.line > 0)
							copyRegion.bottom -= deltaPosition.line;
						if (osModifyRegion.right > clipRegion.right && deltaPosition.column > 0)
							copyRegion.right -= deltaPosition.column;

						if (clipRegion.Overlap(osModifyRegion))
							display->RegionCopy(copyRegion, osModifyRegion.left, osModifyRegion.top);
						ZafRegionList damageList;
						damageList.Allocate(0, osModifyRegion);
						damageList.Allocate(0, osLastRegion);
						clipRegion.Overlap(osModifyRegion, copyRegion);
						if (osLastRegion.bottom > clipRegion.bottom)
						{
							if (deltaPosition.line > 0)
								copyRegion.bottom -= deltaPosition.line;
							else
								copyRegion.bottom += deltaPosition.line;
						}
						if (osLastRegion.right > clipRegion.right)
						{
							if (deltaPosition.column > 0)
								copyRegion.right -= deltaPosition.column;
							else
								copyRegion.right += deltaPosition.column;
						}

						damageList.Split(0, copyRegion, false);
						zafRegion = modifyRegion;
						for (ZafRegionElement *regionElement = damageList.First();
							regionElement; regionElement = regionElement->Next())
								windowManager->OSInvalidateRegion(&regionElement->region);
						windowManager->RepairDamage();
					}
#endif
					lastRegion = modifyRegion;
				}
			}
			break;

		case L_END_SELECT:
			if (!modifyMode)
				break;
			sizeOperation = 0;
			modifyMode = 0;
			windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
#if 0
			if (modifyMode == S_SIZE_MODE)
#endif
			{
				// Erase the xor rectangle.
				ZafRubberBandRegion(this, &lastRegion, 0);

				// Finalize the position.
				Event(ZafEventStruct(S_SIZE, 0, modifyRegion));
			}
			break;
	}

	// Return success.
	return (ccode);
}

ZafEventType ZafWindowObject::MoveEvent(const ZafEventStruct &)
{
	return (S_CONTINUE);
}

bool ZafWindowObject::RegisterMouse(bool view, bool leftMouse, bool rightMouse)
{
	return(true);
}

void ZafWindowObject::RegisterObject(void)
{
	// This code must be here in case a class (such as ZafTableRecord) defines
	// an OSRegisterObject() method that does not call
	// ZafWindowObject::OSRegisterObject() in order to not register the object
	// with the OS.
	if (!screenID)
	{
		// A non-SystemObject() uses the parent screenID.
		if (SystemObject())
			OSRegisterObject();
		else if (parent)
			screenID = parent->screenID;
	}
}

ZafEventType ZafWindowObject::ScrollEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

// ----- Attributes ---------------------------------------------------------

bool ZafWindowObject::SetAcceptDrop(bool acceptDrop)
{
	ZafWindowObject::acceptDrop = acceptDrop;
	return (acceptDrop);
}

bool ZafWindowObject::SetAutomaticUpdate(bool tAutomaticUpdate)
{
	if (automaticUpdate != tAutomaticUpdate)
	{
		automaticUpdate = tAutomaticUpdate;

		if (automaticUpdate && Visible())
			Redisplay();
	}

	return (automaticUpdate);
}

bool ZafWindowObject::SetDisabled(bool setDisabled)
{
	if (disabled != setDisabled)
	{
		disabled = setDisabled;
		Redisplay();
	}

	return (disabled);
}

bool ZafWindowObject::SetEditMode(bool setEditMode)
{
	// Make sure the attribute has changed.
	if (editMode != setEditMode && !screenID)
		editMode = setEditMode;

	// Return the current attribute.
	return (editMode);
}

bool ZafWindowObject::SetFocus(bool tFocus)
{
	// If the object can actually get focus, i.e., its parent has focus,
	// it will receive an S_CURRENT message from the parent's (or
	// windowManager's) NotifyFocus().  S_CURRENT will set the focus
	// boolean.  If the object cannot receive focus, it will be made current
	// in its parent's list so that it will get focus when the parent does.
/* START BLOCK COMMENT
**		if (Disabled() || Noncurrent())
**			focus = false;
**		if (focus == tFocus)
**			return (focus);
**	
**		if (tFocus)
**			NotifyFocus(this, true);
**		else
**			// Tell the object to display itself without focus.
**			Event(N_NON_CURRENT);
**	
**		return (focus);
END BLOCK COMMENT */

	if (Disabled() || Noncurrent())
		tFocus = false;

	// If no screenID just make it the current object.
	if (!screenID && tFocus)
		NotifyFocus(this, true);

	if (focus != tFocus)
	{
		// Propagate the focus.
		if (screenID)
		{
			if (tFocus)
				NotifyFocus(this, true);
			else
			{
				// Tell the object to display itself without focus.
				NotifyFocus(parent, false);
//				if (parent)
//					DynamicPtrCast(parent, ZafWindow)->SetCurrent(ZAF_NULLP(ZafWindowObject));
			}
		}
//		focus = tFocus;
	}

	return (focus);
}

bool ZafWindowObject::SetNoncurrent(bool setNoncurrent)
{
	// Make sure the attribute has changed.
	if (noncurrent != setNoncurrent)
		noncurrent = setNoncurrent;

	// Return the current attribute.
	return (noncurrent);
}

bool ZafWindowObject::SetVisible(bool tVisible)
{
	if (visible != tVisible)
	{
		visible = tVisible;

		if (visible && screenID) // Draw.
		{
			if (parent && regionType == ZAF_AVAILABLE_REGION)
			{
				parent->OSSize();
				Redisplay();
			}
			else
				Redisplay();
		}
		else if (screenID) // Erase.
		{
			if (parent)
			{
				if (!SupportObject())
					parent->OSInvalidateRegion(&zafRegion, false, true);
				else if (regionType == ZAF_AVAILABLE_REGION)
					parent->OSSize();
				else
					parent->OSInvalidateRegion(&zafRegion, false, false);
			}
			else if (screenID)
			{
				// Have the window manager draw behind window.
				windowManager->OSInvalidateRegion(&zafRegion, true);
			}
		}
	}
	return (visible);
}

// ----- OS Specific Functions ----------------------------------------------

ZafEventType ZafWindowObject::OSEvent(const ZafEventStruct &)
{
	return (S_ERROR);
}

void ZafWindowObject::OSInvalidateRegion(ZafRegionStruct *region, bool immediateRedraw, bool)
{
	if (AutomaticUpdate() && Visible() && screenID)
	{
		ZafRegionStruct tRegion = region ? *region : zafRegion;

		// If this is an overlapped child object, make sure we only
		// invalidate the exposed pieces of the object.
		if (parent && overlapped)
		{
			// The comparison with other regions is based on
			// zafRegion.  ie, with respect to all the siblings'
			// parent origin.  So, need to shift the region that 
			// got passed in, since it was relative to the object's
			// origin.
			if (region)
			{
				tRegion.HzShift(zafRegion.left);
				tRegion.VtShift(zafRegion.top);
			}

			// tRegion now has the region that is being requested 
			// to get redrawn.  Need to match that with the actual 
			// exposed parts of the object.
			ZafRegionList regionList;
			regionList.Allocate(0, tRegion);
			OSGetExposedRegionList(regionList);

			for (ZafRegionElement *updateElement = regionList.First(); updateElement;
				updateElement = updateElement->Next())
			{
				ZafRegionStruct updateRegion = updateElement->region;
				if (systemObject)
				{
					// Since the regions were relative to the parent's origin
					// and we need them relative to this object's origin,
					// need to shift them.
					updateRegion.VtShift(-zafRegion.top);
					updateRegion.HzShift(-zafRegion.left);
					windowManager->OSInvalidateObject(&updateRegion, this);
				}
				else
					parent->OSInvalidateRegion(&updateRegion, immediateRedraw, !SupportObject());
			}
			if (systemObject && immediateRedraw)
				windowManager->RepairDamage();
		}
		else
		{
			if (!region)
			{
				tRegion.HzShift(-zafRegion.left);
				tRegion.VtShift(-zafRegion.top);
			}
			if (systemObject || !parent)
			{
				windowManager->OSInvalidateObject(&tRegion, this);
				if (immediateRedraw)
					windowManager->RepairDamage();
			}
			else
			{
				tRegion.HzShift(zafRegion.left);
				tRegion.VtShift(zafRegion.top);
				parent->OSInvalidateRegion(&tRegion, immediateRedraw, !SupportObject());
			}
		}

		return;
	}
}

void ZafWindowObject::OSUpdateRegions(ZafRegionList *regionList)
{
	if (AutomaticUpdate() && Visible() && screenID && (SystemObject() || SupportObject()))
	{
		if (!regionList->First())
			return;

		ZafPositionStruct osPosition;
		osPosition.Assign(0, 0, zafRegion.coordinateType);
		if (parent && regionType == ZAF_OUTSIDE_REGION)
			osPosition = parent->ConvertToOSPosition(parent, &osPosition);
		else
			osPosition = ConvertToOSPosition(this, &osPosition);

		ZafEventStruct event(S_REDISPLAY_REGION);
		event.region = regionList->First()->region;

		// Globalize regionList
		ZafRegionElement *damageElement;
		for (damageElement = regionList->First(); damageElement;
			damageElement = damageElement->Next())
		{
			event.region.left = ZafMin(event.region.left, damageElement->region.left);
			event.region.top = ZafMin(event.region.top, damageElement->region.top);
			event.region.right = ZafMax(event.region.right, damageElement->region.right);
			event.region.bottom = ZafMax(event.region.bottom, damageElement->region.bottom);

			damageElement->region.VtShift(osPosition.line);
			damageElement->region.HzShift(osPosition.column);
		}

		// Set the drawRegion list for the display.
		display->SetDrawRegions(regionList, false);

		// draw.
		Draw(event, S_REDISPLAY_REGION);
		display->SetDrawRegions(0);

		for (damageElement = regionList->First(); damageElement;
			damageElement = damageElement->Next())
		{
			damageElement->region.VtShift(-osPosition.line);
			damageElement->region.HzShift(-osPosition.column);
		}

	}
}

void ZafWindowObject::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType, ZafPaletteState)
{
	if (palette.lineStyle == ZAF_LINE_DEFAULT)
		palette.lineStyle = ZAF_LINE_NULL;
	if (palette.fillPattern == ZAF_PTN_DEFAULT)
		palette.fillPattern = ZAF_PTN_NULL;
	if (palette.colorForeground == ZAF_CLR_DEFAULT)
		palette.colorForeground = ZAF_CLR_NULL;
	if (palette.colorBackground == ZAF_CLR_DEFAULT)
		palette.colorBackground = ZAF_CLR_NULL;
	if (palette.monoForeground == ZAF_MONO_DEFAULT)
		palette.monoForeground = ZAF_MONO_NULL;
	if (palette.monoBackground == ZAF_MONO_DEFAULT)
		palette.monoBackground = ZAF_MONO_NULL;
	if (palette.font == ZAF_FNT_DEFAULT)
		palette.font = ZAF_FNT_NULL;
}

void ZafWindowObject::OSRegisterObject(void)
{
	if (!screenID)
	{
		if (!parent /*|| IsMDI() || Temporary()*/)
			screenID = ++(windowManager->currentScreenID);
		else
			screenID = parent->screenID;
	}
}

OSWindowID ZafWindowObject::OSScreenID(ZafScreenIDType) const
{
	return (screenID);
}

ZafError ZafWindowObject::OSSetText(void)
{
	// Setting ostext at window object level is invalid.
	return (ZAF_ERROR_INVALID);
}

void ZafWindowObject::OSSize(void)
{
	// Don't do anything if didn't change size.
	if (zafRegion == oldRegion)
		return;

	if (!screenID)
		return;

	// Redraw old region.
//	if (parent)
	if (parent && !SupportObject())
	{
		// Only invalidate the parts that don't overlap the new region.
		ZafRegionStruct clip;
		ZafRegionList damageList;
		if (zafRegion.Overlap(oldRegion))
		{
			damageList.Allocate(0, oldRegion);
			clip = zafRegion;
			damageList.Split(0, clip, false);
		}
		else
			damageList.Allocate(0, oldRegion);

		if (damageList.First())
		{
			for (ZafRegionElement *regionElement = damageList.First();
				regionElement; regionElement = regionElement->Next())
					parent->OSInvalidateRegion(&regionElement->region, false, !SupportObject());
		}
	}

	if (AutomaticUpdate() && Visible())
	{
		OSInvalidateRegion(0, false, false);
	}

	if (oldRegion.left != zafRegion.left || oldRegion.top != zafRegion.top)
		Event(N_MOVE);
	Event(N_SIZE);

	oldRegion = zafRegion;
}

ZafError ZafWindowObject::OSUpdatePalettes(ZafPaletteType , ZafPaletteType )
{
	if (screenID)
		Redisplay();
	return (ZAF_ERROR_NONE);
}

void ZafRubberBandRegion(ZafWindowObject *object, ZafRegionStruct *region1,
	ZafRegionStruct *region2)
{
	static ZafPaletteStruct rubberBandPalette =
	{
		ZAF_LINE_SOLID, ZAF_PTN_SOLID_FILL, ZAF_CLR_LIGHTCYAN, ZAF_CLR_BLACK, ZAF_MONO_NULL, ZAF_MONO_NULL, ZAF_FNT_DIALOG
	};
	ZafPaletteStruct *oldPalette = ((ZafScreenDisplay *)object->display)->xorPalette;

	ZafRegionStruct osRegion1;
	ZafRegionStruct osRegion2;
	if (object->parent)
	{
		if (region1)
			osRegion1 = object->parent->ConvertToOSRegion(object, region1);
		if (region2)
			osRegion2 = object->parent->ConvertToOSRegion(object, region2);
	}
	else
	{
		if (region1)
			osRegion1 = *region1;
		if (region2)
			osRegion2 = *region2;
	}
	((ZafScreenDisplay *)object->display)->xorPalette = &rubberBandPalette;

	ZafRegionStruct clip;
	ZafRegionStruct draw;
#if defined(ZAF_GRAPHICS_MODE)
	clip.Assign(0, 0, object->display->columns, object->display->lines,
		ZAF_PIXEL);
#elif defined(ZAF_TEXT_MODE)
	clip.Assign(0, 0, object->display->columns - 1, object->display->lines - 1,
		ZAF_CELL);
#endif
	draw = clip;
	if (object->parent)
		object->parent->GetClip(object, clip, draw);
	object->display->BeginDraw(0, ID_ZAF_SCREEN, draw, clip);
	object->display->SetClipRegion(clip);
	object->display->RectangleXORDiff(region1 ? &osRegion1 : 0,
		region2 ? &osRegion2 : 0);
	object->display->EndDraw();
	((ZafScreenDisplay *)object->display)->xorPalette = oldPalette;
}
