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

#include <z_stdlib.hpp>
#include <z_htips.hpp>
#include <z_string.hpp>
#include "m_popup.hpp"

// ----- MtfCascadeItem widget definition -----------------------------------

XmOffsetPtr MtfCascadeItem::offsets;

XtActionsRec MtfCascadeItem::action[] =
{
	{ "ZafHelp", 	(XtActionProc)help }
};

char MtfCascadeItem::translations[] =
	"<Key>F1:		ZafHelp()\n\
	 <Key>osfHelp:	ZafHelp()";

MtfCascadeItemClassRec MtfCascadeItem::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmCascadeButtonClassRec,	// superclass
		"ZafCascadeItem", 						// class_name
		sizeof(MtfCascadeItemPart),			// mtfObject_size (data part)
		MtfCascadeItem::classInitialize,		// class_initialize
		0,										// class_part_initialize
		false,									// class inited
		0,										// initialize
		0,										// initialize_hook
		XtInheritRealize,						// realize
		action, 								// actions
		XtNumber(action), 						// num_actions
		0, 										// resources
		0, 										// num_resources
		NULLQUARK,								// xrm_class
		true,									// compress_motion
		XtExposeCompressMultiple,				// compress_exposure
		true,									// compress_enterleave
		false,									// visible_interest
		0, 										// destroy
		XtInheritResize,						// resize
		(XtExposeProc)expose,					// expose
		0,										// set_values
		0, 										// set_values_hook
		XtInheritSetValuesAlmost,				// set_values_almost
		0, 										// get_values_hook
		XtInheritAcceptFocus,					// accept_focus
		XtVersionDontCheck,					// version
		0, 										// callback_private
		XtInheritTranslations,					// tm_table
		XtInheritQueryGeometry, 				// query_geometry
		XtInheritDisplayAccelerator,			// display_accelerator
		0,										// extension
	},
	// --- XmPrimitiveClassPart ---
	{
		(XtWidgetProc)highlight,				// border_highlight
		(XtWidgetProc)unhighlight,				// border_unhighlight
		XtInheritTranslations,					// translations
		(XtActionProc)_XtInherit,				// arm_and_activate
		0,										// syn_resources
		0,										// num_syn_resources
		0										// extension
	},
	// --- XmLabelClassPart ---
	{
		XmInheritWidgetProc,					// setOverrideCallback
		XmInheritMenuProc,						// menuProcs
		XtInheritTranslations,					// translations
		0										// extension
	},
	// --- XmCascadeButtonClassPart ---
	{
		0										// extension
	},
	// --- MtfCascadeItemClassPart ---
	{
		0									// extension
	}
};

void MtfCascadeItem::activate(MtfCascadeItem *, ZafPopUpItem *object, XmAnyCallbackStruct *callback)
{
	ZafEventStruct event(L_SELECT, callback->event);
	object->Event(event);
}

void MtfCascadeItem::classInitialize()
{
	XmResolvePartOffsets((WidgetClass) &(MtfCascadeItem::classRecord),
	 &(MtfCascadeItem::offsets));
}

void MtfCascadeItem::expose(MtfCascadeItem *mtfObject, XEvent *xEvent, Region xRegion)
{
	// Draw the object.
	ZafEventStruct event(E_MOTIF, xEvent);
	if (GetZincObject(mtfObject)->OSDraw())
		event.data = xRegion;
	else
	{
	XRectangle xRect;
	XClipBox(xRegion, &xRect);
  	event.region.Assign(xRect.x, xRect.y, xRect.width, xRect.height, ZAF_PIXEL);
	}
	GetZincObject(mtfObject)->Draw(event, E_MOTIF);
}

void MtfCascadeItem::highlight(MtfCascadeItem *mtfObject)
{
	// This is the best place to hook current messages.
	GetZincObject(mtfObject)->Event(N_CURRENT);

	// Defer drawing to the base class.
	(*xmCascadeButtonClassRec.primitive_class.border_highlight)((Widget)mtfObject);
}

