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

#include <z_scrll2.hpp>
#include <z_string.hpp>
#include "m_win.hpp"
#include "m_tree.hpp"

#define OPTIMIZE_REDISPLAY

//??? What algorythm should be used to determine the item height?
#define ITEM_HEIGHT		20

// ----- MtfTreeList widget definition --------------------------------------

XmOffsetPtr MtfTreeList::offsets;

XtActionsRec MtfTreeList::action[] =
{
	{ "ListAddMode",				(XtActionProc)noop },
	{ "ListAddPrevItem", 			(XtActionProc)noop },
	{ "ListAddNextItem", 			(XtActionProc)noop },
	{ "ListBeginData",				(XtActionProc)first_item },
	{ "ListBeginDataExtend",		(XtActionProc)first_extend },
	{ "ListBeginExtend",  			(XtActionProc)button_select },
	{ "ListBeginLine",  			(XtActionProc)noop },
	{ "ListBeginSelect",			(XtActionProc)button_select },
	{ "ListBeginToggle",  			(XtActionProc)button_select },
	{ "ListButtonMotion",			(XtActionProc)button_select },
	{ "ListCopyToClipboard",		(XtActionProc)noop },
	{ "ListCtrlNextItem",  			(XtActionProc)noop },
	{ "ListCtrlPrevItem",  			(XtActionProc)noop },
	{ "ListCtrlSelect",  			(XtActionProc)noop },
	{ "ListCtrlUnSelect",			(XtActionProc)noop },
	{ "ListEndData",				(XtActionProc)last_item },
	{ "ListEndDataExtend",			(XtActionProc)last_extend },
	{ "ListEndExtend",				(XtActionProc)button_select },
	{ "ListEndLine",				(XtActionProc)noop },
	{ "ListEndSelect",				(XtActionProc)button_select },
	{ "ListEndToggle",				(XtActionProc)button_select },
	{ "ListExtendAddNextItem",  	(XtActionProc)noop },
	{ "ListExtendAddSelect",		(XtActionProc)noop },
	{ "ListExtendAddUnSelect",		(XtActionProc)noop },
	{ "ListExtendAddPrevItem",  	(XtActionProc)noop },
	{ "ListExtendNextItem", 		(XtActionProc)next_extend },
	{ "ListExtendPrevItem", 		(XtActionProc)previous_extend },
	{ "ListFocusIn",				(XtActionProc)focus_in },
	{ "ListFocusOut",				(XtActionProc)focus_out },
	{ "ListItemSelect",				(XtActionProc)noop },
	{ "ListItemUnSelect",			(XtActionProc)noop },
	{ "ListKbdActivate",	  		(XtActionProc)toggle_expanded },
	{ "ListKbdBeginExtend",	  		(XtActionProc)first_extend },
	{ "ListKbdBeginSelect",			(XtActionProc)begin_select },
	{ "ListKbdBeginToggle",	  		(XtActionProc)noop },
	{ "ListKbdCancel",				(XtActionProc)noop },
	{ "ListKbdCtrlSelect",			(XtActionProc)noop },
	{ "ListKbdCtrlUnSelect",  		(XtActionProc)noop },
	{ "ListKbdDeSelectAll",			(XtActionProc)deselect_all },
	{ "ListKbdEndExtend",  			(XtActionProc)last_extend },
	{ "ListKbdEndSelect",			(XtActionProc)noop },
	{ "ListKbdEndToggle",  			(XtActionProc)noop },
	{ "ListKbdSelectAll",			(XtActionProc)select_all },
	{ "ListKbdShiftSelect",			(XtActionProc)noop },
	{ "ListKbdShiftUnSelect",		(XtActionProc)noop },
	{ "ListLeftChar",				(XtActionProc)left_item },
	{ "ListLeftPage",				(XtActionProc)noop },
	{ "ListNextItem",	  			(XtActionProc)next_item },
	{ "ListNextPage",				(XtActionProc)next_page },
	{ "ListPrevItem",	  			(XtActionProc)previous_item },
	{ "ListPrevPage",				(XtActionProc)previous_page },
	{ "ListProcessDrag",			(XtActionProc)noop },
	{ "ListRightChar",  			(XtActionProc)right_item },
	{ "ListRightPage",  			(XtActionProc)noop },
	{ "ListScrollCursorVisible",	(XtActionProc)noop },
	{ "ListShiftCtrlSelect",		(XtActionProc)noop },
	{ "ListShiftCtrlUnSelect",		(XtActionProc)noop },
	{ "ListShiftNextItem",  		(XtActionProc)noop },
	{ "ListShiftPrevItem",  		(XtActionProc)noop },
	{ "ListShiftSelect",			(XtActionProc)noop },
	{ "ListShiftUnSelect",			(XtActionProc)noop },
	{ "List_ShiftCtrlPrevItem",		(XtActionProc)noop },
	{ "List_ShiftCtrlNextItem",		(XtActionProc)noop },
	{ "ZafMouse", 			(XtActionProc)button_select },
	{ "ZafCallDefault", 			(XtActionProc)call_default },
	{ "ZafDoubleClick",				(XtActionProc)double_click },
	{ "ZafDragDrop",				(XtActionProc)drag_drop },
	{ "ZafEnter",					(XtActionProc)enter },
	{ "ZafHelp", 					(XtActionProc)help },
	{ "ZafLeave",					(XtActionProc)leave }
};

char MtfTreeList::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\
	 <Key>F1:				ZafHelp()\n\
	 <Key>osfHelp:			ZafHelp()\n\
	 <Leave>:				ZafLeave()";

