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

#include <z_sclwin.hpp>
#include <z_string.hpp>
#include <z_utils.hpp>

// ----- ZafScrolledWindow ------------------------------------------------

ZafPositionStruct ZafScrolledWindow::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *zafPosition) const
{
	ZafPositionStruct osPosition = ZafWindow::ConvertToOSPosition(object, zafPosition);
	if (!object->SupportObject())
	{
		osPosition.column += scrollRegion.left;
		osPosition.line += scrollRegion.top;
	}
	return (osPosition);
}

ZafPositionStruct ZafScrolledWindow::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *osPosition) const
{
	ZafPositionStruct zafPosition = ZafWindow::ConvertToZafPosition(object, osPosition);
	if (!object->SupportObject())
	{
		zafPosition.column -= scrollRegion.left;
		zafPosition.line -= scrollRegion.top;
	}
	return (zafPosition);
}

ZafEventType ZafScrolledWindow::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;

	if (ccode == E_OSEVENT)
		return ZafWindow::OSEvent(event);

	switch (ccode)
	{
	case S_INITIALIZE:
		ConvertRegion(scrollRegion, ZAF_PIXEL);
		ccode = ZafWindow::Event(event);
		break;

	// ----- Position & Size messages -----
	case N_SIZE:
		// Defer to the base class.
		ccode = ZafWindow::Event(event);

		// Adjust the scroll bar information.
		Event(S_HSCROLL_COMPUTE);
		Event(S_VSCROLL_COMPUTE);

		// Adjust the scroll region.
		if (scrollRegion.left < 0 && scrollRegion.right < clientRegion.Width() - 1)
		{
			ZafEventStruct scrollEvent(S_HSCROLL);
			scrollEvent.scroll.delta = -ZafMin(-scrollRegion.left, clientRegion.Width() - scrollRegion.right - 1);
			Event(scrollEvent);
		}

		if (scrollRegion.top < 0 && scrollRegion.bottom < clientRegion.Height() - 1)
		{
			ZafEventStruct scrollEvent(S_VSCROLL);
			scrollEvent.scroll.delta = -ZafMin(-scrollRegion.top, clientRegion.Height() - scrollRegion.bottom - 1);
			Event(scrollEvent);
		}
		break;

	case S_HSCROLL:
	case N_HSCROLL:
		{
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		int delta = (int)event.scroll.delta;
		scrollRegion.left -= delta;
		scrollRegion.right -= delta;
		if (screenID)
		{
			ScrollWindow(screenID, (int)-delta, 0, NULL, NULL);
			UpdateWindow(screenID);
		}
		if (ccode == S_HSCROLL && hzScrollBar)
		{
			ZafScrollData hScroll = *hzScrollBar->ScrollData();
			hScroll.current += delta;
			hzScrollBar->ScrollData()->SetScroll(hScroll);
		}
		}
		break;

	case S_VSCROLL:
	case N_VSCROLL:
		{
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		int delta = (int)event.scroll.delta;
		scrollRegion.top -= delta;
		scrollRegion.bottom -= delta;
		if (screenID)
		{
			ScrollWindow(screenID, 0, (int)-delta, NULL, NULL);
			UpdateWindow(screenID);
		}
		if (ccode == S_VSCROLL && vtScrollBar)
		{
			ZafScrollData vScroll = *vtScrollBar->ScrollData();
			vScroll.current += delta;
			vtScrollBar->ScrollData()->SetScroll(vScroll);
		}
		}
		break;

	case S_VSCROLL_COMPUTE:
		{
		ZafScrollBar *vtScrollBar = VerticalScrollBar();
		if (vtScrollBar)
		{
			ZafScrollStruct vScroll;
			vScroll.minimum = 0;
			vScroll.maximum = scrollRegion.Height() - clientRegion.Height();
			vScroll.showing = clientRegion.Height();
			vScroll.current = -scrollRegion.top;
			vScroll.delta = display->cellHeight;

			if (vScroll.maximum < 0)
				vScroll.maximum = 0;
			vtScrollBar->ScrollData()->SetScroll(vScroll);
		}
		}
		break;

	case S_HSCROLL_COMPUTE:
		{
		ZafScrollBar *hzScrollBar = HorizontalScrollBar();
		if (hzScrollBar)
		{
			ZafScrollStruct hScroll;
			hScroll.minimum = 0;
			hScroll.maximum = scrollRegion.Width() - clientRegion.Width();
			hScroll.showing = clientRegion.Width();
			hScroll.current = -scrollRegion.left;
			hScroll.delta = display->cellWidth;

			if (hScroll.maximum < 0)
				hScroll.maximum = 0;
			hzScrollBar->ScrollData()->SetScroll(hScroll);
		}
		}
		break;

	default:
		// Defer to the base class.
		ccode = ZafWindow::Event(event);
		break;
	}

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