void MtfCascadeItem::unhighlight(MtfCascadeItem *mtfObject)
{
	// This is the best place to hook non-current messages.
	GetZincObject(mtfObject)->Event(N_NON_CURRENT);

	// Defer drawing to the base class.
	(*xmCascadeButtonClassRec.primitive_class.border_unhighlight)((Widget)mtfObject);
}

// ----- MtfToggleItem widget definition ------------------------------------

XmOffsetPtr MtfToggleItem::offsets;

// Comparable to Xm/ToggleB.c
XtActionsRec MtfToggleItem::action[] =
{
	{ "ZafHelp", 	(XtActionProc)help }
};

char MtfToggleItem::translations[] =
	"<Key>F1:		ZafHelp()\n\
	 <Key>osfHelp:	ZafHelp()";

MtfToggleItemClassRec MtfToggleItem::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmToggleButtonClassRec,	// superclass
		"ZafToggleItem", 						// class_name
		sizeof(MtfToggleItemPart), 			// mtfObject_size (data part)
		MtfToggleItem::classInitialize,		// class_initialize
		0,										// class_part_initialize
		false,									// class inited
		0,										// initialize
		0,										// initialize_hook
		XtInheritRealize,						// realize
		action, 								// actions
		XtNumber(action), 						// num_actions
		0, 										// resources
		0, 										// num_resources
		NULLQUARK,								// xrm_class
		true,									// compress_motion
		XtExposeCompressMultiple,				// compress_exposure
		true,									// compress_enterleave
		false,									// visible_interest
		0, 										// destroy
		XtInheritResize,						// resize
		(XtExposeProc)expose,					// expose
		0,										// set_values
		0, 										// set_values_hook
		XtInheritSetValuesAlmost,				// set_values_almost
		0, 										// get_values_hook
		XtInheritAcceptFocus,					// accept_focus
		XtVersionDontCheck,					// version
		0, 										// callback_private
		XtInheritTranslations,					// tm_table
		XtInheritQueryGeometry, 				// query_geometry
		XtInheritDisplayAccelerator,			// display_accelerator
		0,										// extension
	},
	// --- XmPrimitiveClassPart ---
	{
		(XtWidgetProc)highlight,				// border_highlight
		(XtWidgetProc)unhighlight,				// border_unhighlight
		XtInheritTranslations,					// translations
		(XtActionProc)_XtInherit,				// arm_and_activate
		0,										// syn_resources
		0,										// num_syn_resources
		0										// extension
	},
	// --- XmLabelClassPart ---
	{
		XmInheritWidgetProc,					// setOverrideCallback
		XmInheritMenuProc,						// menuProcs
		XtInheritTranslations,					// translations
		0										// extension
	},
	// --- XmToggleButtonClassPart ---
	{
		0										// extension
	},
	// --- MtfToggleItemClassPart ---
	{
		0									// extension
	}
};

void MtfToggleItem::changed(MtfToggleItem *, ZafPopUpItem *zafObject, XmToggleButtonCallbackStruct *callback)
{
	// Match ZAF up with the OS.
	ZafPopUpMenu *menu = DynamicPtrCast(zafObject->parent, ZafPopUpMenu);
	if ((menu->SelectionType() != ZAF_SINGLE_SELECTION && callback->set != zafObject->Selected()) ||
		(menu->SelectionType() == ZAF_SINGLE_SELECTION))
	{
		ZafEventStruct event(L_SELECT, callback->event);
		zafObject->Event(event);
	}
}

void MtfToggleItem::classInitialize()
{
	XmResolvePartOffsets((WidgetClass) &(MtfToggleItem::classRecord),
	 &(MtfToggleItem::offsets));
}