MtfTreeListClassRec MtfTreeList::classRecord =
{
	// --- CoreClassPart ---
	{
		(WidgetClass)&xmListClassRec,	// superclass
		"ZafTreeList", 					// class_name
		sizeof(MtfTreeListPart),  		// widget_size (data part)
		MtfTreeList::classInitialize,		// class_initialize
		0,								// class_part_initialize
		false,							// class inited
		(XtInitProc)initialize,			// 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
		(XtWidgetProc)destroy_pixmap, 	// destroy
		(XtWidgetProc)resize,			// 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 ---
	{
		0,								// border_highlight
		0,								// border_unhighlight
		0,								// translations
		0,								// arm_and_activate
		0,								// syn_resources
		0,								// num_syn_resources
		0								// extension
	},
	// --- MtfTreeListClassPart ---
	{
		0									// extension
	}
};

void MtfTreeList::button_select(MtfTreeList *mtfObject, XEvent *xEvent, String *, Cardinal *)
{
	// Set up the zinc event.
	ZafTreeList *zafObject = GetZincObject(mtfObject);
	ZafEventStruct event(E_MOTIF, xEvent);
	zafObject->ConvertToZafEvent(event);

	// Choose the proper message.
	if (xEvent->xbutton.button == Button1)
	{
		if (xEvent->xbutton.type == ButtonPress && mtfObject->list.DownTime &&
			(xEvent->xbutton.time < mtfObject->list.DownTime + (Time)mtfObject->list.ClickInterval))
		{
			event.type = L_DOUBLE_CLICK;
		    mtfObject->list.DownCount++;
	       	mtfObject->list.DownTime = 0;
		}
		else if (xEvent->xbutton.type == ButtonPress)
		{
			event.type = L_BEGIN_SELECT;
		    mtfObject->list.DownCount = 1;
	       	mtfObject->list.DownTime = xEvent->xbutton.time;
		}
		else if (xEvent->xbutton.type == ButtonRelease)
			event.type = L_END_SELECT;
		else
			event.type = L_CONTINUE_SELECT;
	}
	else if (xEvent->xbutton.button == Button3)
	{
		if (xEvent->xbutton.type == ButtonPress)
			event.type = L_BEGIN_ESCAPE;
		else if (xEvent->xbutton.type == ButtonRelease)
			event.type = L_END_ESCAPE;
		else
			event.type = L_CONTINUE_ESCAPE;
	}
	zafObject->Event(event);
}

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

void MtfTreeList::deselect_all(MtfTreeList *mtfObject, XEvent *, String *, Cardinal *)
{
	// Check for a valid option.
	ZafTreeList *zafObject = GetZincObject(mtfObject);
	if (zafObject->SelectionType() == ZAF_SINGLE_SELECTION)
		return;

	// De-select all the list fields.
	for (ZafTreeItem *object = zafObject->ViewFirst(); object; object = object->ViewNext())
		object->SetSelected(false);
}

void MtfTreeList::destroy_pixmap(MtfTreeList *mtfObject)
{
	// Destroy the pixmap and region.
	if (TreePixmap((Widget)mtfObject))
		XFreePixmap(XtDisplay(mtfObject), TreePixmap((Widget)mtfObject));
	TreePixmap((Widget)mtfObject) = 0;
//	if (mtfObject->pixmap)
//		XFreePixmap(XtDisplay(mtfObject), mtfObject->pixmap);
//	mtfObject->pixmap = 0;
}

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

void MtfTreeList::enter(MtfTreeList *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Chain to the base class.
	XtCallActionProc((Widget)mtfObject, "PrimitiveEnter", xEvent, param, *nparams);
	ZafEventStruct event(N_MOUSE_ENTER, xEvent);
	GetZincObject(mtfObject)->Event(event);
}

void MtfTreeList::expose(MtfTreeList *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 MtfTreeList::focus_in(MtfTreeList *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Chain to the base class.
	XtCallActionProc((Widget)mtfObject, "PrimitiveFocusIn", xEvent, param, *nparams);
	if (!mtfObject->primitive.have_traversal)
		return; // Object is not really getting the keyboard focus.

	// Reflect changes to Zinc.
	ZafTreeList *zafObject = GetZincObject(mtfObject);
	ZafTreeItem *zafItem = zafObject->ViewCurrent();
	if (zafItem)
		zafItem->parent->NotifyFocus(zafItem, true);
	else
		zafObject->NotifyFocus(ZAF_NULLP(ZafWindowObject), true);
}

void MtfTreeList::focus_out(MtfTreeList *mtfObject, XEvent *xEvent, String *param, Cardinal *nparams)
{
	// Chain to the base class.
	XtCallActionProc((Widget)mtfObject, "PrimitiveFocusOut", xEvent, param, *nparams);

	// Update the field.
	ZafTreeList *zafObject = GetZincObject(mtfObject);
	if (!zafObject->ViewCurrent())
	{
		ZafRegionStruct drawRegion = zafObject->BeginDraw();
		drawRegion = zafObject->clientRegion;
		drawRegion.HzShift(-drawRegion.left);
		drawRegion.VtShift(-drawRegion.top);
		zafObject->DrawFocus(drawRegion, S_NON_CURRENT);
		zafObject->EndDraw();
	}
}

void MtfTreeList::initialize(MtfTreeList *, MtfTreeList *mtfObject, ArgList, Cardinal *)
{
	// Set the pixmap.
	TreePixmap((Widget)mtfObject) = 0;
}

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

void MtfTreeList::select_all(MtfTreeList *mtfObject, XEvent *, String *, Cardinal *)
{
	// Check for a valid option.
	ZafTreeList *zafObject = GetZincObject(mtfObject);
	if (zafObject->SelectionType() == ZAF_SINGLE_SELECTION)
		return;

	// Select all the list fields.
	for (ZafTreeItem *object = zafObject->ViewFirst(); object; object = object->ViewNext())
		object->SetSelected(true);
}

// ----- ZafTreeList --------------------------------------------------------

static ZafTreeItem *AdjustNext(ZafTreeItem *object)
{
	// Check the focus to the next selectable item.
	for (ZafTreeItem *newFocus = object; newFocus; newFocus = newFocus->ViewNext())
		if (!newFocus->Disabled(false) && !newFocus->Noncurrent())
			return (newFocus);
	return (object);
}

static ZafTreeItem *AdjustPrevious(ZafTreeItem *object)
{
	// Check the focus to the previous selectable item.
	for (ZafTreeItem *newFocus = object; newFocus; newFocus = newFocus->ViewPrevious())
		if (!newFocus->Disabled(false) && !newFocus->Noncurrent())
			return (newFocus);
	return (object);
}

ZafWindowObject *ZafTreeList::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	// Check for a support or invalid object.
	if (object->parent)
		return (object);
	else if (object->SupportObject())
		return (ZafWindow::Add(object, position));

	// Add the object to the list.
	object->SetBordered(false);
	object->SetSystemObject(false);
	object->SetParentPalette(true);
	ZafWindow::Add(object, position);

	// Reposition the item if the parent is registered.
	ZafTreeItem *item = DynamicPtrCast(object, ZafTreeItem);
	if (screenID && item)
	{
		// Optimize the update.
		ZafTreeItem *oldFirst = firstVisible;
		bool saveUpdate = AutomaticUpdate();
		SetAutomaticUpdate(false);

		// Determine the item positions.
		ZafTreeItem *pItem = item->ViewPrevious();
		ZafScrollBar *horizontalScrollBar = HorizontalScrollBar();
		int column = horizontalScrollBar ? (int)-horizontalScrollBar->ScrollData()->Current() : 0;
		int line = pItem ? pItem->zafRegion.bottom : 0;
		for (ZafTreeItem *temp = item; temp; temp = temp->ViewNext())
		{
			ComputeNextPosition(temp, column, line);
			temp->Event(N_SIZE);
		}

		// Restore the update.
		if (saveUpdate && oldFirst == firstVisible)
		{
			automaticUpdate = saveUpdate;
			ZafEventStruct event(S_REDISPLAY_REGION);
			event.region = object->zafRegion;
			event.region.bottom = clientRegion.Height() - 1;
			Event(event);
		}
		else
			SetAutomaticUpdate(saveUpdate);
	}

	// Return the object pointer.
	return (object);
}

void ZafTreeList::CheckMembers(ZafTreeItem *object)
{
	if (!object)
		firstVisible = lastVisible = cancelObject = viewCurrent = ZAF_NULLP(ZafTreeItem);
	else
	{
		// Check cancelObject.
		ZafWindowObject *temp;
		for (temp = cancelObject; temp; temp = temp->parent)
			if (temp == object)
			{
				cancelObject = ZAF_NULLP(ZafTreeItem);
				break;
			}

		// Check viewCurrent.
		for (temp = viewCurrent; temp; temp = temp->parent)
			if (temp == object)
			{
				viewCurrent = object->Next();
				if (!viewCurrent)
					viewCurrent = object->ViewPrevious();
				break;
			}

		// Check firstVisible.
		for (temp = firstVisible; temp; temp = temp->parent)
			if (temp == object)
			{
				firstVisible = object->Next();
				if (!firstVisible)
					firstVisible = object->ViewPrevious();
				break;
			}

		// Check lastVisible.
		for (temp = lastVisible; temp; temp = temp->parent)
			if (temp == object)
			{
				lastVisible = object->Next();
				if (!lastVisible)
					lastVisible = object->ViewPrevious();
				break;
			}
	}
}

void ZafTreeList::ComputeNextPosition(ZafTreeItem *object, int &column, int &line)
{
	// Set the object region.
	object->zafRegion.left = column;
	object->zafRegion.right = itemWidth - 1;
	object->zafRegion.top = line;
	object->zafRegion.bottom = line + itemHeight - 1;
	line += itemHeight;

	// Update firstVisible and lastVisible.
	if (object->zafRegion.top == 0)
		firstVisible = object;
	else if (!firstVisible)
	{
		firstVisible = lastVisible = object;
		if (!viewCurrent)
			viewCurrent = firstVisible;
	}
	if (object->zafRegion.bottom >= 0 &&
		object->zafRegion.bottom <= clientRegion.bottom - clientRegion.top)
		lastVisible = object;
}

void ZafTreeList::ComputePreviousPosition(ZafTreeItem *object, int &column, int &line)
{
	// Set the object region.
	object->zafRegion.left = column;
	object->zafRegion.right = itemWidth - 1;
	object->zafRegion.bottom = line;
	object->zafRegion.top = line - itemHeight + 1;
	line -= itemHeight;
}

ZafRegionStruct ZafTreeList::ConvertToDrawRegion(const ZafWindowObject *object,
	const ZafRegionStruct *drawRegion) const
{
	if (drawRegion)
		return (*drawRegion);
	return (object->zafRegion);
}

ZafPositionStruct ZafTreeList::ConvertToOSPosition(const ZafWindowObject *object,
	const ZafPositionStruct *zafPosition) const
{
	return (ZafWindow::ConvertToOSPosition(object, zafPosition));
}

ZafPositionStruct ZafTreeList::ConvertToZafPosition(const ZafWindowObject *object,
	const ZafPositionStruct *osPosition) const
{
	return (ZafWindow::ConvertToZafPosition(object, osPosition));
}

ZafEventType ZafTreeList::DragDropEvent(const ZafEventStruct &event)
{
	// Determine the drop message.
	ZafEventType ccode = event.type;
	ZafWindowObject *object = windowManager->dragObject;
	switch (ccode)
	{
	case S_DROP_COPY:
	case S_DROP_MOVE:
		if (Disabled() || !AcceptDrop() || !object || object == this)
			ccode = S_ERROR;
		else if (!(object->IsA(ID_ZAF_TREE_LIST)) && 
		 (!object->IsA(ID_ZAF_TREE_ITEM)))
		{
			const ZafIChar *dropText = object->Text();
			if (dropText && *dropText)
			{
				ZafTreeItem *newTreeItem = new ZafTreeItem(0, 0, dropText);
				Add(newTreeItem);
				if (ccode != S_DROP_COPY)
					object->SetText(ZafLanguageManager::blankString);
			}
			else
			  ccode = S_ERROR;
		}	
		else 
		{
			ZafWindowObject *newTreeItem;
			if (object->IsA(ID_ZAF_TREE_LIST))
				object = DynamicPtrCast(object, ZafTreeList)->ViewCurrent();
			if (ccode == S_DROP_COPY)
				newTreeItem = object->Duplicate();
			else
			{
				newTreeItem = object;
				ZafWindow *itemParent = DynamicPtrCast(newTreeItem->parent, ZafWindow);
				itemParent->Subtract(newTreeItem);
			}
			Add(newTreeItem);
			ScrollEvent(S_VSCROLL_COMPUTE);
			ScrollEvent(S_HSCROLL_COMPUTE);
		}
		break;

	default:
		ccode = ZafWindowObject::DragDropEvent(event);
		break;
	}

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

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

	// Compute the actual draw region.
	ZafRegionStruct drawRegion = BeginDraw();
	ZafRegionStruct clip = drawRegion;
	if (ccode == E_MOTIF || ccode == S_REDISPLAY_REGION)
		clip = event.region;

	// Draw the list items that appear on the screen.
	ZafRegionStruct region = drawRegion; region.bottom = region.top - 1;
	for (ZafTreeItem *object = firstVisible; object; object = object->ViewNext())
		if (object->zafRegion.top <= drawRegion.bottom)
		{
			// Draw the item.
			region = object->zafRegion;
			if (region.Overlap(clip))
				object->Draw(event, object->Focus() ? S_CURRENT : S_NON_CURRENT);
		}
		else
			break; // Stop when items are no longer visible.

	// Clear any remaining blank area.
	region.top = region.bottom + 1;
	region.bottom = drawRegion.bottom;
	if (region.Overlap(clip))
	{
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE));
		display->Rectangle(region, 0, true);
	}

	// Draw the focus rectangle.
	if (ViewCurrent() && Focus())
	{
		drawRegion = ViewCurrent()->textRegion;
		DrawFocus(drawRegion, S_CURRENT);
	}
	else if (Focus())
	{
		drawRegion = clientRegion;
		drawRegion.HzShift(-drawRegion.left);
		drawRegion.VtShift(-drawRegion.top);
		DrawFocus(drawRegion, S_CURRENT);
	}

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

