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

#include <w_app.hpp>
#include "w_imglst.hpp"
#include <z_error.hpp>
#include <z_keymap.hpp>
#include <z_scrll2.hpp>
#include <z_tree.hpp>

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

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

ZafWindowObject *ZafTreeList::Add(ZafWindowObject *object, ZafWindowObject *position)
{
	ZafWindow::Add(object, position);

//???#if defined(ZAF_WIN32)
//???	if (!ZafMSWindowsApp::commonControlsAvailable && screenID)
//???	{
//???		ZafTreeItem *item = DynamicPtrCast(object, ZafTreeItem);
//???		if (item)
//???		{
//???			ResizeVisibleItems(item);
//???			if (ItemInView(item))
//???				Event(ZafEventStruct(S_REDISPLAY));
//???		}
//???	}
//???#else
	ZafTreeItem *item = DynamicPtrCast(object, ZafTreeItem);
	if (item)
	{
		if (!current)
		{
			current = object;
			if (SelectionType() == ZAF_SINGLE_SELECTION)
				object->SetSelected(true);
		}

		if (screenID)
		{
			int showing = 1;
			int showable = clientRegion.Height() / ITEM_HEIGHT;
			ZafTreeItem *item = ViewLast();
			while (item && showing < showable)
			{
				ZafTreeItem *prevItem = item->ViewPrevious();
				if (item == firstVisible && prevItem)
					firstVisible = prevItem;
				item = prevItem;
				showing++;
			}

			ResizeVisibleItems(firstVisible);
			Event(S_VSCROLL_COMPUTE);
			Event(ZafEventStruct(S_REDISPLAY));
		}
	}


//???#endif

	return (object);
}

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));
}

