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

#include <z_ctype.hpp>
// The next two lines must be in this order to compile on SunOS 4.1.x
#include <z_stdlib.hpp>
#include <z_stdio.hpp>
#include <z_string.hpp>
#include <z_cursor.hpp>
#include "m_fmtstr.hpp"
#include "m_win.hpp"

#include <limits.h>

#if defined(__linux__)
	// These are defiined in m_str.cpp.
	extern int LINUX_TILE_WIDTH;					 
	extern int LINUX_TILE_HEIGHT;
	extern char linuxTile[];
#endif

// ----- MtfFormattedString widget definition -------------------------------

XmOffsetPtr MtfFormattedString::offsets;

XtActionsRec MtfFormattedString::action[] =
{
	{ "ZafMouse",						(XtActionProc)MtfWindowObject::mouse },
	{ "backward-character",			(XtActionProc)backward_char },
	{ "backward-word",				(XtActionProc)backward_word },
	{ "beginning-of-line",			(XtActionProc)beginning_of_line },
	{ "copy-clipboard",				(XtActionProc)noop },
	{ "copy-primary",				(XtActionProc)noop },
	{ "copy-to",					(XtActionProc)noop },
	{ "cut-clipboard",				(XtActionProc)noop },
	{ "cut-primary",				(XtActionProc)noop },
	{ "delete-next-character",		(XtActionProc)delete_next_char },
	{ "delete-next-word",			(XtActionProc)delete_next_word },
	{ "delete-previous-character",	(XtActionProc)delete_previous_char },
	{ "delete-previous-word",		(XtActionProc)delete_previous_word },
	{ "delete-selection",			(XtActionProc)delete_selection },
	{ "delete-to-end-of-line",		(XtActionProc)delete_eol },
	{ "delete-to-start-of-line",	(XtActionProc)delete_bol },
	{ "end-of-line",				(XtActionProc)end_of_line },
	{ "forward-character",			(XtActionProc)forward_char },
	{ "forward-word",				(XtActionProc)forward_word },
	{ "insert-string",				(XtActionProc)noop },
	{ "key-select",					(XtActionProc)noop },
	{ "move-to",					(XtActionProc)noop },
	{ "paste-clipboard",			(XtActionProc)noop },
	{ "process-bdrag",				(XtActionProc)noop },
	{ "secondary-adjust",			(XtActionProc)noop },
	{ "secondary-notify",			(XtActionProc)noop },
	{ "secondary-start",			(XtActionProc)noop },
	{ "select-adjust",				(XtActionProc)noop },
	{ "select-all",					(XtActionProc)select_all },
	{ "select-end",					(XtActionProc)noop },
	{ "select-start",				(XtActionProc)noop },
	{ "self-insert",				(XtActionProc)insert_char },
	{ "set-insertion-point",		(XtActionProc)noop },
	{ "set-selection-hit",			(XtActionProc)noop },
	{ "toggle-add-mode",			(XtActionProc)noop }, // not allowed.
	{ "toggle-overstrike",			(XtActionProc)noop }, // not allowed.
	{ "unkill",						(XtActionProc)noop },
	{ "ZafCallDefault", 			(XtActionProc)call_default },
	{ "ZafDragDrop",				(XtActionProc)drag_drop },
	{ "ZafEnter",					(XtActionProc)enter },
	{ "ZafExtendAdjust",			(XtActionProc)extend_adjust },
	{ "ZafExtendEnd",				(XtActionProc)extend_end },
	{ "ZafExtendStart",				(XtActionProc)extend_start },
	{ "ZafFocusIn",					(XtActionProc)focus_in },
	{ "ZafGrabFocus",				(XtActionProc)grab_focus },
	{ "ZafHelp", 					(XtActionProc)help },
	{ "ZafLeave",					(XtActionProc)leave },
	{ "ZafMoveDestination",			(XtActionProc)move_destination }
};

