// TreeListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "apl_gui.h"
#include <windowsx.h>  // required for GET_X_LPARAM, GET_Y_LPARAM)
#include <time.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define ID_TREE_LIST_HEADER 370


IMPLEMENT_DYNAMIC(CaplTreeListCtrl,CTreeCtrl)

/////////////////////////////////////////////////////////////////////////////
// CTLItem

CaplTreeListCtrl::CTLItem::CTLItem()
{
	m_Bold			= FALSE;
	m_Color			= ::GetSysColor(COLOR_WINDOWTEXT);
	m_parent_item	= NULL;
	m_fictive		= false;
	m_expanded		= false;
	m_bCrossOutText = false;
	m_type.Empty();
	itemData		= 0;
}

CaplTreeListCtrl::CTLItem::CTLItem(const CTLItem& copyItem)
{
	m_strings.RemoveAll();
	m_strings.Append(copyItem.m_strings);

	m_Bold			= copyItem.m_Bold;
	m_Color			= copyItem.m_Color;
	itemData		= copyItem.itemData;
	m_parent_item	= copyItem.m_parent_item;
	m_fictive		= copyItem.m_fictive;
	m_expanded		= copyItem.m_expanded;
	m_bCrossOutText = copyItem.m_bCrossOutText;
	m_type			= copyItem.m_type;
}

LPCTSTR CaplTreeListCtrl::CTLItem::GetSubstring(int m_nSub)
{
	if(m_nSub>=m_strings.GetSize()) return 0;
	return m_strings[m_nSub];
}

COLORREF CaplTreeListCtrl::CTLItem::GetSubstringColor(int m_nSub)
{
	if(m_nSub>=m_substring_color.GetSize()) return 0;
	return m_substring_color[m_nSub];
}

void CaplTreeListCtrl::CTLItem::SetSubstring(int m_nSub, LPCTSTR m_sText)
{
	m_strings.SetAtGrow(m_nSub,m_sText);
}

void CaplTreeListCtrl::CTLItem::SetSubstringColor(int m_nSub, COLORREF color)
{
	m_substring_color.SetAtGrow(m_nSub, color);
}

/////////////////////////////////////////////////////////////////////////////
// CaplTreeListCtrl

CaplTreeListCtrl::CaplTreeListCtrl()
{
	m_nColumns = m_nColumnsWidth = 0;
	m_nOffset = 0;
	m_LastSelectedItem=NULL;
	m_nLeftColumnNum=0;
	m_dlg=0;
	m_nItems=0;

	m_bShowHorLiles=true;
	m_bShowVerLiles=true;
	m_bAutoSizeLeftColumn=false;
	m_bSortRoot=true;
	m_wndColor =::GetSysColor(COLOR_WINDOW);

	m_bNoPaint=false;
	m_nHoverTimerID = 0;

	m_IsSingleSelect = true;
	m_lButtonPressed=false;
	m_needDeselectItem=false;

	m_strUniqueName.Empty();
	m_strColumnWidthSection = _T("ColumnWidths");
	m_AutoSaveColumnsWidth = false ;
	m_bNoRegColData = false ;
	m_bAutoSizeIfNoRegData = true ;

}

CaplTreeListCtrl::~CaplTreeListCtrl()
{		
}


BEGIN_MESSAGE_MAP(CaplTreeListCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CaplTreeListCtrl)
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_DESTROY()	
	ON_WM_LBUTTONDOWN()
	ON_WM_RBUTTONDOWN()	
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONUP()
	ON_WM_MOUSEMOVE()	
	ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
	ON_WM_TIMER()		
	ON_WM_SIZE()
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemexpanding)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnItemexpanded)
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
	
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CaplTreeListCtrl message handlers

int CaplTreeListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{	
	if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
		return -1;

	return 0;
} 

HTREEITEM CaplTreeListCtrl::GetTreeItem(int nItem)
{
	HTREEITEM m_ParentItem = GetRootItem();
	int m_nCount = 0;

	while((m_ParentItem!=NULL) && (m_nCount<nItem))
	{
		m_nCount ++ ;
		m_ParentItem=GetNextSiblingItem(m_ParentItem);
	}

	return m_ParentItem;
}

int CaplTreeListCtrl::GetListItem(HTREEITEM hItem)
{
	HTREEITEM m_ParentItem = GetRootItem();
	int m_nCount = 0;

	while((m_ParentItem!=NULL) && (m_ParentItem!=hItem))
	{
		m_nCount ++ ;
		m_ParentItem=GetNextSiblingItem(m_ParentItem);
	}

	return m_nCount;
}

int CaplTreeListCtrl::InsertColumn( int nCol, LPCTSTR lpszColumnHeading, int nFormat, int nWidth, int nSubItem)
{
	HD_ITEM hdi;
	hdi.mask = HDI_TEXT | HDI_FORMAT;
	if(nWidth!=-1)
	{
		hdi.mask |= HDI_WIDTH;
		hdi.cxy = nWidth;
	}
	
	hdi.pszText = (LPTSTR)lpszColumnHeading;
	hdi.fmt = HDF_OWNERDRAW;

	if(nFormat == LVCFMT_RIGHT)
		hdi.fmt |= HDF_RIGHT;
	else
	if(nFormat == LVCFMT_CENTER)
		hdi.fmt |= HDF_CENTER;
	else
		hdi.fmt |= HDF_LEFT;

	m_nColumns ++ ;

	int m_nReturn = m_wndHeader.InsertItem(nCol, &hdi);

	if(m_nColumns==1)
	{
		m_wndHeader.SetItemImage(m_nReturn, 0);
	}
	else
		m_wndHeader.SetItemImage(m_nReturn, -1);

	RecalcColumnsWidth();
	SetBkColor(m_wndColor);

	return m_nReturn;
}

void CaplTreeListCtrl::DeleteAllColumns()
{
	int nCount = m_wndHeader.GetItemCount();
	m_nColumns=0;
	// Delete all of the items.
	for (int i=0;i < nCount;i++)
	{
		 m_wndHeader.DeleteItem(0);	
	}
	RecalcColumnsWidth();
}


int CaplTreeListCtrl::DeleteColumn(int nCol)
{
	int m_nReturn = m_wndHeader.DeleteItem(nCol);
	m_nColumns--;
	RecalcColumnsWidth();
	return m_nReturn;
}

int CaplTreeListCtrl::GetColumnWidth(int nCol)
{
	HD_ITEM hItem;
	hItem.mask = HDI_WIDTH;
	if(!m_wndHeader.GetItem(nCol, &hItem))
		return 0;

	return hItem.cxy;
}

//Функции загрузки-сохранения ширины колонок
const int CaplTreeListCtrl::GetRegColumnWidth( int iColumn ) const
{	//You must set a unique name for each 
	ASSERT( m_strUniqueName.GetLength() );

	CString strEntry( m_strUniqueName );
	CString strValue, strSubString;
	CString strSection( m_strColumnWidthSection );

	strValue=_T("");
	CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
	if(0!=app) strValue = app->GetProfileString( strSection, strEntry, _T("") );
	AfxExtractSubString(strSubString, strValue, iColumn, _T(','));
	return _atoi( (LPCTSTR )strSubString );
}

void CaplTreeListCtrl::AutoSizeColumn( int iColumn )
{
	SetRedraw(false);
	HD_ITEM hItem;
	hItem.mask = HDI_WIDTH;
	hItem.cxy = LVSCW_AUTOSIZE;
	m_wndHeader.SetItem(iColumn,&hItem);
	int wc1 = GetColumnWidth (iColumn);
	hItem.cxy = LVSCW_AUTOSIZE_USEHEADER;
	m_wndHeader.SetItem(iColumn,&hItem);
	int wc2 = GetColumnWidth (iColumn);
	int wc = max(MINCOLWIDTH*12,max( wc1,wc2 ));

	if( wc > MAXCOLWIDTH )
		wc = MAXCOLWIDTH;

	if( wc < MINCOLWIDTH )	// M:18427
		wc = MINCOLWIDTH;

	hItem.cxy = wc;
	m_wndHeader.SetItem(iColumn,&hItem);
	SetRedraw(true);
}

void CaplTreeListCtrl::SetColumnWidth( int nCol )
{
	int iWidth = GetRegColumnWidth( nCol );
	if( iWidth < MINCOLWIDTH )
	{
		if (m_bAutoSizeIfNoRegData)
		{
			AutoSizeColumn( nCol );
		}
		m_bNoRegColData = true ;
	}
	else
	{
		HD_ITEM hItem;
		hItem.mask = HDI_WIDTH;
		hItem.cxy = iWidth ;
		m_wndHeader.SetItem(nCol, &hItem);
	}
}

void CaplTreeListCtrl::SetColumnWidth( int nCol, int iWidth )
{
		HD_ITEM hItem;
		hItem.mask = HDI_WIDTH;
		hItem.cxy = iWidth ;
		m_wndHeader.SetItem(nCol, &hItem);
}

