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

#include <z_string.hpp>
#include <z_icon1.hpp>
#include <z_utils.hpp>
#include <z_mdiwin.hpp>
#include "m_button.hpp"

// ----- ZafIcon ------------------------------------------------------------

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafIcon::Draw(const ZafEventStruct &, ZafEventType ccode)
{
	// Make sure there is a screenID.
	if (!screenID)
		return (S_ERROR);

	// Compute the actual draw region.
	ZafPaletteState state = PaletteState();
	ZafRegionStruct drawRegion = BeginDraw();

	// Draw the focus.
	DrawFocus(drawRegion, Focus() ? S_CURRENT : S_NON_CURRENT);

	// Draw the shadow.
	if (Bordered())
		DrawShadow(drawRegion, (Depressed() || Selected()) ? -ZAF_SHADOW_SIZE : ZAF_SHADOW_SIZE, ccode);
	display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, state));
	display->Rectangle(drawRegion, 0, true);
	drawRegion -= ZAF_MARGIN_SIZE;

	// Clip the region.
	display->SetClipRegion(drawRegion);

	// Compute the draw regions.
	ZafRegionStruct imageRegion, textRegion;
	if (iconData)
		imageRegion.Assign(1, 1, iconData->Width(), iconData->Height(), ZAF_PIXEL);
	else
		imageRegion.Assign(1, 1, 0, 0, ZAF_PIXEL);
	if (stringData)
		textRegion = display->TextSize(*stringData);
	else
		textRegion.Assign(1, 1, 0, 0, ZAF_PIXEL);
	ComputeDrawRegions(drawRegion, imageRegion, textRegion, ZAF_MARGIN_SIZE);

	// Draw the icon.
	if (iconData)
	{
		display->SetPalette(LogicalPalette(ZAF_PM_OUTLINE, state));
		display->Icon(imageRegion.left, imageRegion.top, *iconData);
	}

	// Draw the title.
	if (stringData)
	{
		display->SetPalette(LogicalPalette(ZAF_PM_TEXT, state));
		display->Text(textRegion, stringData->Text(), -1, hzJustify, ZAF_VT_CENTER, hotKeyIndex);
	}

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

ZafEventType ZafIcon::DrawFocus(ZafRegionStruct &region, ZafEventType ccode)
{
	// Defer to the base class.
	return (ZafButton::DrawFocus(region, ccode));
}

ZafEventType ZafIcon::DrawShadow(ZafRegionStruct &region, int tDepth, ZafEventType ccode)
{
	// Check for a system object.
	if (!tDepth)
		return (S_ERROR);
	else if (!SystemObject())
		return (parent->DrawShadow(region, tDepth, ccode));

	// Draw the shadow and update the region.
	ZafPaletteState state = PaletteState();
	ZafPaletteStruct topShadow = LogicalPalette(ZAF_PM_LIGHT_SHADOW, state);
	ZafPaletteStruct bottomShadow = LogicalPalette(ZAF_PM_DARK_SHADOW, state);
	_XmDrawShadows(XtDisplay(screenID), XtWindow(screenID),
		topShadow.osPalette, bottomShadow.osPalette, region.left,
		region.top, region.Width(), region.Height(), 2 * ZafAbs(tDepth),
		XmSHADOW_ETCHED_OUT);
	region -= 2 * ZafAbs(tDepth);

	// Return the status.
	return (ccode);
}
#endif