void MtfToggleItem::expose(MtfToggleItem *mtfObject, XEvent *xEvent, Region xRegion)
{
	// Draw the object.
	ZafEventStruct event(E_MOTIF, xEvent);
//	if (GetZincObject(mtfObject)->OSDraw())
		event.data = xRegion;
//	else
//	{
//		XRectangle xRect;
//		XClipBox(xRegion, &xRect);
//  		event.region.Assign(xRect.x, xRect.y, xRect.width, xRect.height, ZAF_PIXEL);
//	}
	GetZincObject(mtfObject)->Draw(event, E_MOTIF);
}

void MtfToggleItem::highlight(MtfToggleItem *mtfObject)
{
	// This is the best place to hook current messages.
	GetZincObject(mtfObject)->Event(N_CURRENT);

	// Defer drawing to the base class.
	(*xmToggleButtonClassRec.primitive_class.border_highlight)((Widget)mtfObject);
}

void MtfToggleItem::unhighlight(MtfToggleItem *mtfObject)
{
	// This is the best place to hook non-current messages.
	GetZincObject(mtfObject)->Event(N_NON_CURRENT);

	// Defer drawing to the base class.
	(*xmToggleButtonClassRec.primitive_class.border_unhighlight)((Widget)mtfObject);
}

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

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafPopUpItem::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Defer drawing to the OS.
	if (!screenID)
		return (S_ERROR);
	else if (XmIsToggleButton(screenID))
		(*xmToggleButtonClassRec.core_class.expose)
			(screenID, event.osEvent.type ? (XEvent *)&event.osEvent : ZAF_NULLP(XEvent), (_XRegion *)event.data);
	else if (XmIsCascadeButton(screenID))
		(*xmCascadeButtonClassRec.core_class.expose)
			(screenID, event.osEvent.type ? (XEvent *)&event.osEvent : ZAF_NULLP(XEvent), (_XRegion *)event.data);

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

ZafEventType ZafPopUpItem::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		// This widget will be in the motif frame, not in the client area.
		ccode = ZafWindowObject::Event(event);
		menu.Event(event);
		zafRegion.left = zafRegion.top = zafRegion.right = zafRegion.bottom = -1;
		break;

	case S_DEINITIALIZE:
		ccode = ZafWindowObject::Event(event);
		menu.Event(S_DESTROY);
		break;

	case S_REGISTER_OBJECT:
		// Create the support menu.
		ccode = ZafWindowObject::Event(event);
		menu.Event(event);
		break;

	// ----- Actions -----
	case L_SELECT:
		// Defer to the immediate base class.
		ccode = ZafButton::Event(event);
		break;

	case N_CURRENT:
	case N_NON_CURRENT:
		// Defer to the immediate base class.
		ccode = ZafWindowObject::Event(event);

		// Update the helpTips help object.
		if (HelpObjectTip() && RootObject()->Focus())
		{
			ZafEventStruct tEvent = event;
			tEvent.type = DH_UPDATE_HELP_OBJECT;
			tEvent.windowObject = (ccode == N_CURRENT) ? this : ZAF_NULLP(ZafWindowObject);
			eventManager->Event(tEvent, E_HELPTIPS);
		}
		break;

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

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

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

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

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

bool ZafPopUpItem::SetSelected(bool setSelected)
{
	// Defer to the base class.
	if (selected != setSelected)
	{
		ZafWindowObject::SetSelected(setSelected);

		// Reflect the state in the system.
		if (screenID && AllowToggling())
			XmToggleButtonSetState(screenID, Selected() ? true : false, false);
	}

	// Return the current attribute.
	return (selected);
}

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

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

void ZafPopUpItem::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Defer to the top-most base class.
	ZafWindowObject::OSMapPalette(palette, type, state);
}