int CaplTreeListCtrl::LoadColumnWidths()
{	//This function will load all the column widths and apply the widths to each respective column
	int iNumColumns = m_wndHeader.GetItemCount();
	for( int i = 0; i < iNumColumns; i++ )
	{
		SetColumnWidth( i );
	}
	return 1;
}

void CaplTreeListCtrl::SaveColumnWidths()
{	//You must set a unique name for every listctrl
	bool bBadValue = false ;
	ASSERT( m_strUniqueName.GetLength() );
	CString strEntry( m_strUniqueName );
	CString strValue;
	int iNumColumns = m_wndHeader.GetItemCount();
	for( int i = 0; i < iNumColumns; i++ )
	{
		CString strTemp;
		strTemp.Format(_T("%d,"), GetColumnWidth( i ) );
		strValue += strTemp;

		if (10 > GetColumnWidth(i))
		{
			bBadValue = true ;
		}
	}

	if (bBadValue && m_bNoRegColData)
	{
		//Ещё ни разу не сохраняли информацию о колонках, а в значениях явно дрянь - такое бывает, когда первый раз
		//запуситили программу и не открыли вкладку с данной таблицей
	}
	else
	{
		CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
		if(0!=app)	app->WriteProfileString( m_strColumnWidthSection, strEntry, strValue );
	}

}

void CaplTreeListCtrl::SetUniqueName(LPCTSTR lpszUniqueName)
{
	m_strUniqueName = lpszUniqueName;
	m_AutoSaveColumnsWidth = true;
}

int CaplTreeListCtrl::GetColumnAlign(int nCol)
{
	HD_ITEM hItem;
	hItem.mask = HDI_FORMAT;
	if(!m_wndHeader.GetItem(nCol, &hItem))
		return LVCFMT_LEFT;

	if(hItem.fmt & HDF_RIGHT)
		return LVCFMT_RIGHT;
	else
	if(hItem.fmt & HDF_CENTER)
		return LVCFMT_CENTER;
	else
		return LVCFMT_LEFT;
}

void CaplTreeListCtrl::RecalcColumnsWidth()
{
	m_nColumnsWidth = 0;
	for(int i=0;i<m_nColumns;i++)
		m_nColumnsWidth += GetColumnWidth(i);
}

void CaplTreeListCtrl::DrawItemText (CDC* pDC, CString text, CRect rect, int nWidth, int nFormat)
{
	// сам текст
    rect.left+=4;
	rect.right--;
	if((text.GetLength()<=0) || (rect.right<=rect.left)) return;

    UINT nStyle = DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS;

    if (nFormat == LVCFMT_LEFT)         nStyle |= DT_LEFT;
    else if (nFormat == LVCFMT_CENTER)  nStyle |= DT_CENTER;
    else                                nStyle |= DT_RIGHT;

	pDC->DrawText (text, rect, nStyle);	
}


bool CaplTreeListCtrl::PaintAll(CDC &dc, int cx, int cy)
{
	int cur_y=21;
	dc.SetBkColor(RGB(255,255,255));
	CPen pen;
	pen.CreatePen(PS_SOLID,1,RGB(192,192,192));
	CPen *oldPen=dc.SelectObject(&pen);

	CFont *pFont = CFont::FromHandle((HFONT)GetStockObject(ANSI_VAR_FONT));
	CFont *pOldFont=dc.SelectObject(pFont);

	PaintItem(TVI_ROOT,dc,-1,cur_y,cy);

	// рисуем линии
	CHeaderCtrl* pHeadC = (CHeaderCtrl*)&(m_wndHeader);
	int SubItemCount = pHeadC->GetItemCount();

	int Width = 0;
	int High = cur_y;

	CRect txt_rect;
	txt_rect.top=2;
	txt_rect.bottom=18;

	HDITEM hdi;
	enum   { sizeOfBuffer = 256 };
	TCHAR  lpBuffer[sizeOfBuffer];
	bool   fFound = false;

	hdi.mask = HDI_TEXT;
	hdi.pszText = lpBuffer;
	hdi.cchTextMax = sizeOfBuffer;

	CFont font;


	for(int i=0;i<m_nColumns;i++)
	{
		txt_rect.left=Width+2;
		txt_rect.right=txt_rect.left+GetColumnWidth(i)-3;
		//dc.FillSolidRect(LPRECT(txt_rect),RGB(255,0,0));
		pHeadC->GetItem(i,&hdi);
		dc.DrawText(hdi.pszText,LPRECT(txt_rect),DT_LEFT|DT_SINGLELINE|DT_WORD_ELLIPSIS|DT_VCENTER);

		Width += GetColumnWidth(i);
		dc.MoveTo(Width,0);
		dc.LineTo(Width,High);
	}
	/*int cy=GetItemHeight();
	int y=cy-1;
	while(y<High)
	{
		dc.MoveTo(0,y);
		dc.LineTo(Width,y);
		y+=cy;
	}*/
	dc.MoveTo(0,0); dc.LineTo(Width,0);
	dc.MoveTo(0,0); dc.LineTo(0,High);
	dc.MoveTo(0,21); dc.LineTo(Width,21);

	dc.SelectObject(pOldFont);
	dc.SelectObject(&oldPen);
	pen.DeleteObject();
	return true;
}


bool CaplTreeListCtrl::PaintItem(HTREEITEM hItem, CDC &dc, int level, int &cur_y, int cy)
{
	if(hItem!=TVI_ROOT)
	{
		//CRect rect;
		CRect m_labelRect;
		GetItemRect( hItem, &m_labelRect, TRUE );
		//GetItemRect( hItem, &rect, FALSE );

		m_labelRect.top=cur_y+1;
		m_labelRect.bottom=cur_y+GetItemHeight()-1;
		m_labelRect.right=GetColumnWidth(0);
		CString buf=GetItemText(hItem, 0);
		dc.DrawText(buf,m_labelRect,DT_LEFT|DT_SINGLELINE|DT_PATH_ELLIPSIS|DT_VCENTER);

		CHeaderCtrl* pHeadC = (CHeaderCtrl*)&(m_wndHeader);
		int SubItemCount = pHeadC->GetItemCount();

		for (int nSubItem = 1; nSubItem < SubItemCount; nSubItem++)
		{
			m_labelRect.left=m_labelRect.right;
			m_labelRect.right=m_labelRect.left+GetColumnWidth(nSubItem);
			m_labelRect.left+=4;
			buf= GetItemText(hItem, nSubItem);
			if(buf!=_T(""))dc.DrawText(buf,m_labelRect,DT_LEFT|DT_SINGLELINE|DT_WORD_ELLIPSIS|DT_VCENTER);
		}
		cur_y+=GetItemHeight();
		//int Width=m_labelRect.right+1;
		int Width=cy;

		dc.MoveTo(0,cur_y); dc.LineTo(Width,cur_y);
	}

	level++;
	bool bOnlyWithData=true;
	HTREEITEM hChildItem = GetNextItem(hItem, TVGN_CHILD);
	while (hChildItem)
	{
		int data=1;
		if(bOnlyWithData) data= GetItemData(hChildItem);
		if(data!=0) PaintItem(hChildItem, dc,level,cur_y,cy);
		hChildItem = GetNextItem(hChildItem, TVGN_NEXT);
	}
	return true;
}




void CaplTreeListCtrl::OnPaint()
{
	if(m_bNoPaint)return;

	CPaintDC dc(this); // device context for painting
	if(!IsWindowVisible( ))
	{
		CWnd::DefWindowProc( WM_PAINT, (WPARAM)dc.m_hDC, 0 );
		return;
	}
	else
	{
		CWnd* parent = GetParent();
		if(parent)
			if(!parent->IsWindowVisible())
				return;
	}

	CRect rcClip, rcClient;
	dc.GetClipBox( &rcClip );
	GetClientRect(&rcClient);
	
	int width = this->GetColumnsWidth();

	dc.SetViewportOrg(m_nOffset, 0);
	dc.SetTextColor(m_wndColor);
	 
	// First let the control do its default drawing.
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)dc.m_hDC, 0 );

