/*

Jabber Protocol Plugin for Miranda IM
Copyright ( C ) 2002-04  Santithorn Bunchua
Copyright ( C ) 2005-11  George Hazan
Copyright ( C ) 2007     Victor Pavlychko

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or ( at your option ) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

Revision       : $Revision: 13452 $
Last change on : $Date: 2011-03-17 21:12:56 +0200 (Чт, 17 мар 2011) $
Last change by : $Author: george.hazan $

*/

#include "jabber.h"

#define TLIF_VISIBLE	0x01
#define TLIF_EXPANDED	0x02
#define TLIF_MODIFIED	0x04
#define TLIF_ROOT		0X08
#define TLIF_HASITEM	0X10
#define TLIF_REBUILD	0x20
#define TLIF_FAKEPARENT	0x40
#define TLIF_FILTERED	0x80

struct TTreeList_ItemInfo
{
	BYTE flags;
	int indent, sortIndex;

	struct TTreeList_ItemInfo *parent;
	int iIcon, iOverlay;
	LIST<TCHAR> text;
	LPARAM data;
	LIST<TTreeList_ItemInfo> subItems;

	TTreeList_ItemInfo(int columns = 3, int children = 5):
		text(columns), subItems(children), parent(NULL),
		flags(0), indent(0), sortIndex(0), iIcon(0), iOverlay(0), data(0) {}
	~TTreeList_ItemInfo()
	{
		int i;
		for (i = text.getCount(); i--; )
			mir_free(text[i]);
		text.destroy();
		for (i = subItems.getCount(); i--; )
			delete subItems[i];
		subItems.destroy();
	}
};

struct TTreeList_Data
{
	int mode, sortMode;
	TCHAR *filter;
	HTREELISTITEM hItemSelected;
	TTreeList_ItemInfo *root;

	TTreeList_Data()
	{
		sortMode = 0;
		filter = NULL;
		mode = TLM_TREE;
		root = NULL;
	}
	~TTreeList_Data()
	{
		if (root) delete root;
		if (filter) mir_free(filter);
	}
};

// static utilities
static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data);
static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data);
static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data);
static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data);
static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data);
static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

static __forceinline void sttTreeList_SeWindowData(HWND hwnd, HANDLE data)
{
	SetPropA(hwnd, "Miranda.TreeList", (HANDLE)data);
}

static __forceinline HANDLE sttTreeList_GeWindowData(HWND hwnd)
{
	return GetPropA(hwnd, "Miranda.TreeList");
}

// tree list implementation
LPARAM TreeList_GetData(HTREELISTITEM hItem)
{
	return hItem->data;
}

HTREELISTITEM TreeList_GetRoot(HWND hwnd)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	return data->root;
}

int TreeList_GetChildrenCount(HTREELISTITEM hItem)
{
	return hItem->subItems.getCount();
}

HTREELISTITEM TreeList_GetChild(HTREELISTITEM hItem, int i)
{
	return hItem->subItems[i];
}

void TreeList_Create(HWND hwnd)
{
	TTreeList_Data *data = new TTreeList_Data;
	data->root = new TTreeList_ItemInfo;
	data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT;
	data->root->indent = -1;
	data->hItemSelected = data->root;
	sttTreeList_SeWindowData(hwnd, data);

	ListView_SetExtendedListViewStyle(hwnd, LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER | LVS_EX_GRIDLINES | LVS_EX_INFOTIP );

	HIMAGELIST hIml;
	hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1);
	ListView_SetImageList (hwnd, hIml, LVSIL_SMALL);

	hIml = ImageList_Create(16, 16, ILC_MASK + ( IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16 ), 2, 1);
	ImageList_AddIcon_Icolib(hIml, (HICON)JCallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPOPEN, 0 ));
	ImageList_AddIcon_Icolib(hIml, (HICON)JCallService( MS_SKIN_LOADICON, SKINICON_OTHER_GROUPSHUT, 0 ));
	ImageList_AddIcon_Icolib(hIml, (HICON)JCallService( MS_SKIN_LOADICON, SKINICON_OTHER_DOWNARROW, 0 ));
	ListView_SetImageList (hwnd, hIml, LVSIL_STATE);
}

void TreeList_Destroy(HWND hwnd)
{
	ListView_DeleteAllItems(hwnd);
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	delete data;
}

void TreeList_Reset(HWND hwnd)
{
	ListView_DeleteAllItems(hwnd);
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	delete data->root;
	data->root = new TTreeList_ItemInfo;
	data->root->flags = TLIF_EXPANDED|TLIF_VISIBLE|TLIF_ROOT;
	data->root->indent = -1;
	data->hItemSelected = data->root;
}

