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

#include <z_border.hpp>
#include <z_icon1.hpp>
#include <z_mdiwin.hpp>
#include <z_max.hpp>
#include <z_min.hpp>
#include <z_scrll2.hpp>
#include <z_sys.hpp>
#include <z_title.hpp>
#include <z_utils.hpp>
#include "i_close.hpp"

// ----- ZafMDIWindow -----------------------------------------------------

ZafWindowObject *ZafMDIWindow::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// Check for a null object.
	if (!object)
		return (ZAF_NULLP(ZafWindowObject));

	bool newChild = (Index(object) == -1 && !object->SupportObject());
	ZafWindow::Add(object, position);
	if (!parent && Index(object) != -1)
		OSInvalidateRegion(&object->zafRegion, true, true);

//	if (!parent && !position && object != Current())
	if (!parent && !position && newChild && !object->Focus())
	{
		// Make the child current and first in the list.
		object->SetFocus(true);
	}

	if (!object->SupportObject())
		object->overlapped = true;

	// Return a pointer to the object.
	return (object);
}

ZafPositionStruct ZafMDIWindow::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *zafPosition) const
{
	ZafPositionStruct osPosition = ZafWindow::ConvertToOSPosition(object, zafPosition);
	if (object != this && !object->SupportObject())
	{
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		if (vtScrollBar)
			osPosition.line -= (int)vtScrollBar->ScrollData()->Current();
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (hzScrollBar)
			osPosition.column -= (int)hzScrollBar->ScrollData()->Current();
	}
	return (osPosition);
}

ZafPositionStruct ZafMDIWindow::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *osPosition) const
{
	ZafPositionStruct zafPosition = ZafWindow::ConvertToZafPosition(object, osPosition);
	if (object != this && !object->SupportObject())
	{
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		if (vtScrollBar)
			zafPosition.line += (int)vtScrollBar->ScrollData()->Current();
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (hzScrollBar)
			zafPosition.column += (int)hzScrollBar->ScrollData()->Current();
	}
	return (zafPosition);
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafMDIWindow::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	return (ZafWindow::Draw(event, ccode));
}
#endif

void ZafMDIWindow::GetClip(ZafWindowObject *object, ZafRegionStruct &clip,
	ZafRegionStruct &viewPort)
{
	ZafWindow::GetClip(object, clip, viewPort);
	ZafScrollBar *vtScrollBar = VerticalScrollBar();
	ZafScrollBar *hzScrollBar = HorizontalScrollBar();
	if (object != this && !object->SupportObject())
	{
		if (hzScrollBar)
			viewPort.HzShift(-(int)hzScrollBar->ScrollData()->Current());
		if (vtScrollBar)
			viewPort.VtShift(-(int)vtScrollBar->ScrollData()->Current());

		if (!parent)
		{
			int clipValue;
			clipValue = zafRegion.left + clientRegion.left;
			if (viewPort.left + object->zafRegion.left < clipValue &&
				clip.left > clipValue)
				clip.left = clipValue;

			clipValue = zafRegion.top + clientRegion.top;
			if (viewPort.top + object->zafRegion.top < clipValue &&
				clip.top > clipValue)
				clip.top = clipValue;
		}
	}
}

