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

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

// ----- ZafPopUpMenu ----------------------------------------------------

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafPopUpMenu::DrawBorder(ZafRegionStruct &region, ZafEventType ccode)
{
	// Draw the object border.

	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(lightShadow);
	display->Line(region.left, region.top, region.right - 1, region.top);
	display->Line(region.left, region.top + 1, region.left, region.bottom - 1);

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

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

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

	region -= ZAF_BORDER_SIZE;

	return (ccode);
}
#endif

ZafEventType ZafPopUpMenu::Event(const ZafEventStruct &event)
{
	ZafEventType ccode = LogicalEvent(event);
	ZafWindowObject *object;

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_CREATE:
		{
			for (object = First(); object; object = object->Next())
//				if (object != current)
					object->Event(S_NON_CURRENT);
			ccode = ZafWindow::Event(event);
		}
		break;

	case S_COMPUTE_SIZE:
		{
			ccode = ZafWindow::Event(event);
			ZafRegionStruct newRegion = zafRegion;

			// Adjust the non-support object sizes.
			for (object = First(); object; object = object->Next())
				object->Event(S_COMPUTE_SIZE);

			int height = 0, width = 0, top = 0;
			for (object = First(); object; object = object->Next())
			{
				if (object->zafRegion.Height() + display->preSpace + display->postSpace > height)
					height = object->zafRegion.Height() + display->preSpace + display->postSpace;
				if (object->zafRegion.Width() > width)
					width = object->zafRegion.Width();
			}
			for (object = First(); object; object = object->Next())
			{
				object->zafRegion.left = 0;
				object->zafRegion.top = top;
#if defined(ZAF_GRAPHICS_MODE)
				object->zafRegion.bottom = top + height;
#elif defined(ZAF_TEXT_MODE)
				object->zafRegion.bottom = top;
#endif
				object->zafRegion.right = width;
				top += height;
			}

			// zafRegion.left and zafRegion.top are set by the constructor or
			// by the calling object (for instance, if a system button menu).
			newRegion.right = newRegion.left + width;
			newRegion.bottom = newRegion.top + Count() * height;

			if (Bordered())
			{
				newRegion.right += 2 * ZAF_BORDER_SIZE;
#if defined(ZAF_GRAPHICS_MODE)
				newRegion.bottom += 2 * ZAF_BORDER_SIZE;
#elif defined(ZAF_TEXT_MODE)
				newRegion.bottom += 1;
#endif
			}

			int menuHeight = newRegion.Height(), menuWidth = newRegion.Width();

			// Check for menus off the screen.
			int maxX = display->columns - 1;
			int maxY = display->lines - 1;
			if (parent)
			{
				if (!parent->IsA(ID_ZAF_POP_UP_ITEM) && newRegion.right >= maxX)
					newRegion.left = ZafMax(0, maxX - width);

				if (newRegion.bottom >= maxY)
				{
					if (parent->IsA(ID_ZAF_POP_UP_ITEM))
						newRegion.top = ZafMax(0, maxY - menuHeight);
					else
						newRegion.top = newRegion.top - parent->zafRegion.Height() - menuHeight - 1;
				}
				// One final check to make sure we don't cover the parent item.
/* START BLOCK COMMENT
**					if ((relative.top < parent->true.top && relative.top + height > parent->true.top) ||
**						(relative.top < parent->true.bottom && relative.top + height > parent->true.bottom) ||
**						(relative.left + width > maxX))
**						relative.left = (parent->true.right + width) > maxX ?
**							MaxValue(0, parent->true.left - width) : MaxValue(0, parent->true.right);
**					relative.left = MaxValue(0, relative.left);
**					relative.top = MaxValue(0, relative.top);
END BLOCK COMMENT */
			}
			newRegion.right = newRegion.left + menuWidth - 1;
			newRegion.bottom = newRegion.top + menuHeight - 1;

			SetRegion(newRegion);
		}
		break;

	case N_SIZE:
		// Finalize the sizing operation.  Don't pass S_COMPUTE_SIZE to
		// children to prevent them from sizing.  We already sized them
		// in S_COMPUTE_SIZE.
		for (object = First(); object; object = object->Next())
			object->OSSize();
		break;

	case L_PREVIOUS:
	case L_NEXT:
		ccode = S_UNKNOWN;
		break;

	case L_UP:
	case L_DOWN:
		ccode = ZafWindow::Event((ccode == L_UP) ? L_PREVIOUS : L_NEXT);
		break;

	case L_LEFT:
	case L_RIGHT:
		if (parent && parent->IsA(ID_ZAF_PULL_DOWN_ITEM))
		{
			ZafWindow *menu = DynamicPtrCast(parent->parent, ZafWindow);
			ZafWindowObject *menuCurrent;

			windowManager->Event(S_CLOSE_TEMPORARY);
		   	menu->Event(event);
			menuCurrent = menu->Current();
			if (menuCurrent)
				menuCurrent->Event(L_DOWN);
		}
		else
			ccode = ZafWindow::Event(event);
		break;

	case S_ADD_OBJECT:
	case S_SUBTRACT_OBJECT:
		if (parent)
			ccode = parent->Event(event);
		else
			ccode = ZafWindow::Event(event);
		break;

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

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

void ZafPopUpMenu::GetClip(ZafWindowObject *object, ZafRegionStruct &clip,
	ZafRegionStruct &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);

	// Adjust for the client region if the object is in the client area.
	if (object != this)
	{
		viewPort.left += clientRegion.left;
		viewPort.top += clientRegion.top;
		viewPort.right += clientRegion.left;
		viewPort.bottom += clientRegion.top;

		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 + clientRegion.Width() - 1);
		clip.bottom = ZafMin(clip.bottom, clip.top + clientRegion.Height() - 1);
	}
}

ZafWindowObject *ZafPopUpMenu::Subtract(ZafWindowObject *object)
{
	// Defer to the base class.
	return (ZafWindow::Subtract(object));
}

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

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

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

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

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