void TreeList_SetMode(HWND hwnd, int mode)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	data->mode = mode;
	ListView_DeleteAllItems(hwnd);
	TreeList_Update(hwnd);
}

void TreeList_SetSortMode(HWND hwnd, int col, BOOL descending)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	if ((col >= 0) && (col < 2))
		data->sortMode = 1 + col * 2 + (descending ? 1 : 0);
	else
		data->sortMode = 0;
	TreeList_Update(hwnd);
}

void TreeList_SetFilter(HWND hwnd, TCHAR *filter)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	if (data->filter) mir_free(data->filter);
	data->filter = NULL;
	if (filter) data->filter = mir_tstrdup(filter);
	TreeList_Update(hwnd);
}

HTREELISTITEM TreeList_GetActiveItem(HWND hwnd)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	LVITEM lvi = {0};
	lvi.mask = LVIF_PARAM;
	lvi.iItem = ListView_GetNextItem(hwnd, -1, LVNI_SELECTED);
	if (lvi.iItem < 0)
		return (data->hItemSelected->flags & TLIF_ROOT) ? NULL : data->hItemSelected;
	ListView_GetItem(hwnd, &lvi);
	return (HTREELISTITEM)lvi.lParam;
}

HTREELISTITEM TreeList_AddItem(HWND hwnd, HTREELISTITEM hParent, TCHAR *text, LPARAM nodeDdata)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	if (!hParent) hParent = data->root;

	TTreeList_ItemInfo *item = new TTreeList_ItemInfo;
	item->data = nodeDdata;
	item->parent = hParent;
	item->text.insert(mir_tstrdup(text));
	item->flags |= TLIF_MODIFIED;
	if (hParent->flags & TLIF_ROOT)
	{
		item->flags |= TLIF_EXPANDED;
		data->hItemSelected = item;
	}
	item->indent = hParent->indent+1;
	hParent->subItems.insert(item);
	return item;
}

void TreeList_ResetItem(HWND hwnd, HTREELISTITEM hParent)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);

	for (int i = hParent->subItems.getCount(); i--; )
		delete hParent->subItems[i];
	hParent->subItems.destroy();

	data->hItemSelected = hParent;
	ListView_DeleteAllItems(hwnd);
}

void TreeList_MakeFakeParent(HTREELISTITEM hItem, BOOL flag)
{
	if (flag)
		hItem->flags |= TLIF_FAKEPARENT;
	else
		hItem->flags &= ~TLIF_FAKEPARENT;
	hItem->flags |= TLIF_MODIFIED;
}

void TreeList_AppendColumn(HTREELISTITEM hItem, TCHAR *text)
{
	hItem->text.insert(mir_tstrdup(text));
	hItem->flags |= TLIF_MODIFIED;
}

int TreeList_AddIcon(HWND hwnd, HICON hIcon, int iOverlay)
{
	HIMAGELIST hIml = ListView_GetImageList(hwnd, LVSIL_SMALL);
	int idx = ImageList_AddIcon(hIml, hIcon);
	g_ReleaseIcon(hIcon);
	if (iOverlay) ImageList_SetOverlayImage(hIml, idx, iOverlay);
	return idx;
}

void TreeList_SetIcon(HTREELISTITEM hItem, int iIcon, int iOverlay)
{
	if (iIcon >= 0) hItem->iIcon = iIcon;
	if (iOverlay >= 0) hItem->iOverlay = iOverlay;
	if ((iIcon >= 0) || (iOverlay >= 0)) hItem->flags |= TLIF_MODIFIED;
}

void TreeList_RecursiveApply(HTREELISTITEM hItem, void (*func)(HTREELISTITEM, LPARAM), LPARAM data)
{
	for ( int i = 0; i < hItem->subItems.getCount(); i++ ) {
		func( hItem->subItems[i], data );
		TreeList_RecursiveApply( hItem->subItems[i], func, data );
}	}