char MtfFormattedString::translations[] =
	"<Key>osfActivate:			ZafCallDefault()\n\
	 <Key>osfSelect:		ZafCallDefault()\n\
	 ~s ~m ~a <Key>Return:		ZafCallDefault()\n\
	 <Btn2Down>:				ZafDragDrop()\n\
	 <Btn3Down>:				ZafMouse()\n\
	 <Btn3Up>:					ZafMouse()\n\
	 <Btn3Motion>:				ZafMouse()\n\
	 <Enter>:					ZafEnter()\n\
	 ~c ~m ~a <Btn1Motion>:		ZafExtendAdjust()\n\
	 ~c ~m ~a <Btn1Up>:			ZafExtendEnd()\n\
	 ~c s ~m ~a <Btn1Down>:		ZafExtendStart()\n\
	 <FocusIn>:					ZafFocusIn()\n\
	 ~c ~s ~m ~a <Btn1Down>:	ZafGrabFocus()\n\
	 <Key>F1:					ZafHelp()\n\
	 <Key>osfHelp:				ZafHelp()\n\
	 <Leave>:					ZafLeave()\n\
	 c ~s ~m ~a <Btn1Down>:		ZafMoveDestination()";

MtfFormattedStringClassRec MtfFormattedString::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmTextFieldClassRec,	// superclass
		"ZafFormattedString", 				// class_name
		sizeof(MtfFormattedStringPart), 		// widget_size (data part)
		MtfFormattedString::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
		0,									// arm_and_activate
		0,									// syn_resources
		0,									// num_syn_resources
		0									// extension
	},
	// --- XmTextFieldClassPart ---
	{
		0									// extension
	},
	// --- MtfFromattedStringClassPart ---
	{
		0									// extension
	}
};

void MtfFormattedString::beep(MtfFormattedString *, XEvent *, String *, Cardinal *)
{
	// Ring the bell.
	XBell(((ZafScreenDisplay *)zafDisplay)->xDisplay, 100);
}

void MtfFormattedString::call_default(MtfFormattedString *mtfObject, XEvent *, String *, Cardinal *)
{
	// First, call the class, then call the root.
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	zafObject->Event(L_SELECT);
	zafObject->RootObject()->Event(L_SELECT);
}

void MtfFormattedString::changed(MtfFormattedString *, ZafFormattedString *object, XmTextVerifyCallbackStruct *)
{
	// Modify the object changed flag.
	object->changed = true;
}

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

void MtfFormattedString::drag_drop(MtfFormattedString *mtfObject, XEvent *xEvent, 
	String *param, Cardinal *nparams)
{
	ZafFormattedString *fString = GetZincObject(mtfObject);
	if (!fString->CopyDraggable() && !fString->MoveDraggable() && !fString->LinkDraggable())
	{
		XtCallActionProc((Widget)mtfObject, "copy-primary", xEvent, param, *nparams);
		ZafIChar *currentValue;
#if defined(ZAF_UNICODE)
		XtVaSetValues((Widget)mtfObject, XmNvalueWcs, &currentValue, NULL);
#else
		XtVaGetValues((Widget)mtfObject, XmNvalue, &currentValue, NULL);
#endif
		fString->StringData()->SetText(currentValue);
		XtFree((char *)currentValue);
	}
	else
	{
		// Begin the drag/drop operation.
		ZafEventStruct event(S_BEGIN_DRAG, xEvent);
		fString->Event(event);
	}
}

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