ZafEventType ZafMDIWindow::DispatchMouseEvent(const ZafEventStruct &event)
{
	// Dispatch all mouse events to the leaf-most object.
	if (modifyMode)
		return (Modify(event));

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

	if (parent)
		return (ZafWindow::DispatchMouseEvent(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);

/* START BLOCK COMMENT
**		// If minimized, pass the event to the minimize icon.
**		if (Minimized())
**			return (MinimizeIcon()->DispatchMouseEvent(event));
END BLOCK COMMENT */

	// Convert mouse position to the coordinates of this object.
	bool overClient = false;
	ZafPositionStruct mousePosition = event.position;
	ZafRegionStruct windowClient = ClientRegion();
	if (windowClient.Overlap(mousePosition))
	{
		// If the mouse is over the client region, convert to the client
		// region's coordinates.
		overClient = true;
		mousePosition.column -= windowClient.left;
		mousePosition.line -= windowClient.top;
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (vtScrollBar)
			mousePosition.line += (int)vtScrollBar->ScrollData()->Current();
		if (hzScrollBar)
			mousePosition.column += (int)hzScrollBar->ScrollData()->Current();
		// Cast away the constness so we can have event.position relative
		// to the client region.
		((ZafEventStruct &)event).position = mousePosition;
	}

	// Process drag and drop events.
	ZafWindowObject *object;
	if (windowManager->dragObject)
	{
		if (overClient)
		{
			for (object = First(); object; object = object->Next())
				if (object->Visible() && object->zafRegion.Overlap(mousePosition))
				{
					ccode = object->DispatchMouseEvent(event);
					break;
				}
		}
		else
		{
			for (object = SupportLast(); object; object = object->Previous())
				if (!object->IsA(ID_ZAF_BORDER) &&
					object->Visible() && object->zafRegion.Overlap(mousePosition))
				{
					ccode = object->DispatchMouseEvent(event);
					break;
				}
		}

		// If the mouse is not over a child object, this is the
		// leaf-most object so it processes the event.
		if (!object)
			ccode = ZafWindowObject::DispatchMouseEvent(event);
		return (ccode);
	}

	if (overClient)
	{
		for (object = First(); object; object = object->Next())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{
				// An object being clicked on receives focus before
				// processing the selection event.
				if (ccode == L_BEGIN_SELECT &&
					!object->Disabled() && !object->Noncurrent())
					object->SetFocus(true);

				ccode = object->DispatchMouseEvent(event);
				break;
			}
	}
	else
	{
		// Start with last object, since the border is the first object
		// and its region covers the entire window.
		for (object = SupportLast(); object; object = object->Previous())
			if (object->Visible() && object->zafRegion.Overlap(mousePosition))
			{
				// An object being clicked on receives focus before processing
				// the selection event.
				if (ccode == L_BEGIN_SELECT && !object->Disabled() && !object->Noncurrent())
					object->SetFocus(true);
//				ZafWindow::Add(object);

				ccode = object->DispatchMouseEvent(event);
				break;
			}

		if (!object && Border())
		{
//??? Check to see that mouse overlaps the border.				
			// Allow the border object to process its mouse events.
			// Set the object variable so we know an object was found.
			object = Border();
			ccode = object->DispatchMouseEvent(event);
		}
	}

	// If the mouse is not over a child object, this is the
	// leaf-most object so it processes the event.
	if (!object)
		ccode = ZafWindowObject::DispatchMouseEvent(event);

	return (ccode);
}

ZafWindowObject *ZafMDIWindow::FindMouseObject(const ZafEventStruct &event)
{
	// If the object is disabled return a null pointer.
	if (Disabled())
		return (ZAF_NULLP(ZafWindowObject));

	if (modifyMode)
		return (this);

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

	if (parent)
		return (ZafWindow::FindMouseObject(event));

	// Convert mouse position to the coordinates of this object.
	ZafPositionStruct position;
	position.line = event.osEvent.position.line;
	position.column = event.osEvent.position.column;
#if defined(ZAF_GRAPHICS_MODE)
	position.coordinateType = ZAF_PIXEL;
#else
	position.coordinateType = ZAF_CELL;
#endif

	position = ConvertToZafPosition(this, &position);

	bool overClient = false;
	ZafRegionStruct windowClient = ClientRegion();
	if (windowClient.Overlap(position))
	{
		// If the mouse is over the client region, convert to the client
		// region's coordinates.
		overClient = true;
		position.column -= windowClient.left;
		position.line -= windowClient.top;
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (vtScrollBar)
			position.line += (int)vtScrollBar->ScrollData()->Current();
		if (hzScrollBar)
			position.column += (int)hzScrollBar->ScrollData()->Current();
	}

	ZafWindowObject *mouseObject = 0;

	// Process drag and drop events.
	ZafWindowObject *object;
/* START BLOCK COMMENT
**		if (windowManager->dragObject)
**		{
**			if (overClient)
**			{
**				for (object = First(); object; object = object->Next())
**					if (object->Visible() && object->zafRegion.Overlap(position))
**					{
**						mouseObject = object->FindMouseObject(event);
**						break;
**					}
**			}
**			else
**			{
**				for (object = SupportLast(); object; object = object->Previous())
**					if (!object->IsA(ID_ZAF_BORDER) &&
**						object->Visible() && object->zafRegion.Overlap(position))
**					{
**						mouseObject = object->FindMouseObject(event);
**						break;
**					}
**			}
**	
**			// If the mouse is not over a child object, this is the
**			// leaf-most object so it processes the event.
**			if (!object)
**				mouseObject = this;
**			return (mouseObject);
**		}
END BLOCK COMMENT */

	if (overClient)
	{
		for (object = First(); object; object = object->Next())
			if (object->Visible() && object->zafRegion.Overlap(position))
			{
				mouseObject = object->FindMouseObject(event);
				break;
			}
	}
	else
	{
		// Start with last object, since the border is the first object
		// and its region covers the entire window.
		for (object = SupportLast(); object; object = object->Previous())
			if (object->Visible() && object->zafRegion.Overlap(position))
			{
				mouseObject = object->FindMouseObject(event);
				break;
			}

		if (!mouseObject)
		{
			mouseObject = ZafWindowObject::FindMouseObject(event);
		}
	}

	// If the mouse is not over a child object, this is the
	// leaf-most object so it processes the event.
	if (!object)
		mouseObject = ZafWindowObject::FindMouseObject(event);

	return (mouseObject);
}

ZafEventType ZafMDIWindow::Event(const ZafEventStruct &event)
{
	// Return the control code.
	ZafEventType ccode = LogicalEvent(event);
	ZafWindowObject *object = First();

	switch (ccode)
	{
	case S_INITIALIZE:
		// Force the correct mdiType (for persistence and programmer mistakes).
		if (parent && mdiType == ZAF_MDI_PARENT)
			mdiType = ZAF_MDI_CHILD;
		else if (!parent && mdiType == ZAF_MDI_CHILD)
			mdiType = ZAF_MDI_PARENT;

		ccode = ZafWindow::Event(event);
		if (parent)
		{
			ZafSystemButton *sysButton = SystemButton();
			if (sysButton)
				for (ZafPopUpItem *object = DynamicPtrCast(sysButton->menu.First(), ZafPopUpItem);
					object; object = DynamicPtrCast(object->Next(), ZafPopUpItem))
					switch (object->ItemType())
					{
						case ZAF_RESTORE_OPTION:
							object->SetValue(S_MDI_RESTORE);
							break;

						case ZAF_MINIMIZE_OPTION:
							object->SetValue(S_MDI_MINIMIZE);
							break;

						case ZAF_MAXIMIZE_OPTION:
							object->SetValue(S_MDI_MAXIMIZE);
							break;

						case ZAF_CLOSE_OPTION:
							object->SetValue(S_MDI_CLOSE);
							break;

						case ZAF_ABOUT_OPTION:
						case ZAF_COPY_OPTION:
						case ZAF_CUT_OPTION:
						case ZAF_EXIT_OPTION:
						case ZAF_MOVE_OPTION:
						case ZAF_NORMAL_ITEM:
						case ZAF_PASTE_OPTION:
						case ZAF_SEPARATOR:
						case ZAF_SIZE_OPTION:
						case ZAF_SWITCH_OPTION:
							// Do nothing.
							break;
					}
			ZafCloseButton *close = ZAF_NULLP(ZafCloseButton);
			for (ZafWindowObject *object = SupportFirst(); object && !close; object = object->Next())
				if ((close = DynamicPtrCast(object, ZafCloseButton)) != 0)
					close->SetValue(S_MDI_CLOSE);
		}
		break;

	case S_COMPUTE_SIZE:
		ccode = ZafWindow::Event(event);
		if (parent)
		{
			ZafTitle *title = Title();
			if (title)
				title->SetValue((Maximized() ? S_MDI_RESTORE : S_MDI_MAXIMIZE));
			ZafMaximizeButton *max = MaximizeButton();
			if (max)
				max->SetValue((Maximized() ? S_MDI_RESTORE : S_MDI_MAXIMIZE));
			ZafMinimizeButton *min = MinimizeButton();
			if (min)
				min->SetValue((Minimized() ? S_MDI_RESTORE : S_MDI_MINIMIZE));
		}
		break;

	case N_SIZE:
		if (!parent && current)
		{
			ZafWindow *currentWin = DynamicPtrCast(current, ZafWindow);
			if (currentWin->Maximized())
			{
				ZafRegionStruct newRegion = clientRegion;
				newRegion.HzShift(-newRegion.left);
				newRegion.VtShift(-newRegion.top);
				Current()->SetRegion(newRegion);
				Current()->OSSize();
			}
		}
		ccode = ZafWindow::Event(event);
		if (parent)
		{
			windowManager->RepairDamage();
			parent->ScrollEvent(S_VSCROLL_COMPUTE);
			parent->ScrollEvent(S_HSCROLL_COMPUTE);
		}
		else
		{
			for (ZafWindowObject *object = First(); object; object = object->Next())
				object->overlapped = false;
			ScrollEvent(S_VSCROLL_COMPUTE);
			ScrollEvent(S_HSCROLL_COMPUTE);
		}
		
		break;

	case S_MDI_CASCADE_WINDOWS:
		// Cascade the child windows.
		if (object && !parent)
		{
			ZafEventStruct aEvent(S_SIZE);
			aEvent.region.left = aEvent.region.top = 0;
			aEvent.region.coordinateType = zafRegion.coordinateType;
			for (object = Last(); object; object = object->Previous())
			{
				// Move the window.
				aEvent.region.right = aEvent.region.left + object->zafRegion.Width();
				aEvent.region.bottom = aEvent.region.top + object->zafRegion.Height();
				object->Event(aEvent);

				// Update the region.
				aEvent.region.left += display->cellHeight;
				aEvent.region.top += display->cellHeight;
			}
		}
		break;

	case S_MDI_CLOSE:
		if (MDIType() == ZAF_MDI_PARENT)
		{
			ZafWindow *child = DynamicPtrCast(First(), ZafWindow);
			if (child && !child->Locked() &&
				(child->Event(ZafEventStruct(N_CLOSE)) == 0))
			{
				ZafWindowObject *mouseRoot;
				for (mouseRoot = windowManager->mouseObject; mouseRoot; mouseRoot = mouseRoot->parent)
					if (mouseRoot == child)
					{
						windowManager->mouseObject = 0;
						break;
					}
				Subtract(child);
				if (child->Destroyable())
					delete child;
				if (First())
					First()->SetFocus(true);
			}
		}
		break;

	case S_MDI_MAXIMIZE:
		if (MDIType() == ZAF_MDI_CHILD)
			SetMaximized(true);
		else if (Current())
			ccode = Current()->Event(event);
		break;

	case S_MDI_MINIMIZE:
		if (MDIType() == ZAF_MDI_CHILD)
			SetMinimized(true);
		else if (Current())
			ccode = Current()->Event(event);
		break;

	case S_MDI_RESTORE:
		if (MDIType() == ZAF_MDI_CHILD)
		{
			if (Maximized())
				SetMaximized(false);
			else if (Minimized())
				SetMinimized(false);
		}
		else if (Current())
			ccode = Current()->Event(event);
		break;

	case S_MDI_TILE_WINDOWS:
		// Tile the child windows.
		if (object)
		{
			// Determine the proper size of each child.  Algorithm keeps
			// computing until the window ratio is 1-to-1 (100% as wide as 
			// it is tall).
			int tCount = Count();
			int width = 0, height = 0;
			int rows;
			for (rows = 1; rows <= tCount && width <= height; rows++)
			{
				width = clientRegion.Width() / ((tCount + rows - 1) / rows);
				height = clientRegion.Height() / rows;
			}

			// Resize the children.
			ZafEventStruct event(S_SIZE);
			event.region.left = event.region.top = 0;
			event.region.coordinateType = zafRegion.coordinateType;
			for (object = First(); object; object = object->Next())
			{
				// Check for off-screen position.
				if (event.region.left + width > clientRegion.Width())
				{
					event.region.left = 0;
					event.region.top += height;
				}

				// Reposition the object.
				event.region.right = event.region.left + width - 1;
				event.region.bottom = event.region.top + height - 1;
				object->Event(event);

				// Determine the new object position.
				event.region.left += width;
			}
		}
		break;

	case S_MDI_NEXT_WINDOW:
	case L_MDI_NEXT_WINDOW:
		if (!parent)
		{
			if (current && current->Next())
			{
				bool saveUpdate = automaticUpdate;
				automaticUpdate = false;
				ZafWindowObject *oldCurrent = Current();
				ZafWindowObject *newCurrent = oldCurrent->Next();
				newCurrent->SetFocus(true);
				ZafList::Subtract(oldCurrent);
				ZafList::Add(oldCurrent);
				automaticUpdate = saveUpdate;
				ZafRegionStruct osRegion;
				osRegion = ConvertToOSRegion(oldCurrent, &oldCurrent->zafRegion);
				windowManager->OSInvalidateRegion(&osRegion);
				osRegion = ConvertToOSRegion(newCurrent, &newCurrent->zafRegion);
				windowManager->OSInvalidateRegion(&osRegion);
			}
		}
		break;

	case L_DOWN:
	case L_LEFT:
	case L_RIGHT:
	case L_UP:
		if (parent)
			ZafWindow::Event(event);
		else
			ccode = ZafWindow::Event(event);
		break;
	default:
		ccode = ZafWindow::Event(event);
	}

	return (ccode);
}

ZafEventType ZafMDIWindow::MoveEvent(const ZafEventStruct &event)
{
	return (ZafWindow::MoveEvent(event));
}

ZafWindowObject *ZafMDIWindow::NotifyFocus(ZafWindowObject *object, bool setFocus)
{
	ZafWindowObject *invalidObject = ZafWindow::NotifyFocus(object, setFocus);
	if (MDIType() == ZAF_MDI_PARENT && setFocus)
	{
		if (!invalidObject && Index(object) != -1)
		{
			if (screenID && Visible() && AutomaticUpdate())
			{
				ZafRegionStruct clipRegion;
				for (ZafWindowObject *tObject = Last(); tObject; tObject = tObject->Previous())
					if (tObject != object && tObject->zafRegion.Overlap(object->zafRegion, clipRegion)
						&& tObject->Visible())
					{
						clipRegion = ConvertToOSRegion(object, &clipRegion);
						clipRegion.VtShift(-zafRegion.top);
						clipRegion.HzShift(-zafRegion.left);
//						zafRegion.Overlap(clipRegion, clipRegion);
						OSInvalidateRegion(&clipRegion);
					}
			}
			ZafList::Subtract(object);
			ZafList::Add(object, First());
			ZafList::SetCurrent(object);
		}
	}

	return (invalidObject);
}

ZafEventType ZafMDIWindow::ScrollEvent(const ZafEventStruct &event)
{
	// Process the scrolling request.  Scrolling at the window level is based 
	// on pixel boundaries.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_VSCROLL:
		// Scroll the window contents <delta> cells in the direction 
		// indicated by the type of scrolling operation.
		if (VerticalScrollBar())
		{
			ZafEventStruct scrollEvent = event;
			scrollEvent.type = N_VSCROLL;
			VerticalScrollBar()->Event(scrollEvent);
			ScrollEvent(scrollEvent);
		}
		break;

	case S_HSCROLL:
		// Scroll the window contents <delta> cells in the direction 
		// indicated by the type of scrolling operation.
		if (HorizontalScrollBar())
		{
			ZafEventStruct scrollEvent = event;
			scrollEvent.type = N_HSCROLL;
			HorizontalScrollBar()->Event(scrollEvent);
			ScrollEvent(scrollEvent);
		}
		break;

	case N_VSCROLL:
		{
			// Scroll the window contents <delta> pixels in the direction 
			// indicated by the type of scrolling operation.
			ZafRegionStruct updateRegion = clientRegion;
			updateRegion.left = updateRegion.top = 0;
			updateRegion.right = clientRegion.Width() - 1;
			updateRegion.bottom = clientRegion.Height() - 1;
			int delta = (int)event.scroll.delta;
			
			if (event.scroll.delta < 0)
				updateRegion.bottom += delta;
			else
				updateRegion.top += delta;

			// Entire client region needs to be redrawn?
			if (updateRegion.top > updateRegion.bottom)
			{
				updateRegion = clientRegion;
				updateRegion = ConvertToOSRegion(this, &updateRegion);
				windowManager->OSInvalidateRegion(&updateRegion);
			}
			else
			{
				// Scroll contents of client region.
				BeginDraw();
				display->RegionCopy(updateRegion, updateRegion.left, updateRegion.top - delta);
				EndDraw();

				// Paint exposed region.
				updateRegion = clientRegion;
				if (event.scroll.delta < 0)
					updateRegion.bottom = updateRegion.top - delta + clientRegion.top;
				else
					updateRegion.top = updateRegion.bottom - delta - clientRegion.top;

				updateRegion = ConvertToOSRegion(this, &updateRegion);
				windowManager->OSInvalidateRegion(&updateRegion, true);
			}
			ScrollEvent(S_VSCROLL_COMPUTE);
		}
		break;

	case N_HSCROLL:
		{
			// Scroll the window contents <delta> cells in the direction 
			// indicated by the type of scrolling operation.
			ZafRegionStruct updateRegion = clientRegion;
			updateRegion.left = updateRegion.top = 0;
			updateRegion.right = clientRegion.Width() - 1;
			updateRegion.bottom = clientRegion.Height() - 1;
			int delta = (int)event.scroll.delta;
			
			if (event.scroll.delta < 0)
				updateRegion.right += delta;
			else
				updateRegion.left += delta;

			// Entire client region needs to be redrawn?
			if (updateRegion.left > updateRegion.right)
			{
				updateRegion = clientRegion;
				updateRegion = ConvertToOSRegion(this, &updateRegion);
				windowManager->OSInvalidateRegion(&updateRegion);
			}
			else
			{
				// Scroll contents of client region.
				BeginDraw();
				display->RegionCopy(updateRegion, updateRegion.left - (int)event.scroll.delta, updateRegion.top);
				EndDraw();

				updateRegion = clientRegion;
				if (delta < 0)
					updateRegion.right = updateRegion.left - delta + clientRegion.left;
				else
					updateRegion.left = updateRegion.right - delta - clientRegion.left;

				updateRegion = ConvertToOSRegion(this, &updateRegion);
				windowManager->OSInvalidateRegion(&updateRegion, true);
			}
			ScrollEvent(S_HSCROLL_COMPUTE);
		}
		break;

	case S_VSCROLL_CHECK:
		{
			if (!VerticalScrollBar())
				break;

			// Check the current object to ensure it is currently visible within
			// the window.  If not, scroll the window so the object appears on 
			// the screen.

			long delta = 0;
			long current = VerticalScrollBar()->ScrollData()->Current();
			ZafWindowObject *object = Current();
			if (object)
			{
				if (object->zafRegion.top < current)
					delta = object->zafRegion.top - current;
				else if (object->zafRegion.bottom > current + clientRegion.Height())
					delta = object->zafRegion.bottom - clientRegion.Height() - current;
			}

			if (delta)
			{
				ZafEventStruct sEvent(S_VSCROLL);
				sEvent.scroll.delta = delta;
				Event(sEvent);
			}
		}
		break;

	case S_HSCROLL_CHECK:
		{
			if (!HorizontalScrollBar())
				break;

			// Check the current object to ensure it is currently visible within
			// the window.  If not, scroll the window so the object appears on 
			// the screen.

			long delta = 0;
			long current = HorizontalScrollBar()->ScrollData()->Current();
			ZafWindowObject *object = Current();
			if (object)
			{
				if (object->zafRegion.left < current)
					delta = object->zafRegion.left - current;
				else if (object->zafRegion.right > current + clientRegion.Width())
					delta = object->zafRegion.right - clientRegion.Width() - current;
			}

			if (delta)
			{
				ZafEventStruct sEvent(S_HSCROLL);
				sEvent.scroll.delta = delta;
				Event(sEvent);
			}
		}
		break;

	case S_HSCROLL_COMPUTE:
		{
			ZafScrollBar *hzScrollBar = HorizontalScrollBar();
			if (hzScrollBar)
			{
				int min = 0;
				int max = 0;
				int scrollCurrent = (int)hzScrollBar->ScrollData()->Current();
				bool resizeChildren = false;
				ZafWindow *object = DynamicPtrCast(first, ZafWindow);
				ZafWindowObject *child = object;
				if (object && !object->Maximized())
				{
					min = child->zafRegion.left;
					max = child->zafRegion.right;
					for (child = child->Next(); child; child = child->Next())
					{
						min = ZafMin(min, child->zafRegion.left);
						max = ZafMax(max, child->zafRegion.right);
					}
					int width = clientRegion.Width();
					if (min < 0)
					{
						resizeChildren = true;
//						if (!scrollCurrent || max < width)
						if (!scrollCurrent && max < width)
							max = width - min;
						else
							max -= min;
						if (max < width)
							max = width - min;
						scrollCurrent -= min;
						if (max < scrollCurrent + width)
							max = scrollCurrent + width;
						for (child = First(); child; child = child->Next())
						{
							child->zafRegion.HzShift(-min);
							child->SetRegion(child->zafRegion);
						}
						min = 0;
					}
					else if (max - min < width &&
						max <= scrollCurrent + width &&
						scrollCurrent && scrollCurrent <= min)
					{
						resizeChildren = true;
						for (child = First(); child; child = child->Next())
						{
							child->zafRegion.HzShift(-scrollCurrent);
							child->SetRegion(child->zafRegion);
						}
						max = width;
					}
					else if (scrollCurrent && max < scrollCurrent + width)
						max = scrollCurrent + width;
				}
				ZafScrollStruct hScroll;
				hScroll.minimum = 0;
				hScroll.maximum = max - clientRegion.Width();
				hScroll.showing = clientRegion.Width();
				hScroll.current = scrollCurrent;
				hScroll.delta = display->cellWidth;

				if (hScroll.maximum < 0)
					hScroll.maximum = scrollCurrent ? clientRegion.Width() : 0;
				hzScrollBar->ScrollData()->SetScroll(hScroll);
				if (resizeChildren)
				{
					windowManager->RepairDamage();
					bool saveAuto = automaticUpdate;
					automaticUpdate = false;
					for (child = Last(); child; child = child->Previous())
						child->OSSize();
					automaticUpdate = saveAuto;
				}
			}
		}
		break;

	case S_VSCROLL_COMPUTE:
		{
			ZafScrollBar *vtScrollBar = VerticalScrollBar();
			if (vtScrollBar)
			{
				int min = 0;
				int max = 0;
				int scrollCurrent = (int)vtScrollBar->ScrollData()->Current();
				bool resizeChildren = false;
				ZafWindow *object = DynamicPtrCast(first, ZafWindow);
				ZafWindowObject *child = object;
				if (object && !object->Maximized())
				{
					min = child->zafRegion.top;
					max = child->zafRegion.bottom;
					for (child = child->Next(); child; child = child->Next())
					{
						min = ZafMin(min, child->zafRegion.top);
						max = ZafMax(max, child->zafRegion.bottom);
					}
					int height = clientRegion.Height();
					if (min < 0)
					{
						resizeChildren = true;
						if (!scrollCurrent && max < height)
							max = height - min;
						else
							max -= min;
						if (max < height)
							max = height - min;
						scrollCurrent -= min;
						if (max < scrollCurrent + height)
							max = scrollCurrent + height;
						for (child = First(); child; child = child->Next())
						{
							child->zafRegion.VtShift(-min);
							child->SetRegion(child->zafRegion);
						}
						min = 0;
					}
					else if (max - min < height &&
						max <= scrollCurrent + height &&
						scrollCurrent && scrollCurrent <= min)
					{
						resizeChildren = true;
						for (child = First(); child; child = child->Next())
						{
							child->zafRegion.VtShift(-scrollCurrent);
							child->SetRegion(child->zafRegion);
						}
						max = height;
					}
					else if (scrollCurrent && max < scrollCurrent + height)
						max = scrollCurrent + height;
				}
				ZafScrollStruct vScroll;
				vScroll.minimum = 0;
				vScroll.maximum = max - clientRegion.Height();
				vScroll.showing = clientRegion.Height();
				vScroll.current = scrollCurrent;
				vScroll.delta = display->cellWidth;

				if (vScroll.maximum < 0)
					vScroll.maximum = scrollCurrent ? clientRegion.Height() : 0;
				vtScrollBar->ScrollData()->SetScroll(vScroll);
				if (resizeChildren)
				{
					windowManager->RepairDamage();
					bool saveAuto = automaticUpdate;
					automaticUpdate = false;
					for (child = Last(); child; child = child->Previous())
						child->OSSize();
					automaticUpdate = saveAuto;
				}
			}
		}
		break;

	default:
		// No other messages apply to the scrolling window object.
		return (S_ERROR);
	}

	// Return the control code.
	return (event.type);
}

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