void TreeList_Update(HWND hwnd)
{
	TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(hwnd);
	HTREELISTITEM hItem = data->root;
	int sortIndex = 0;

	SendMessage(hwnd, WM_SETREDRAW, FALSE, 0);
	if (data->sortMode)
		TreeList_RecursiveApply(hItem, sttTreeList_SortItems, (LPARAM)data->sortMode);
	TreeList_RecursiveApply(hItem, sttTreeList_ResetIndex, (LPARAM)&sortIndex);
	if (data->filter)
		TreeList_RecursiveApply(hItem, sttTreeList_FilterItems, (LPARAM)data->filter);
	for ( int i = ListView_GetItemCount(hwnd); i--; ) {
		LVITEM lvi = {0};
		lvi.mask = LVIF_PARAM;
		lvi.iItem = i;
		lvi.iSubItem = 0;
		ListView_GetItem(hwnd, &lvi);

		HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam;
		if (( ptli->flags & TLIF_VISIBLE ) && (!data->filter || ( ptli->flags & TLIF_FILTERED ))) {
			ptli->flags |= TLIF_HASITEM;
			if ( ptli->flags & TLIF_MODIFIED ) {
				lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE | LVIF_TEXT;
				lvi.iItem = i;
				lvi.iSubItem = 0;
				lvi.pszText = ptli->text[0];
				lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK;
				lvi.iImage = ptli->iIcon;
				if (data->mode == TLM_TREE)
				{
					lvi.state =
						INDEXTOSTATEIMAGEMASK(
							((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 :
								(ptli->flags & TLIF_EXPANDED) ? 1 : 2 ) |
						INDEXTOOVERLAYMASK( ptli->iOverlay );
				} else
				{
					lvi.state =
						INDEXTOSTATEIMAGEMASK(
							((ptli->subItems.getCount() == 0) && !(ptli->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) |
						INDEXTOOVERLAYMASK( ptli->iOverlay );
				}
				ListView_SetItem(hwnd, &lvi);
				for (int j = 1; j < ptli->text.getCount(); ++j)
					ListView_SetItemText( hwnd, i, j, ptli->text[j]);
			}
		} 
		else ListView_DeleteItem(hwnd, i);
	}
	if (data->mode == TLM_TREE)
		TreeList_RecursiveApply(hItem, sttTreeList_CreateItems, (LPARAM)hwnd);
	else
	{
		for (int i = data->hItemSelected->subItems.getCount(); i--; )
			sttTreeList_CreateItems_List(data->hItemSelected->subItems[i], (LPARAM)hwnd);
		for  (HTREELISTITEM hItem = data->hItemSelected; !(hItem->flags & TLIF_ROOT); hItem = hItem->parent)
			sttTreeList_CreateItems_List(hItem, (LPARAM)hwnd);
	}
	ListView_SortItems(hwnd, sttTreeList_SortFunc, 0);
	SendMessage(hwnd, WM_SETREDRAW, TRUE, 0);
	UpdateWindow(hwnd);
}

BOOL TreeList_ProcessMessage(HWND hwnd, UINT msg, WPARAM, LPARAM lparam, UINT idc, BOOL* )
{
	LVITEM lvi = {0};

	switch (msg) {
	case WM_NOTIFY:
	{
		if (((LPNMHDR)lparam)->idFrom != idc)
			break;

		TTreeList_Data *data = (TTreeList_Data *)sttTreeList_GeWindowData(GetDlgItem(hwnd, idc));
		switch (((LPNMHDR)lparam)->code) {
		case LVN_COLUMNCLICK:
			{
				LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW)lparam;
				TreeList_SetSortMode(lpnmlv->hdr.hwndFrom, lpnmlv->iSubItem, FALSE);
			}
			break;

		case LVN_ITEMACTIVATE:
			if (data->mode == TLM_REPORT) {
				LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam;
				lvi.mask = LVIF_PARAM;
				lvi.iItem = lpnmia->iItem;
				ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi);
				
				HTREELISTITEM hItem = (lvi.iItem < 0) ? data-> root : (HTREELISTITEM)lvi.lParam;
				if (!hItem->subItems.getCount() && !(hItem->flags & TLIF_FAKEPARENT)) break;
				data->hItemSelected = hItem;

				NMTREEVIEW nmtv;
				nmtv.hdr.code = TVN_ITEMEXPANDED;
				nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom;
				nmtv.hdr.idFrom = lpnmia->hdr.idFrom;
				nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam;
				SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv);

				if (data->mode == TLM_REPORT)
				{
					ListView_DeleteAllItems(lpnmia->hdr.hwndFrom);
					TreeList_Update(lpnmia->hdr.hwndFrom);
				}
			}
			break;

		case LVN_KEYDOWN:
			if (data->mode == TLM_TREE) {
				LPNMLVKEYDOWN lpnmlvk = (LPNMLVKEYDOWN)lparam;

				lvi.mask = LVIF_PARAM|LVIF_INDENT;
				lvi.iItem = ListView_GetNextItem(lpnmlvk->hdr.hwndFrom, -1, LVNI_SELECTED);
				if (lvi.iItem < 0) return FALSE;
				lvi.iSubItem = 0;
				ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi);
				HTREELISTITEM hItem = (HTREELISTITEM)lvi.lParam;

				switch (lpnmlvk->wVKey) {
				case VK_SUBTRACT:
				case VK_LEFT:
				{
					if ( hItem->subItems.getCount() && (hItem->flags & TLIF_EXPANDED )) {
						hItem->flags &= ~TLIF_EXPANDED;
						hItem->flags |= TLIF_MODIFIED;
						TreeList_Update( lpnmlvk->hdr.hwndFrom );
					} 
					else if ( hItem->indent && (lpnmlvk->wVKey != VK_SUBTRACT )) {
						for ( int i = lvi.iItem; i--; ) {
							lvi.mask = LVIF_INDENT;
							lvi.iItem = i;
							lvi.iSubItem = 0;
							ListView_GetItem(lpnmlvk->hdr.hwndFrom, &lvi);
							if (lvi.iIndent < hItem->indent) {
								lvi.mask = LVIF_STATE;
								lvi.iItem = i;
								lvi.iSubItem = 0;
								lvi.state = lvi.stateMask = LVIS_FOCUSED|LVNI_SELECTED;
								ListView_SetItem(lpnmlvk->hdr.hwndFrom, &lvi);
								break;
					}	}	}
					break;
				}

				case VK_ADD:
				case VK_RIGHT:
					if ( (hItem->subItems.getCount() || (hItem->flags & TLIF_FAKEPARENT)) &&
						!( hItem->flags & TLIF_EXPANDED ))
					{
						hItem->flags |= TLIF_EXPANDED;
						hItem->flags |= TLIF_MODIFIED;

						NMTREEVIEW nmtv;
						nmtv.hdr.code = TVN_ITEMEXPANDED;
						nmtv.hdr.hwndFrom = lpnmlvk->hdr.hwndFrom;
						nmtv.hdr.idFrom = lpnmlvk->hdr.idFrom;
						nmtv.itemNew.hItem = (HTREEITEM)hItem;
						SendMessage(hwnd, WM_NOTIFY, lpnmlvk->hdr.idFrom, (LPARAM)&nmtv);
						TreeList_Update( lpnmlvk->hdr.hwndFrom );
					}
					break;
			}	}
			break;

		case NM_CLICK:
			if (data->mode == TLM_TREE) {
				LPNMITEMACTIVATE lpnmia = (LPNMITEMACTIVATE)lparam;
				LVHITTESTINFO lvhti = {0};
				lvi.mask = LVIF_PARAM;
				lvi.iItem = lpnmia->iItem;
				ListView_GetItem(lpnmia->hdr.hwndFrom, &lvi);
				lvhti.pt = lpnmia->ptAction;
				ListView_HitTest(lpnmia->hdr.hwndFrom, &lvhti);

				HTREELISTITEM ptli = ( HTREELISTITEM )lvi.lParam;
				if ((lvhti.iSubItem == 0) && ( (lvhti.flags&LVHT_ONITEM) == LVHT_ONITEMSTATEICON ) &&
					(ptli->subItems.getCount() || ptli->flags & TLIF_FAKEPARENT))
				{
					if ( ptli->flags & TLIF_EXPANDED )
						ptli->flags &= ~TLIF_EXPANDED;
					else {
						ptli->flags |= TLIF_EXPANDED;

						NMTREEVIEW nmtv;
						nmtv.hdr.code = TVN_ITEMEXPANDED;
						nmtv.hdr.hwndFrom = lpnmia->hdr.hwndFrom;
						nmtv.hdr.idFrom = lpnmia->hdr.idFrom;
						nmtv.itemNew.hItem = (HTREEITEM)lvi.lParam;
						SendMessage(hwnd, WM_NOTIFY, lpnmia->hdr.idFrom, (LPARAM)&nmtv);
					}
					ptli->flags |= TLIF_MODIFIED;
					TreeList_Update( lpnmia->hdr.hwndFrom );
			}	}
			break;
		}
		break;
	}	}
	return FALSE;
}

