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

#include <z_stdlib.hpp>
#include <z_string.hpp>
#include "m_prompt.hpp"
#include "m_win.hpp"

// ----- MtfPrompt widget definition ----------------------------------------

XmOffsetPtr MtfPrompt::offsets;

XtActionsRec MtfPrompt::action[] =
{
	{ "ZafMouse",		(XtActionProc)MtfWindowObject::mouse },
	{ "ZafDragDrop",	(XtActionProc)drag_drop },
	{ "ZafEnter",		(XtActionProc)enter },
	{ "ZafLeave",		(XtActionProc)leave }
};

char MtfPrompt::translations[] =
	"<Btn2Down>:	ZafDragDrop()\n\
	 <Btn1Down>:			ZafMouse()\n\
	 <Btn1Up>:				ZafMouse()\n\
	 <Btn1Motion>:			ZafMouse()\n\
	 <Btn3Down>:			ZafMouse()\n\
	 <Btn3Up>:				ZafMouse()\n\
	 <Btn3Motion>:			ZafMouse()\n\
	 <Enter>:		ZafEnter()\n\
	 <Leave>:		ZafLeave()";

MtfPromptClassRec MtfPrompt::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmLabelClassRec,	// superclass
		"ZafPrompt", 					// class_name
		sizeof(MtfPromptPart), 				// widget_size (data part)
		MtfPrompt::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 ---
	{
		XmInheritBorderHighlight,		// border_highlight
		XmInheritBorderUnhighlight,		// border_unhighlight
		XtInheritTranslations,			// translations
		0,								// arm_and_activate
		0,								// syn_resources
		0,								// num_syn_resources
		0								// extension
	},
	// --- XmLabelClassPart ---
	{
		XmInheritWidgetProc,			// setOverrideCallback
		0,								// menuProcs
		0,								// translations
		0								// extension
	},
	// --- MtfPromptClassPart ---
	{
		0									// extension
	}
};

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