bool ZafMDIWindow::SetMaximized(bool setMaximized)
{
	if (maximized != setMaximized && MaximizeButton() && parent)
	{
		maximized = setMaximized;

		ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);
		ZafRegionStruct parentClientRegion = parentWindow->ClientRegion();
		parentClientRegion.HzShift(-parentClientRegion.left);
		parentClientRegion.VtShift(-parentClientRegion.top);

		if (maximized)
		{
			MaximizeButton()->SetValue(S_MDI_RESTORE);

			// Save restore region unless the window is minimized.
			if (minimized)
			{
				if (MinimizeButton())
					MinimizeButton()->SetValue(S_MDI_MINIMIZE);
				minimized = false;
			}
			else
				restoreRegion = zafRegion;

			SetRegion(parentClientRegion);
		}
		else
		{
			// Restore settings in case the window was minimized from a maximized
			// state or vice versa.
			minimized = false;
			MaximizeButton()->SetValue(S_MDI_MAXIMIZE);
			MinimizeButton()->SetValue(S_MDI_MINIMIZE);

			SetRegion(restoreRegion);
		}

		Event(S_COMPUTE_SIZE);
		OSSize();
/* START BLOCK COMMENT
**			ZafRegionStruct osRegion = parent->ConvertToOSRegion(this, &parentClientRegion);
**			windowManager->OSInvalidateRegion(&osRegion);
END BLOCK COMMENT */
		parent->ScrollEvent(S_VSCROLL_CHECK);
		parent->ScrollEvent(S_HSCROLL_CHECK);
		parent->OSInvalidateRegion(&parentClientRegion);
	}
	else
		ZafWindow::SetMaximized(setMaximized);

	return (maximized);
}