///////////////////////////////////////////////////////////////////////////
static int sttTreeList_SortItems_Cmp0(const void *p1, const void *p2) { return  lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); }
static int sttTreeList_SortItems_Cmp1(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[0], (*(HTREELISTITEM *)p2)->text[0]); }
static int sttTreeList_SortItems_Cmp2(const void *p1, const void *p2) { return  lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); }
static int sttTreeList_SortItems_Cmp3(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[1], (*(HTREELISTITEM *)p2)->text[1]); }
static int sttTreeList_SortItems_Cmp4(const void *p1, const void *p2) { return  lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); }
static int sttTreeList_SortItems_Cmp5(const void *p1, const void *p2) { return -lstrcmp((*(HTREELISTITEM *)p1)->text[2], (*(HTREELISTITEM *)p2)->text[2]); }

static void sttTreeList_SortItems(HTREELISTITEM hItem, LPARAM data)
{
	if (!hItem->subItems.getCount()) return;

	typedef int (__cdecl *TQSortCmp)(const void *, const void *);
	static TQSortCmp funcs[] =
	{
		sttTreeList_SortItems_Cmp0,
		sttTreeList_SortItems_Cmp1,
		sttTreeList_SortItems_Cmp2,
		sttTreeList_SortItems_Cmp3,
		sttTreeList_SortItems_Cmp4,
		sttTreeList_SortItems_Cmp5,
	};
	qsort(((SortedList *)&hItem->subItems)->items, hItem->subItems.getCount(), sizeof(void *), funcs[data-1]);
}