//	dc.FillSolidRect(GetColumnWidth(0),1,rcClient.Width(),rcClient.Height(),m_wndColor);
	dc.FillSolidRect(GetColumnWidth(0), 0, width, rcClient.Height(),m_wndColor);
	CFont *pFont = GetFont();
	CFont *pFontCrossOut = GetFont();
	CFont *pFontOld = dc.SelectObject( pFont );

	LOGFONT logfont;
	pFont->GetLogFont( &logfont );

	logfont.lfWeight = 700;
	CFont boldFontDC;
	boldFontDC.CreateFontIndirect( &logfont );

	LOGFONT logfontBold;
	boldFontDC.GetLogFont(&logfontBold);
	if(logfont.lfWeight == logfontBold.lfWeight) logfont.lfWeight=400;
	
	LOGFONT logfontCrossOut;
	pFontCrossOut->GetLogFont( &logfontCrossOut );
	logfontCrossOut.lfStrikeOut = 1;
	CFont crossOutFont;
	crossOutFont.CreateFontIndirect( &logfontCrossOut );

	// and now let's get to the painting itself
	COLORREF clrBack=GetSysColor(COLOR_WINDOW);
	COLORREF clrText=GetSysColor(COLOR_HIGHLIGHTTEXT);
	COLORREF crSelect = GetSysColor(COLOR_HIGHLIGHT);
	COLORREF crSelectFill=aplColor_GetHilightColor(crSelect,75);

	RECT rectSelItem; rectSelItem.left=-1;

	CTLItem *pItem;
	HTREEITEM hItem = GetFirstVisibleItem();
	int n = GetVisibleCount(), m_nWidth;
	while(hItem!=NULL && n>=0)
	{
		CRect rect;
		CRect m_labelRect;
		GetItemRect( hItem, &m_labelRect, TRUE );
		GetItemRect( hItem, &rect, FALSE );
		
		if(GetColumnsNum()>1)
			rect.left = min(m_labelRect.left, GetColumnWidth(0));
		else
			rect.left = m_labelRect.left;

		rect.right = m_nColumnsWidth;
		
		pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);		

		if(pItem!=0)
		{

		CString sItem = pItem->GetItemText();

			UINT selflag =  TVIS_SELECTED;
			UINT dropflag = TVIS_DROPHILITED ;
			UINT curState = GetItemState( hItem, selflag | dropflag);
		
			if ( !(curState & selflag ) && !(curState & dropflag ))
			{
				// Если не выделено
				dc.SetBkMode(TRANSPARENT);
				dc.SetBkColor( m_wndColor );
				dc.SetTextColor( pItem->m_Color );
			}
			else
			{
				// Выделено
				if(CaplTreeView::m_xp_mode)
				{
					dc.FillSolidRect (&rect, crSelectFill);
					//dc.Draw3dRect(&rect,crSelect,crSelect);

					dc.SetTextColor(pItem->m_Color );
					dc.SetBkColor(crSelectFill);

					rectSelItem=rect;
					//rectSelItem.top-=2;
					//rectSelItem.bottom+=2;
				}
				else
				{
					dc.FillSolidRect (rect, crSelect);
				
					if(curState&TVIS_SELECTED)
						dc.DrawFocusRect (rect);

					dc.SetTextColor(clrText);
					dc.SetBkColor(crSelect);
				}
			}
			
			if(pItem->m_Bold) dc.SelectObject( &boldFontDC );
			else if(pItem->m_bCrossOutText) dc.SelectObject(&crossOutFont);
			else dc.SelectObject( pFont );

			DrawItemText(&dc, sItem, CRect(rect.left - 2, rect.top, GetColumnWidth(0), rect.bottom), GetColumnWidth(0)-rect.left-2, GetColumnAlign(0));
			m_nWidth = 0;
			for(int i=1;i<m_nColumns;i++)
			{
				m_nWidth += GetColumnWidth(i-1);

				if(CaplTreeView::m_xp_mode)
				{
					dc.SetTextColor(pItem->GetSubstringColor(i));
				}
				else
				{
					if ( !(curState & selflag )) dc.SetTextColor(pItem->GetSubstringColor(i)); // не выделено
					else 	dc.SetTextColor(::GetSysColor (COLOR_HIGHLIGHTTEXT)); //выделено
				}

				CString tmp = pItem->GetSubstring(i);
				dc.SelectObject( pFont );
				
				DrawItemText(&dc, tmp, CRect(m_nWidth, rect.top, m_nWidth+GetColumnWidth(i), rect.bottom), GetColumnWidth(i), GetColumnAlign(i));
			}
		}
		hItem = GetNextVisibleItem( hItem );
		n--;
	}
	dc.SelectObject( pFontOld );

	// Отрисовка вертикальных и горизонтальных линий
	if(m_bShowVerLiles||m_bShowHorLiles)
	{
		CPen pen;
		pen.CreatePen(PS_SOLID,1,RGB(192,192,192));
		CPen *oldPen=dc.SelectObject(&pen);
		int Width = 0, High=rcClient.Height();
		if(m_bShowVerLiles)
		{
			for(int i=0;i<m_nColumns;i++)
			{
				Width += GetColumnWidth(i);
				dc.MoveTo(Width-1,0);
				dc.LineTo(Width-1,High);
			}
		}
		else Width=rcClient.Width();

		if(m_bShowHorLiles)
		{
			int cy=GetItemHeight();
			int y=cy-1;
			while(y<High)
			{
				dc.MoveTo(0,y);
				dc.LineTo(Width,y);
				y+=cy;
			}
		}
		dc.SelectObject(&oldPen);
		pen.DeleteObject();
	}

	if(CaplTreeView::m_xp_mode)
	{
		if(rectSelItem.left>-1)
			dc.Draw3dRect(&rectSelItem,crSelect,crSelect);
	}

	
	boldFontDC.DeleteObject();
}

void CaplTreeListCtrl::ResetVertScrollBar()
{
	CaplTreeListCtrlView *pFrame = (CaplTreeListCtrlView*)GetParent();

	CRect m_treeRect;
	GetClientRect(&m_treeRect);

	CRect m_wndRect;
	pFrame->GetClientRect(&m_wndRect);

	CRect m_headerRect;
	m_wndHeader.GetClientRect(&m_headerRect);	

	CRect m_barRect;
	pFrame->m_horScrollBar.GetClientRect(&m_barRect);

	if(!pFrame->HorizontalScrollVisible())
		SetWindowPos(&wndTop, 0, 0, m_wndRect.Width(), m_wndRect.Height()-m_headerRect.Height(), SWP_NOMOVE);
	else
		SetWindowPos(&wndTop, 0, 0, m_wndRect.Width(), m_wndRect.Height()-m_barRect.Height()-m_headerRect.Height(), SWP_NOMOVE);

	if(pFrame->HorizontalScrollVisible())
	{
		if(!pFrame->VerticalScrollVisible())
		{
			pFrame->m_horScrollBar.SetWindowPos(&wndTop, 0, 0, m_wndRect.Width(), m_barRect.Height(), SWP_NOMOVE);
			
			int nMin, nMax;
			pFrame->m_horScrollBar.GetScrollRange(&nMin, &nMax);
			if((nMax-nMin) == (GetColumnsWidth()-m_treeRect.Width()+GetSystemMetrics(SM_CXVSCROLL)))
				// i.e. it disappeared because of calling
				// SetWindowPos
			{
				if(nMax - GetSystemMetrics(SM_CXVSCROLL) > 0)
					pFrame->m_horScrollBar.SetScrollRange(nMin, nMax - GetSystemMetrics(SM_CXVSCROLL));
				else
					// hide the horz scroll bar and update the tree
				{
					pFrame->m_horScrollBar.EnableWindow(FALSE);

					// we no longer need it, so hide it!
					{
						pFrame->m_horScrollBar.ShowWindow(SW_HIDE);

						SetWindowPos(&wndTop, 0, 0, m_wndRect.Width(), m_wndRect.Height() - m_headerRect.Height(), SWP_NOMOVE);
						// the tree takes scroll's place
					}

					pFrame->m_horScrollBar.SetScrollRange(0, 0);

					// set scroll offset to zero
					{
						m_nOffset = 0;
						Invalidate();
						m_wndHeader.GetWindowRect(&m_headerRect);
						m_wndHeader.SetWindowPos(&wndTop, m_nOffset, 0, max(pFrame->StretchWidth(GetColumnsWidth(),m_wndRect.Width()),m_wndRect.Width()), m_headerRect.Height(), SWP_SHOWWINDOW);
					}
				}
			}
		}
		else
		{
			pFrame->m_horScrollBar.SetWindowPos(&wndTop, 0, 0, m_wndRect.Width() - GetSystemMetrics(SM_CXVSCROLL), m_barRect.Height(), SWP_NOMOVE);

			int nMin, nMax;
			pFrame->m_horScrollBar.GetScrollRange(&nMin, &nMax);
			if((nMax-nMin) == (GetColumnsWidth()-m_treeRect.Width()-GetSystemMetrics(SM_CXVSCROLL)))
				// i.e. it appeared because of calling
				// SetWindowPos
			{
				pFrame->m_horScrollBar.SetScrollRange(nMin, nMax + GetSystemMetrics(SM_CXVSCROLL));
			}
		}
	}
	else
	if(pFrame->VerticalScrollVisible())
	{
		if(GetColumnsWidth()>m_treeRect.Width())
			// the vertical scroll bar takes some place
			// and the columns are a bit bigger than the client
			// area but smaller than (client area + vertical scroll width)
		{
			// show the horz scroll bar
			{
				pFrame->m_horScrollBar.EnableWindow(TRUE);

				pFrame->m_horScrollBar.ShowWindow(SW_SHOW);

				// the tree becomes smaller
				SetWindowPos(&wndTop, 0, 0, m_wndRect.Width(), m_wndRect.Height()-m_barRect.Height()-m_headerRect.Height(), SWP_NOMOVE);

				pFrame->m_horScrollBar.SetWindowPos(&wndTop, 0, 0, m_wndRect.Width() - GetSystemMetrics(SM_CXVSCROLL), m_barRect.Height(), SWP_NOMOVE);
			}

			pFrame->m_horScrollBar.SetScrollRange(0, GetColumnsWidth()-m_treeRect.Width());
		}
	}
}