bool ZafMDIWindow::SetMinimized(bool setMinimized)
{
	if (minimized != setMinimized && MinimizeButton() && parent)
	{
		minimized = setMinimized;

		ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);
		ZafRegionStruct parentClientRegion = parentWindow->ClientRegion();
		parentClientRegion.HzShift(-parentClientRegion.left);
		parentClientRegion.VtShift(-parentClientRegion.top);

		if (minimized)
		{
			MinimizeButton()->SetValue(S_MDI_RESTORE);

			ZafIcon *minIcon = MinimizeIcon();
			if (!minIcon)
			{
				// Create blank icon.
				ZafIcon::ImageAllocate();
				minIcon = new ZafIcon(0, 0, Text(), ZafIcon::imageTable[ZAF_APPLICATION_ICON]);
				minIcon->SetIconType(ZAF_MINIMIZE_ICON);
				minIcon->SetSupportObject(true);
				Add(minIcon);

				// Make sure minIcon has regions initialized.
				minIcon->Event(S_CREATE);
			}

			ZafRegionStruct minRegion;
			if (!minIcon->Initialized())
			{
				minRegion = parentClientRegion;
				minRegion.left += display->cellWidth;
				minRegion.top = minRegion.bottom - 2 * display->cellHeight;
				minRegion.right = display->cellWidth * 31;
				minRegion.bottom -= display->cellHeight;
//				minRegion.coordinateType = minIcon->zafRegion.coordinateType;

				// Check for overlapping minimized windows.
				ZafRegionStruct boundRegion;
				ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);
				if (parentWindow)
					boundRegion = parentWindow->ClientRegion();
				else
				{
					boundRegion.left = boundRegion.top = 0;
					boundRegion.right = Display()->columns - 1;
					boundRegion.bottom = Display()->lines - 1;
				}
				int width = minRegion.Width();
				int height = minRegion.Height();
				int left = minRegion.left;
				int top = minRegion.top;
				ZafWindow *window = parentWindow ? DynamicPtrCast(parentWindow->Last(), ZafWindow) :
					DynamicPtrCast(windowManager->Last(), ZafWindow);

				while (window)
				{
					if (window->Minimized() && window != this && minRegion.Overlap(window->zafRegion))
					{
						left = window->zafRegion.right + 2 * Display()->cellWidth;
						if (left + width > boundRegion.right)
						{
							top -= (height + Display()->cellHeight);
							minRegion.top = top;
							minRegion.bottom = top + height;
							left = Display()->cellWidth;
						}
						minRegion.left = left;
						minRegion.right = left + width;
					}
					window = DynamicPtrCast(window->Previous(), ZafWindow);
				}

				minIcon->SetRegion(minRegion);
				minIcon->SetInitialized(true);
			}
			else
				minRegion = minIcon->zafRegion;

			// Save restore region unless the window is maximized.
			if (maximized)
			{
				if (MaximizeButton())
					MaximizeButton()->SetValue(S_MDI_MAXIMIZE);
				maximized = false;
			}
			else
				restoreRegion = zafRegion;

			SetRegion(minRegion);
		}
		else
		{
			// Restore settings in case the window was minimized from a maximized
			// state or vice versa.
			maximized = false;
			MaximizeButton()->SetValue(S_MDI_MAXIMIZE);
			MinimizeButton()->SetValue(S_MDI_MINIMIZE);

			SetRegion(restoreRegion);
		}

		Event(S_COMPUTE_SIZE);
		OSSize();
		ZafRegionStruct osRegion = parent->ConvertToOSRegion(this, &parentClientRegion);
		windowManager->OSInvalidateRegion(&osRegion);
	}
	else
		ZafWindow::SetMinimized(setMinimized);

	return (minimized);
}