ZafEventType ZafTreeList::DrawFocus(ZafRegionStruct &region, ZafEventType ccode)
{
	// Draw the proper focus rectangle.
	MtfTreeList *mtfObject = MtfTreeList::GetMotifWidget(screenID);
	int width = mtfObject->primitive.highlight_thickness;
	if (ccode == S_CURRENT)
	{
		display->SetPalette(LogicalPalette(ZAF_PM_FOCUS, ZAF_PM_ANY_STATE));
		display->Rectangle(region, width);
		region -= width;
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE));
		display->Rectangle(region, 1);
		region--;
	}
	else
	{
		display->SetPalette(LogicalPalette(ZAF_PM_BACKGROUND, ZAF_PM_ANY_STATE));
		display->Rectangle(region, ++width);
		region -= width;
	}

	// Return success.
	return (ccode);
}
#endif

ZafEventType ZafTreeList::Event(const ZafEventStruct &event)
{
	// Check for zinc events.
	ZafTreeItem *object;
	ZafEventType ccode = event.type;
	
	switch (ccode)
	{
	case S_INITIALIZE:
		itemWidth = 0;
		itemHeight = ITEM_HEIGHT;
		if (!ViewCurrent())
			SetViewCurrent(Current());
		ccode = ZafWindow::Event(event);
		break;

	// ----- Position & Size messages -----
	case N_SIZE:
		{
		// Clean up the scroll pixmap.
		MtfTreeList::destroy_pixmap(MtfTreeList::GetMotifWidget(screenID));

		// Compute the cell sizes.
		if (!itemWidth || !itemHeight || OSDraw())
		{
			itemWidth = clientRegion.Width();
//???			if (OSDraw())
//???			{
//???				// Use the font size to determine the size of the field.
//???				display->SetPalette(LogicalPalette(ZAF_PM_TEXT, PaletteState()));
//???				itemHeight = display->TextSize(StringID()).Height() + 2 * ZAF_BORDER_SIZE;
//???			}
//???			else
//???				itemHeight = 0;
//???
//???			// Use the field that has the largest area.
//???			for (object = ViewFirst(); object; object = object->ViewNext())
//???			{
//???				object->Event(S_COMPUTE_SIZE);
//???				if (object->zafRegion.Height() > itemHeight)
//???					itemHeight = object->zafRegion.Height();
//???			}
//???
//???			itemHeight = ITEM_HEIGHT;
		}

		// Check on first visible spacing.
		if (firstVisible)
		{
			int tCount = clientRegion.Height() / itemHeight;
			ZafTreeItem *newFirst = firstVisible, *newLast = firstVisible;
			for ( ; tCount > 0 && newLast; tCount--)
				newLast = newLast->ViewNext();
			for ( ; tCount > 0 && newFirst; tCount--)
				newFirst = newFirst->ViewPrevious();
			firstVisible = newFirst ? newFirst : ZAF_NULLP(ZafTreeItem);
		}

		// Work down from firstVisible.
		ZafScrollBar *horizontalScrollBar = HorizontalScrollBar();
		int column = horizontalScrollBar ? (int)-horizontalScrollBar->ScrollData()->Current() : 0;
		int line = firstVisible ? firstVisible->zafRegion.top : 0;
		object = firstVisible ? firstVisible : ViewFirst();
		for ( ; object; object = object->ViewNext())
		{
			ComputeNextPosition(object, column, line);
			object->Event(N_SIZE);
		}

		// Work up from firstVisible.
		line = firstVisible ? firstVisible->zafRegion.top : 0;
		object = firstVisible ? firstVisible->ViewPrevious() : ZAF_NULLP(ZafTreeItem);
		for ( ; object; object = object->ViewPrevious())
		{
			ComputePreviousPosition(object, column, line);
			object->Event(N_SIZE);
		}

		// Adjust the scroll information.
		ScrollEvent(S_VSCROLL_CHECK);
		ScrollEvent(S_VSCROLL_COMPUTE);
		ScrollEvent(S_HSCROLL_CHECK);
		ScrollEvent(S_HSCROLL_COMPUTE);
		}
		break;

	case S_SIZE:
	case S_COMPUTE_SIZE:
		ccode = ZafWindowObject::Event(event);
		break;

	// ----- Selection messages -----
	case L_SELECT:
		// Select or double-click the current item.
		object = ViewCurrent();
		if (object && !object->Disabled(false))
		{
			object->ToggleSelected();

			// Call the associated user function.
			(object->*(object->memberUserFunction))(event, ccode);
		
			if (object->Expandable())
				object->ToggleExpanded();
		}
		break;

	case L_TOGGLE_EXPANDED:
	case L_DOUBLE_CLICK:
		// Expand the current item.
		object = ViewCurrent();
		if (object && !object->Disabled(false))
		{
			// Pass the event to the object double clicked on.
			for (object = firstVisible; object; object = object->ViewNext())
				if (object->zafRegion.Overlap(event.position))
				{
					// Reset the focus.
					object->Event(event);
					break;
				}
			// Call the associated user function.
			object = ViewCurrent();
			(object->*(object->memberUserFunction))(event, ccode);
			if (object->Expandable() && ccode == L_TOGGLE_EXPANDED)
				object->ToggleExpanded();
		}
		break;

	case L_BEGIN_SELECT:
	case L_CONTINUE_SELECT:
	case L_END_SELECT:
		// Check for the current focus.
		if (ccode == L_BEGIN_SELECT && !Focus())
			SetFocus(true);
		else if (!Focus())
			break; // illegal selection process.

		// Check for out-of-bounds.
		if (!clientRegion.Overlap(event.position, clientRegion.left, clientRegion.top))
			break;

		// Try to find an overlapping item.
		for (object = firstVisible; object; object = object->ViewNext())
			if (object->zafRegion.Overlap(event.position))
			{
				// Check for non-selectable overlaps.
				if (object->Disabled())
					return (S_ERROR);

				// Reset the focus.
				object->SetFocus(true);
				if (ccode == L_END_SELECT)
				{
					object->ToggleSelected();
					object->Event(L_SELECT);
				}
				else
					object->Event(event);
				SetViewCurrent(object);
				break;
			}

		// Check for a new selection.
		object = ViewCurrent();
		if (ccode == L_END_SELECT)
		{
			// Change the selection.
			if (object && object->expandRegion.Overlap(event.position))
				object->ToggleExpanded();
		}
		break;

	case L_BEGIN_ESCAPE:
	case L_CONTINUE_ESCAPE:
	case L_END_ESCAPE:
	case L_VIEW:
		// Try to find an overlapping item.
		for (object = firstVisible; object; object = object->ViewNext())
			if (object->zafRegion.Overlap(event.position))
			{
				// Reset the focus.
				object->Event(event);
				break;
			}
		ccode = ZafWindow::Event(event);
		break;

	case L_CANCEL:
		// Notify the parent if a temporary window.
		if (cancelObject)
			cancelObject->SetFocus(true);
		break;

	// ----- Miscellaneous -----
	case S_HOT_KEY:
		ccode = S_UNKNOWN;
		break;

	case N_CURRENT:
		ccode = ZafWindow::Event(event);

		// Update the cancel object (Used with L_CANCEL).
		cancelObject = ViewCurrent();
		break;

	case S_REDISPLAY:
	case S_REDISPLAY_DATA:
	case S_REDISPLAY_REGION:
		ccode = ZafWindowObject::Event(event);
		break;

	// ----- Default operation -----
	default:
		ccode = ZafWindow::Event(event);
		break;
	}

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

void ZafTreeList::GetClip(ZafWindowObject *object, ZafRegionStruct &clip,
	ZafRegionStruct &virtualRegion)
{
	ZafWindow::GetClip(object, clip, virtualRegion);
}

ZafEventType ZafTreeList::MoveEvent(const ZafEventStruct &event)
{
	// Determine the new selection.
	ZafEventType ccode = event.type;
	ZafTreeItem *object = ViewCurrent();
	if (!object)
		return (S_ERROR);
	ZafTreeItem *cObject = object;
	ZafTreeItem *pObject = cObject ? cObject->ViewPrevious() : ZAF_NULLP(ZafTreeItem);
	ZafTreeItem *nObject = cObject ? cObject->ViewNext() : ZAF_NULLP(ZafTreeItem);
	int height = clientRegion.bottom - clientRegion.top;

	switch (ccode)
	{
	case L_PREVIOUS:
	case L_EXTEND_PREVIOUS:
		if (pObject)
			object = AdjustPrevious(pObject);
		break;

	case L_NEXT:
	case L_EXTEND_NEXT:
		if (nObject)
			object = AdjustNext(nObject);
		break;

	case L_PGUP:
		// Check for page actions.
		if (!object || !pObject)
			break; // No current object exists.
		else if (object == firstVisible)
		{
			// Go to the top of the previous page.
			for ( ; pObject->ViewPrevious(); pObject = pObject->ViewPrevious())
				if (object->zafRegion.bottom - pObject->ViewPrevious()->zafRegion.top > height)
					break;
			object = AdjustPrevious(pObject);
		}
		else
			object = AdjustPrevious(firstVisible);
		break;

	case L_PGDN:
		// Check for page actions.
		if (!object || !nObject)
			break; // No current object exists.
		else if (object == lastVisible)
		{
			// Go to the bottom of the next page.
			for ( ; nObject->ViewNext(); nObject = nObject->ViewNext())
				if (nObject->ViewNext()->zafRegion.bottom - object->zafRegion.top > height)
					break;
			object = AdjustNext(nObject);
		}
		else
			object = AdjustNext(lastVisible);
		break;

	case L_FIRST:
		object = AdjustNext(ViewFirst());
		break;

	case L_LAST:
		object = AdjustPrevious(ViewLast());
		break;

	case L_LEFT:
		{
		ZafScrollBar *scrollBar = HorizontalScrollBar();
		if (scrollBar &&
			scrollBar->ScrollData()->Current() > scrollBar->ScrollData()->Minimum())
		{
			ZafEventStruct sEvent(S_HSCROLL);
			sEvent.scroll.delta = -1;
			ScrollEvent(sEvent);
		}
		}
		break;

	case L_RIGHT:
		{
		ZafScrollBar *scrollBar = HorizontalScrollBar();
		if (scrollBar && 
			scrollBar->ScrollData()->Current() < scrollBar->ScrollData()->Maximum())
		{
			ZafEventStruct sEvent(S_HSCROLL);
			sEvent.scroll.delta = 1;
			ScrollEvent(sEvent);
		}
		}
		break;
	}

	// Check the current object.
	if (object && object != viewCurrent)
	{
		// Reset the current object.
		object->SetFocus(true);
		SetViewCurrent(DynamicPtrCast(object, ZafTreeItem));

		// Check the scroll information.
		ScrollEvent(S_VSCROLL_CHECK);
	}
	return (ccode);
}

ZafWindowObject *ZafTreeList::NotifyFocus(ZafWindowObject *focusObject, bool setFocus)
{
	// Defer to the base class.
	ZafWindowObject *object = ViewCurrent();
	ZafWindowObject *invalidObject = ZafWindow::NotifyFocus(focusObject, setFocus);
	focusObject = ViewCurrent();

	// Update the focus.
	if (screenID)
	{
		 // object has not been deleted.
		if (!focusObject)
		{
			// Draw a full window focus rectangle.
			ZafRegionStruct drawRegion = BeginDraw();
			drawRegion = clientRegion;
			drawRegion.HzShift(-drawRegion.left);
			drawRegion.VtShift(-drawRegion.top);
			DrawFocus(drawRegion, focus ? S_CURRENT : S_NON_CURRENT);
			EndDraw();
		}
		else
		{
			ZafRegionStruct drawRegion = BeginDraw();

			// Turn off the old item focus.
			ZafTreeItem *item = DynamicPtrCast(object, ZafTreeItem);
			if (!item)
			{
				drawRegion = clientRegion;
				drawRegion.HzShift(-drawRegion.left);
				drawRegion.VtShift(-drawRegion.top);
				DrawFocus(drawRegion, S_NON_CURRENT);
			}
			else if (item != focusObject)
			{
				drawRegion = item->textRegion;
				DrawFocus(drawRegion, S_NON_CURRENT);
			}

			// Turn on the new item focus.
			item = DynamicPtrCast(focusObject, ZafTreeItem);
			drawRegion = item->textRegion;
			DrawFocus(drawRegion, setFocus ? S_CURRENT : S_NON_CURRENT);

			EndDraw();
		}
	}

	// Return the invalid object.
	return (invalidObject);
}

ZafWindowObject *ZafTreeList::NotifySelection(ZafWindowObject *selectedItem, bool setSelected)
{
	// Check for a valid object.
	ZafTreeItem *selectedObject = DynamicPtrCast(selectedItem, ZafTreeItem);
	if (!selectedObject)
		return (ZAF_NULLP(ZafWindowObject));

	// Update the old selected objects (this clears the area that will be
	// updated after calling the base notify selection).
	if (setSelected && SelectionType() == ZAF_SINGLE_SELECTION)
	{
		// Deselect all objects except "selectedObject."
		for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
			if (object->Selected() && object != selectedObject)
				object->SetSelected(false);

		// Reset the current pointer.
		SetViewCurrent(selectedObject);
	}
	else if (SelectionType() == ZAF_SINGLE_SELECTION)
	{
		// Check for a valid change of selection.
		ZafTreeItem *object = ViewFirst();
		while (object)
			if (object->Selected() && object != selectedObject)
				break;
			else
				object = object->ViewNext();

		// De-selection is not allowed.
		if (!object)
			selectedObject->selected = true;
	}

	// Redisplay the selected object.
	if (selectedObject && selectedObject->screenID)
		selectedObject->RedisplayData();

	// Return the object selection.
	return (selectedObject);
}

ZafEventType ZafTreeList::ScrollEvent(const ZafEventStruct &event)
{
	// Process the list scrolling requests.
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_VSCROLL_CHECK:
		// Check for a valid object.
		if (ViewCurrent())
		{
			// Determine the scrolling values.
			int delta = 0;
			ZafTreeItem *object = ViewCurrent();
			for ( ; object && object->zafRegion.top < firstVisible->zafRegion.top; object = object->ViewNext())
				delta--;
			for ( ; object && object->zafRegion.bottom > lastVisible->zafRegion.bottom; object = object->ViewPrevious())
				delta++;

			// Scroll the list elements or adjust the values.
			if (delta)
			{
				ZafEventStruct sEvent(S_VSCROLL);
				sEvent.scroll.delta = delta;
				ScrollEvent(sEvent);
			}
		}
		break;

	case S_VSCROLL:
	case N_VSCROLL:
		// Scroll the list elements according to the delta.
		if (event.scroll.delta && firstVisible)
		{
			// Determine the new first and last items.
			int delta = (int)event.scroll.delta;
			ZafTreeItem *oldFirst = firstVisible;
			for ( ; delta > 0 && lastVisible->ViewNext(); delta--)
			{
				firstVisible = firstVisible->ViewNext();
				lastVisible = lastVisible->ViewNext();
			}
			for ( ; delta < 0 && firstVisible->ViewPrevious(); delta++)
			{
				firstVisible = firstVisible->ViewPrevious();
				lastVisible = lastVisible->ViewPrevious();
			}

			// Check for a valid scroll operation.
			if (delta == event.scroll.delta)
				return (ccode);
			else if (ccode == S_VSCROLL)
				ScrollEvent(S_VSCROLL_COMPUTE);

			delta = oldFirst->zafRegion.top - firstVisible->zafRegion.top;
			for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
			{
				object->zafRegion.top += delta;
				object->zafRegion.bottom += delta;
				object->Event(N_SIZE);
			}

#			if defined(OPTIMIZE_REDISPLAY)
			// Check for existing repaint directives.
			if (!screenID || !Visible() || !XtIsRealized(screenID) || !XtWindow(screenID))
				break;
			ZafEventStruct check;
			check.route = this;
			if (eventManager->Get(check, Q_NO_BLOCK | Q_NO_DESTROY | Q_NO_POLL | Q_END) == 0 && check.route == this)
			{
				// Optimize for keyboard operations.
				if (check.type == S_CONTINUE && ccode == S_VSCROLL)
				{
					check.type = S_REDISPLAY;
					eventManager->Put(check);
				}
				break;
			}

			// Optimize the redisplay of list items.
			MtfTreeList *mtfObject = MtfTreeList::GetMotifWidget(screenID);
			int width = mtfObject->core.width;
			int height = mtfObject->core.height;
			if (!TreePixmap((Widget)mtfObject))
				TreePixmap((Widget)mtfObject) = XCreatePixmap(XtDisplay(screenID), XtWindow(screenID),
					width, height, mtfObject->core.depth);

			if (event.scroll.delta == 1)
			{
				// Shift the current items up.
				int size = firstVisible->zafRegion.top - oldFirst->zafRegion.top;
				XCopyArea(XtDisplay(screenID), XtWindow(screenID), TreePixmap((Widget)mtfObject),
					mtfObject->list.NormalGC, 0, size, width, height - size, 0, 0);
				XCopyArea(XtDisplay(screenID), TreePixmap((Widget)mtfObject), XtWindow(screenID),
					mtfObject->list.NormalGC, 0, 0, width, height - size, 0, 0);
				check.type = S_REDISPLAY_REGION;
				check.region.Assign(0, height - size, width, size, ZAF_PIXEL);
				Draw(check, check.type);
				check.type = (ccode == S_VSCROLL) ? S_CONTINUE : 0;
			}
			else if (event.scroll.delta == -1)
			{
				// Shift the current items down.
				int size = oldFirst->zafRegion.top - firstVisible->zafRegion.top;
				XCopyArea(XtDisplay(screenID), XtWindow(screenID), TreePixmap((Widget)mtfObject),
					mtfObject->list.NormalGC, 0, 0, width, height - size, 0, 0);
				XCopyArea(XtDisplay(screenID), TreePixmap((Widget)mtfObject), XtWindow(screenID),
					mtfObject->list.NormalGC, 0, 0, width, height - size, 0, size);
				check.type = S_REDISPLAY_REGION;
				check.region.Assign(0, 0, width, size, ZAF_PIXEL);
				Draw(check, check.type);
				check.type = (ccode == S_VSCROLL) ? S_CONTINUE : 0;
			}
			else
				check.type = S_REDISPLAY;

			// Put draw optimizations on the event manager.
			if (check.type)
				eventManager->Put(check);
#			else
			RedisplayData();
#			endif
		}
		break;

	case S_HSCROLL:
	case N_HSCROLL:
		// Compute the new field offset.
		{
		int offset = (int)event.scroll.delta * itemHeight;
		for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
		{
			object->zafRegion.left -= offset;
			object->Event(N_SIZE);
		}

		// Adjust the scroll values, if appropriate.
		ZafScrollBar *scrollBar = HorizontalScrollBar();
		if (ccode == S_HSCROLL && scrollBar)
			scrollBar->ScrollData()->Increment((int)event.scroll.delta);

#		if defined(OPTIMIZE_REDISPLAY)
		// Check for existing repaint directives.
		if (!screenID || !Visible() || !XtIsRealized(screenID) || !XtWindow(screenID))
			break;
		ZafEventStruct check;
		check.route = this;
		if (eventManager->Get(check, Q_NO_BLOCK | Q_NO_DESTROY | Q_NO_POLL | Q_END) == 0 && check.route == this)
		{
			// Optimize for keyboard operations.
			if (check.type == S_CONTINUE && ccode == S_VSCROLL)
			{
				check.type = S_REDISPLAY;
				eventManager->Put(check);
			}
			break;
		}

		// Put draw optimizations on the event manager.
		check.type = S_REDISPLAY;
		eventManager->Put(check);
#		else
		RedisplayData();
#		endif
		}
		break;

	case S_VSCROLL_COMPUTE:
		// Check for a scroll-bar.
		{
		ZafScrollBar *scrollBar = VerticalScrollBar();
		if (itemHeight && scrollBar && firstVisible)
		{
			// Reset the scroll values.
			ZafScrollStruct vScroll;
			vScroll.delta = 0;
			vScroll.showing = (lastVisible->zafRegion.bottom - firstVisible->zafRegion.top) / itemHeight;
			vScroll.current = (firstVisible->zafRegion.bottom - ViewFirst()->zafRegion.top) / itemHeight;
			vScroll.minimum = 0;
			vScroll.maximum = (ViewLast()->zafRegion.bottom - ViewFirst()->zafRegion.top) / itemHeight - vScroll.showing;

			scrollBar->ScrollData()->SetScroll(vScroll);
		}
		}
		break;

	case S_HSCROLL_COMPUTE:
		{
		// Check for a scroll-bar.
		ZafScrollBar *scrollBar = HorizontalScrollBar();
		if (!scrollBar)
			return (S_ERROR);

		// Reset the scroll values.
		ZafScrollStruct hScroll = *scrollBar->ScrollData();
		hScroll.delta = 1;
		hScroll.minimum = 0;
		hScroll.showing = (clientRegion.right - clientRegion.left) / itemWidth;
		hScroll.maximum = 0;
		for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
			if (object->textRegion.right > hScroll.maximum)
				hScroll.maximum = object->textRegion.right;
		hScroll.maximum /= itemWidth;

		// Adjust the Horizontal scroll-bar values.
		scrollBar->ScrollData()->SetScroll(hScroll);
		}
		break;

	default:
		// No other messages apply to the vertical list object.
		return (S_ERROR);
	}

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

bool ZafTreeList::SetAutomaticUpdate(bool setAutomaticUpdate)
{
	// Defer to the base class.
	if (automaticUpdate == setAutomaticUpdate)
		return (automaticUpdate);
	ZafWindowObject::SetAutomaticUpdate(setAutomaticUpdate);

	// Now, update the children.
	if (screenID && AutomaticUpdate() && SystemObject())
	{
		ScrollEvent(S_VSCROLL_COMPUTE);
		RedisplayData();
	}
	return (automaticUpdate);
}

ZafTreeItem *ZafTreeList::SetViewCurrent(ZafTreeItem *newViewCurrent)
{
	// Update the view-current pointer.
	if (viewCurrent != newViewCurrent)
	{
		if (screenID && Focus())
		{
			ZafRegionStruct drawRegion = BeginDraw();

			// Turn off the old item focus.
			if (viewCurrent)
			{
				drawRegion = viewCurrent->textRegion;
				DrawFocus(drawRegion, S_NON_CURRENT);
			}

			// Turn on the new item focus.
			viewCurrent = newViewCurrent;
 			drawRegion = viewCurrent->textRegion;
  			DrawFocus(drawRegion, S_CURRENT);

			EndDraw();
		}
		else
			viewCurrent = newViewCurrent;
	}
	return (viewCurrent);
}

void ZafTreeList::Sort(void)
{
	// Sort on the Zinc level.
	ZafList::Sort();
	for (ZafTreeItem *item = (ZafTreeItem *)first; item; item = (ZafTreeItem *)item->Next())
		item->Sort();

	// Items must be re-positioned in the list.
	if (screenID)
	{
		firstVisible = lastVisible = ZAF_NULLP(ZafTreeItem);
		Event(N_SIZE);
		RedisplayData();
	}
}

ZafWindowObject *ZafTreeList::Subtract(ZafWindowObject *temp)
{
	// Make sure the object is part of this list.
	ZafTreeItem *object = temp->SupportObject() ? ZAF_NULLP(ZafTreeItem) : DynamicPtrCast(temp, ZafTreeItem);

	if (!object)
		return (ZafWindow::Subtract(temp));
	
	ZafTreeItem *replaceItem = object->Next() ? (ZafTreeItem *)object->Next() : object->ViewPrevious();
	ZafWindowObject *currentTest = Current();

	// Test if the current object is a child of the object being removed.
	while (currentTest && currentTest != object)
		currentTest = currentTest->parent;
	if (currentTest)
		current = replaceItem;

	// Check to see if the first visible item is a child of the object
	// being removed.
	currentTest = firstVisible;
	while (currentTest && currentTest != object)
		currentTest = currentTest->parent;
	if (currentTest)
		firstVisible = replaceItem;

	if (object->parent != this)
	{
		object = DynamicPtrCast(temp->parent, ZafTreeItem);
		return (object ? object->Subtract(temp) : temp);
	}

	// Optimize the update.
	bool saveUpdate = AutomaticUpdate();
	SetAutomaticUpdate(false);

	// Remove the object from the list.
	CheckMembers(object);
	ZafWindowObject *nextObject = ZafWindow::Subtract(object);

	// Reposition items if the list is registered.
	if (screenID)
		Event(N_SIZE);

	// Restore the update and return the next object.
	SetAutomaticUpdate(saveUpdate);
	return (nextObject);
}

ZafTreeItem *ZafTreeList::ViewCurrent(void)
{
	// Return the current view item.
	return (viewCurrent);
}

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

void ZafTreeList::OSDestroy(void)
{
	// Update the list.
	CheckMembers(ZAF_NULLP(ZafTreeItem));

	// Defer the notification to the base class.
	ZafWindow::OSDestroy();
}

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

void ZafTreeList::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.
	MtfTreeList *mtfObject = MtfTreeList::GetMotifWidget(screenID);
	if (type == ZAF_PM_TEXT || type == ZAF_PM_HOT_KEY)
	{
		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->list.InsensitiveGC;
			XChangeGC(XtDisplay(screenID), palette.osPalette, mask, &values);
		}
		else if (state & ZAF_PM_SELECTED)
			palette.osPalette = mtfObject->list.InverseGC;
		else
			palette.osPalette = mtfObject->list.NormalGC;
	}
	else if (type == ZAF_PM_BACKGROUND)
		palette.osPalette = (state & ZAF_PM_SELECTED) ? mtfObject->list.NormalGC : mtfObject->list.InverseGC;
	else
		ZafWindowObject::OSMapPalette(palette, type, state);
}