ZafWindowObject *ZafTreeList::Subtract(ZafWindowObject *object)
{
	ZafTreeItem *item = DynamicPtrCast(object, ZafTreeItem);
	if (item)
	{
		bool inView = ItemInView(item);

		ZafTreeItem *replaceItem = item->Next() ? (ZafTreeItem *)item->Next() : item->ViewPrevious();
		ZafWindowObject *currentTest = Current();

		// Test if the current object is a child of the object being removed.
		while (currentTest && currentTest != item)
			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 != item)
			currentTest = currentTest->parent;
		if (currentTest)
			firstVisible = replaceItem;

		if (SelectionType() == ZAF_SINGLE_SELECTION && replaceItem && replaceItem == current)
			replaceItem->SetSelected(true);
		ZafWindow::Subtract(object);

//???	#if defined(ZAF_WIN32)
//???	if (screenID && !ZafMSWindowsApp::commonControlsAvailable)
//???	#else
		if (screenID)
//???#endif
		{
			ResizeVisibleItems(inView ? replaceItem : firstVisible);
			Event(S_VSCROLL_COMPUTE);
			Event(ZafEventStruct(S_REDISPLAY));
		}
	}
	else
		ZafWindow::Subtract(object);

	return (object);
}

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

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafTreeList::Draw(const ZafEventStruct &event, ZafEventType ccode)
{
	// Begin the drawing operation.
	ZafRegionStruct drawRegion = BeginDraw();

	// Draw the list items that appear on the screen.
	for (ZafTreeItem *object = firstVisible; object; object = object->ViewNext())
	{
		if (object->zafRegion.Overlap(event.region))
			object->Draw(event, ccode);

		if (object == lastVisible)
			break;
	}

	// Erase the background.
	if (!firstVisible)
		DrawBackground(drawRegion, ccode);
	else if (lastVisible && lastVisible->zafRegion.bottom < drawRegion.bottom)
	{
		drawRegion.top = lastVisible->zafRegion.bottom + 1;
		DrawBackground(drawRegion, ccode);
	}

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

ZafEventType ZafTreeList::Event(const ZafEventStruct &event)
{
//???#if defined(ZAF_WIN32)
//???	if (ZafMSWindowsApp::commonControlsAvailable)
//???	{
//???		if (event.type == E_OSEVENT)
//???			return ZafTreeList::OSEvent(event);
//???		else
//???			return ZafWindow::Event(event);
//???	}
//???#endif

	ZafEventType ccode;
	if (event.InputType() == E_KEY || event.InputType() == E_MOUSE)
		ccode = LogicalEvent(event);
	else if (event.type == E_OSEVENT)
		return ZafTreeList::OSEvent(event);
	else
		ccode = event.type;

	ZafTreeItem *object;
	switch (ccode)
	{
	// ----- Create messages -----
	case S_INITIALIZE:
		ccode = ZafWindow::Event(event);
		firstVisible = ViewFirst();
//???#if defined(ZAF_WIN32)
//???		imageList = ZAF_NULLP(ZafTreeImageList);
//???#endif
		break;

//???#if defined(ZAF_WIN32)
//???	case S_DEINITIALIZE:
//???		if (ZafMSWindowsApp::commonControlsAvailable)
//???		{
//???			delete imageList;
//???			imageList = ZAF_NULLP(ZafTreeImageList);
//???		}
//???		ccode = ZafWindow::Event(event);
//???		break;
//???#endif

	case S_CURRENT:
	case N_CURRENT:
		ccode = ZafWindowObject::Event(event);
		if (current)
			Current()->Event(event);
		break;

	case S_NON_CURRENT:
	case N_NON_CURRENT:
		ccode = ZafWindowObject::Event(event);
		if (current)
			Current()->Event(event);
		break;

	// ----- Position & Size messages -----
	case N_SIZE:
		ResizeVisibleItems(firstVisible);
		Event(S_HSCROLL_COMPUTE);
		Event(S_VSCROLL_COMPUTE);
		break;

	// ----- Selection messages -----
	case L_SELECT:
	case L_DOUBLE_CLICK:
		// Select or double-click the current item.
		object = ViewCurrent();
		if (object)
		{
			if (ccode == L_DOUBLE_CLICK && !object->zafRegion.Overlap(event.position))
				break;

			if (!object->Disabled())
			{
				// Call the associated user function.
				(object->*(object->memberUserFunction))(event, ccode);

				if (object->Expandable() && ccode == L_SELECT)
					object->ToggleExpanded();
			}
		}
		break;

	case L_VIEW:
	case L_CONTINUE_SELECT:
	case L_BEGIN_ESCAPE:
	case L_CONTINUE_ESCAPE:
	case L_END_ESCAPE:
		{
		// Determine which object the mouse is over and pass the event
		// to the item.
		ZafPositionStruct position = event.position;
		for (object = firstVisible; object; object = object->ViewNext())
			if (object->zafRegion.Overlap(position))
			{
				ZafEventStruct tEvent = event;
				tEvent.converted = object;
				ccode = object->Event(tEvent);
				break;
			}
		if (!object)
			ccode = ZafWindowObject::Event(event);
		}
		break;

	case L_BEGIN_SELECT:
	case L_END_SELECT:
		ZafWindowObject::Event(event);
		if (ccode == L_BEGIN_SELECT)
			::SetFocus(screenID);
		if (!windowManager->dragObject)
		{
			ZafPositionStruct position = event.position;
			ZafScrollBar *scrollBar = HorizontalScrollBar();
			if (scrollBar)
				position.column += (int)scrollBar->ScrollData()->Current();

			if (ccode != L_BEGIN_SELECT && !Focus())
				break;

			// Try to find an overlapping item.
//??? Stop after viewLast.
			for (object = firstVisible; object; object = object->ViewNext())
				if (object->zafRegion.Overlap(position))
				{
					// Make sure the current item also recieves the event.
					if (ccode == L_BEGIN_SELECT)
					{
						ZafEventStruct tEvent = event;
						tEvent.converted = object;
						ccode = object->Event(tEvent);
					}

					if (current != object)
					{
						if (SelectionType() == ZAF_SINGLE_SELECTION)
							object->SetSelected(true);
						object->SetFocus(true);
					}
					break;
				}

			// Check for a new selection.
			object = ViewCurrent();
			if (ccode == L_END_SELECT)
			{
				if (!object)
					break;
				if (!object->Disabled())
				{
					// Make sure the current item also recieves the event.
					ccode = object->Event(event);
					if (object->expandRegion.Overlap(position))
						object->ToggleExpanded();
					(object->*(object->memberUserFunction))(event, L_SELECT);
				}
			}
		}
		break;

	// ----- Movement messages -----
//??? Should be at window level?
//??? How can mapping twice be avoided?
	case L_DOWN:
	case L_FIRST:
	case L_LAST:
	case L_PGDN:
	case L_PGUP:
	case L_UP:
		ccode = MoveEvent(event);
		break;

	case L_NEXT:
	case L_PREVIOUS:
		ccode = S_UNKNOWN;
		break;

	default:
		ccode = ZafWindow::Event(event);
		break;
	}

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

ZafEventType ZafTreeList::DragDropEvent(const ZafEventStruct &event)
{
	ZafEventType ccode = event.type;

	switch (ccode)
	{
	case S_BEGIN_DRAG:
		windowManager->dragObject = Current();
		break;

	case S_DROP_DEFAULT:
		if (windowManager->dragObject->MoveDraggable())
			ccode = S_DROP_MOVE;
		else if (windowManager->dragObject->CopyDraggable())
			ccode = S_DROP_COPY;
		else
		{
			ccode = S_ERROR;
			break;
		}
		//Continue.
	case S_DROP_COPY:
	case S_DROP_MOVE:
		if (Disabled())
			return (S_ERROR);
		else if (windowManager->dragObject->IsA(ID_ZAF_TREE_ITEM))
		{
			// Try to find an overlapping item.
			ZafWindow *dropObject = ZAF_NULLP(ZafWindow);
			for (ZafTreeItem *item = firstVisible; item; item = item->ViewNext())
				if (item->zafRegion.Overlap(event.position))
				{
					dropObject = item;
					break;
				}
			if (!dropObject)
				dropObject = this;

			// Make sure drop is allowed.
			ZafWindowObject *dropTest = dropObject;
			while (dropTest)
			{
				if (dropTest == windowManager->dragObject)
				{
					// Can't drop item into its own sub-item.
					return S_ERROR;
				}
				dropTest = dropTest->parent;
			}

			ZafWindowObject *dragObject;
			if (ccode == S_DROP_MOVE)
			{
				dragObject = windowManager->dragObject;
				ZafWindow *dragParent = DynamicPtrCast(dragObject->parent, ZafWindow);
				dragParent->Subtract(dragObject);
			}
			else
				dragObject = windowManager->dragObject->Duplicate();
			dropObject->Add(dragObject);
		}
		break;

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

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

bool ZafTreeList::ItemInView(ZafTreeItem *item)
{
	bool inView = false;
	for (ZafTreeItem *testItem = firstVisible; testItem; testItem = testItem->ViewNext())
	{
		if (testItem == item)
			return (true);
		if (testItem == lastVisible)
			break;
	}

	return inView;
}

ZafEventType ZafTreeList::MoveEvent(const ZafEventStruct &event)
{
	// Determine the new selection.
	ZafEventType ccode;
	if (event.InputType() == E_KEY || event.InputType() == E_MOUSE)
		ccode = LogicalEvent(event);
	else
		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);

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

	case L_DOWN:
	case L_EXTEND_NEXT:
		if (nObject)
			object = nObject;
		break;

	case L_PGUP:
		// Check for page actions.
		if (!object || !pObject)
			break; // No current object exists.
		else if (object == firstVisible)
		{
			int count = clientRegion.Height() / object->zafRegion.Height() - 1;
			while (count-- > 0 && object->ViewPrevious())
				object = object->ViewPrevious();
		}
		else
			object = firstVisible;
		break;

	case L_PGDN:
		// Check for page actions.
		if (!object || !nObject)
			break; // No current object exists.
		else if (object == lastVisible || object->ViewNext() == lastVisible)
		{
			int count = clientRegion.Height() / object->zafRegion.Height() - 1;
			while (count-- > 0 && object->ViewNext())
				object = object->ViewNext();
		}
		else
			object = lastVisible;
		break;

	case L_FIRST:
		object = ViewFirst();
		break;

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

	// Check the current object.
	if (object && object != current)
	{
		if (SelectionType() == ZAF_SINGLE_SELECTION)
			object->SetSelected(true);

		// Reset the current object.
		object->SetFocus(true);

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

ZafWindowObject *ZafTreeList::NotifyFocus(ZafWindowObject *focusObject, bool setFocus)
{
	return (ZafWindowObject::NotifyFocus(focusObject, setFocus));
}

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

	// Update the old selected objects. If a window allows multiple 
	// selections, selecting an object doesn't affect other objects 
	// in the window.
	if (SelectionType() == ZAF_SINGLE_SELECTION && !selectedObject->SupportObject())
	{
		if (setSelected)
		{
			// Un-select all objects except "selectedObject."
			for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
				if (object->Selected() && object != selectedObject)
					object->SetSelected(false);
		}
		else
		{
			// 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;
		}
	}

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

void ZafTreeList::ResizeVisibleItems(ZafTreeItem *startItem)
{
	if (!firstVisible)
	{
		if (ViewFirst())
			firstVisible = ViewFirst();
		else
			return;
	}

	if (!startItem)
		startItem = firstVisible;

	int height = ITEM_HEIGHT;
	int width = zafRegion.Width();
	int line = 0;
	if (startItem != firstVisible && startItem->ViewPrevious())
		line = startItem->ViewPrevious()->zafRegion.bottom + 1;
	lastVisible = ViewLast();

	for(ZafTreeItem *item = startItem; item; item = item->ViewNext())
	{
		item->zafRegion.left = 0;
		item->zafRegion.right = width - 1;
		item->zafRegion.top = line;
		item->zafRegion.bottom = line + height - 1;
//??? Technically incorrect.
		item->Event(ZafEventStruct(N_SIZE));
		line += height;

		if (item->zafRegion.bottom >= clientRegion.bottom)
		{
			lastVisible = item;
			break;
		}
	}
}

ZafEventType ZafTreeList::ScrollEvent(const ZafEventStruct &event)
{
	ZafEventType ccode = event.type;
	switch (ccode)
	{
	case S_VSCROLL_CHECK:
		{
		ZafTreeItem *currentItem = ViewCurrent();
		if (!currentItem)
			break;

		// Dont include partially visible items.
		ZafTreeItem *lastItem = lastVisible;
		if (lastItem->zafRegion.bottom > clientRegion.bottom)
			lastItem = lastItem->ViewPrevious();

		bool currentItemInView = true;
		ZafTreeItem *item;
		for (item = firstVisible; item; item = item->ViewNext())
		{
			if (item == currentItem)
				break;
			else if (item == lastItem)
			{
				currentItemInView = false;
				break;
			}
		}

		if (!currentItemInView)
		{
			ZafScrollStruct vScroll;
			vScroll.delta = 0;

			while (item && item != currentItem)
			{
				vScroll.delta++;
				item = item->ViewNext();
			}

			if (!item)
			{
				vScroll.delta = 0;
				item = firstVisible;
				while (item && item != currentItem)
				{
					vScroll.delta--;
					item = item->ViewPrevious();
				}
			}

			Event(ZafEventStruct(S_VSCROLL, 0, vScroll));
		}
		}
		break;

	case S_VSCROLL:
	case N_VSCROLL:
		{
		if (event.scroll.delta > 0)
		{
			for (int i = (int)event.scroll.delta; i > 0; i--)
				firstVisible = firstVisible->ViewNext();
		}
		else if (event.scroll.delta < 0)
		{
			for (int i = (int)event.scroll.delta; i < 0; i++)
				firstVisible = firstVisible->ViewPrevious();
		}
		else
			return (S_ERROR);

		ResizeVisibleItems(firstVisible);

		// Update only the client region.
		Redisplay();

		// Adjust the scroll values, if appropriate.
		if (ccode == S_VSCROLL)
		{
			ZafScrollBar *scrollBar = VerticalScrollBar();
			if (scrollBar)
				scrollBar->Event(event);
		}
		}
		break;

	case S_HSCROLL:
	case N_HSCROLL:
		{
		// Adjust the scroll values, if appropriate.
		if (ccode == S_HSCROLL)
		{
			ZafScrollBar *scrollBar = HorizontalScrollBar();
			if (scrollBar)
				scrollBar->Event(event);
		}

		// Update only the client region.
		Redisplay();
		}
		break;

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

		// Reset the scroll values.
		ZafScrollStruct hScroll;
		hScroll.current = scrollBar->ScrollData()->Current();
		hScroll.delta = display->cellWidth;
		hScroll.minimum = 0;
		hScroll.showing = clientRegion.Width();
		hScroll.maximum = 0;
		for (ZafTreeItem *object = ViewFirst(); object; object = object->ViewNext())
			if (object->textRegion.right > hScroll.maximum)
				hScroll.maximum = object->textRegion.right;
		hScroll.maximum -= hScroll.showing;
		if (hScroll.maximum < 0)
			hScroll.maximum = 0;
		if (hScroll.current > hScroll.maximum)
		{
			hScroll.current = hScroll.maximum;
			if (screenID)
				Redisplay();
		}

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

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

		// Reset the scroll values.
		ZafScrollStruct vScroll;
		vScroll.delta = 1;
		vScroll.minimum = vScroll.maximum = 0;
		vScroll.showing = vScroll.current = 0;

		int count = 0;
		bool inView = false;
		for (ZafTreeItem *item = ViewFirst(); item; item = item->ViewNext())
		{
			if (item == firstVisible)
			{
				inView = true;
				vScroll.current = count;
			}
			if (inView)
				vScroll.showing++;
			if (item == lastVisible)
				inView = false;
			count++;
		}

		if (lastVisible && lastVisible->zafRegion.bottom > clientRegion.bottom)
			vScroll.showing--;

		vScroll.maximum = count - vScroll.showing;
		scrollBar->Event(ZafEventStruct(S_VSCROLL_SET, 0, vScroll));
		}
		break;

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

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

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);
		ResizeVisibleItems(firstVisible);
		Event(S_VSCROLL_CHECK);
		Redisplay();
	}
}

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

//??? This function is not really needed.
ZafTreeItem *ZafTreeList::SetViewCurrent(ZafTreeItem *newViewCurrent)
{
	if (Focus())
		newViewCurrent->SetFocus(true);
	else
		SetCurrent(newViewCurrent);
	return ViewCurrent();
}

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

void ZafTreeList::OSDestroy(void)
{
	ZafWindow::OSDestroy();

// ??? The following is not "OS" destruction!
	firstVisible = lastVisible = ZAF_NULLP(ZafTreeItem);

	// Destroy the list elements (low level).
	ZafList::Destroy();

	Event(S_VSCROLL_COMPUTE);
	Redisplay();
//???#if defined(ZAF_WIN32)
//???	imageList = ZAF_NULLP(ZafTreeImageList);
//???#endif
}

ZafEventType ZafTreeList::OSEvent(const ZafEventStruct &event)
{
	if (editMode && event.InputType() == E_MOUSE)
		return (ZafWindowObject::Event(event));

	ZafEventType ccode = event.osEvent.message;

	switch (ccode)
	{
	case WM_PAINT:
	case WM_ERASEBKGND:
		// Call the Draw() function.
		ccode = ZafWindowObject::OSEvent(event);
		break;
//???#if defined (ZAF_WIN32)
//???	case WM_LBUTTONUP:
//???		if (ZafMSWindowsApp::commonControlsAvailable && windowManager->dragObject)
//???		{
//???			ImageList_EndDrag();
//???			ShowCursor(TRUE);
//???			windowManager->dragObject = ZAF_NULLP(ZafWindowObject);
//???		}
//???//		else
//???			ccode = ZafWindowObject::OSEvent(event);
//???		break;
//???
//???	case WM_MOUSEMOVE:
//???		if (ZafMSWindowsApp::commonControlsAvailable && windowManager->dragObject)
//???		{
//???			int x = LOWORD(event.osEvent.lParam);
//???			int y = HIWORD(event.osEvent.lParam);
//???			ImageList_DragMove(x, y);
//???
//???			TV_HITTESTINFO hitTestInfo;
//???			hitTestInfo.pt.x = x;
//???			hitTestInfo.pt.y = y;
//???
//???			HTREEITEM hTarget = (HTREEITEM)SendMessage(screenID, TVM_HITTEST, (WPARAM)0, (LPARAM)&hitTestInfo);
//???			if (hTarget)
//???				SendMessage(screenID, TVM_SELECTITEM, (WPARAM)TVGN_DROPHILITE, (LPARAM)hTarget);
//???		}
//???//		else
//???			ccode = ZafWindowObject::OSEvent(event);
//???		break;
//???
//???	case WM_NOTIFY:
//???		{
//???//??? Native drag and drop is not working yet.
//???		NM_TREEVIEW *nmTreeView = (NM_TREEVIEW *)event.osEvent.lParam;
//???
//???		if (nmTreeView->hdr.code == TVN_BEGINDRAG)
//???		{
//???			HIMAGELIST hImageList = (HIMAGELIST)SendMessage(screenID, TVM_CREATEDRAGIMAGE, (WPARAM)0, (LPARAM)nmTreeView->itemNew.hItem);
//???			RECT itemRect;
//???			SendMessage(screenID, TVM_GETITEMRECT, (WPARAM)TRUE, (LPARAM)&itemRect);
//???			ImageList_BeginDrag(hImageList, 0, nmTreeView->ptDrag.x, nmTreeView->ptDrag.y);
//???			ShowCursor(FALSE);
//???			SetCapture(screenID);
//???			windowManager->dragObject = this;
//???		}
//???//		else
//???			ccode = ZafWindowObject::OSEvent(event);
//???		}
//???		break;
//???#endif

	case WM_SETFOCUS:
		ccode = ZafWindowObject::OSEvent(event);
		break;

//???#if defined(ZAF_WIN32)
//???	case WM_CTLCOLOREDIT:
//???		{
//???		// Get the palettes.
//???		ZafPaletteState state = PaletteState();
//???		ZafPaletteStruct textPalette = LogicalPalette(ZAF_PM_TEXT, state);
//???		ZafPaletteStruct backgroundPalette = LogicalPalette(ZAF_PM_BACKGROUND, state);
//???
//???		// Get the OS colors from the text palette.
//???		COLORREF colorForeground = (textPalette.colorForeground == ZAF_CLR_DEFAULT) ?
//???			textPalette.osPalette.colorForeground :
//???			display->colorTable[textPalette.colorForeground];
//???		COLORREF colorBackground = (backgroundPalette.colorBackground == ZAF_CLR_DEFAULT) ?
//???			backgroundPalette.osPalette.colorBackground :
//???			display->colorTable[backgroundPalette.colorBackground];
//???
//???		// Set the OS colors.
//???		SelectPalette((HDC)event.osEvent.wParam, display->logicalPalette, FALSE);
//???		::SetTextColor((HDC)event.osEvent.wParam, colorForeground);
//???		SetBkColor((HDC)event.osEvent.wParam, colorBackground);
//???
//???		// Get a background brush.
//???		HBRUSH backgroundBrush = display->GetGdiCacheBrush(backgroundPalette);
//???		display->ReleaseGdiCacheObject(backgroundBrush);
//???		ccode = (ZafEventType)backgroundBrush;
//???		}
//???		break;
//???#endif

	default:
		ccode = ZafWindow::OSEvent(event);
		break;
	}

	return (ccode);
}

void ZafTreeList::OSMapPalette(ZafPaletteStruct &palette, ZafPaletteType type, ZafPaletteState state)
{
	// Get default colors from the operating system.
	if (type == ZAF_PM_TEXT)
	{
		if (state & ZAF_PM_SELECTED)
		{
			if (palette.colorForeground == ZAF_CLR_DEFAULT && palette.osPalette.colorForeground == 0xFFFFFFFFL)
				palette.osPalette.colorForeground = GetSysColor(COLOR_HIGHLIGHTTEXT);
			if (palette.colorBackground == ZAF_CLR_DEFAULT && palette.osPalette.colorBackground == 0xFFFFFFFFL)
				palette.osPalette.colorBackground = GetSysColor(COLOR_HIGHLIGHT);
		}
		else
		{
			if (palette.colorForeground == ZAF_CLR_DEFAULT && palette.osPalette.colorForeground == 0xFFFFFFFFL)
			{
				if (state & ZAF_PM_DISABLED)
					palette.osPalette.colorForeground = GetSysColor(COLOR_GRAYTEXT);
				else
					palette.osPalette.colorForeground = GetSysColor(COLOR_WINDOWTEXT);
			}
			if (palette.colorBackground == ZAF_CLR_DEFAULT && palette.osPalette.colorBackground == 0xFFFFFFFFL)
			{
				ZafPaletteStruct backgroundPalette = LogicalPalette(ZAF_PM_BACKGROUND, state);
				palette.colorBackground = backgroundPalette.colorBackground;
				palette.osPalette.colorBackground = backgroundPalette.osPalette.colorBackground;
			}
		}
	}
	else if (type == ZAF_PM_BACKGROUND)
	{
		if (palette.colorForeground == ZAF_CLR_DEFAULT && palette.osPalette.colorForeground == 0xFFFFFFFFL)
			palette.osPalette.colorForeground = GetSysColor(COLOR_WINDOW);
		if (palette.colorBackground == ZAF_CLR_DEFAULT && palette.osPalette.colorBackground == 0xFFFFFFFFL)
			palette.osPalette.colorBackground = GetSysColor(COLOR_WINDOW);
	}
	else
		ZafWindow::OSMapPalette(palette, type, state);

}

OSWindowID ZafTreeList::OSScreenID(ZafScreenIDType type) const
{
	// Return the os handle.
//???#if defined(ZAF_WIN32)
//???	if (ZafMSWindowsApp::commonControlsAvailable)
//???		return screenID;
//???	else
//???		return ZafWindow::OSScreenID(type);
//???#else
	return ZafWindow::OSScreenID(type);
//???#endif
}

void ZafTreeList::OSRegisterObject(void)
{
//???#if defined(ZAF_WIN32)
//???	if (ZafMSWindowsApp::commonControlsAvailable)
//???	{
//???		DWORD dwStyle = WS_CHILD | WS_VISIBLE | TVS_HASBUTTONS;
//???		DWORD dwExStyle = WS_EX_NOPARENTNOTIFY;
//???
//???		if (Bordered())
//???		{
//???#if defined(ZAF_MSWINDOWS_3D)
//???			dwExStyle |= WS_EX_CLIENTEDGE;
//???#else
//???			dwStyle |= WS_BORDER;
//???#endif
//???		}
//???
//???		// Create the tree view.
//???		InitCommonControls();
//???		screenID = ZafMSWindowsApp::CreateSubclassedWindow(this, WC_TREEVIEW, dwStyle, NULL, 0, dwExStyle);
//???
//???		// Create the image list.
//???		imageList = new ZafTreeImageList(display, screenID);
//???		SendMessage(screenID, TVM_SETIMAGELIST, (WPARAM)TVSIL_NORMAL, (LPARAM)imageList->Handle());
//???	}
//???	else
//???		ZafWindow::OSRegisterObject();
//???#else	
	ZafWindow::OSRegisterObject();
//???#endif
}

// ----- Stubs --------------------------------------------------------------

bool ZafTreeList::SetAutomaticUpdate(bool setAutomaticUpdate)
{
	// Defer to the base class.
	return (ZafWindow::SetAutomaticUpdate(setAutomaticUpdate));
}

#if defined(ZAF_DEFAULT_DRAW)
ZafEventType ZafTreeList::DrawFocus(ZafRegionStruct &region, ZafEventType ccode)
{
	return (ZafWindow::DrawFocus(region, ccode));
}
#endif