bool ZafMDIWindow::SetVisible(bool setVisible)
{
	return (ZafWindow::SetVisible(setVisible));
}

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

ZafEventType ZafMDIWindow::OSEvent(const ZafEventStruct &)
{
	return (S_CONTINUE);
}

void ZafMDIWindow::OSInvalidateRegion(ZafRegionStruct *region, bool immediateRedraw, bool client)
{
	// Don't need to worry about whether this is an overlapped
	// child, since ZafW::OSInvalidateReg() will.
	if (parent)
		ZafWindow::OSInvalidateRegion(region, immediateRedraw, client);
	else if (AutomaticUpdate() && Visible() && screenID)
	{
		// Parent window, so don't need to worry about overlapping.
		ZafRegionStruct tRegion = region ? *region : zafRegion;
		if (!region)
		{
			tRegion.HzShift(-zafRegion.left);
			tRegion.VtShift(-zafRegion.top);
		}
		if (client)
		{
			tRegion.HzShift(clientRegion.left);
			tRegion.VtShift(clientRegion.top);

			ZafScrollBar *vtScrollBar = VerticalScrollBar();
			ZafScrollBar *hzScrollBar = HorizontalScrollBar();
			if (hzScrollBar)
				tRegion.HzShift(-(int)hzScrollBar->ScrollData()->Current());
			if (vtScrollBar)
				tRegion.VtShift(-(int)vtScrollBar->ScrollData()->Current());
		}

		if (!systemObject)
			ZafWindowObject::OSInvalidateRegion(&tRegion, immediateRedraw, client);
		else
		{
			windowManager->OSInvalidateObject(&tRegion, this);
			if (immediateRedraw)
				windowManager->RepairDamage();
		}
	}
}