void ZafPopUpItem::OSRegisterObject(void)
{
	// Create the Motif widget.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	screenID = parent->OSScreenID(ZAF_CLIENTID);
	if (ItemType() == ZAF_SEPARATOR)
	{
		screenID = XtVaCreateManagedWidget(name,
			xmSeparatorWidgetClass, screenID,
			0);
		return;
	}

	// Prepare the label.
	char *osText = stringData ? stringData->DynamicOSText() : ZAF_NULLP(char);
#	if defined(ZAF_UNICODE)
	XmString label = XmStringCreateLocalized(osText);
#	else
	XmString label = XmStringCreate(osText, XmFONTLIST_DEFAULT_TAG);
#	endif

	// Create the widget.
	if (AllowToggling())
	{
		ZafPopUpMenu *parentMenu = DynamicPtrCast(parent, ZafPopUpMenu);

		// Create the motif widget.
		screenID = XtVaCreateManagedWidget(name,
			(WidgetClass)&MtfToggleItem::classRecord, screenID,
			// user information
			XmNuserData, this,
			// miscellaneous
			XmNlabelString, label,
			XmNsensitive, Disabled(false) ? false : true,
			XmNindicatorType, (parentMenu->SelectionType() == ZAF_MULTIPLE_SELECTION) ? XmN_OF_MANY : XmONE_OF_MANY,
			XmNvisibleWhenOff, (parentMenu->SelectionType() == ZAF_SINGLE_SELECTION) ? false : true,
			XmNindicatorOn, true,
			XmNset, Selected() ? true : false,
			0);
		OSSetText();

		// Override translations.
		XtTranslations translationTable = XtParseTranslationTable(MtfToggleItem::translations);
		XtOverrideTranslations(screenID, translationTable);

		// Override the action callbacks.
		XtAddCallback(screenID, XmNvalueChangedCallback,
			(XtCallbackProc)MtfToggleItem::changed, (XtPointer)this);
	}
	else
	{
		// Create the motif widget.
		screenID = XtVaCreateManagedWidget(name,
			(WidgetClass)&MtfCascadeItem::classRecord, screenID,
			// user information
			XmNuserData, this,
			// miscellaneous
			XmNlabelString, label,
#if defined(_IBM_RS6000)
			// On AIX the arrow pixmap clips the text needs larger margin.
			XmNmarginRight, 13,
#endif
			XmNsensitive, Disabled(false) ? false : true,
			0);

		// Override translations.
		XtTranslations translationTable = XtParseTranslationTable(MtfCascadeItem::translations);
		XtOverrideTranslations(screenID, translationTable);

		// Override the action callbacks.
		XtAddCallback(screenID, XmNactivateCallback,
			(XtCallbackProc)MtfCascadeItem::activate, (XtPointer)this);
	}

	// Determine the hot key.
	if (hotKeyIndex >= 0 && stringData)
	{
		KeySym keySym = ZafKeySym(stringData->Char(hotKeyIndex));
		if (keySym != NoSymbol)
			XtVaSetValues(screenID, XmNmnemonic, keySym, 0);
	}

	// Free the label memory.
	XmStringFree(label);
	if (osText)
		delete []osText;
}

ZafError ZafPopUpItem::OSSetText(void)
{
	// Reset the system value.
	if (screenID && SystemObject() && ItemType() != ZAF_SEPARATOR)
	{
		// Set the label.
		char *osText = stringData ? stringData->DynamicOSText() : ZAF_NULLP(char);
#		if defined(ZAF_UNICODE)
		XmString label = XmStringCreateLocalized(osText);
#		else
		XmString label = XmStringCreate(osText, XmFONTLIST_DEFAULT_TAG);
#		endif
		XtVaSetValues(screenID, XmNlabelString, label, 0);
		XmStringFree(label);
		if (osText)
			delete []osText;

		// Determine the hot key.
		if (hotKeyIndex >= 0 && stringData)
		{
			KeySym keySym = ZafKeySym(stringData->Char(hotKeyIndex));
			if (keySym != NoSymbol)
				XtVaSetValues(screenID, XmNmnemonic, keySym, 0);
		}
	}
	else if (screenID)
		RedisplayData();
	return (ZAF_ERROR_NONE);
}

void ZafPopUpItem::OSSize(void)
{
	// Menu item does not need to be sized.
}

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

