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

#include <z_mouse2.hpp>	// For DM_VIEW.
#include <z_plldn.hpp>
#include <z_stdio.hpp>
#include <z_string.hpp>

// ----- ZafPullDownMenu -------------------------------------------------------

ZafEventType ZafPullDownMenu::DispatchMouseEvent(const ZafEventStruct &event)
{
	return (ZafWindowObject::DispatchMouseEvent(event));
}

ZafWindowObject *ZafPullDownMenu::FindMouseObject(const ZafEventStruct &event)
{
	return (ZafWindowObject::FindMouseObject(event));
}

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

ZafEventType ZafPullDownMenu::DrawBorder(ZafRegionStruct &region, ZafEventType ccode)
{
	ZafPaletteStruct lightShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, 0);
	ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, 0);
	ZafPaletteStruct whiteShadow = lightShadow;

	// 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;

	int bottom = zafRegion.Height() - 1, right = zafRegion.Width() - 1;

	// Draw separator below menu.
	display->SetPalette(lightShadow);
	display->Line(0, bottom, right, bottom);
	display->Line(0, bottom - 3, right, bottom - 3);

	display->SetPalette(whiteShadow);
	display->Line(0, bottom - 1, right, bottom - 1);

	display->SetPalette(darkShadow);
	display->Line(0, bottom - 2, right, bottom - 2);

	region.bottom -= 2 * ZAF_BORDER_SIZE;

	return (ccode);
}
#endif

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

	// Check for zinc events.
	ZafWindowObject *object;
	switch (ccode)
	{
	// ----- Create messages -----
	case S_COMPUTE_SIZE:
		{
			// Call the base class to position the pull-down menu and its children.
			ccode = ZafWindow::Event(event);

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

#if defined(ZAF_GRAPHICS_MODE)
			zafRegion.bottom = zafRegion.top + display->cellHeight -
				display->preSpace - display->postSpace;
#elif defined(ZAF_TEXT_MODE)
			zafRegion.bottom = zafRegion.top;
#endif
			int left = 0, top = 0, menuRight = zafRegion.Width() - 1;

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

#if defined(ZAF_WIN95_STYLE)
			// Increase menu size so can put separator below.
			if (bordered)
				zafRegion.bottom += 2 * ZAF_BORDER_SIZE;
#endif
		}
		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.

			// Perform geometry management based on the new window size.
			ZafWindowObject *geometryManager = GetObject(ZAF_NUMID_GEOMETRY);
			if (geometryManager)
				geometryManager->Event(S_COMPUTE_SIZE);

			for (object = First(); object; object = object->Next())
				object->OSSize();
		}
		break;

	case L_VIEW:
		if (!Focus())
		{
			// Release mouse capture if not tracking.
			windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
			ccode = ZafWindow::Event(event);
			break;
		}
		// Continue to L_BEGIN_SELECT, etc., to allow tracking.

	case L_BEGIN_SELECT:
	case L_CONTINUE_SELECT:
	case L_END_SELECT:
		{
			ZafPositionStruct mousePosition = event.position;

			// Set the mouse capture as appropriate.
			if (ccode == L_BEGIN_SELECT)
			{
				// If the mouse is not already captured by this menu,
				// capture it and start tracking.
				if (windowManager->MouseEventRoute() != this)
					windowManager->CaptureMouse(this);
				else if (!clientRegion.Overlap(event.position))
				{
					// If it is already captured by this menu and the click
					// was not over the menu, stop the capture and let the
					// windowManager handle the event.
					windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
					windowManager->DispatchMouseEvent(event);
					break;
				}
			}
			else if (ccode == L_CONTINUE_SELECT)
			{
				// If the mouse isn't captured, ignore the continue select.
				if (windowManager->MouseEventRoute() != this)
					break;
			}
			else if (ccode == L_END_SELECT)
				// Release the capture.
				windowManager->CaptureMouse(ZAF_NULLP(ZafWindowObject));
			else if (ccode == L_VIEW)
				windowManager->CaptureMouse(this);

			// Over the client region?
			ZafRegionStruct windowClient = ClientRegion();
			// event.position is 0,0 based for the client region after it has been
			// dispatched.
			windowClient.HzShift(-windowClient.left);
			windowClient.VtShift(-windowClient.top);
			bool overClient = false;
			if (windowClient.Overlap(mousePosition))
				overClient = true;

			// Route to proper pull-down item if over the client region.
			ZafWindowObject *object = ZAF_NULLP(ZafWindowObject);
			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;
					}
			}
			// If not over the client region, check if over a pop-up menu.
			else
			{
				ZafWindowObject *rootObject = RootObject();
				ZafWindow *popup = DynamicPtrCast(windowManager->First(), ZafWindow);
				ZafPositionStruct osPosition;
				osPosition.Assign(event.osEvent.position.column, event.osEvent.position.line, ZAF_PIXEL);
				while(popup && popup != rootObject && !popup->zafRegion.Overlap(osPosition))
					popup = DynamicPtrCast(popup->Next(), ZafWindow);

				if (popup && popup != rootObject)
				{
					// Route to proper pop-up menu, if there is one.
					popup->DispatchMouseEvent(event);
				}
				else if (ccode == L_END_SELECT)
				{
					// Otherwise, if end select and not on part of the menu,
					// leave the menu.
					windowManager->Event(L_ALT_KEY);
				}
			}
		}
		break;

	case L_LEFT:
	case L_RIGHT:
		ccode = ZafWindow::Event((ccode == L_LEFT) ? L_PREVIOUS : L_NEXT);
		break;

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

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

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

ZafRegionStruct ZafPullDownMenu::MaxRegion(ZafWindowObject *, ZafVtJustify, ZafHzJustify)
{
	// Set up client region.
	ZafRegionStruct region;
	region.left = 0;
	region.top = 0;
	region.right = zafRegion.right - zafRegion.left;
#if defined(ZAF_GRAPHICS_MODE)
	region.bottom = zafRegion.bottom - zafRegion.top -
		(bordered ? 2 * ZAF_BORDER_SIZE : 0);
#elif defined(ZAF_TEXT_MODE)
	region.bottom = zafRegion.bottom - zafRegion.top;
#endif
	region.coordinateType = zafRegion.coordinateType;

	return (region);
}

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

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

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

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

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