void ZafMDIWindow::ModifyOSShift(ZafPositionStruct &osPosition)
{
	osPosition.line -= clientRegion.top;
	osPosition.column -= clientRegion.left;
	if (!parent)
	{
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (hzScrollBar)
			osPosition.column += (int)hzScrollBar->ScrollData()->Current();
		if (vtScrollBar)
			osPosition.line += (int)vtScrollBar->ScrollData()->Current();
	}

}
void ZafMDIWindow::OSDrawChildren(ZafRegionList *regionList)
{
	if (parent)
		ZafWindow::OSDrawChildren(regionList);
	else
	{
		ZafRegionList childList;
		ZafWindowObject *child;
		ZafRegionElement *damageElement;
		ZafRegionElement *nextElement;
		ZafRegionStruct childRegion;

		for (child = First(); child; child = child->Next())
		{
//			if (child->Visible(false) && child->IsTransparent())
			{
				childList.Destroy();
				for (damageElement = regionList->First();
					damageElement; damageElement = nextElement)
				{
					nextElement = damageElement->Next();
					if (child->zafRegion.Overlap(damageElement->region, childRegion))
					{
						// Remove the region we are repairing from the damage list.
						regionList->Split(0, childRegion, false);

						childRegion.HzShift(-child->zafRegion.left);
						childRegion.VtShift(-child->zafRegion.top);
						childList.Allocate(0, childRegion);
					}
				}
				if (childList.First())
					child->OSUpdateRegions(&childList);
			}
		}
	}

}

void ZafMDIWindow::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType  type, ZafPaletteState state)
{
	ZafWindowObject::OSMapPalette(palette, type, state);
}

void ZafMDIWindow::OSRegisterObject(void)
{
	if (!screenID)
		screenID = ++(windowManager->currentScreenID);
}

void ZafMDIWindow::OSSize(void)
{
	ZafWindow::OSSize();
}