ZafEventType ZafIcon::Event(const ZafEventStruct &event)
{
	// Check for motif events.
	ZafEventType ccode = event.type;
	if (iconType == ZAF_MINIMIZE_ICON && NumberID() != ZAF_NUMID_MIN_ICON)
	{
		if (ccode == S_COMPUTE_SIZE)
			zafRegion.left = zafRegion.top = zafRegion.right = zafRegion.bottom = -1;
		else if (ccode == S_INITIALIZE || ccode == S_REGISTER_OBJECT)
			ZafWindowObject::Event(event);
		return (ccode);
	}

	// Check for zinc events.
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		ccode = ZafButton::Event(event);
		break;

	case S_COMPUTE_SIZE:
		// Compute the size from the default window event.
		ccode = ZafWindowObject::Event(event);

		// Recompute the desired zafRegion location.
		if (AutoSize())
		{
			// Determine the minimum size for the icon.
			zafRegion.right = zafRegion.left - 1;
			zafRegion.bottom = zafRegion.top - 1;
			if (iconData)
			{
				zafRegion.right += iconData->Width();
				zafRegion.bottom += iconData->Height();
			}

			// Add the minimum size for text.
			if (stringData && stringData->Char(0))
			{
				display->SetPalette(LogicalPalette(ZAF_PM_TEXT, PaletteState()));
				ZafRegionStruct region = display->TextSize(stringData->Text());
				if (HzJustify() == ZAF_HZ_CENTER)
				{
					zafRegion.bottom += region.Height() + ZAF_MARGIN_SIZE; // space between text and icon.
					if (zafRegion.Width() < region.Width())
						zafRegion.right = zafRegion.left + region.right - region.left;
				}
				else
				{
					zafRegion.right += region.Width() + ZAF_MARGIN_SIZE; // space between text and icon.
					if (zafRegion.Height() < region.Height())
						zafRegion.bottom = zafRegion.top + region.bottom - region.top;
				}
			}

			// Adjust for general spacing.
			zafRegion.right += 2 * ZAF_MARGIN_SIZE;
			zafRegion.bottom += 2 * ZAF_MARGIN_SIZE;
			// Adjust for border.
			if (Bordered())
			{
				zafRegion.right += 4 * ZAF_SHADOW_SIZE;
				zafRegion.bottom += 4 * ZAF_SHADOW_SIZE;
			}
			// Adjust for focus highlight.
			zafRegion.right += 2 * ZAF_BORDER_SIZE;
			zafRegion.bottom += 2 * ZAF_BORDER_SIZE;
		}
		break;

	case S_MDI_MINIMIZE:
		if (iconType == ZAF_MINIMIZE_ICON && NumberID() == ZAF_NUMID_MIN_ICON)
		{
 			ZafWindow *window = ZAF_NULLP(ZafWindow); 
			if (((ZafMDIWindow *)parent)->MDIType() != ZAF_MDI_PARENT)
				window = DynamicPtrCast(parent, ZafWindow);
			if (window && window->Minimized())
			{
				parent = parent->parent;
				supportObject = false;
				oldRegion.Assign(-1, -1, -1, -1, ZAF_PIXEL);

				const ZafIChar *text = Text();
				if (!text || !text[0])
					SetText(window->Text());

				ZafButton::SetSendMessageWhenSelected(true);
				ZafButton::SetValue(S_MDI_MINIMIZE);
				ZafButton::OSRegisterObject();
				XtTranslations translationTable = XtParseTranslationTable("<Btn1Motion>:ZafMotion()");
				XtOverrideTranslations(screenID, translationTable);
				ZafButton::OSUpdatePalettes(ZAF_PM_ANY_TYPE, ZAF_PM_LIGHT_SHADOW | ZAF_PM_DARK_SHADOW);
				Event(S_COMPUTE_SIZE);
				OSSize();
			}
			else if (screenID)
			{
				ZafButton::Event(S_DESTROY);

				parent = next ? Next()->parent : previous ? Previous()->parent : 0;
				supportObject = true;
				parent->Event(S_MDI_MINIMIZE);
			}
		}
		break;

	case L_BEGIN_SELECT:
		if (iconType == ZAF_MINIMIZE_ICON && NumberID() == ZAF_NUMID_MIN_ICON)
		{
			if (!Focus() && !Noncurrent())
				SetFocus(true);
			if (event.rawCode & S_DOUBLE_CLICK)
				Event(L_DOUBLE_CLICK);
			else
				Modify(event);
		}
		else
			ccode = ZafButton::Event(event);
		break;

	// ----- Data transfer -----
	case S_COPY_DATA:
		{
		ZafWindowObject *object = event.windowObject;
		ZafIcon *icon = DynamicPtrCast(object, ZafIcon);
		if (icon)
			iconData->SetIcon(*icon->IconData());
		}
		break;

	case S_SET_DATA:
		{
		ZafWindowObject *object = event.windowObject;
		if (object)
		{
			ZafIcon *icon = DynamicPtrCast(object, ZafIcon);
			if (icon)
				SetIconData(icon->IconData());
		}
		else
			SetIconData(new ZafIconData(*iconData));
		}
		break;

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

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

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

bool ZafIcon::SetDisabled(bool setDisabled)
{
	// Defer to the base class.
	return (ZafWindowObject::SetDisabled(setDisabled));
}

bool ZafIcon::SetSelected(bool setSelected)
{
	// Defer to the base class.
	return (ZafWindowObject::SetSelected(setSelected));
}

bool ZafIcon::SetVisible(bool setVisible)
{
	// Defer to the base class.
	return (ZafWindowObject::SetVisible(setVisible));
}

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

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

void ZafIcon::OSRegisterObject(void)
{
	// Check for a minimize icon.
	if (iconType == ZAF_MINIMIZE_ICON && NumberID() != ZAF_NUMID_MIN_ICON)
	{
		// Specify the iconic image and title.
		OSSetImage();
		OSSetText();
	}
	else if (iconType != ZAF_MINIMIZE_ICON)
		ZafButton::OSRegisterObject();
}

ZafError ZafIcon::OSSetImage(void)
{
	// The specified method of icon specification does not work.  Thus,
	// the minimize icon must be initialized by hand.
	Widget shell = parent ? parent->OSScreenID(ZAF_SHELLID) : 0;
	if (iconType == ZAF_MINIMIZE_ICON && NumberID() != ZAF_NUMID_MIN_ICON && iconData && shell)
	{
		Window iconWindow = 0;
		XtVaGetValues(shell, XtNiconWindow, &iconWindow, 0);
		if (!iconWindow)
			iconWindow = XCreateSimpleWindow(((ZafScreenDisplay *)display)->xDisplay,
				RootWindow(((ZafScreenDisplay *)display)->xDisplay, ((ZafScreenDisplay *)display)->xScreenNumber), 0, 0,
				iconData->width, iconData->height, 0,
				CopyFromParent, CopyFromParent);

		display->ConvertToOSIcon(*iconData);
		if (!iconWindow)
			XtVaSetValues(shell, XtNiconPixmap, iconData->handle, 0);
		else
			XtVaSetValues(shell, XtNiconWindow, iconWindow, 0);
		XSetWindowBackgroundPixmap(((ZafScreenDisplay *)display)->xDisplay, iconWindow, iconData->handle);
		XClearWindow(((ZafScreenDisplay *)display)->xDisplay, iconWindow);
	}
	else if (screenID)
		RedisplayData();
	return (ZAF_ERROR_NONE);
}

ZafError ZafIcon::OSSetText(void)
{
	Widget shell = parent ? parent->OSScreenID(ZAF_SHELLID) : 0;
	if (iconType == ZAF_MINIMIZE_ICON && NumberID() != ZAF_NUMID_MIN_ICON && stringData && shell)
		XtVaSetValues(shell, XtNiconName, stringData->Text(), 0);
	else if (screenID)
	{
		// Check for auto-size.
		if (AutoSize())
		{
			ZafRegionStruct tRegion = zafRegion;
			Event(S_COMPUTE_SIZE);
			if (tRegion != zafRegion)
				OSSize();
			else
				RedisplayData();
		}
		else
			RedisplayData();
	}
	return (ZAF_ERROR_NONE);
}

void ZafIcon::OSSize(void)
{
	// Defer to the base class.
	ZafWindowObject::OSSize();
}

ZafError ZafIcon::OSUpdatePalettes(ZafPaletteType zafTypes, ZafPaletteType osTypes)
{
	// Make sure the widget can be updated.
	if (!screenID || !AutomaticUpdate() || !SystemObject())
		return (ZAF_ERROR_INVALID);

	// Defer to the base class.
	ZafError tError = ZafWindowObject::OSUpdatePalettes(zafTypes, osTypes);
	if (AutoSize())
	{
		ZafRegionStruct tRegion = zafRegion;
		Event(S_COMPUTE_SIZE);
		if (tRegion != zafRegion)
			OSSize();
	}
	return (tError);
}