static void sttTreeList_ResetIndex(HTREELISTITEM hItem, LPARAM data)
{
	hItem->flags &= ~TLIF_HASITEM;

	if ( !hItem->parent || (hItem->parent->flags & TLIF_VISIBLE) && (hItem->parent->flags & TLIF_EXPANDED ))
		hItem->flags |= TLIF_VISIBLE;
	else
		hItem->flags &= ~TLIF_VISIBLE;

	hItem->sortIndex = (*(int *)data)++;
}

static void sttTreeList_FilterItems(HTREELISTITEM hItem, LPARAM data)
{
	int i = 0;
	for (i = 0; i < hItem->text.getCount(); ++i)
		if (JabberStrIStr(hItem->text[i], (TCHAR *)data))
			break;

	if (i < hItem->text.getCount())
	{
		while (!(hItem->flags & TLIF_ROOT))
		{
			hItem->flags |= TLIF_FILTERED;
			hItem = hItem->parent;
		}
	} else
	{
		hItem->flags &= ~TLIF_FILTERED;
	}
}

static void sttTreeList_CreateItems(HTREELISTITEM hItem, LPARAM data)
{
	TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data);
	if (( hItem->flags & TLIF_VISIBLE ) && (!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) {
		LVITEM lvi = {0};
		lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE;
		lvi.iIndent = hItem->indent;
		lvi.lParam = (LPARAM)hItem;
		lvi.pszText = hItem->text[0];
		lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK;
		lvi.iImage = hItem->iIcon;
		lvi.state =
			INDEXTOSTATEIMAGEMASK(
				((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 :
					(hItem->flags & TLIF_EXPANDED) ? 1 : 2 ) |
			INDEXTOOVERLAYMASK(hItem->iOverlay);

		int idx = ListView_InsertItem((HWND)data, &lvi);
		for ( int i = 1; i < hItem->text.getCount(); i++ )
			ListView_SetItemText((HWND)data, idx, i, hItem->text[i]);
}	}

static void sttTreeList_CreateItems_List(HTREELISTITEM hItem, LPARAM data)
{
	TTreeList_Data *listData = (TTreeList_Data *)sttTreeList_GeWindowData((HWND)data);
	if ((!listData->filter || ( hItem->flags & TLIF_FILTERED )) && !( hItem->flags & TLIF_HASITEM ) && !( hItem->flags & TLIF_ROOT )) {
		LVITEM lvi = {0};
		lvi.mask = LVIF_INDENT | LVIF_PARAM | LVIF_IMAGE | LVIF_TEXT | LVIF_STATE;
		lvi.iIndent = hItem->indent;
		lvi.lParam = (LPARAM)hItem;
		lvi.pszText = hItem->text[0];
		lvi.stateMask = LVIS_OVERLAYMASK|LVIS_STATEIMAGEMASK;
		lvi.iImage = hItem->iIcon;
		lvi.state =
			INDEXTOSTATEIMAGEMASK(
				((hItem->subItems.getCount() == 0) && !(hItem->flags & TLIF_FAKEPARENT)) ? 0 : 3 ) |
			INDEXTOOVERLAYMASK( hItem->iOverlay );

		int idx = ListView_InsertItem((HWND)data, &lvi);
		for ( int i = 1; i < hItem->text.getCount(); i++ )
			ListView_SetItemText((HWND)data, idx, i, hItem->text[i]);
}	}

static int CALLBACK sttTreeList_SortFunc(LPARAM lParam1, LPARAM lParam2, LPARAM )
{
	HTREELISTITEM p1 = ( HTREELISTITEM )lParam1, p2 = ( HTREELISTITEM )lParam2; 
	if ( p1->sortIndex < p2->sortIndex )
		return -1;

	if ( p1->sortIndex > p2->sortIndex )
		return +1;

	return 0;
}