bool CaplTreeListCtrl::GetListSelected(CArray<HTREEITEM,HTREEITEM> &list_selected)
{
	HTREEITEM ht;
	UINT state=0;
	ht=GetFirstVisibleItem();
	while(ht)
	{
		state = GetItemState(ht, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
		if(state&TVIS_SELECTED){
			list_selected.Add(ht);
		}
		ht = GetNextVisibleItem(ht);
	}
	return true;
}

void CaplTreeListCtrl::DeselectAll(bool selected,bool droplited)
{
	HTREEITEM ht;
	UINT state=0;
	if(!selected && !droplited)return;
	ht=GetFirstVisibleItem();
	while(ht)
	{
		state = GetItemState(ht, TVIS_SELECTED|TVIS_DROPHILITED);
		if(selected){if(state&TVIS_SELECTED)state = state&~TVIS_SELECTED;}
		if(droplited){if(state&TVIS_DROPHILITED)state = state&~TVIS_DROPHILITED;}
		SetItemState(ht, state, TVIS_SELECTED|TVIS_DROPHILITED);
		ht = GetNextVisibleItem(ht);
	}

	//Select(NULL, TVGN_CARET);	
}

BOOL CaplTreeListCtrl::SingleSelectItem(HTREEITEM hItem,bool is_select_parent)
{
	UINT state=0;
	state = GetItemState(hItem, TVIS_SELECTED|TVIS_DROPHILITED);
	if(!(state&TVIS_SELECTED)){
		state = state|TVIS_SELECTED;
	}
	if((state&TVIS_DROPHILITED)){
		state = state&~TVIS_DROPHILITED;
	}
	SetItemState(hItem, state, TVIS_SELECTED|TVIS_DROPHILITED);
	if(is_select_parent)CTreeCtrl::Select(hItem,TVGN_CARET);

	SetFocus();
	return TRUE;
}


BOOL CaplTreeListCtrl::SelectItem(HTREEITEM hItem,bool ButtonDown)
{
	HTREEITEM currItem=0;
	HTREEITEM lastCurrItem=0;
	if(hItem==0)return FALSE;
//	OutputDebugString(" CaplTreeListCtrl::SelectItem \n");

	UINT code;

	SHORT Ctrl = GetAsyncKeyState(VK_CONTROL);
	SHORT Shift = GetAsyncKeyState(VK_SHIFT);
	UINT state=0;

	if(m_IsSingleSelect){
		if(ButtonDown){
			DeselectAll();
			SingleSelectItem(hItem);
		}
		return TRUE;
	}

	if(Shift<0)
	{
		if(!ButtonDown){
			// как в проводнике - с шифтом выделение по нажатию мыши
			return TRUE;
		}

		RECT rect_last;
		RECT rect_curr;
		if(Ctrl>=0){
			// как в проводнике - если контрол и шифт - выделение не снимается
			DeselectAll();
		}
		
		// выделяем от последнего нажатого без Shift
		lastCurrItem=m_LastSelectedItem;
		// в каком направлении работаем?
		GetItemRect(m_LastSelectedItem,&rect_last,FALSE);
		GetItemRect(hItem,&rect_curr,FALSE);
		code=(rect_last.top<rect_curr.top)?TVGN_NEXTVISIBLE:TVGN_PREVIOUSVISIBLE;
		// начинаем с последнего нажатого без Shift
		currItem=m_LastSelectedItem;
		do{
			SingleSelectItem(currItem,false);
//			state = GetItemState(currItem, TVIS_SELECTED|TVIS_DROPHILITED);
//			if(!(state&TVIS_SELECTED)){
//				state = state|TVIS_SELECTED;
//			}
////			if((state&TVIS_DROPHILITED)){
////				state = state&~TVIS_DROPHILITED;
////			}
//			SetItemState(currItem, state, TVIS_SELECTED|TVIS_DROPHILITED);

			if(currItem==hItem){
				break;
			}
			currItem=GetNextItem(lastCurrItem,code);
			if(currItem==0){
				break;
			}
			lastCurrItem=currItem;
		}while(true);
		return TRUE;
	}
	else if(Ctrl<0)
	{
		// опять как в проводнике - там если шифт с контролом, то выделенеие по шифьу
		// инвертируем выделение (при нажатии всегда выделен для блага драг-н-дропа)
		m_LastSelectedItem = hItem;
		state = GetItemState(m_LastSelectedItem, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
		if(state&TVIS_SELECTED /*|| state&TVIS_DROPHILITED*/){
			state = state&~TVIS_SELECTED;
			//if(state&TVIS_DROPHILITED)state = state&~TVIS_DROPHILITED;
			if(ButtonDown){
				m_needDeselectItem=true;
			}
		}else{
			state = state|TVIS_SELECTED/*|TVIS_DROPHILITED*/;
			if(ButtonDown){
				m_needDeselectItem=false;
				SetItemState(m_LastSelectedItem, state, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
			}
		}
		if(!ButtonDown){
			if(m_needDeselectItem){
				SetItemState(m_LastSelectedItem, state, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
			}
			m_needDeselectItem=false;
		}
		return TRUE;
	}
	else
	{
		// ну и остались нажатия/отпускания без вспомогательных клавиш
		m_LastSelectedItem = hItem;
		if(ButtonDown){
			// проверяем - выделен ли кликнутый item
			state = GetItemState(m_LastSelectedItem, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
			if(state&TVIS_SELECTED /*|| state&TVIS_DROPHILITED*/){
				// выделен - наверно, это начала драг-н-дропа
				return TRUE;
			}else{
				DeselectAll();
				SingleSelectItem(m_LastSelectedItem);
			}
		}else{
			// при отпускании - просто выделяем текущий (в проводнике еще 
			// и редактирование метки начинается, но это не для нас)
			DeselectAll();
			SingleSelectItem(m_LastSelectedItem,false);
		}
//		CTreeCtrl::Select(hItem,TVGN_CARET);
//		return SetItemState(hItem, TVIS_SELECTED|TVIS_DROPHILITED, TVIS_SELECTED|TVIS_DROPHILITED);
	}

	return TRUE;
}


void CaplTreeListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{	
	UINT flags;
	HTREEITEM curr_item;
//	OutputDebugString(" CaplTreeListCtrl::OnLButtonDown \n");

	curr_item = HitTest(point, &flags);
	if(curr_item==0)
	{
		DeselectAll();

		if(m_dlg)
			m_dlg->SendMessage(WM_LBUTTONDOWN,(WPARAM)MK_LBUTTON,MAKELPARAM(point.x,point.y));			
		
		CWnd *parent = GetParent();
		if(parent)
		{
			ClientToScreen(&point);
			parent->SendMessage(WM_LBUTTONDOWN,(WPARAM)MK_LBUTTON,MAKELPARAM(point.x,point.y));
		}
	}
	else
	{
		m_lButtonPressed=true;

		SelectItem(curr_item,true);
		if(flags&TVHT_ONITEMSTATEICON && m_dlg) m_dlg->CheckItem();

		if(m_dlg)
		{
			m_dlg->SendMessage(WM_SELCHANGE,(WPARAM)this->GetDlgCtrlID(),0);
			//ClientToScreen(&point);
			m_dlg->SendMessage(WM_LBUTTONDOWN,(WPARAM)MK_LBUTTON,MAKELPARAM(point.x,point.y));
			//m_dlg->UpdateUserData();
		}
		else
		{
			CWnd *parent=GetParent();
			if(parent)
			{
				ClientToScreen(&point);
				parent->SendMessage(WM_LBUTTONDOWN,(WPARAM)nFlags,MAKELPARAM(point.x,point.y));
			}
		}
	}

	CTreeCtrl::OnLButtonDown(nFlags, point);
}

void CaplTreeListCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{		
//	OutputDebugString(" CaplTreeListCtrl::OnLButtonUp \n");
	HTREEITEM curr_item;
	m_lButtonPressed=false;
	curr_item = HitTest(point, &nFlags);
	if(curr_item==0)return;
	SelectItem(curr_item,false);

//	if(m_dlg){
//		m_dlg->SendMessage(WM_SELCHANGE,(WPARAM)this->GetDlgCtrlID(),0);
//		m_dlg->UpdateUserData();
//	}
//	else
//	{
		CWnd *parent=GetParent();
		if(parent)
		{
			ClientToScreen(&point);
			parent->SendMessage(WM_LBUTTONUP,(WPARAM)nFlags,MAKELPARAM(point.x,point.y));
		}
//	}
	CTreeCtrl::OnLButtonUp(nFlags, point);
}

void CaplTreeListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	if((GetColumnsNum()==0) || (point.x<GetColumnWidth(0)))
	{
		CTreeCtrl::OnLButtonDblClk(nFlags, point);
		ResetVertScrollBar();
	}
	CWnd *parent=GetParent();
	if(parent)
	{
		ClientToScreen(&point);
		parent->SendMessage(WM_LBUTTONDBLCLK,(WPARAM)MK_LBUTTON,MAKELPARAM(point.x,point.y));
	}
	
/*
	Эту аццкую функцию закомментировал я, Орлов И.Н., потому что она мешала мне создавать
	in-place edit & combo controls в мега-плагине PdfCharListAddIn.
	Т.е. создавать она не мешала, но мешала получению этими контролами фокуса ввода после 
	создания.
 */
//	SetFocus();
}

void CaplTreeListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	CTreeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
	ResetVertScrollBar();
	if (nChar > VK_ESCAPE)
	{
		HTREEITEM curr_item;
		curr_item = GetSelectedItem();
		SelectItem(curr_item, true);

		CWnd* parent = GetParent();
		if (parent)
			parent->SendMessage(WM_KEYDOWN, (WPARAM)nChar, ::MapVirtualKey(nChar, 0) << 16 | 1);
	}
	if(!m_IsSingleSelect){
		SHORT Ctrl = GetAsyncKeyState(VK_CONTROL);
		if(Ctrl<0 && nChar==65){
			HTREEITEM ht;
			UINT state=0;
			ht=GetFirstVisibleItem();
			while(ht)
			{
				SingleSelectItem(ht, false);
				ht = GetNextVisibleItem(ht);
			}

		}
	}
	if(m_dlg) m_dlg->UpdateUserData();
}

bool CaplTreeListCtrl::IsItemFictive(HTREEITEM hItem)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	if(pItem->m_fictive) return true;
	return false;
}

bool CaplTreeListCtrl::SetItemType(HTREEITEM hItem,CString &type)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return false;
	pItem->m_type=type;
	return true;
}

bool CaplTreeListCtrl::GetItemType(HTREEITEM hItem,CString &type)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return false;
	type=pItem->m_type;
	return true;
}