void MtfFormattedString::expose(MtfFormattedString *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 MtfFormattedString::extend_adjust(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;
	// Check motion to ensure marking only in valid areas.
	if (!motion_filter(zafObject, xEvent->xbutton.x, xEvent->xbutton.y))
		XtCallActionProc((Widget)mtfObject, "extend-adjust", xEvent, params, *nparams);
}

void MtfFormattedString::extend_end(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;
	// Adjust to end mark in valid areas.
	motion_filter(zafObject, xEvent->xbutton.x, xEvent->xbutton.y);
	XtCallActionProc((Widget)mtfObject, "extend-end", xEvent, params, *nparams);
}

void MtfFormattedString::extend_start(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;
	// Adjust to start mark in valid areas.
	motion_filter(zafObject, xEvent->xbutton.x, xEvent->xbutton.y);
	XtCallActionProc((Widget)mtfObject, "extend-start", xEvent, params, *nparams);
}

void MtfFormattedString::focus_in(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	// Chain to the base class.
	XtCallActionProc((Widget)mtfObject, "focusIn", xEvent, params, *nparams);
	if (!mtfObject->primitive.have_traversal)
		return; // Object is not really getting the keyboard focus.

	// Reflect changes to Zinc.
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	zafObject->NotifyFocus(zafObject, true);
}

void MtfFormattedString::grab_focus(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	if (zafObject->Noncurrent() && (zafObject->HzJustify() == ZAF_HZ_CENTER ||
	 zafObject->HzJustify() == ZAF_HZ_RIGHT))
		return;
	// Adjust to start mark in valid areas.
	motion_filter(zafObject, xEvent->xbutton.x, xEvent->xbutton.y);
	XtCallActionProc((Widget)mtfObject, "grab-focus", xEvent, params, *nparams);
}

void MtfFormattedString::highlight(MtfFormattedString *mtfObject)
{
	// Draw the button highlight.
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	ZafRegionStruct drawRegion = zafObject->BeginDraw();
	zafObject->DrawFocus(drawRegion, S_CURRENT);
	zafObject->EndDraw();
}

void MtfFormattedString::insert_char(MtfFormattedString *mtfObject, XEvent *xEvent, String *, Cardinal *)
{
	char value;
	KeySym keySym;
	XLookupString(&xEvent->xkey, &value, 1, &keySym, 0);
	GetZincObject(mtfObject)->InsertChar(value);
}

void MtfFormattedString::leave(MtfFormattedString *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Perform the motif enter and match with zinc.
	XtCallActionProc((Widget)mtfObject, "leave", xEvent, param, *nparams);
	ZafEventStruct event(N_MOUSE_LEAVE, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfFormattedString::move_destination(MtfFormattedString *mtfObject, XEvent *xEvent, String *params, Cardinal *nparams)
{
	// Adjust to start mark in valid areas.
	motion_filter(GetZincObject(mtfObject), xEvent->xbutton.x, xEvent->xbutton.y);
	XtCallActionProc((Widget)mtfObject, "move-destination", xEvent, params, *nparams);
}

bool MtfFormattedString::motion_filter(ZafFormattedString *zafObject, int &column, int &line)
{
	// Adjust the coordinates to prevent movement onto literal characters.
	Position x = (Position)column;
	Position y = (Position)line;
	int oldOffset = (int)XmTextXYToPos(zafObject->screenID, x, y);
	int newOffset = oldOffset;

	const ZafIChar *format = zafObject->InputFormatData()->Text();
	while (zafObject->IsLiteralChar(format[newOffset]))
		newOffset++;
	while (newOffset && zafObject->IsLiteralChar(format[newOffset]))
		newOffset--;

	// Check the motion filter status.
	if (oldOffset == newOffset)
		return (false);
	XmTextPosToXY(zafObject->screenID, newOffset, &x, &y);
	column = (int)x;
	line = (int)y;
	return (true);
}

void MtfFormattedString::select_all(MtfFormattedString *mtfObject, XEvent *, String *, Cardinal *)
{
	// Adjust to start mark in valid areas.
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	const ZafIChar *format = zafObject->InputFormatData()->Text();

	XmTextPosition startOffset = 0;
	while (format[startOffset] && zafObject->IsLiteralChar(format[startOffset]))
		startOffset++;
	XmTextPosition endOffset = zafObject->InputFormatData()->Length();
	while (endOffset > 0 && zafObject->IsLiteralChar(format[endOffset]))
		endOffset--;

	// Make sure the area is valid.
	if (startOffset < endOffset)
		XmTextSetSelection(zafObject->screenID, startOffset, endOffset, CurrentTime);
}

void MtfFormattedString::unhighlight(MtfFormattedString *mtfObject)
{
	// Draw the button highlight.
	ZafFormattedString *zafObject = GetZincObject(mtfObject);
	ZafRegionStruct drawRegion = zafObject->BeginDraw();
	zafObject->DrawFocus(drawRegion, S_NON_CURRENT);
	zafObject->EndDraw();
}

// ----- ZafFormattedString -------------------------------------------------

void ZafFormattedString::DeleteText(ZafEventType ccode)
{
	// Check for edit flags.
	if (ViewOnly())
		return;

	// Check for pending selection delete.
	XmTextPosition startOffset, endOffset;
	if (XmTextFieldGetSelectionPosition(screenID, &startOffset, &endOffset))
	{
		XmTextFieldClearSelection(screenID, CurrentTime);
		ccode = L_DELETE;
	}
	else
		startOffset = endOffset = XmTextFieldGetCursorPosition(screenID);

	// Determine the delete range.
	const ZafIChar *format = inputFormatData->Text();
	switch (ccode)
	{
	case L_LEFT:
		if (endOffset > 0)
			startOffset = endOffset - 1;
		while (startOffset && IsLiteralChar(format[startOffset]))
			startOffset--;
		endOffset = startOffset + 1;
		break;

	case L_WORD_LEFT:
		startOffset = endOffset - 1;
		break;

	case L_BOL:
		startOffset = 0;
		while (IsLiteralChar(format[startOffset]))
			startOffset++;
		break;

	case L_RIGHT:
		while (IsLiteralChar(format[startOffset]))
			startOffset++;
		endOffset = startOffset + 1;
		break;

	case L_WORD_RIGHT:
		endOffset = startOffset + 1;
		break;

	case L_EOL:
		endOffset = deleteData->Length();
		break;
	}

	// Replace the specified characters.
	if (startOffset < endOffset && !IsLiteralChar(format[startOffset]))
	{
		int length = (int)(endOffset - startOffset);
		ZafIChar *text = new ZafIChar[length+1];
		memcpy(text, deleteData->Text() + startOffset, length * sizeof(ZafIChar));
		text[length] = '\0';
#		if defined(ZAF_UNICODE)
		XmTextFieldReplaceWcs(screenID, startOffset, endOffset, text);
#		else
		XmTextFieldReplace(screenID, startOffset, endOffset, text);
#		endif
		XmTextFieldSetCursorPosition(screenID, startOffset);
		delete []text;
	}
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafFormattedString::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Defer to the base class.
	return (ZafString::Draw(event, ccode));
}
#endif

ZafEventType ZafFormattedString::Event(const ZafEventStruct &event)
{
	// Check for edit mode.
	if (editMode && event.InputType() == L_LOGICAL_EVENT)
		return (ZafWindowObject::Event(event));

	// Check for zinc events.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		// Check for an unanswered string.
		if (Unanswered())
			compressedData->SetText(ZafLanguageManager::blankString);
		ccode = ZafWindowObject::Event(event);
		break;

	case S_DEINITIALIZE:
		{
#if defined(__linux__)
		MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
//		if (SystemObject() && mtfObject->linuxTileStipple)
		if (SystemObject() && LinuxTileStipple((Widget)mtfObject))
		{
//			XFreePixmap(XtDisplay(mtfObject), mtfObject->linuxTileStipple);
			XFreePixmap(XtDisplay(mtfObject), LinuxTileStipple((Widget)mtfObject));
//			mtfObject->linuxTileStipple = 0;
			LinuxTileStipple((Widget)mtfObject) = 0;
		}
#endif
		ccode = ZafWindowObject::Event(event);
		}
		break;

	// ----- Action messages -----
	case S_CURRENT:
		{	
		MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
		if (mtfObject)
			mtfObject->text.overstrike = true;
		ccode = ZafString::Event(event);
		}
		break;

	case S_NON_CURRENT:
		{	
		MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
		if (mtfObject)
			mtfObject->text.overstrike = false;
		ccode = ZafString::Event(event);
		}
		break;

	case N_CURRENT:

		// Check for auto focus.
		ccode = ZafWindowObject::Event(event);
		if (screenID && SystemObject())
		{
			if (hzJustify != ZAF_HZ_LEFT)
				RedisplayData();
			if (AutoClear())
				MtfFormattedString::select_all(MtfFormattedString::GetMotifWidget(screenID), 0, 0, 0);
		}
		break;

	case S_COPY_DATA:
	case S_SET_DATA:
		// Defer to the base class.
		ccode = ZafString::Event(event);

		// Reposition the cursor.
		MoveCursor(L_BOL);
		break;

	// ----- Default or unknown messages -----
	default:
		ccode = ZafString::Event(event);
		break;
	}

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

void ZafFormattedString::InsertChar(ZafIChar value)
{
	// Check for edit flags.
	if (ViewOnly())
	{
		MtfFormattedString::beep(MtfFormattedString::GetMotifWidget(screenID), 0, 0, 0);
		return;
	}

	// Check for selected text.
	XmTextPosition startOffset, endOffset;
	if (XmTextFieldGetSelectionPosition(screenID, &startOffset, &endOffset))
		DeleteText(L_DELETE);

	// Check for a valid position.
	int offset = (int)XmTextFieldGetCursorPosition(screenID);
	value = IsLegalChar(value, offset);
	if (value)
	{
		// Insert the character.
#if defined(ZAF_UNICODE)
		wchar_t osChar[4];
		zafCodeSet->ConvertToOSWChar(value, osChar);
		XmTextFieldReplaceWcs(screenID, offset, offset + 1, osChar);
#else
		ZafIChar osChar[4];
		osChar[0] = value;
		osChar[1] = '\0';
		XmTextFieldReplace(screenID, offset, offset + 1, osChar);
#endif

		// Adjust to the new position.
		offset++;
		const ZafIChar *format = inputFormatData->Text();
		while (format[offset] && IsLiteralChar(format[offset]))
			offset++;
		XmTextFieldSetCursorPosition(screenID, offset);
	}
}

void ZafFormattedString::InsertText(ZafIChar *value)
{
	// Check for edit flags.
	if (ViewOnly())
	{
		MtfFormattedString::beep(MtfFormattedString::GetMotifWidget(screenID), 0, 0, 0);
		return;
	}

	// Insert the characters into the text.
	while (*value)
		InsertChar(*value);
}

void ZafFormattedString::MoveCursor(ZafEventType ccode)
{
	// Get the current cursor position.
	int oldOffset = (int)XmTextFieldGetCursorPosition(screenID);
	int newOffset = oldOffset;
	const ZafIChar *format = inputFormatData->Text();

	// Determine the new cursor position.
	switch (ccode)
	{
	case L_BOL:
		// Go to the beginning of line.
		newOffset = 0;
		while (format[newOffset] && IsLiteralChar(format[newOffset]))
			newOffset++;
		break;

	case L_WORD_LEFT:
		// Move off the beginning of the word.
		if (newOffset)
			newOffset--;
		while (newOffset && IsLiteralChar(format[newOffset]))
			newOffset--;
		// Move to the start of the current word.
		while (newOffset && !IsLiteralChar(format[newOffset-1]))
			newOffset--;
		break;

	case L_LEFT:
		// Move left one character.
		if (newOffset)
			newOffset--;
		while (newOffset && IsLiteralChar(format[newOffset]))
			newOffset--;
		break;

	case L_EOL:
		// Go to the end of line.
		newOffset = inputFormatData->Length();
		break;

	case L_WORD_RIGHT:
		// Move to the start of the next word.
		while (format[newOffset] && !IsLiteralChar(format[newOffset]))
			newOffset++;
		while (format[newOffset] && IsLiteralChar(format[newOffset]))
			newOffset++;
		break;

	case L_RIGHT:
		if (format[newOffset])
			newOffset++;
		while (format[newOffset] && IsLiteralChar(format[newOffset]))
			newOffset++;
		break;
	}

	// Move to the specified position.
	if (oldOffset != newOffset && (!format[newOffset] || !IsLiteralChar(format[newOffset])))
	{
		XmTextFieldClearSelection(screenID, CurrentTime);
		XmTextFieldSetCursorPosition(screenID, newOffset);
	}
}

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

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

ZafError ZafFormattedString::OSGetText(void)
{
	// Update the internal text.
	if (screenID && SystemObject() && Changed())
	{
		stringData->SetUpdate(this, ZAF_UPDATE_NONE);
#if defined(ZAF_UNICODE)
		wchar_t *osText = XmTextGetStringWcs(screenID);
		stringData->SetOSWText(osText);
		XtFree((char *)osText);
#else
		char *osText = XmTextGetString(screenID);
		stringData->SetOSText(osText);
		XtFree(osText);
#endif
		stringData->SetUpdate(this, ZAF_UPDATE_ALL);
	}

	// Update the compressed data.
	UpdateCompressedData();
	return (ZAF_ERROR_NONE);
}

void ZafFormattedString::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.
	XGCValues values;
	XtGCMask mask = GCForeground | GCBackground | GCFillStyle;
	MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
	if (type == ZAF_PM_TEXT || type == ZAF_PM_HOT_KEY)
	{
	   values.foreground = mtfObject->primitive.foreground;
    	values.background = mtfObject->core.background_pixel;
		if (state & ZAF_PM_DISABLED)
		{
			mask |= GCTile;
			values.fill_style = FillTiled;
#if defined(__linux__)
			// The liniux tile_stipple pixmap is created with the depth of one so
			// it we need to create on of the correct depth.
//			if (!mtfObject->linuxTileStipple)
			if (!LinuxTileStipple((Widget)mtfObject))
				LinuxTileStipple((Widget)mtfObject) = XCreatePixmapFromBitmapData(XtDisplay(screenID),
//				mtfObject->linuxTileStipple = XCreatePixmapFromBitmapData(XtDisplay(screenID),
				 XtWindow(screenID), linuxTile, LINUX_TILE_WIDTH, LINUX_TILE_HEIGHT, 
				 values.foreground, values.background, mtfObject->core.depth);
//			values.tile = mtfObject->linuxTileStipple;
			values.tile = LinuxTileStipple((Widget)mtfObject);
#else
			values.tile = mtfObject->text.stipple_tile;
#endif	
		}
		else
 			values.fill_style = FillSolid;

		palette.osPalette = mtfObject->text.gc;
		XChangeGC(XtDisplay(screenID), palette.osPalette, mask, &values);
	}
	else if (type == ZAF_PM_BACKGROUND)
	{
	    values.foreground = mtfObject->core.background_pixel;
    	values.background = mtfObject->primitive.foreground;
		values.fill_style = FillSolid;
		palette.osPalette = mtfObject->text.gc;
		XChangeGC(XtDisplay(screenID), palette.osPalette, mask, &values);
	}
	else
		ZafWindowObject::OSMapPalette(palette, type, state);
}

void ZafFormattedString::OSRegisterObject(void)
{
	
	// Create the Motif widget.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	
	// Find what the text margin should be.
	Display()->SetFont(Font());
	ZafRegionStruct textHeight = Display()->TextSize(ZAF_ITEXT("Ky"));
	int margin = (zafRegion.Height() - textHeight.Height()) / 2;
	if (Bordered())
		margin -= 2 * ZAF_BORDER_SIZE;
	if (margin > ZAF_TEXT_MARGIN_SIZE)
		margin = ZAF_TEXT_MARGIN_SIZE;
	
	screenID = parent->OSScreenID(ZAF_CLIENTID);
	screenID = XtVaCreateWidget(name,
		(WidgetClass)&MtfFormattedString::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNsensitive, Disabled(false) ? false : true,
		XmNtraversalOn, Noncurrent() ? false : true,
		XmNshadowThickness, Bordered() ? 2 : 0,
		XmNeditable, (ViewOnly() || Disabled(false)) ? false : true,
		XmNcursorPositionVisible, (ViewOnly() || Disabled(false)) ? false : true,
		XmNblinkRate, ZafCursor::BlinkRate(),
		XmNmarginHeight, margin < 0 ? 0 : margin,
		0);
	OSSetText();

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

	// special callbacks
	XtAddCallback(screenID, XmNactivateCallback, 
		(XtCallbackProc)MtfFormattedString::activate, (XtPointer)this);
	XtAddCallback(screenID, XmNvalueChangedCallback, 
		(XtCallbackProc)MtfFormattedString::changed, (XtPointer)this);

#if defined(__linux__)
	MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
	LinuxTileStipple((Widget)mtfObject) = 0;
#elif defined(_IBM_RS6000)
	MtfFormattedString *mtfObject = MtfFormattedString::GetMotifWidget(screenID);
	mtfObject->text.gc = XCreateGC(XtDisplay(screenID),
	 RootWindow(XtDisplay(screenID), DefaultScreen(XtDisplay(screenID))), 0, NULL);
#endif
	MoveCursor(L_BOL);

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

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

ZafError ZafFormattedString::OSSetText(void)
{
	// Format the string data.
	UpdateExpandedData();

	// Set the os text.
	if (screenID && SystemObject())
	{
		int maxLength = stringData->MaxLength();
		// If maxLength is -1 set it to the largest int. (Default value on Motif)
		if (maxLength < 0)
			maxLength = INT_MAX;
#		if defined(ZAF_UNICODE)
		wchar_t *osText = stringData->DynamicOSWText();
		XtVaSetValues(screenID,
			XmNmaxLength, maxLength,
			XmNvalueWcs, osText,
			0);
		delete []osText;
#		else
		char *osText = stringData->DynamicOSText();
		XtVaSetValues(screenID,
			XmNmaxLength, maxLength,
			XmNvalue, osText,
			0);
		delete []osText;
#		endif
	}
	else if (screenID)
		RedisplayData();
	return (ZAF_ERROR_NONE);
}