OSWindowID ZafTreeList::OSScreenID(ZafScreenIDType type) const
{
	// Return the os handle.
	return (ZafWindow::OSScreenID(type));
}

void ZafTreeList::OSRegisterObject(void)
{
	// Level 1 - Create the frame area.
	char *name = zafCodeSet->ConvertToOSString(stringID, 0, false);
	screenID = parent->OSScreenID(ZAF_CLIENTID);
	screenID = XtVaCreateWidget(name,
		(WidgetClass)&MtfWindowFrame::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNresizePolicy, XmRESIZE_NONE,
		XmNshadowThickness, Bordered() ? ZAF_SHADOW_SIZE : 0,
		XmNmarginWidth, 0,
		XmNmarginHeight, 0,
		0);

	// Level 2 - Create the client area.
	screenID = XtVaCreateManagedWidget(name,
		(WidgetClass)&MtfTreeList::classRecord, screenID,
		// user information
		XmNuserData, this,
		// miscellaneous
		XmNallowOverlap, true,
		XmNlistSizePolicy, XmCONSTANT,
		XmNtraversalOn, Noncurrent() ? false : true,
		XmNborderWidth, 0,
		0);

#if defined(sun)
	MtfTreeList *mtfObject = MtfTreeList::GetMotifWidget(screenID);
	mtfObject->list.InsensitiveGC = XCreateGC(XtDisplay(screenID),
	 RootWindow(XtDisplay(screenID), DefaultScreen(XtDisplay(screenID))), 0, NULL);
#endif

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

	// Set additional default values.
	MtfWindowFrame *mtfFrame = MtfWindowFrame::GetMotifWidget(OSScreenID(ZAF_FRAMEID));
	mtfFrame->OverrideTranslations();
	Shadow_Type((Widget)mtfFrame) = Temporary() ? XmSHADOW_OUT : XmSHADOW_IN;

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

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