BOOL CaplTreeListCtrl::SetItemData(HTREEITEM hItem, DWORD dwData)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->itemData = dwData;
	return CTreeCtrl::SetItemData(hItem, (LPARAM)pItem);
}

CaplTreeListCtrl::CTLItem* CaplTreeListCtrl::GetTLItem(HTREEITEM hItem)
{
	if(hItem==0) return 0;
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	return pItem;
}

DWORD CaplTreeListCtrl::GetItemData(HTREEITEM hItem) const
{
	if(hItem==0) return 0;
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return NULL;
	return pItem->itemData;
}

HTREEITEM CaplTreeListCtrl::InsertItem(LPCTSTR lpszItem, HTREEITEM hParent, HTREEITEM hInsertAfter,bool fictive)
{	
	CTLItem *pItem = new CTLItem;
	pItem->InsertItem(lpszItem);
	pItem->m_parent_item=hParent;
	if(fictive) pItem->m_fictive=true;
	m_nItems++;
	((CaplTreeListCtrlView*)GetParent())->ResetScrollBar();
	
	return CTreeCtrl::InsertItem(TVIF_PARAM|TVIF_TEXT, _T(""), 0, 0, 0, 0, (LPARAM)pItem, hParent, hInsertAfter);
}

HTREEITEM CaplTreeListCtrl::InsertItem( LPCTSTR lpszItem, int nImage, int nSelectedImage, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	CTLItem *pItem = new CTLItem;
	pItem->InsertItem(lpszItem);
	pItem->m_parent_item=hParent;
	m_nItems++;
	((CaplTreeListCtrlView*)GetParent())->ResetScrollBar();
	
	return CTreeCtrl::InsertItem(TVIF_PARAM|TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE, _T(""), nImage, nSelectedImage, 0, 0, (LPARAM)pItem, hParent, hInsertAfter);
}

HTREEITEM CaplTreeListCtrl::InsertItem(UINT nMask, LPCTSTR lpszItem, int nImage, int nSelectedImage, UINT nState, UINT nStateMask, LPARAM lParam, HTREEITEM hParent, HTREEITEM hInsertAfter )
{
	CTLItem *pItem = new CTLItem;
	pItem->InsertItem(lpszItem);
	pItem->itemData = lParam;
	pItem->m_parent_item=hParent;
	m_nItems++;
	((CaplTreeListCtrlView*)GetParent())->ResetScrollBar();	
	
	return CTreeCtrl::InsertItem(nMask, _T(""), nImage, nSelectedImage, nState, nStateMask, (LPARAM)pItem, hParent, hInsertAfter); 
}

HTREEITEM CaplTreeListCtrl::CopyItem(HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
{	
	TVINSERTSTRUCT insert;
	::ZeroMemory(&insert, sizeof(TVINSERTSTRUCT));

	HTREEITEM htiNew = NULL;
	CString text;

	insert.item.hItem = hItem;
	insert.item.mask = TVIF_CHILDREN|TVIF_HANDLE|TVIF_IMAGE|TVIF_SELECTEDIMAGE;
	GetItem(&(insert.item));

	insert.hParent = hParent;
	insert.hInsertAfter = hInsertAfter;
	insert.item.mask = TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXT;
	htiNew = CTreeCtrl::InsertItem(&insert);

	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	CTLItem *pNewItem = new CTLItem(*pItem);
	m_nItems++;

	CTreeCtrl::SetItemData( htiNew, (DWORD)pNewItem );
	SetItemState( htiNew, CTreeCtrl::GetItemState( hItem,
                            TVIS_STATEIMAGEMASK ), TVIS_STATEIMAGEMASK );

	return htiNew;
}

HTREEITEM CaplTreeListCtrl::MoveItem(HTREEITEM hItem, HTREEITEM hParent, HTREEITEM hInsertAfter)
{
	TV_ITEM item;
	item.mask = TVIF_IMAGE | TVIF_PARAM | TVIF_SELECTEDIMAGE | TVIF_STATE | TVIF_TEXT;
	item.hItem = hItem;	
	GetItem(&item);
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	CTLItem *pNewItem = new CTLItem(*pItem);
	DeleteItem(hItem);
	
	item.lParam = (LPARAM)pNewItem;

	TV_INSERTSTRUCT insStruct;	
	insStruct.item = item;
	insStruct.hParent = hParent;
	insStruct.hInsertAfter = hInsertAfter;
	

	return CTreeCtrl::InsertItem(&insStruct);
}

BOOL CaplTreeListCtrl::SetItemText( HTREEITEM hItem, int nCol ,LPCTSTR lpszItem)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->SetSubstring(nCol, lpszItem);
	pItem->SetSubstringColor(nCol, pItem->m_Color);	
	return CTreeCtrl::SetItemData(hItem, (LPARAM)pItem);
}

BOOL CaplTreeListCtrl::SetItemColor( HTREEITEM hItem, COLORREF m_newColor, BOOL m_bInvalidate )
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->m_Color = m_newColor;
	//pItem->m_bCrossOutText = false;

	for(int i=0; i<pItem->m_substring_color.GetSize(); i++)
		pItem->m_substring_color[i] = m_newColor;
	if(!CTreeCtrl::SetItemData(hItem, (LPARAM)pItem))
		return FALSE;
	if(m_bInvalidate)
		Invalidate();
	return TRUE;	
}

BOOL CaplTreeListCtrl::SetSubItemColor(HTREEITEM hItem , int nCol, COLORREF color, BOOL m_bInvalidate)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->SetSubstringColor(nCol, color);
	
	if(!CTreeCtrl::SetItemData(hItem, (LPARAM)pItem))
		return FALSE;
	if(m_bInvalidate)
		Invalidate();
	return TRUE;
}

COLORREF CaplTreeListCtrl::GetSubItemColor(HTREEITEM hItem , int nCol)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return 0;
	
	return pItem->GetSubstringColor(nCol);
}

BOOL CaplTreeListCtrl::SetItemBold( HTREEITEM hItem, BOOL m_Bold, BOOL m_bInvalidate )
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->m_Bold = m_Bold;
	if(!CTreeCtrl::SetItemData(hItem, (LPARAM)pItem))
		return FALSE;
	if(m_bInvalidate)
		Invalidate();
	return TRUE;
}