void MtfPrompt::drag_drop(MtfPrompt *mtfObject, XEvent *xEvent, String *, Cardinal *)
{
	// Begin the drag/drop operation.
	ZafEventStruct event(S_BEGIN_DRAG, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfPrompt::enter(MtfPrompt *mtfObject, XEvent *xEvent, String *, Cardinal *)
{
	// Perform the motif enter and match with zinc.
	ZafEventStruct event(N_MOUSE_ENTER, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfPrompt::expose(MtfPrompt *mtfObject, XEvent *xEvent, Region xRegion)
{
	// Draw the object.
	ZafEventStruct event(E_MOTIF, xEvent);
	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 MtfPrompt::leave(MtfPrompt *mtfObject, XEvent *xEvent, String *, Cardinal *)
{
	// Perform the motif enter and match with zinc.
	ZafEventStruct event(N_MOUSE_LEAVE, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

// ----- ZafPrompt ----------------------------------------------------------

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafPrompt::Draw(const ZafEventStruct &, ZafEventType ccode)
{
	// Check for draw errors.
	if (!screenID)
		return (S_ERROR);

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

	// Draw the background.
	if (!TransparentBackground())
	{
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, state));
		display->Rectangle(drawRegion, 0, true);
	}

	// Adjust for edit mode and draw the text.
	display->SetPalette(LogicalPalette(ZAF_PM_TEXT, state));
	if (!AutoSize() || TransparentBackground() || EditMode())
	{
		if (Bordered())
			drawRegion.top += ZAF_BORDER_SIZE + ZAF_SHADOW_SIZE + ZAF_MARGIN_SIZE;
		drawRegion.bottom -= ZAF_BORDER_SIZE + ZAF_SHADOW_SIZE + ZAF_MARGIN_SIZE;
	}
	display->Text(drawRegion, stringData->Text(), -1, hzJustify, (zafRegion.Height() > display->cellHeight) ? vtJustify : ZAF_VT_CENTER, hotKeyIndex);

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

ZafEventType ZafPrompt::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_COMPUTE_SIZE:
		zafRegion = saveRegion;
        if (AutoSize() && !EditMode())
		{
			// Recompute the zafRegion.
			display->SetPalette(LogicalPalette(ZAF_PM_TEXT, PaletteState()));
			ZafRegionStruct size = display->TextSize(stringData->Text());

			// Adjust the horizontal size.
			if (HzJustify() == ZAF_HZ_LEFT)
				zafRegion.right = zafRegion.left + size.right - size.left;
			else if (HzJustify() == ZAF_HZ_RIGHT)
				zafRegion.left = zafRegion.right - size.right + size.left;
			else if (size.Width() < zafRegion.Width())
			{
				zafRegion.left += (zafRegion.Width() - size.Width()) / 2;
				zafRegion.right = zafRegion.left + size.Width() - 1;
			}

			// Adjust the vertical size so the prompt alignes with normal
			// ZafString objects.
			if (Bordered())
				zafRegion.top += ZAF_BORDER_SIZE + ZAF_SHADOW_SIZE + ZAF_MARGIN_SIZE;
			zafRegion.bottom = zafRegion.top + size.bottom - size.top;
		}
		break;

	case S_HOT_KEY:
		// Check for a valid hot-key.
		if (event.key.value == hotKeyChar)
		{
			// Set the focus to the next object.
			if (Next())
				Next()->SetFocus(true);
		}
		else
			ccode = S_UNKNOWN;
		break;

	case S_REDISPLAY:
	case S_REDISPLAY_DATA:
	case S_REDISPLAY_REGION:
		// Prompt needs special redisplay because of parent colors.
		if (screenID && Visible() && XtIsRealized(screenID) && XtWindow(screenID))
			XClearArea(XtDisplay(screenID), XtWindow(screenID), 0, 0, 0, 0, true);
		else
			ccode = ZafWindowObject::Event(event);
		break;

	case S_UPDATE_OBJECT:
		OSSetText();
		break;

	// ----- Base class messages -----
	default:
		ccode = ZafWindowObject::Event(event);
		break;
	}

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

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

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

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

void ZafPrompt::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Check for a non-system object.
	if (!screenID)
		return;
	else if (!SystemObject())
	{
		parent->OSMapPalette(palette, type, state);
		return;
	}

	// Determine the proper palette.
	MtfPrompt *mtfObject = MtfPrompt::GetMotifWidget(screenID);
	if (type == ZAF_PM_TEXT || type == ZAF_PM_HOT_KEY)
#if defined(__linux__)
		if (state & ZAF_PM_DISABLED)
		{
			XGCValues values;
			XtGCMask mask = GCForeground | GCBackground | GCFillStyle | GCTile;
			values.background = mtfObject->core.background_pixel;
			values.foreground = mtfObject->primitive.foreground;
			values.fill_style = FillTiled;
			values.tile = XmGetPixmapByDepth(XtScreen(screenID), "50_foreground",
				values.foreground, values.background, mtfObject->core.depth);
			palette.osPalette = mtfObject->label.insensitive_GC;
			XChangeGC(XtDisplay(screenID), palette.osPalette, mask, &values);
		}
		else
			palette.osPalette = mtfObject->label.normal_GC; 
#else
		palette.osPalette = (state & ZAF_PM_DISABLED) ? mtfObject->label.insensitive_GC : mtfObject->label.normal_GC;
#endif
	else
		ZafWindowObject::OSMapPalette(palette, type, state);
}

ZafError ZafPrompt::OSSetText(void)
{
	// The ZafButton object draws it's own information, so the object
	// just needs to be updated.
	if (stringData && screenID && AutomaticUpdate())
	{
		Event(S_COMPUTE_SIZE);
		OSSize();
		RedisplayData();
	}
	return (ZAF_ERROR_NONE);
}

void ZafPrompt::OSRegisterObject(void)
{
	// Create the motif widget.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	screenID = parent->OSScreenID(ZAF_CLIENTID);
	screenID = XtVaCreateWidget(name,
		(WidgetClass)&MtfPrompt::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNborderWidth, 0,
		XmNshadowThickness, 0,
		XmNrecomputeSize, false,
		0);
	// justification
	if (HzJustify() == ZAF_HZ_LEFT)
		XtVaSetValues(screenID, XmNalignment, XmALIGNMENT_BEGINNING, 0);
	else if (HzJustify() == ZAF_HZ_RIGHT)
		XtVaSetValues(screenID, XmNalignment, XmALIGNMENT_END, 0);
	else
		XtVaSetValues(screenID, XmNalignment, XmALIGNMENT_CENTER, 0);

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

	// Add edit mode overrides.
	ZafEditModeRegister(this);

	// Add drag/drop capabilities.
	ZafDropSiteRegister(this);
}

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

	// Bypass the ZafWindowObject layer because we do all the drawing
	// ourselves in Draw().  Thus, no system changes are needed.
	ZafRegionStruct tRegion = zafRegion;
	Event(S_COMPUTE_SIZE);
	if (tRegion != zafRegion)
		OSSize();
	else
		Redisplay();
	return (ZAF_ERROR_NONE);
}

