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

#include <z_border.hpp>
#include <z_mouse2.hpp>

// ----- ZafBorder ---------------------------------------------------------

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafBorder::Draw(const ZafEventStruct &, ZafEventType ccode)
{
	// Compute the actual draw region.
	BeginDraw();

	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, 0);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, 0);
	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;

	ZafRegionStruct region = parent->zafRegion;
	int outsideRight = region.Width() - 1, outsideBottom = region.Height() - 1;

	// Fill the border region. Since the border uses an outside region, its
	// zafRegion is the *inside* edge of the border's region. The border's
	// origin (0, 0) is at the window's origin.

	display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE));

	// Top of border.
	display->Rectangle(2, 2, outsideRight - 2, zafRegion.top - 1, 0, true);

	// Left of border.
	display->Rectangle(2, zafRegion.top - 1, zafRegion.left - 1,
		zafRegion.bottom + 1, 0, true);

	// Bottom of border.
	display->Rectangle(2, zafRegion.bottom + 1, outsideRight - 2,
		outsideBottom - 2, 0, true);

	// Right of border.
	display->Rectangle(zafRegion.right + 1, zafRegion.top - 1,
		outsideRight - 2, zafRegion.bottom + 1, 0, true);

	display->SetPalette(lightShadow);

	// Top of border.
	display->Line(0, 0, outsideRight, 0);

	// Left of border.
	display->Line(0, 0, 0, outsideBottom);

	display->SetPalette(whiteShadow);

	// Top of border.
	display->Line(1, 1, outsideRight - 2, 1);

	// Left of border.
	display->Line(1, 1, 1, outsideBottom - 1);

	display->SetPalette(blackShadow);

	// Bottom of border.
	display->Line(0, outsideBottom, outsideRight, outsideBottom);

	// Right of border.
	display->Line(outsideRight, 0, outsideRight, outsideBottom);

	display->SetPalette(darkShadow);

	// Bottom of border.
	display->Line(1, outsideBottom - 1, outsideRight - 1, outsideBottom - 1);

	// Right of border.
	display->Line(outsideRight - 1, 1, outsideRight - 1, outsideBottom - 1);

	EndDraw();

	return (ccode);
}
#endif

ZafEventType ZafBorder::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
#if defined(ZAF_GRAPHICS_MODE)
		SetWidth(4);
#elif defined(ZAF_TEXT_MODE)
		SetWidth(1);
#endif
		ccode = ZafWindowObject::Event(event);
		break;

	case S_COMPUTE_SIZE:
		ZafWindowObject::Event(event);
		zafRegion -= Width();
		break;

	// ----- Display messages -----
	case S_REDISPLAY_REGION:
	case S_REDISPLAY:
	case S_REDISPLAY_DATA:
		if (AutomaticUpdate())
		{
			ZafRegionStruct tRegion = parent->zafRegion;
			tRegion.VtShift(-tRegion.top);
			tRegion.HzShift(-tRegion.left);
			OSInvalidateRegion(&tRegion, (ccode == S_REDISPLAY_DATA));

//			ZafWindowObject::Event(S_REDISPLAY);
		}
		break;

	// ----- Action messages -----
	case L_BEGIN_SELECT:
	case L_VIEW:
		{
			ZafWindow *parentWindow = DynamicPtrCast(parent, ZafWindow);

			ZafDeviceImage image = DM_VIEW;

			// Can't size if the window is non-sizeable, maximized, or minimized.
			if (parentWindow->Sizeable() && !parentWindow->Maximized() &&
				!parentWindow->Minimized())
			{
				ZafPositionStruct mousePosition = event.position;
				mousePosition.line += zafRegion.top;
				mousePosition.column += zafRegion.left;
				ZafRegionStruct region = zafRegion;

				// Adjust the region to allow cellHeight-size grabbing area in
				// the corners of the window.
		 		region -= display->cellHeight;

#if defined(ZAF_GRAPHICS_MODE)
				// If the window is too small, allow for a smaller corner
				// grabbing area.
				if (region.top >= region.bottom)
				{
					region.top = zafRegion.top + zafRegion.Height() / 2;
					region.bottom = zafRegion.bottom - zafRegion.Height() / 2;
				}
#endif

				// Determine where the mouse is overlapping the border.
				ZafRawCode sizeFlags = 0;
				if (mousePosition.column <= region.left)
					sizeFlags |= ZAF_SIZE_LEFT;
				else if (mousePosition.column >= region.right)
					sizeFlags |= ZAF_SIZE_RIGHT;
				if (mousePosition.line <= region.top)
					sizeFlags |= ZAF_SIZE_TOP;
				else if (mousePosition.line >= region.bottom)
					sizeFlags |= ZAF_SIZE_BOTTOM;

				// If the mouse is just being clicked, its image has already been
				// updated, so just send the size message to the window.
				if (ccode == L_BEGIN_SELECT)
				{
					ZafEventStruct sizeEvent = event;
					sizeEvent.type = S_SIZE_MODE;
					sizeEvent.rawCode = sizeFlags;
					parent->Event(sizeEvent);
					windowManager->CaptureMouse(this);
					break;
				}

				// Determine which mouse image is appropriate.
				if ((SizeLeft(sizeFlags) && SizeTop(sizeFlags)) ||
			    	(SizeRight(sizeFlags) && SizeBottom(sizeFlags)))
					image = DM_TOP_LEFT_CORNER;
				else if ((SizeLeft(sizeFlags) && SizeBottom(sizeFlags)) ||
					(SizeRight(sizeFlags) && SizeTop(sizeFlags)))
					image = DM_TOP_RIGHT_CORNER;
				else if (SizeLeft(sizeFlags) || SizeRight(sizeFlags))
					image = DM_LEFT_SIDE;
				else if (SizeTop(sizeFlags) || SizeBottom(sizeFlags))
					image = DM_TOP_SIDE;
			}

			// Update the mouse image.
			eventManager->SetDeviceState(E_MOUSE, image);
		}
		break;

	case L_END_SELECT:
	case L_CONTINUE_SELECT:
		if (windowManager->MouseEventRoute() == this)
			parent->Modify(event);
		if (ccode == L_END_SELECT)
			windowManager->CaptureMouse(0);
		break;

	// ----- Unknown or error messages -----
	default:
        ccode = ZafWindowObject::Event(event);
        break;
	}

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

void ZafBorder::GetClip(ZafWindowObject *, ZafRegionStruct &clip,
	ZafRegionStruct &viewPort)
{
	if (parent)
		parent->GetClip(this, clip, viewPort);

	viewPort.left += zafRegion.left;
	viewPort.top += zafRegion.top;
	viewPort.right += zafRegion.left;
	viewPort.bottom += zafRegion.top;

	// Adjust for the fact that the border is an outside region.
	viewPort += Width();
}

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

ZafError ZafBorder::OSGetWidth(void)
{
	return (ZAF_ERROR_NONE);
}

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

void ZafBorder::OSRegisterObject(void)
{
	ZafWindowObject::OSRegisterObject();
}

ZafError ZafBorder::OSSetWidth(void)
{
	return (ZAF_ERROR_NONE);
}

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

	if (!screenID)
		return;

	oldRegion = zafRegion;

	if (AutomaticUpdate() && Visible())
	{
		ZafRegionStruct clip = parent->zafRegion;
		clip.HzShift(-clip.left);
		clip.VtShift(-clip.top);
		windowManager->OSInvalidateObject(&clip, this);
	}

	Event(N_SIZE);
}

ZafError ZafBorder::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
	// Skip the button level.
	return (ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes));
}