BOOL CaplTreeListCtrl::SetItemCrossOutText( HTREEITEM hItem, BOOL m_bCrossOutText, BOOL m_bInvalidate )
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	pItem->m_bCrossOutText = m_bCrossOutText;
	if(!CTreeCtrl::SetItemData(hItem, (LPARAM)pItem))
		return FALSE;
	if(m_bInvalidate)
		Invalidate();
	return TRUE;
}

CString CaplTreeListCtrl::GetItemText( HTREEITEM hItem, int nSubItem )
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
		
	if(!pItem)
		return _T("");
	return pItem->GetSubstring(nSubItem);
}

CString CaplTreeListCtrl::GetItemText( int nItem, int nSubItem )
{
	return GetItemText(GetTreeItem(nItem), nSubItem);
}

BOOL CaplTreeListCtrl::DeleteItem( HTREEITEM hItem )
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(!pItem)
		return FALSE;
	if(ItemHasChildren(hItem))
		DeleteSubItems(hItem);
	delete pItem;
	pItem = NULL;
	m_nItems --;
	
	return CTreeCtrl::DeleteItem(hItem);
}

BOOL CaplTreeListCtrl::DeleteItem( int nItem )
{
	return DeleteItem(GetTreeItem(nItem));
}



int CALLBACK CaplTreeListCtrl::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
	CTLItem *pItem1 = (CTLItem *)lParam1;
	CTLItem *pItem2 = (CTLItem *)lParam2;
	
	SSortType *pSortType = (SSortType *)lParamSort;
	CString str1 = pItem1->GetSubstring(pSortType->nCol);
	CString str2 = pItem2->GetSubstring(pSortType->nCol);

	if(!pItem1->m_parent_item && !pItem2->m_parent_item && !pSortType->m_bSortRoot) return 0;

	int m_nComp;
	// compare the two strings, but
	// notice:
	// in this case, "xxxx10" comes after "xxxx2"
	if(pSortType->ColType==APL_COLUMN_STRING)
	{
		if(str1!=_T("") && str2!=_T("")) return aplCompareNumericStr(LPCTSTR(str1),LPCTSTR(str2)); // Сравниваем как цифры
		/*{
			char c1=str1[0];
			char c2=str2[0];
			if(c1>=_T('0') && c1<=_T('9') && c2>=_T('0') && c2<=_T('9')) return aplCompareNumericStr(LPCSTR(str1),LPCSTR(str2)); // Сравниваем как цифры
		}*/

		m_nComp = str1.CompareNoCase(str2);
		if(m_nComp>1) m_nComp=1;
		else if (m_nComp<-1) m_nComp=-1;

		/*
		CString tmpStr1, tmpStr2;
		int index = str1.FindOneOf("0123456789");
		if(index!=-1)
			tmpStr1 = str1.Right(str1.GetLength()-index);
		index = str2.FindOneOf("0123456789");
		if(index!=-1)
			tmpStr2 = str2.Right(str2.GetLength()-index);
		
		tmpStr1 = tmpStr1.SpanIncluding("0123456789");
		tmpStr2 = tmpStr2.SpanIncluding("0123456789");

		if((tmpStr1=="") && (tmpStr2==""))
			m_nComp = str1.CompareNoCase(str2);
		else
		{
			int num1 = atoi(tmpStr1);
			int num2 = atoi(tmpStr2);

			tmpStr1 = str1.SpanExcluding("0123456789");
			tmpStr2 = str2.SpanExcluding("0123456789");

			if(tmpStr1 == tmpStr2)
			{
				if(num1 > num2)
					m_nComp = 1;
				else
				if(num1 < num2)
					m_nComp = -1;
				else
					m_nComp = str1.CompareNoCase(str2);
			}
			else
				m_nComp = str1.CompareNoCase(str2);			
		}*/
	}
	else if(pSortType->ColType==APL_COLUMN_NUMERIC)
	{
		double d1 = __atof(str1);
		double d2 = __atof(str2);
		if(d1>d2) m_nComp = 1;
		else if(d1<d2) m_nComp = -1;
		else m_nComp = 0;
	}
	else if(pSortType->ColType==APL_COLUMN_DATE)
	{
		COleDateTime date1, date2;
		date1.ParseDateTime(str1);
		date2.ParseDateTime(str2);
		if(date2.GetStatus( )==COleDateTime::invalid) 
			date2.SetDateTime(9000,1,1,0,0,0);
		if(date1.GetStatus( )==COleDateTime::invalid) 
			date1.SetDateTime(9000,1,1,0,0,0);
		if(date1>date2) m_nComp = 1;
		else if(date1<date2) m_nComp = -1;
		else m_nComp = 0;
	}


	if(!pSortType->bAscending)
	{
		if(m_nComp == 1)
			m_nComp = -1;
		else
		if(m_nComp == -1)
			m_nComp = 1;
	}

	return m_nComp;
}

BOOL CaplTreeListCtrl::SortItems( int nCol, BOOL bAscending, HTREEITEM low)
{
	TV_SORTCB tSort;

	tSort.hParent = low;	
	tSort.lpfnCompare = CompareFunc;

	SSortType *pSortType = new SSortType;
	pSortType->nCol = nCol;
	pSortType->bAscending = bAscending;
	pSortType->pmyTreeListCtrl=this;
	pSortType->m_bSortRoot=m_bSortRoot;
	pSortType->ColType = GetColType(nCol);
	tSort.lParam = (LPARAM)pSortType;
	
	BOOL m_bReturn = SortChildrenCB(&tSort);
	
	delete pSortType;	
	if(m_dlg)
	{
		m_dlg->Sort(nCol);
		if(nCol) m_dlg->RefreshAllItems();	
	}

	return m_bReturn;
}

void CaplTreeListCtrl::MemDeleteAllItems(HTREEITEM hParent)
{
	HTREEITEM hItem = hParent;	
	CTLItem *pItem;	
	
	while(hItem!=NULL)
	{			
		pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
		if(pItem!=0)
			MemItemArray.Add(pItem);
			
		if(ItemHasChildren(hItem))
			MemDeleteAllItems(GetChildItem(hItem));			
				
		hItem = GetNextSiblingItem(hItem);		
	}	
}

BOOL CaplTreeListCtrl::DeleteAllItems()
{
	LockWindowUpdate();
	BeginWaitCursor();
	
	MemDeleteAllItems(GetRootItem());		
	BOOL m_bReturn = CTreeCtrl::DeleteAllItems();
	
	for (int i=0;i<MemItemArray.GetSize();i++)
	{
		CTLItem* item = MemItemArray.GetAt(i);
		delete item;
		item = NULL;
	}
	MemItemArray.RemoveAll();	
	EndWaitCursor();
	UnlockWindowUpdate();
	return m_bReturn;
}

void CaplTreeListCtrl::OnDestroy()
{
	DeleteAllItems();

	if(m_AutoSaveColumnsWidth)
		SaveColumnWidths();	

	CTreeCtrl::OnDestroy();
}

BOOL CaplTreeListCtrl::DeleteSubItems( HTREEITEM hItem )
{
  HTREEITEM hChild(0);
  BOOL bRet(false), bErr(false);

  while(ItemHasChildren(hItem))
  {
    hChild = GetChildItem(hItem);
	if (ItemHasChildren(hChild))
	{
      DeleteSubItems(hChild);
    }
    bRet = DeleteItem(hChild);
    if (!bRet){
      bErr = true;
    }
  }

  return bErr;
}

void CaplTreeListCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{	
	//DeselectAll(true, true);

	// find what item is selected
	HTREEITEM curr_item;
	curr_item = HitTest(point, &nFlags);
	m_LastSelectedItem = curr_item ;
//	
//	if((nFlags & TVHT_ONITEMRIGHT) || (nFlags & TVHT_ONITEMINDENT) ||
//	   (nFlags & TVHT_ONITEM))
//	{
//		SelectItem(curr_item,true);
//	}	
	
	SelectItem(curr_item,true);

	CWnd *parent=GetParent();
	if(parent)
	{
		ClientToScreen(&point);
		parent->SendMessage(WM_RBUTTONDOWN,(WPARAM)nFlags,MAKELPARAM(point.x,point.y));
	}

	CTreeCtrl::OnRButtonDown(nFlags, point);
}

void CaplTreeListCtrl::OnRButtonUp(UINT nFlags, CPoint point) 
{	
	// find what item is selected
	CWnd *parent=GetParent();
	if(parent)
	{
		//ClientToScreen(&point);
		parent->SendMessage(WM_RBUTTONUP,(WPARAM)nFlags,MAKELPARAM(point.x,point.y));
	}

	CTreeCtrl::OnRButtonDown(nFlags, point);
}

	


void CaplTreeListCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{	
//	SetFocus();
	
	if ( m_nHoverTimerID )
	{
		KillTimer( m_nHoverTimerID );
		m_nHoverTimerID = 0;
	}	
	
	// sets counter to expand if hovered over item for a while
//	m_nHoverTimerID = SetTimer(2, 750, NULL);

	CWnd *parent=GetParent();
	if(parent)
	{
		ClientToScreen(&point);
		parent->SendMessage(WM_MOUSEMOVE,(WPARAM)nFlags,MAKELPARAM(point.x,point.y));
	}
		
	CTreeCtrl::OnMouseMove(nFlags, point);
}


CString CaplTreeListCtrl::GetNextLine(CString &message)
{
CString result;
BOOL bOK = FALSE;
TCHAR k = 13;
TCHAR j;
int nSize = message.GetLength();
int nIndex = 0;
	
	//Search for the return character in the string
	while(nIndex < nSize && !bOK)
	{
		j = message.GetAt(nIndex);
		if(j == k)
		{
			result = message.Left(nIndex);
			//Drop the carriage return and line feed characters
			message = message.Right(nSize - (nIndex + 2));
			bOK = TRUE;
		}
		nIndex++;
	}
	return result;
}


void CaplTreeListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
{

  DWORD dw = GetMessagePos();                   // retrieve mouse cursor position when msg was sent
  CPoint p(GET_X_LPARAM(dw), GET_Y_LPARAM(dw)); // ..and put into point structure
  ScreenToClient(&p);                    // make coords local to tree client area

  UINT htFlags = 0;
  HTREEITEM it = HitTest(p, &htFlags);   // See where the click was on

  if (it != NULL && htFlags==TVHT_ONITEMSTATEICON) {   
    // the check box was hit.
    // we just post a message
    PostMessage(UWM_TV_CHECKBOX, pNMHDR->idFrom, (LPARAM) it);
  }
	
  *pResult = 0;
}


void CaplTreeListCtrl::OnTimer(UINT nIDEvent) 
{
	if ( nIDEvent == m_nHoverTimerID )
	{
		KillTimer( m_nHoverTimerID );
		m_nHoverTimerID = 0;

		if ( m_LastSelectedItem )
		{
//			SelectItem( m_LastSelectedItem );
			Expand(m_LastSelectedItem,TVE_EXPAND);	
		}
	}
	else
	{
		CTreeCtrl::OnTimer(nIDEvent);
	}
}



void CaplTreeListCtrl::OnSize(UINT nType, int cx, int cy) 
{
	if(m_bAutoSizeLeftColumn)
	{
		if(cx>0 && m_nColumnsWidth>0 /*&& cx>m_nColumnsWidth*/)
		{
			if(m_nLeftColumnNum>=GetColumnsNum()) m_nLeftColumnNum=0;
			HDITEM hditem;
			hditem.mask=HDI_WIDTH;
			m_wndHeader.GetItem(m_nLeftColumnNum,&hditem);
			int x=cx-(m_nColumnsWidth-hditem.cxy);
			if(x>0)hditem.cxy=x;
			m_wndHeader.SetItem(m_nLeftColumnNum,&hditem);
		}
	}	
	CTreeCtrl::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here

}

HTREEITEM CaplTreeListCtrl::GetParentItem(HTREEITEM hItem)
{
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetParentItem(hItem);
	if(!pItem)
		return NULL;
	return HTREEITEM(pItem);
}

void CaplTreeListCtrl::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	if(m_dlg)
	{
		HTREEITEM hItem = pNMTreeView->itemNew.hItem;
		if(hItem)
		{
			CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
			if(pItem)
			{
				if(pItem->m_expanded && pNMTreeView->action==TVE_COLLAPSE)
				{
					m_dlg->Expand(hItem,TVE_COLLAPSE);
					pItem->m_expanded=false;
				}
				else if(!pItem->m_expanded && pNMTreeView->action==TVE_EXPAND)
				{
					m_dlg->Expand(hItem,TVE_EXPAND);
					pItem->m_expanded=true;
				}
			}
		}
	}
	else
	{
		CWnd* parent = GetParent();
		if(parent)
			parent->SendMessage(WM_NOTIFY, TVN_ITEMEXPANDING, (WPARAM)pNMHDR);
	}
	*pResult = 0;
}

void CaplTreeListCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	UINT id = GetParent()->GetDlgCtrlID();
	if(m_dlg!=0) 
	{
		m_dlg->SendMessage(WM_COMMAND,id,0);
		m_dlg->SendMessage(WM_COMMAND,WM_SELCHANGE, 0);
	}
	else
	{
		CWnd* parent = GetParent();
		if(parent)
			parent->SendMessage(WM_NOTIFY, TVN_SELCHANGED, (WPARAM)pNMHDR);

	}
	*pResult = 0;
}

int CaplTreeListCtrl::SetColumnDate(int Col)
{
	return m_dateCols.Add(Col);
}
int CaplTreeListCtrl::SetColumnNum(int Col)
{
	return m_numCols.Add(Col);
}
int CaplTreeListCtrl::GetColType(int Col)
{
	int i;
	for(i=0; i<m_dateCols.GetSize();i++)
		if(Col==(int)m_dateCols.GetAt(i)) return APL_COLUMN_DATE;
	for(i=0; i<m_numCols.GetSize();i++)
		if(Col==(int)m_numCols.GetAt(i)) return APL_COLUMN_NUMERIC;
	return APL_COLUMN_STRING;
}

LRESULT CaplTreeListCtrl::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	if(message==WM_SETREDRAW)
	{
		CWnd *par=GetParent();
		
		if(wParam==0)	
		{
			m_bNoPaint =true;
			if(par->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrlView)))
			{
				par->SetRedraw(FALSE);
			}
		}
		else
		{
			m_bNoPaint =false;
			if(par->IsKindOf(RUNTIME_CLASS(CaplTreeListCtrlView)))
			{
				par->SetRedraw(TRUE);
				par->Invalidate();
			}
		}
	}
	return CTreeCtrl::DefWindowProc(message, wParam, lParam);
}

void CaplTreeListCtrl::OnItemexpanded(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here
	if(m_dlg)
	{
		HTREEITEM hItem = pNMTreeView->itemNew.hItem;
		if(hItem) m_dlg->Expanded(hItem,pNMTreeView->action, pNMHDR->hwndFrom);
		
	}
	else
	{
		CWnd* parent = GetParent();
		if(parent)
			parent->SendMessage(WM_NOTIFY, TVN_ITEMEXPANDED, (WPARAM)pNMHDR);
	}
	*pResult = 0;
}

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

CaplTreeListCtrlWithToolTip::CaplTreeListCtrlWithToolTip()
{
	m_wndHeader.m_ToolTip=&m_ToolTip;
}
CaplTreeListCtrlWithToolTip::~CaplTreeListCtrlWithToolTip()
{
}

BOOL CaplTreeListCtrlWithToolTip::IsAppActive()
{
//	return TRUE;

	BOOL bAppActive = FALSE;
	CWnd* pTopParent = GetTopLevelParent();
	CWnd* pActiveWnd = GetActiveWindow();
	if (pActiveWnd == pTopParent || pTopParent->IsChild(pActiveWnd))
	{
		bAppActive = TRUE;
	}
	return bAppActive;
}


BEGIN_MESSAGE_MAP(CaplTreeListCtrlWithToolTip, CaplTreeListCtrl)
	//{{AFX_MSG_MAP(CaplTreeListCtrlWithToolTip)
	ON_WM_MOUSEMOVE()
	//}}AFX_MSG_MAP
	ON_MESSAGE(LB_ADDSTRING, OnContentChanged)
	ON_MESSAGE(LB_INSERTSTRING, OnContentChanged)
	ON_MESSAGE(LB_DELETESTRING, OnContentChanged)
	ON_MESSAGE(LB_ADDFILE, OnContentChanged)
	ON_MESSAGE(LB_DIR, OnContentChanged)
	ON_MESSAGE(LB_RESETCONTENT, OnContentChanged)
	ON_MESSAGE(LB_SETCARETINDEX, OnContentChanged)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CaplTreeListCtrlWithToolTip message handlers


LONG CaplTreeListCtrlWithToolTip::OnContentChanged(UINT, LONG)
{
	// Turn off title tip.
	m_ToolTip.Hide();
	return Default();
}


