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

#include <z_error.hpp>
#include <z_htips.hpp>
#include <z_mouse2.hpp>	// For DM_VIEW.
#include <z_popup.hpp>
#include <z_string.hpp>

#define ZAF_POPUP_INFO
#include "img_def.cpp"

const int ITEM_OFFSET = 4;

// ----- ZafPopUpItem ----------------------------------------------------

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafPopUpItem::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Compute the actual draw region.
	ZafPaletteState state = PaletteState();
	ZafRegionStruct drawRegion = BeginDraw();

	display->SetClipRegion(event.region);

	if (Bordered())
		DrawBorder(drawRegion, ccode);

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

	display->Rectangle(drawRegion, 0, true);

	if (itemType == ZAF_SEPARATOR)
	{
		drawRegion.top = (drawRegion.top + drawRegion.bottom) / 2;

		ZafPaletteStruct whiteShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, ZAF_PM_ANY_STATE);
		ZafPaletteStruct darkShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, ZAF_PM_ANY_STATE);

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

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

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

		// Update the display.
		EndDraw();
		return (ccode);
	}

	drawRegion.left += ITEM_OFFSET;

	// Draw the check mark.
	if (Selected() && allowToggling)
	{
		if (Focus())
			bitmapData = popupCheckCurrentBitmap;
		else
			bitmapData = popupCheckBitmap;

		int top = (drawRegion.Height() - bitmapData->height) / 2;

		display->Bitmap(drawRegion.left, top, *bitmapData);
	}

	drawRegion.left += 2 * display->cellWidth;

	ZafPaletteStruct textPalette = LogicalPalette(ZAF_PM_TEXT, state);

	const ZafIChar *text = Text();
	const ZafIChar *tabText = text ? strchr(text, '\t') : 0;
	int tabTextOffset = 0;

	// Handle tab character.
	if (tabText)
	{
		tabTextOffset = zafRegion.Width() - (display->TextSize(tabText,
			(int)(tabText - text)).Width() + 2 * display->cellWidth);
	}
		
	if (disabled)
	{
		display->SetPalette(textPalette);

		// If disabled, chisel color is in palette background.
		display->SetForeground(textPalette.colorBackground);

		// Draw chisel.
		ZafRegionStruct chiselRegion = drawRegion;
		chiselRegion.HzShift(1);
		chiselRegion.VtShift(1);
		display->Text(chiselRegion.left, chiselRegion.top, chiselRegion.right,
			chiselRegion.bottom, text, tabText ? (int)(tabText - text) : -1,
			HzJustify(), VtJustify(), hotKeyIndex, false);
		if (tabText)
			display->Text(chiselRegion.left + tabTextOffset, chiselRegion.top,
				chiselRegion.right, chiselRegion.bottom,
				tabText + 1, -1, HzJustify(), VtJustify(), hotKeyIndex, false);

		// Draw text.
		display->SetForeground(textPalette.colorForeground);
		display->Text(drawRegion.left, drawRegion.top, drawRegion.right,
			drawRegion.bottom, text, tabText ? (int)(tabText - text) : -1,
			HzJustify(), VtJustify(), hotKeyIndex, false);
		if (tabText)
			display->Text(drawRegion.left + tabTextOffset, drawRegion.top,
				drawRegion.right, drawRegion.bottom, tabText + 1, -1, HzJustify(),
				VtJustify(), hotKeyIndex, false);

	}
	else
	{
		display->SetPalette(textPalette);
		display->Text(drawRegion.left, drawRegion.top, drawRegion.right,
			drawRegion.bottom, text, tabText ? (int)(tabText - text) : -1, HzJustify(),
			VtJustify(), hotKeyIndex, false);

		if (tabText)
			display->Text(drawRegion.left + tabTextOffset, drawRegion.top,
				drawRegion.right, drawRegion.bottom, tabText + 1, -1, HzJustify(),
				VtJustify(), hotKeyIndex, false);
	}

	// Draw the right arrow.
	if (menu.First())
	{
		if (Focus())
			bitmapData = popupArrowCurrentBitmap;
		else
			bitmapData = popupArrowBitmap;

		int left = drawRegion.right - bitmapData->width;
		int top = (drawRegion.Height() - bitmapData->height) / 2;

		display->Bitmap(left, top, *bitmapData);
	}

	EndDraw();
	return (ccode);
}
#endif

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

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		{
/* START BLOCK COMMENT
**				// Adjust for MDI child menu options.
**				for (ZafWindowObject *object = this; object; object = object->parent)
**				{
**					ZafWindow *window = DynamicPtrCast(object, ZafWindow);
**					if (window && window->WindowType() == ZafMDIWindow && object->parent)
**					{
**						if (Value() < 0)
**							SetValue(Value() + S_MDICHILD_EVENT);
**						else
**							SetValue(Value() + L_MDICHILD_EVENT);
**						break;
**					}
**				}
END BLOCK COMMENT */
            menu.SetBordered(true);
            menu.SetTemporary(true);
            menu.SetDestroyable(false);
            ZafButton::Event(event);
		}
		break;

	case S_COMPUTE_SIZE:
		ccode = ZafButton::Event(event);
		display->SetPalette(LogicalPalette(ZAF_PM_TEXT, ZAF_PM_ANY_STATE));
		if (itemType == ZAF_SEPARATOR)
		{
#if defined(ZAF_GRAPHICS_MODE)
			zafRegion.bottom = zafRegion.top + display->cellHeight / 2;
#elif defined(ZAF_TEXT_MODE)
			zafRegion.bottom = zafRegion.top;
#endif
			zafRegion.right = zafRegion.left;
		}
		else
		{
#if defined(ZAF_GRAPHICS_MODE)
			zafRegion.bottom = zafRegion.top + display->TextSize(Text()).Height();
#elif defined(ZAF_TEXT_MODE)
			zafRegion.bottom = zafRegion.top;
#endif
			// Pad a little for a check mark.
			zafRegion.right = zafRegion.left + display->TextSize(Text()).Width() + display->cellHeight;

			// Pad a little for the right arrow.
			if (menu.First())
				zafRegion.right += display->cellHeight / 2;
		}
		break;

	case S_ADD_OBJECT:
		Add(event.windowObject);
		break;

	case S_SUBTRACT_OBJECT:
		Subtract(event.windowObject);
		break;

	case S_NON_CURRENT:
		// Make sure menu.current doesn't get "stuck" in a focus state.
		if (menu.Current())
			menu.Current()->Event(event);
		ccode = ZafButton::Event(event);
		break;

	// ----- Action messages -----
	case L_VIEW:
		{
			// Send event to the pull-down menu so it can process "drags" using
			// its algorithm.  If pull-down menu is already capturing the mouse
			// don't send the event, since this would result in an infinite loop.
			ZafWindowObject *pWindow;
			for (pWindow = parent; pWindow && !pWindow->IsA(ID_ZAF_PULL_DOWN_MENU);
				pWindow = pWindow->parent)
				;
			if (pWindow && windowManager->MouseEventRoute() != pWindow)
			{
				pWindow->Event(event);

				// break, since the event will come back from the pull-down menu.
				break;
			}
		}

	case L_CONTINUE_SELECT:
		{
		if (disabled)
			break;
		SetFocus(true);

		ZafPositionStruct mousePosition = event.position;
		mousePosition.line += zafRegion.top;
		mousePosition.column += zafRegion.left;
		if	(windowManager->Index(parent) != -1 && zafRegion.Overlap(mousePosition))
		{
			ZafWindow *popup = DynamicPtrCast(windowManager->First(), ZafWindow);
			while(popup && popup != parent && popup != &menu)
				if (popup->Temporary())
				{
					windowManager->Event(ZafEventStruct(S_CLOSE_TEMPORARY));
					popup = DynamicPtrCast(windowManager->First(), ZafWindow);
				}
			if (menu.First() && windowManager->Index(&menu) == -1)
				Event(ZafEventStruct(L_RIGHT));
		}
		}
		break;

	case L_BEGIN_SELECT:
		{
		if (menu.First())
			Event(L_SELECT);

		// Send event to the pull-down menu so it can process drags using
		// its algorithm.  If pull-down menu is already capturing the mouse
		// don't send the event, since this would result in an infinite loop.
		ZafWindowObject *pWindow;
		for (pWindow = parent; pWindow && !pWindow->IsA(ID_ZAF_PULL_DOWN_MENU);
			pWindow = pWindow->parent)
			;
		if (pWindow && windowManager->MouseEventRoute() != pWindow)
			pWindow->Event(event);
		}
		break;

	case L_END_SELECT:
	case L_SELECT:
	case L_LEFT:
	case L_RIGHT:
		if (windowManager->Index(parent) == -1)
			ccode = S_UNKNOWN;
		else if ((ccode == L_SELECT || ccode == L_END_SELECT) &&
			menu.First() && windowManager->Index(&menu) != -1)
			break;
		else if ((ccode == L_RIGHT || ccode == L_SELECT || ccode == L_END_SELECT) && menu.First())
		{
			// Put up submenu.
#if defined(ZAF_GRAPHICS_MODE)
	 		menu.zafRegion.coordinateType = ZAF_PIXEL;
#elif defined(ZAF_TEXT_MODE)
			menu.zafRegion.coordinateType = ZAF_CELL;
#endif
			ZafPositionStruct origin;
			origin.column = zafRegion.right;
			origin.line = zafRegion.top;
			origin.coordinateType = zafRegion.coordinateType;
			if (menu.Bordered())
				origin.line -= ZAF_BORDER_SIZE;
			origin = parent->ConvertToOSPosition(this, &origin);
			menu.zafRegion.left = parent->zafRegion.right + 1;
			menu.zafRegion.top = origin.line;
			if (menu.Current())
				menu.Current()->SetFocus(true);
			windowManager->Add(&menu);
		}
		else if (ccode == L_SELECT || ccode == L_END_SELECT)
		{
			if (!Disabled() && allowToggling)
				ToggleSelected();

			// Close menu(s).
			if (parent && parent == windowManager->First() &&
				DynamicPtrCast(parent, ZafWindow)->Temporary() &&
				!DynamicPtrCast(parent, ZafWindow)->Destroyable())
					windowManager->Event(L_ALT_KEY);
			else if (parent && parent == windowManager->First() &&
				DynamicPtrCast(parent, ZafWindow)->Temporary())
			{
				for (ZafWindowObject *object = parent; object &&
					DynamicPtrCast(object, ZafWindow)->Temporary();
					object = object->parent)
					eventManager->Put(S_CLOSE_TEMPORARY, Q_BEGIN);
			}

			// Call user callback.
			(this->*memberUserFunction)(event, L_SELECT);

		}
		// Close one level of pop-up menu if more than one is open.
		else if (ccode == L_LEFT && parent->parent && parent->parent->IsA(ID_ZAF_POP_UP_ITEM))
			windowManager->Event(S_CLOSE_TEMPORARY);
		// Arrowing around.  Close pop-up menus, shift on the
		// pull-down menu and open that menu.
		else
		{
			for (ZafWindowObject *object = windowManager->First();
				object && DynamicPtrCast(object, ZafWindow)->Temporary();
				object = windowManager->First())
				windowManager->Event(S_CLOSE_TEMPORARY);
			eventManager->Put(ccode);
			eventManager->Put(L_DOWN);
		}
		break;

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

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

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

bool ZafPopUpItem::SetDisabled(bool setDisabled)
{
	return (ZafButton::SetDisabled(setDisabled));
}

bool ZafPopUpItem::SetSelected(bool tSelected)
{
	return (ZafWindowObject::SetSelected(tSelected));
}

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

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

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

void ZafPopUpItem::OSRegisterObject(void)
{
	ZafButton::OSRegisterObject();
}

ZafError ZafPopUpItem::OSSetText(void)
{
	return (ZafButton::OSSetText());
//	return (ZAF_ERROR_NONE);
}

void ZafPopUpItem::OSSize(void)
{
	ZafWindowObject::OSSize();
}

ZafError ZafPopUpItem::OSUpdatePalettes(ZafPaletteType zafTypes, 
 ZafPaletteType osTypes)
{
	// Defer to the base class.
	ZafError tError = ZafButton::OSUpdatePalettes(zafTypes, osTypes);
	return (tError);
}