ZafWindowObject *ZafScrolledWindow::NotifyFocus(ZafWindowObject *focusObject, bool setFocus)
{
	ZafWindowObject *invalidObject = ZafWindow::NotifyFocus(focusObject, setFocus);

	if (!invalidObject && setFocus && focusObject != this)
	{
		ZafRegionStruct visibleRegion = clientRegion;
		visibleRegion.left -= scrollRegion.left;
		visibleRegion.right -= scrollRegion.left;
		visibleRegion.top -= scrollRegion.top;
		visibleRegion.bottom -= scrollRegion.top;

		if (!focusObject->zafRegion.Encompassed(visibleRegion))
		{
			ZafEventStruct scrollEvent(S_HSCROLL);
			if ((focusObject->zafRegion.Width() <= visibleRegion.Width()) ||
				(focusObject->zafRegion.left > visibleRegion.right ||
				focusObject->zafRegion.right < visibleRegion.left))
			{
				if(focusObject->zafRegion.left > visibleRegion.left || 
					focusObject->zafRegion.right < visibleRegion.right)
				{
					if (focusObject->zafRegion.left < visibleRegion.left)
					{
						scrollEvent.scroll.delta = focusObject->zafRegion.left - visibleRegion.left;
						Event(scrollEvent);
					}
					else if (focusObject->zafRegion.right > visibleRegion.right)
					{
						scrollEvent.scroll.delta = focusObject->zafRegion.right - visibleRegion.right;
						Event(scrollEvent);
					}
				}
			}

			if(focusObject->zafRegion.top > visibleRegion.top || 
				focusObject->zafRegion.bottom < visibleRegion.bottom)
			{
				scrollEvent.type = S_VSCROLL;
				if ((focusObject->zafRegion.Height() <= visibleRegion.Height()) ||
					(focusObject->zafRegion.top > visibleRegion.bottom ||
					focusObject->zafRegion.bottom < visibleRegion.top))
				{
					if (focusObject->zafRegion.top < visibleRegion.top)
					{
						scrollEvent.scroll.delta = focusObject->zafRegion.top - visibleRegion.top;
						Event(scrollEvent);
					}
					else if (focusObject->zafRegion.bottom > visibleRegion.bottom)
					{
						scrollEvent.scroll.delta = focusObject->zafRegion.bottom - visibleRegion.bottom;
						Event(scrollEvent);
					}
				}
			}
		}
	}

	return (invalidObject);
}

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

void ZafScrolledWindow::OSRegisterObject(void)
{
	ZafWindow::OSRegisterObject();
}

// ----- Stubs --------------------------------------------------------------

void ZafScrolledWindow::GetClip(ZafWindowObject *, ZafRegionStruct &, ZafRegionStruct &)
{
}

OSWindowID ZafScrolledWindow::OSScreenID(ZafScreenIDType type) const
{
	return ZafWindow::OSScreenID(type);
}

ZafEventType ZafScrolledWindow::OSEvent(const ZafEventStruct &event)
{
	if (editMode && event.InputType() == E_MOUSE)
		return (ZafWindowObject::Event(event));

	return ZafWindow::OSEvent(event);
}

ZafEventType ZafScrolledWindow::ScrollEvent(const ZafEventStruct &event)
{
	return event.type;
}

void ZafScrolledWindow::OSSize(void)
{
	// Defer to the base class.
	ZafWindow::OSSize();
}