void CaplTreeListCtrlWithToolTip::OnMouseMove(UINT nFlags, CPoint point) 
{
	bool bNeedTestToolTip=true;
	if(m_ToolTip.IsShowed())
	{
		if(!m_TitledRect.PtInRect(point)) m_ToolTip.Hide();
		else 
			bNeedTestToolTip=false;
	}

	CaplTreeListCtrl::OnMouseMove(nFlags, point);

	if(bNeedTestToolTip)
	{
		int i,nIndexHit = -1;

		CRect ClientRect;
		GetClientRect(ClientRect);
		if (ClientRect.PtInRect(point))
		{
			// Hit test.
			

			TVHITTESTINFO hInfo;
			hInfo.pt = point;	
			HitTest(&hInfo);				
			
			if (hInfo.hItem!=NULL) 
			{
				CDC* pDC=GetDC();
				pDC->SelectObject(GetFont());
				// Определение позиции прокрутки
				int hscr=0;
				CaplTreeListCtrlView *pFrame = (CaplTreeListCtrlView*)GetParent();
				if(pFrame!=0) hscr=pFrame->m_horScrollBar.GetScrollPos(); 

				int mouse_x=hInfo.pt.x;

				RECT TextItemRect;
				GetItemRect(hInfo.hItem,&TextItemRect,TRUE);

				for (i=0;i<m_wndHeader.GetItemCount();i++)
				{
					RECT ColumnRect;					
					m_wndHeader.GetItemRect(i,&ColumnRect);
					if(ColumnRect.right>ClientRect.right) ColumnRect.right=ClientRect.right;
					int WidthOfColumn=ColumnRect.right-ColumnRect.left;	
					if(hscr>ColumnRect.left && hscr<ColumnRect.right) WidthOfColumn=ColumnRect.right-hscr;
					ColumnRect.left-=hscr;
					ColumnRect.right-=hscr;
					CString Text=GetItemText(hInfo.hItem,i);	
					CSize Width=pDC->GetTextExtent(Text);				

					if (i==0)
					{					
						if ( (mouse_x>TextItemRect.left-hscr)
							&&(mouse_x<ColumnRect.right))
						{
							if((TextItemRect.left-hscr<0)||
								(Width.cx>(WidthOfColumn-TextItemRect.left-8)))
							{				
								CString colText=GetItemText(hInfo.hItem,i);							
								TextItemRect.left-=hscr;
								if(TextItemRect.left<0) TextItemRect.left=0;
								ClientToScreen(&TextItemRect);
								m_ToolTip.Show(TextItemRect.left,TextItemRect.top, colText);
								break;
							}
						}
					}
					else
					{
						if ((mouse_x>ColumnRect.left) && (mouse_x<ColumnRect.right))
						{
							if((ColumnRect.left<0) || (Width.cx>(WidthOfColumn-8)) )
							{						
								CString colText=GetItemText(hInfo.hItem,i);							
								CRect rect=ColumnRect;
								rect.top=TextItemRect.top;
								if(rect.left<0) rect.left=0;
								ClientToScreen(&rect);
								m_ToolTip.Show(rect.left,rect.top, colText);
								break;
							}
						}
					}
				}	
				ReleaseDC(pDC);
			}
		}
	}	
	
	TRACKMOUSEEVENT te;
	te.cbSize=sizeof(TRACKMOUSEEVENT);
	te.dwFlags=TME_LEAVE|TME_HOVER;
	te.hwndTrack=m_hWnd;
	te.dwHoverTime=HOVER_DEFAULT;
	BOOL b=::_TrackMouseEvent(&te);

}


void CaplTreeListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default
	CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
	CWnd* parent = GetParent();
	if(parent)
		parent->SendMessage(WM_VSCROLL, (WPARAM)nPos,(LPARAM)pScrollBar);
}

BOOL CaplTreeListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	HTREEITEM m_CurrentlySelectedItem = GetSelectedItem();
	
	// M:4885 оригинальный код функции. первая строка закоменчена 
	// из-за проблем с отрисовкой дерева
	//CWnd::OnMouseWheel(nFlags,zDelta,pt); 
	CWnd* parent = GetParent();
	if(parent) {
		parent->SendMessage(WM_MOUSEWHEEL, (WPARAM)zDelta, MAKELPARAM(pt.x,pt.y));
	}
	// оставшаяся часть оригинального код нужна для прокрутки Scroll"баров дерева
	//

	// выбераем по знаку zDelta, в каком направлении двигаться при выделении эл-ов
	if(zDelta > 0) { 
		// крутим элементы вверх, спускаясь по списку вниз
		m_CurrentlySelectedItem = GetNextItem(m_CurrentlySelectedItem, TVGN_PREVIOUSVISIBLE);
	}
	else { 
		// крутим элементы вниз, спускаясь по списку вверх
		// при "сокрытии" выделенного элемента за границами видимости дерева, 
		// фокус с дерева слетает. как результат "скроление" прекращается...
		m_CurrentlySelectedItem = GetNextItem(m_CurrentlySelectedItem, TVGN_NEXTVISIBLE);
	}

	SelectItem(m_CurrentlySelectedItem);
    // конец правки функции

	return -1;
}


bool CaplTreeListCtrl::SetSelectMode(bool bSingleSelect /* = true */)
{
	bool old = m_IsSingleSelect;
	m_IsSingleSelect = bSingleSelect;
	return old;
}

HTREEITEM CaplTreeListCtrl::GetNextSelectedItem(HTREEITEM hItem /* = NULL */)
{
	HTREEITEM ht = hItem;
	while(true)
	{
		if(ht==NULL)
			ht = GetFirstVisibleItem();
		else
			ht = GetNextVisibleItem(ht);
		if(ht==NULL)
			return NULL;
		
		UINT state = GetItemState(ht, TVIS_SELECTED/*|TVIS_DROPHILITED*/);
		if(state&TVIS_SELECTED/* || state&TVIS_DROPHILITED*/)
			return ht;
	}
	return NULL;
}

COLORREF CaplTreeListCtrl::SetBkColor(COLORREF nColor)
{
	m_wndColor = nColor;
	return CTreeCtrl::SetBkColor(nColor);
}	

BOOL CaplTreeListCtrl::Expand(HTREEITEM hItem, UINT nCode)
{
	if(!hItem) return FALSE;
	CTLItem *pItem = (CTLItem *)CTreeCtrl::GetItemData(hItem);
	if(pItem)
	{
		if(pItem->m_expanded && nCode==TVE_COLLAPSE)
		{
			pItem->m_expanded=false;
			return CTreeCtrl::Expand(hItem,TVE_COLLAPSE);
		}
		else if(!pItem->m_expanded && nCode==TVE_EXPAND)
		{
			pItem->m_expanded=true;
			return CTreeCtrl::Expand(hItem,TVE_EXPAND);
		}
	}
	return CTreeCtrl::Expand(hItem,nCode);
}



BOOL CaplTreeListCtrlWithToolTip::PreTranslateMessage(MSG* pMsg) 
{
	// TODO: Add your specialized code here and/or call the base class
	if(pMsg!=0)
	{
		if(m_ToolTip.IsNeedHideOnMessage(pMsg->message))
			m_ToolTip.Hide();		
	}
	return CaplTreeListCtrl::PreTranslateMessage(pMsg);
}

BOOL CaplTreeListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	CWnd *pParent = GetParent();
	if(pParent && ::IsWindow(pParent->m_hWnd))
	{
		pParent->SendMessage(WM_NOTIFY, wParam, lParam);		
	}
	
	return CTreeCtrl::OnNotify(wParam, lParam, pResult);
}

// Поиск предыдущего (direct==-1) или  следующего (direct==1) элемента в дереве, с вхождением в поддеревья
HTREEITEM aplGetNextTreeItem(CTreeCtrl *tree, HTREEITEM hitem, int direct)
{
	if(0==tree) return 0;
	if(direct!=1 && direct!=-1) return 0;

	if(1==direct) //вперед
	{
		HTREEITEM next_hitem=tree->GetNextItem(hitem,TVGN_CHILD);
		if(0==next_hitem)
		{
			next_hitem=tree->GetNextItem(hitem,TVGN_NEXT);
			if(0==next_hitem)
			{
				while(true)
				{
					next_hitem=tree->GetNextItem(hitem,TVGN_PARENT);
					if(0==next_hitem) return 0;
					hitem=next_hitem;
					next_hitem=tree->GetNextItem(next_hitem,TVGN_NEXT);
					if(0!=next_hitem) return  next_hitem;
				}
			}
		}
		return  next_hitem;
	}
	else if(-1==direct) //назад
	{
		HTREEITEM next_hitem=tree->GetNextItem(hitem,TVGN_PREVIOUS);
		if(0==next_hitem)
		{
			HTREEITEM par_hitem=tree->GetNextItem(hitem,TVGN_PARENT);
			return par_hitem;
		}

		//Теперь надо выбрать самого нижнего ребенка
		HTREEITEM child_hitem=next_hitem;
		while(true)
		{
			HTREEITEM loc_child_hitem=tree->GetNextItem(child_hitem,TVGN_CHILD);
			if(0==loc_child_hitem) break;

			HTREEITEM next_child_hitem=loc_child_hitem;
			while(true)
			{
				HTREEITEM child=tree->GetNextItem(next_child_hitem,TVGN_NEXT);
				if(0==child) break;
				next_child_hitem=child;
			}
			child_hitem=next_child_hitem;
		}
		return  child_hitem;
	}

	return 0;
}