// aplListCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "apl_gui.h"
#include "resource.h"

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

/////////////////////////////////////////////////////////////////////////////
// CaplSizingListCtrl

IMPLEMENT_DYNCREATE(CaplSizingListCtrl, CScrollView)

CaplSizingListCtrl::CaplSizingListCtrl()
{
	m_items=0;
	m_nColumnsWidth=0;
	m_nItemsHeight=0;
	m_nItemsCount=0;
	m_nRowsCount=0;
	m_nColumnsCount=0;
	m_nItemsMaxCount=0;
	m_sort_items=0;
	m_xIndent=0;
	m_yIndent=0;
	m_headerFont=0;
	m_listFont=0;
	m_defItemHeigth=0;
	m_wndColor =::GetSysColor(COLOR_WINDOW);
	m_btSelectMode=HG_SINGLE_ITEM_SELECT|HG_ENTIRE_ROW_SELECT;
	m_highlightColor =::GetSysColor (COLOR_HIGHLIGHT);
	m_highlightTextColor =::GetSysColor (COLOR_HIGHLIGHTTEXT);
	m_lineColor=RGB(192,192,192);
	m_lFont=new CFont();
	m_hFont=new CFont();
	m_oldSelItem=-1;
	m_oldSelSubItem=-1;
	m_hDefCursor=0;
	CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
	if(0!=app) m_hDefCursor=app->LoadStandardCursor(IDC_ARROW);
	m_hCurCursor=m_hDefCursor;
	m_resizingCol=0;
	m_prev_drag_point_x=0;
	m_ToolTip =new CaplToolTip();
	m_curSortColumn=-1;
	m_bSortAscending=TRUE;
	m_cImageItemList = NULL;
	m_bShowDrawErrMsg=true;
	m_mode = MM_TEXT;
	m_bAlwaysUseDefaultColorForSelected=false;
	m_bEnableSort=true;
}

CaplSizingListCtrl::~CaplSizingListCtrl()
{
	if(m_items) delete [] m_items;
	if(m_lFont) 
	{
		if(m_lFont->m_hObject) m_lFont->DeleteObject();
		delete m_lFont;
	}
	if(m_hFont) 
	{
		if(m_hFont->m_hObject) m_hFont->DeleteObject();
		delete m_hFont;
	}
	if(m_ToolTip)
	{
		delete m_ToolTip;
	}
}


BEGIN_MESSAGE_MAP(CaplSizingListCtrl, CScrollView)
	//{{AFX_MSG_MAP(CaplSizingListCtrl)
	ON_WM_SIZE()
	ON_WM_PAINT()
	ON_WM_HSCROLL()
	ON_WM_ERASEBKGND()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_KEYDOWN()
	ON_WM_RBUTTONDOWN()
	ON_WM_SETCURSOR()
	ON_WM_MOUSEMOVE()
	ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
	ON_WM_MOUSEACTIVATE()
	//}}AFX_MSG_MAP
	ON_WM_NCHITTEST()
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CaplSizingListCtrl drawing

void CaplSizingListCtrl::OnInitialUpdate()
{
	CScrollView::OnInitialUpdate();

	m_wndHeader.m_view=this;
	CSize sizeTotal;
	// TODO: calculate the total size of this view
	sizeTotal.cx = sizeTotal.cy = 100;
	SetScrollSizes(MM_TEXT, sizeTotal);

	CaplSetResourceHandle setres(module_inst);

	CRect m_wndRect;
	GetWindowRect(&m_wndRect);
	LOGFONT logfont;
	CFont *tmpFont=0;
	
	//tmpFont=CFont::FromHandle((HFONT)GetStockObject(SYSTEM_FONT));
	tmpFont=CFont::FromHandle((HFONT)GetStockObject(ANSI_VAR_FONT));
	if(m_headerFont)
	{
		tmpFont=m_headerFont;
	}
	tmpFont->GetLogFont( &logfont );
	m_hFont->CreateFontIndirect( &logfont );
	m_wndHeader.m_lFont=m_hFont;

	m_cImageList.Create(IDB_HEADER, 10, 2, RGB(192,192,192));
	m_wndHeader.SetImageList(&m_cImageList);	

	tmpFont=CFont::FromHandle((HFONT)GetStockObject(ANSI_VAR_FONT));
	if(m_listFont)
	{
		tmpFont=m_listFont;
	}
	tmpFont->GetLogFont( &logfont );
	if(m_lFont)m_lFont->CreateFontIndirect( &logfont );
	if(m_defItemHeigth==0)
	{
		if(m_lFont)
		{
			m_lFont->GetLogFont( &logfont );
			m_defItemHeigth=logfont.lfHeight+4;
		}
		else
		{
			m_defItemHeigth=16;
		}
	}
}

bool CaplSizingListCtrl::SetImageList(CImageList *cImageList)
{
	if(cImageList == NULL) return false;

	m_cImageItemList = cImageList;
	return true;
}

CImageList* CaplSizingListCtrl::GetImageList()
{
	return m_cImageItemList;
}

bool CaplSizingListCtrl::SetItemIco(int nItem, int nSubItem, int ico, bool bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;
	if(ico < 0) return false;
	
	CaplSizingListItem *foundItem=0;
	foundItem=GetItem(nItem,nSubItem);
	if(foundItem==0) return false;
	foundItem->m_iImage = ico;
	
	
	if(bInvalidate) Invalidate();

	return true;
}

void CaplSizingListCtrl::OnDraw(CDC* pDC)
{
	int oldMM = pDC->SetMapMode(m_mode);
	unsigned int cx = 0;
	unsigned int cy = 0;
	CRect clRect;
	
	CDC memDC;
	CBitmap bmp;
	CBitmap *old = NULL;

	memDC.CreateCompatibleDC(pDC);
	
	GetClientRect(clRect);
	if(GetColumnsWidth()<clRect.Width())
		cx = clRect.Width();
	else
		cx = GetColumnsWidth();
	cx+=m_xIndent*2;

	if(m_nItemsHeight<clRect.Height())
		cy = clRect.Height();
	else
		cy = m_nItemsHeight;
	cy+=m_yIndent*2;

	int DPI = 300;
	
	BITMAPINFO bmi;
	bmi.bmiColors[0].rgbBlue = GetBValue(m_wndColor);
	bmi.bmiColors[0].rgbRed = GetRValue(m_wndColor);
	bmi.bmiColors[0].rgbGreen = GetGValue(m_wndColor);
	bmi.bmiColors[0].rgbReserved = 0;
	
	bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth = cx;
	bmi.bmiHeader.biHeight= clRect.Height();
	bmi.bmiHeader.biPlanes = 1;
	bmi.bmiHeader.biBitCount = 32;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biSizeImage = 0;
	bmi.bmiHeader.biXPelsPerMeter = DPI;
	bmi.bmiHeader.biYPelsPerMeter = DPI;
	bmi.bmiHeader.biClrUsed = 0;
	bmi.bmiHeader.biClrImportant = 0;

	void *buf;
	HBITMAP hBm = ::CreateDIBSection(memDC.m_hDC, &bmi, DIB_RGB_COLORS, &buf,NULL, NULL);
	if(!hBm)
	{
		if(m_bShowDrawErrMsg) AfxMessageBox( APL_T("Невозможно выделить необходимое количество памяти!"));
		return;
	}

	bmp.Attach(hBm);
	old = memDC.SelectObject(&bmp);

	OnPrepareDC(&memDC);
	CRect m_wndRect;
	GetWindowRect(&m_wndRect);
	ScreenToClient(m_wndRect);

	memDC.FillSolidRect(0, 0, cx, cy, m_wndColor);

	m_wndHeader.PaintHeader(memDC);
	
	PaintItems(memDC);
	PaintGrid(memDC);
	m_wndHeader.PaintHeader(memDC);

	pDC->BitBlt(0, 0, cx, cy, &memDC, 0, 0, SRCCOPY);
	
	memDC.SelectObject(old);
	bmp.DeleteObject();
	
	ReleaseDC(&memDC);

	memDC.DeleteDC();	
	pDC->SetMapMode(oldMM);	
	if(m_nItemsHeight<0) m_nItemsHeight=0;
	SetScrollSizes(m_mode, CSize(GetColumnsWidth()+m_xIndent*2,m_nItemsHeight+m_yIndent*2));		
}

/////////////////////////////////////////////////////////////////////////////
// CaplSizingListCtrl diagnostics

#ifdef _DEBUG
void CaplSizingListCtrl::AssertValid() const
{
	CScrollView::AssertValid();
}

void CaplSizingListCtrl::Dump(CDumpContext& dc) const
{
	CScrollView::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CaplSizingListCtrl message handlers

CaplSizingListCtrl* CaplSizingListCtrl::CreateListCtrl(CWnd *parent, RECT rect, int id)
{
	if(parent==0) return 0;

	CaplSizingListCtrl *view=
		(CaplSizingListCtrl*)(RUNTIME_CLASS(CaplSizingListCtrl)->CreateObject());
	ASSERT(view);
	if(view!=0)
	{
		view->Create(0,0,WS_BORDER|WS_VISIBLE|WS_CHILD|WS_TABSTOP|AFX_WS_DEFAULT_VIEW,rect,parent,id);
		view->OnInitialUpdate();
		view->MoveWindow(&rect);
	}
	return view;
}

int CaplSizingListCtrl::AddColumn( LPCTSTR lpszColumnHeading, int nFormat, int nWidth ,int nSubItem)
{
	m_nColumnsCount++;

	int m_nReturn = m_wndHeader.AddItem(lpszColumnHeading, nFormat, nWidth);

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

	RecalcColumnsWidth();

	return m_nReturn;
}

void CaplSizingListCtrl::DeleteAllItems()
{
	delete [] m_items;
	m_items = NULL;
	m_nItemsCount=0;
	m_nItemsMaxCount=0;
	m_nRowsCount=0;
	DeselectAll();
	Invalidate();
}

int CaplSizingListCtrl::DeleteItem(int nItem)
{
	if(!GetColumnCount()) return -1;
	if(nItem<0 || nItem>=GetItemCount()) 
		return -1;
	
	int curItem=nItem,j=0;
	for(int i=nItem*GetColumnCount();i<m_nItemsCount-GetColumnCount();i++)
	{
		m_items[i]=m_items[i+GetColumnCount()];
		if(j==GetColumnCount())
		{
			j=0;
			curItem++;
		}
		m_items[i].m_iItem=curItem;
		j++;
	}
	m_nItemsCount-=GetColumnCount();
	int res=m_nRowsCount--;

	RecalcItemsTextRect();
	return res;
}

void CaplSizingListCtrl::DeleteAllColumns()
{
	DeleteAllItems();
	m_wndHeader.DeleteAllItems();
	m_nColumnsCount=0;
	RecalcColumnsWidth();
}


int CaplSizingListCtrl::DeleteColumn(int nCol)
{
	if(nCol<0 || nCol>=GetColumnCount()) return -1;
	if(m_nItemsCount)
	{
		int newItemsCount=m_nRowsCount*(m_nColumnsCount-1);
		CaplSizingListItem *data1=new CaplSizingListItem[m_nItemsMaxCount];

		int i,j;
		for( i=0;i<GetItemCount();i++)
		{
			int old_index,new_index;
			for( j=0;j<nCol;j++)
			{
				old_index=GetItemIndex(i,j);
				new_index=i*(m_nColumnsCount-1)+j;	
				data1[new_index]=m_items[old_index];
			}
			for(j=nCol+1;j<m_nColumnsCount;j++)
			{
				old_index=GetItemIndex(i,j);
				new_index=i*(m_nColumnsCount-1)+j-1;	
				data1[new_index]=m_items[old_index];
				data1[new_index].m_iItem=i;
				data1[new_index].m_iSubItem=j-1;
			}
		}
		delete [] m_items;
		m_items=data1;
		m_nItemsCount=newItemsCount;
	}

	int m_nReturn = m_wndHeader.DeleteItem(nCol);
	m_nColumnsCount--;
	RecalcColumnsWidth();
	return m_nReturn;
}

int CaplSizingListCtrl::GetColumnWidth(int nCol)
{
	return m_wndHeader.GetColumnWidth(nCol);
}

UINT CaplSizingListCtrl::GetColumnAlign(int nCol)
{
	return m_wndHeader.GetColumnAlign(nCol);
}

long CaplSizingListCtrl::GetHeaderColumnSortType(int nCol)
{
	return m_wndHeader.GetHeaderColumnSortType(nCol);
}


void CaplSizingListCtrl::RecalcColumnsWidth()
{
	m_wndHeader.RecalcColumnsWidth();
	m_nColumnsWidth=m_wndHeader.GetColumnsWidth();

	SetScrollSizes(MM_TEXT, CSize(GetColumnsWidth()+m_xIndent*2,m_nItemsHeight+m_yIndent*2));
	Invalidate();

}

void CaplSizingListCtrl::OnSize(UINT nType, int cx, int cy) 
{
	CScrollView::OnSize(nType, cx, cy);
	
	if(GetColumnsWidth())
	{
		//AutoResizeDiagram();
		CPoint cur_pos=GetScrollPosition(); 
		SetScrollSizes(MM_TEXT, CSize(GetColumnsWidth()+m_xIndent*2,m_nItemsHeight+m_yIndent*2));
		ScrollToPosition(cur_pos);
	}

	RecalcItemsTextRect();
}

BOOL CaplSizingListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{
	HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;	

	return CScrollView::OnNotify(wParam, lParam, pResult);
}

int compare_Items_asc( const void *arg1, const void *arg2)
{
	CaplSizingListCtrl::CaplSizingListItem *lItem1 = (CaplSizingListCtrl::CaplSizingListItem *)arg1;
	CaplSizingListCtrl::CaplSizingListItem *lItem2 = (CaplSizingListCtrl::CaplSizingListItem *)arg2;
	if(!lItem1 || !lItem2) return 0;
	
	long sortType = lItem1->m_listCtrl->GetHeaderColumnSortType(lItem1->GetSubItemNum());

	int m_nComp;
	CString str1=lItem1->m_sText;
	CString str2=lItem2->m_sText;

	if(sortType==APL_COLUMN_STRING)
	{
		if(str1>str2) m_nComp=1;
		else if(str1==str2) m_nComp=0;
		else m_nComp=-1;
	}
	else if(sortType==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(sortType==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;
	}

	return m_nComp;
 
}

int compare_Items_desc( const void *arg1, const void *arg2 )
{
	CaplSizingListCtrl::CaplSizingListItem *lItem1 = (CaplSizingListCtrl::CaplSizingListItem *)arg1;
	CaplSizingListCtrl::CaplSizingListItem *lItem2 = (CaplSizingListCtrl::CaplSizingListItem *)arg2;
	if(!lItem1 || !lItem2) return 0;
	
	long sortType = lItem1->m_listCtrl->GetHeaderColumnSortType(lItem1->GetSubItemNum());

	int m_nComp;
	CString str1=lItem1->m_sText;
	CString str2=lItem2->m_sText;

	if(sortType==APL_COLUMN_STRING)
	{
		if(str1>str2) m_nComp=-1;
		else if(str1==str2) m_nComp=0;
		else m_nComp=1;
	}
	else if(sortType==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(sortType==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;
	}

	return m_nComp;
}

bool CaplSizingListCtrl::EnableSort(bool bEnable)
{
	bool b=m_bEnableSort;
	m_bEnableSort=!m_bEnableSort;
	return b;
}


BOOL CaplSizingListCtrl::SortItems( int nCol, BOOL bAscending)
{
	if(!m_bEnableSort) return FALSE;
	if(GetItemCount()<=0) return FALSE;
	if(nCol<0 || nCol>GetColumnCount()) return FALSE;

	int i;
	for(i=0;i<GetColumnCount();i++)
	{
		m_wndHeader.SetItemImage(i, -1);
	}
	if(bAscending)
	{
		m_wndHeader.SetItemImage(nCol, 0);
	}
	else
	{
		m_wndHeader.SetItemImage(nCol, 1);
	}

	m_sort_items=new CaplSizingListItem[GetItemCount()];
	for(i=0;i<GetItemCount();i++)
	{
		CaplSizingListItem *lItem=GetItem(i,nCol);
		m_sort_items[i]=*lItem;
	}
	if(bAscending) qsort(m_sort_items,GetItemCount(),sizeof(CaplSizingListItem),compare_Items_asc);
	else qsort(m_sort_items,GetItemCount(),sizeof(CaplSizingListItem),compare_Items_desc);
	
	m_curSortColumn=nCol;
	m_bSortAscending=bAscending;

	CaplSizingListItem *tmp_items=new CaplSizingListItem[m_nItemsCount];
	for(i=0;i<m_nItemsCount;i++)
		tmp_items[i]=m_items[i];

	int i_cnt=0;
	for(i=0;i<GetItemCount();i++)
	{
		for(int j=0;j<GetColumnCount();j++)
		{
			m_items[i_cnt]=tmp_items[m_sort_items[i].m_iItem*GetColumnCount()+j];
			m_items[i_cnt].m_iItem=i;
			m_items[i_cnt].m_iSubItem=j;
			i_cnt++;
		}
	}
	delete [] m_sort_items;
	delete [] tmp_items;
	
	RecalcItemsTextRect();
	return TRUE;
}

void CaplSizingListCtrl::ReSort()
{
	if(m_curSortColumn>-1 && m_curSortColumn<m_nColumnsCount) SortItems(m_curSortColumn,m_bSortAscending);
}


CaplSizingListCtrl::CaplSizingListItem::CaplSizingListItem()
{
	SetDefaults();
}

void CaplSizingListCtrl::CaplSizingListItem::SetDefaults()
{
    m_iItem=-1; 
	m_iSubItem=-1; 
	m_sText=_T(""); 
	m_iImage=-1; 
	m_dData=0;
	m_bgrColor=::GetSysColor(COLOR_WINDOW);
	m_bBold=false;
	m_bItalic=false;
	m_textColor=::GetSysColor(COLOR_WINDOWTEXT);
	m_itemRect.SetRect(0,0,0,0);
	m_itemColor=::GetSysColor(COLOR_WINDOW);
	m_cx=2;
	m_cy=2;
	m_bSelected=false;
	m_textRect.SetRect(0,0,0,0);
	m_bShowTooltip=false;
}

bool CaplSizingListCtrl::SetItemsCount(int nCount)
{
	CaplSizingListItem *data1=new CaplSizingListItem[nCount];

	if(m_items!=0)
	{
		for(int i=0;i<m_nItemsCount;i++)
		{
			if(i>=nCount) break;
			data1[i]=m_items[i];
		}
		delete [] m_items;
	}
	m_items=data1;
	m_nItemsMaxCount=nCount;
	return true;
}

int CaplSizingListCtrl::AddItem()
{
	if(m_nItemsCount+GetColumnCount()>m_nItemsMaxCount) 
		SetItemsCount((m_nItemsCount+GetColumnCount())*2);

	int j=0;
	for(int i=m_nItemsCount;i<m_nItemsCount+GetColumnCount();i++)
	{
		m_items[i].m_iItem=GetItemCount();
		m_items[i].m_iSubItem=j;
		m_items[i].m_listCtrl=this;
		j++;
	}
	m_nItemsCount+=GetColumnCount();

	return m_nRowsCount++;
}

int CaplSizingListCtrl::InsertItem(int nItem)
{
	int i;
	if(!GetColumnCount()) return -1;
	if(nItem<0 || nItem>GetItemCount()) 
		return -1;
	
	if(m_nItemsCount+GetColumnCount()>m_nItemsMaxCount) 
		SetItemsCount((m_nItemsCount+GetColumnCount())*2);

	m_nItemsCount+=GetColumnCount();

	for(i=m_nItemsCount-1;i>=nItem*GetColumnCount()+GetColumnCount();i--)
	{
		m_items[i]=m_items[i-GetColumnCount()];
	}
	for(i=nItem*GetColumnCount();i<nItem*GetColumnCount()+GetColumnCount();i++)
	{
		m_items[i].SetDefaults();
		m_items[i].m_listCtrl=this;
	}
	int curItem=nItem,j=0;
	for(i=nItem*GetColumnCount();i<m_nItemsCount;i++)
	{
		if(j==GetColumnCount())
		{
			j=0;
			curItem++;
		}
		m_items[i].m_iItem=curItem;
		m_items[i].m_iSubItem=j;
		j++;
	}
	Invalidate();
	m_nRowsCount++;
	return nItem;
}

int CaplSizingListCtrl::GetItemIndex(int nItem, int nSubItem)
{
	if(nItem<0 || nItem>GetItemCount()) return -1;
	if(nSubItem<0 || nSubItem>GetColumnCount()) return -1;

	int index=nItem*GetColumnCount()+nSubItem;
	if(m_items[index].m_iItem==nItem && m_items[index].m_iSubItem==nSubItem)
		return index;
	
	return -1;
}

CaplSizingListCtrl::CaplSizingListItem* CaplSizingListCtrl::GetItem(int nItem, int nSubItem)
{
	int res_index=GetItemIndex(nItem,nSubItem);
	if(res_index<0) return 0;
	return &m_items[res_index];
}

bool CaplSizingListCtrl::SetItem(int nItem, int nSubItem,CaplSizingListItem &lItem,BOOL bInvalidate)
{
	if(nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=GetItem(nItem,nSubItem);
	if(foundItem==0) return false;
	
	foundItem=&lItem;
	if(bInvalidate) Invalidate();
	return true;
}


DWORD CaplSizingListCtrl::GetItemData(int nItem, int nSubItem)
{
	DWORD retVal=0;
	if(nItem<0 || nItem>GetItemCount()) return 0;
	if(nSubItem<0 || nSubItem>GetColumnCount()) return 0;

	CaplSizingListItem *foundItem=GetItem(nItem,nSubItem);
	if(foundItem==0) return 0;
	
	retVal=foundItem->m_dData;
	
	return retVal;
}



CString CaplSizingListCtrl::GetItemText(int nItem, int nSubItem)
{
	CString retVal;
	retVal.Empty();
	if(nItem<0 || nItem>GetItemCount()) return _T("");
	if(nSubItem<0 || nSubItem>GetColumnCount()) return _T("");

	CaplSizingListItem *foundItem=GetItem(nItem,nSubItem);
	if(foundItem==0) return _T("");
	
	retVal=foundItem->m_sText;
	
	return retVal;
}

void CaplSizingListCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
		
	OnPrepareDC(&dc);
	OnDraw(&dc);
	ReleaseDC(&dc);
}

BOOL CaplSizingListCtrl::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;
}

void CaplSizingListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{	
	m_ToolTip->Hide();
	CScrollView::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CaplSizingListCtrl::DrawItemIco(CDC &dc, CaplSizingListCtrl::CaplSizingListItem *lItem, bool bDraw)
{
	CRect rect = lItem->m_itemRect;
	IMAGEINFO *pImageInfo = new IMAGEINFO;
	
	m_cImageItemList->GetImageInfo(lItem->m_iImage, pImageInfo);
	//if((pImageInfo->rcImage.bottom-pImageInfo->rcImage.top) + lItem->m_cx*4 >= (lItem->m_textRect.bottom-lItem->m_textRect.top))
	//{
		if(bDraw)
		{
			rect.top = lItem->m_itemRect.bottom - ((lItem->m_itemRect.bottom-lItem->m_itemRect.top)/2) - (pImageInfo->rcImage.bottom-pImageInfo->rcImage.top)/2;										
		}
		lItem->m_textRect.bottom += lItem->m_cx*3+1;
	//}
	
	if(lItem->m_sText.IsEmpty()) 
	{
		rect.left = lItem->m_textRect.right - ((lItem->m_textRect.right-lItem->m_textRect.left)/2) - (pImageInfo->rcImage.right-pImageInfo->rcImage.left)/2 - lItem->m_cx;
		if(bDraw)
			if(lItem->m_iImage>-1 && lItem->m_iImage<m_cImageItemList->GetImageCount())
				m_cImageItemList->Draw(&dc, lItem->m_iImage, CPoint(rect.left, rect.top), ILD_TRANSPARENT);			
	}
	else
	{
		if(bDraw)
			if(lItem->m_iImage>-1 && lItem->m_iImage<m_cImageItemList->GetImageCount())
				m_cImageItemList->Draw(&dc, lItem->m_iImage, CPoint(rect.left+ lItem->m_cx, rect.top), ILD_TRANSPARENT);					
	}	
		
	delete pImageInfo;
}

void CaplSizingListCtrl::DrawItemText(CDC &dc,CaplSizingListCtrl::CaplSizingListItem *lItem,int cx,int cy,bool bDraw)
{
	if(!lItem) return;
	if(!bDraw) lItem->m_textRect.left=cx+lItem->m_cx;
	int right=cx+GetColumnWidth(lItem->m_iSubItem);
	if(!bDraw)
	{
		lItem->m_textRect.right=right-lItem->m_cx;
		lItem->m_textRect.top=cy+lItem->m_cy;
	}
	int colAlign=GetColumnAlign(lItem->m_iSubItem);
	
	if(lItem->m_sText==_T("")) 
	{
		if(!bDraw) lItem->m_textRect.bottom=lItem->m_textRect.top+m_defItemHeigth;
		
		if(lItem->m_iImage != -1 && m_cImageItemList != NULL)
			DrawItemIco(dc, lItem, bDraw);								
	}
	else
	{
		LOGFONT logfont;
		if(m_lFont)
			m_lFont->GetLogFont( &logfont );
		
		if(lItem->m_bBold) 
			logfont.lfWeight=FW_BOLD;
		if(lItem->m_bItalic) 
			logfont.lfItalic =TRUE;
		CFont chgdFontDC;
		chgdFontDC.CreateFontIndirect( &logfont );
		
		if(lItem->m_bSelected)
		{
			// Выделено
			if(m_wndColor!=lItem->m_bgrColor)
				dc.SetBkColor( lItem->m_bgrColor );
			else if(m_wndColor==lItem->m_itemColor)
				dc.SetBkColor(m_highlightColor);	
			dc.SetTextColor(m_highlightTextColor);
		}
		else
		{
			// Если не выделено
			if(m_wndColor!=lItem->m_bgrColor)
				dc.SetBkColor( lItem->m_bgrColor );
			dc.SetTextColor(lItem->m_textColor);
		}
		CFont *oldFont=dc.SelectObject(&chgdFontDC);

		//для иконки
		CRect rect = lItem->m_textRect;
		if(lItem->m_iImage != -1  && m_cImageItemList!=NULL)
			DrawItemIco(dc, lItem, bDraw);		
			
		if(!bDraw)
		{
			dc.DrawText(lItem->m_sText,lItem->m_textRect,colAlign|DT_CALCRECT|DT_VCENTER|DT_EXTERNALLEADING|DT_WORDBREAK);
			TEXTMETRIC tm;
			dc.GetTextMetrics(&tm);
			lItem->m_textRect.bottom+=tm.tmDescent;
			lItem->m_bShowTooltip=false;
			if(lItem->m_textRect.right>right) 
			{
				lItem->m_bShowTooltip=true;
			}
			lItem->m_textRect.bottom+=lItem->m_cy;
		}
		if(bDraw) 
		{
			if(lItem->m_bShowTooltip) colAlign=DT_LEFT;
			dc.DrawText(lItem->m_sText,lItem->m_textRect,colAlign|DT_END_ELLIPSIS|DT_VCENTER|DT_EXTERNALLEADING|DT_WORDBREAK);
		}

		dc.SelectObject(oldFont);
	}
}

void CaplSizingListCtrl::PaintItems(CDC &dc)
{
	CPen pen(PS_SOLID,1,m_lineColor);
	//CPen select_pen(PS_SOLID,2,m_lineColor);
	COLORREF clrBack=GetSysColor(COLOR_HIGHLIGHT);
	CPen select_pen(PS_SOLID,2,clrBack);
	CPen *oldPen=dc.SelectObject(&pen);
	
	CRect rcClient;
	GetClientRect(&rcClient);
	
	IMAGEINFO *pImageInfo = NULL;	//для иконок
	int top=m_wndHeader.m_sumItemsHeight+m_yIndent-1;
	int left=rcClient.left+m_xIndent;
	//int right=GetColumnsWidth()+m_xIndent;
	int right=max(rcClient.Width()-m_xIndent,GetColumnsWidth()+m_xIndent);
	int cy=top;
	int j=0;

	CPoint pt = GetScrollPosition();	

	int lastBound = cy;
	int screenTop=pt.y;
	int screenBottom=screenTop+rcClient.Height();

	//отрисовка текста элементов (фикс ширина и изменяющаяся высота ячеек)
	for(int i=0;i<GetItemCount();i++)	
	{
		//подсчет координат
		int maxItemHeight = 0;
		int cx=left;

		for(j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *lItem=GetItem(i, j);
			if(!lItem) continue;

			if(maxItemHeight < lItem->m_itemRect.Height())
				maxItemHeight = lItem->m_itemRect.Height();			
		}

		if(maxItemHeight<m_defItemHeigth)
			maxItemHeight=m_defItemHeigth;

		cx=left;
		for(j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *lItem=GetItem(i,j);
			if(!lItem) continue;

			// отображаем только те элементы, которые влазят в экран по Y
			if( lItem->m_itemRect.bottom>=screenTop && lItem->m_itemRect.top<=screenBottom )
			{
	
				//собственно отрисовка
				if(lItem->m_bSelected) 
				{
					if(lItem->m_itemColor==m_wndColor || m_bAlwaysUseDefaultColorForSelected) 
					{
						dc.FillSolidRect(lItem->m_itemRect,m_highlightColor);
					}
					else
					{
						//dc.FillSolidRect(lItem->m_itemRect,lItem->m_itemColor);
						COLORREF color_sel=aplColor_GetHilightColor(lItem->m_itemColor,-50);
						dc.FillSolidRect(lItem->m_itemRect,color_sel);
					}

					dc.SelectObject(&select_pen);
					dc.MoveTo(lItem->m_itemRect.left,lItem->m_itemRect.top);
					dc.LineTo(lItem->m_itemRect.right,lItem->m_itemRect.top);
					dc.MoveTo(lItem->m_itemRect.left,lItem->m_itemRect.bottom);
					dc.LineTo(lItem->m_itemRect.right,lItem->m_itemRect.bottom);
					dc.SelectObject(&pen);
				}
				else
				{
					dc.FillSolidRect(lItem->m_itemRect,lItem->m_itemColor);

					CRect tmpRect = lItem->m_itemRect;
					tmpRect.DeflateRect(0, -1, 0, -1);
					//dc.Rectangle(tmpRect);
				}

				DrawItemText(dc,lItem,cx,cy);
			}			

			cx+=GetColumnWidth(j);
			if(j == GetColumnCount()-1) 
				lastBound = lItem->m_itemRect.bottom;							
		}
		
		//отрисовка линии, отделяющей строку		
		cy+=maxItemHeight;

		// заменил отрисовку линии отрисовкой прямоугольника каждой ячейки
		dc.MoveTo(left,lastBound);
		dc.LineTo(right,lastBound);
	}

	cy = lastBound;
	m_nItemsHeight=cy;

	//дорисовка горизонтальных линий без элементов
	if(GetColumnCount() > 0)
	{
		for(int i=0; i<GetItemCount(); i++)
		{
			CaplSizingListItem *lItem=GetItem(i,0);
			if(!lItem) continue;

			dc.MoveTo(left, lItem->m_itemRect.bottom);
			dc.LineTo(right, lItem->m_itemRect.bottom);
		}
	}

	//дорисовка вертикальных линий без элементов (стандартная ширина строк)
	while(cy<rcClient.Height())
	{
		if(cy>rcClient.Height()-m_yIndent) break;
		dc.MoveTo(left,cy);
		dc.LineTo(right,cy);
		cy+=m_defItemHeigth;
	}
	dc.SelectObject(&oldPen);
	

}
void CaplSizingListCtrl::PaintGrid(CDC &dc)
{
	CRect rcClip, rcClient;
//	dc.GetClipBox( &rcClip );
	GetClientRect(&rcClient);

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

	CPen pen(PS_SOLID,1,m_lineColor);
//	CPen pen1(PS_SOLID,1,RGB(255, 0, 0));

	CPen *oldPen=dc.SelectObject(&pen);

	int top=m_wndHeader.m_sumItemsHeight-1+m_xIndent;
	int left=rcClient.left+m_xIndent;
	int high=max(rcClient.Height()-m_yIndent,m_nItemsHeight);
	//int right=GetColumnsWidth()+m_xIndent;
	int right=max(rcClient.Width()-m_xIndent,GetColumnsWidth()+m_xIndent);
	int cx=left;
	//отрисовка вертикальных линий
	if(m_xIndent)
	{
		dc.MoveTo(cx,m_yIndent);
		dc.LineTo(cx,high);
	}
	for(int i=0;i<GetColumnCount();i++)
	{
		int col_width=GetColumnWidth(i);
		cx+=col_width;
		dc.MoveTo(cx,top);
		dc.LineTo(cx,high);
	}
	if(m_xIndent && GetColumnsWidth()<rcClient.right)
	{
		dc.MoveTo(right,m_yIndent);
		dc.LineTo(right,high);
	}
	if(m_yIndent && m_nItemsHeight<rcClient.bottom)
	{
		dc.MoveTo(rcClient.left+m_xIndent,rcClient.bottom-m_yIndent);
		dc.LineTo(right,rcClient.bottom-m_yIndent);
	}
	dc.SelectObject(&oldPen);
}

void CaplSizingListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	m_ToolTip->Hide();

	Invalidate();

	if(nSBCode == SB_THUMBTRACK || nSBCode == SB_THUMBPOSITION)
	{
		SCROLLINFO t_ScrollInfo;

		ZeroMemory(&t_ScrollInfo, sizeof(SCROLLINFO));
		t_ScrollInfo.cbSize = sizeof(SCROLLINFO);
		t_ScrollInfo.fMask = SIF_TRACKPOS;

		GetScrollInfo(SB_VERT, &t_ScrollInfo);

		nPos = t_ScrollInfo.nTrackPos;
	}

	CScrollView::OnVScroll(nSBCode, nPos, pScrollBar);
}


BOOL CaplSizingListCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	m_ToolTip->Hide();
	Invalidate();
	BOOL res=CScrollView::OnMouseWheel(nFlags, zDelta/2, pt);

	/*CPoint pos=GetScrollPosition(); 

	int nMapMode; SIZE sizeTotal; SIZE sizePage; SIZE sizeLine;
	GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine );

	CRect rcClient;
	GetClientRect(&rcClient);

	int dy=rcClient.Height()/3;

	if(zDelta<0)
	{
		pos.y+=dy;
		if(pos.y>(sizeTotal.cy-rcClient.Height()) )pos.y=sizeTotal.cy-rcClient.Height();
	}
	else
	{
		pos.y-=dy;
		if(pos.y<0) pos.y=0;
	}
	ScrollToPosition(pos);
	Invalidate();

	/*int delta;
	if(zDelta>0)delta=-sizeLine.cy;
	else delta=sizeLine.cy;
	CPoint new_pos(cur_pos.x,cur_pos.y+delta); 
	ScrollToPosition(new_pos);*/
	
	return res;
}

CaplSizingListCtrl::CaplSizingListItem *CaplSizingListCtrl::GetItemByPoint(CPoint point)
{
	if(!m_items) return 0;
	CPoint cur_pos=GetScrollPosition();
	point.x+=cur_pos.x;
	point.y+=cur_pos.y;

	CRect headerRect;
	headerRect.SetRect(m_xIndent,cur_pos.y,m_xIndent+m_wndHeader.GetColumnsWidth(),m_yIndent+m_wndHeader.m_sumItemsHeight+cur_pos.y);
	if(headerRect.PtInRect(point))
	{
		return 0;
	}
	for(int i=0;i<m_nItemsCount;i++)
	{
		CRect cl_rect=m_items[i].m_itemRect;
		if(cl_rect.PtInRect(point))
		{
			return &m_items[i];
		}
	}
	return 0;
}

void CaplSizingListCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	m_ToolTip->Hide();
	SetFocus();	
	if(GetParentFrame())
	{
		// Когда во фрейме сплитер и несколько CaplSizingListCtrl
		// виды не становятся активными при переключении
		if(GetParentFrame()->IsChild(this))
			GetParentFrame()->SetActiveView(this);		
	}
	
	CPoint cur_pos=GetScrollPosition();
	m_resizingCol=m_wndHeader.GetResizingColumn(point);
	if(m_resizingCol) 
	{
		m_prev_drag_point_x=point.x+cur_pos.x;
		m_hCurCursor=0;
		CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
		if(0!=app) m_hCurCursor=app->LoadCursor(IDC_RESIZE_COLUMN_CUR);
		SetCursor(m_hCurCursor);
	}
	else
	{
		int nRow,nCol;
		if(m_wndHeader.GetActiveItem(point,nCol,nRow))
		{
			if(!m_bEnableSort) return;

			BOOL bAscending = FALSE;

			if(m_wndHeader.GetItemImage(nCol)==-1)
			{
				bAscending = TRUE;
			}
			else
			{
				if(m_wndHeader.GetItemImage(nCol)==1)
					bAscending = TRUE;
			}

			SortItems(nCol, bAscending);
			Invalidate();	
			return;
		}
	}
	
	CaplSizingListItem *fItem=GetItemByPoint(point);
	if(!fItem) return;
	if(m_btSelectMode & HG_SINGLE_ITEM_SELECT) 
	{
		if(!fItem->m_bSelected) SelectItem(fItem->m_iItem, fItem->m_iSubItem);
	}
	else
	{
		SelectItem(fItem->m_iItem, fItem->m_iSubItem,!fItem->m_bSelected);
	}
		
	Invalidate();
	CScrollView::OnLButtonDown(nFlags, point);
}

void CaplSizingListCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	if(m_resizingCol) RecalcItemsTextRect();

	m_resizingCol=0;
	m_hCurCursor=m_hDefCursor;
	SetCursor(m_hCurCursor);
	CScrollView::OnLButtonUp(nFlags, point);
}

void CaplSizingListCtrl::SetCtrlIndents(int cx,int cy)
{
	if(cx<0) cx=0;
	if(cy<0) cy=0;
	if(cx==m_xIndent && cy==m_yIndent) return;
	m_xIndent=cx;
	m_yIndent=cy;
	m_wndHeader.m_xIndent=cx;
	m_wndHeader.m_yIndent=cy;
	CRect m_wndRect;
	GetWindowRect(&m_wndRect);
	ScreenToClient(m_wndRect);
	SetScrollSizes(MM_TEXT, CSize(GetColumnsWidth()+m_xIndent*2,m_nItemsHeight+m_yIndent*2));
	Invalidate();
}

bool CaplSizingListCtrl::EnsureVisible(int nItem)
{
	if(nItem<0 || nItem>GetItemCount()) return FALSE;
	OnPaint(); 
	
	CaplSizingListItem *foundItem=GetItem(nItem,0);
	if(foundItem==0) return FALSE;

	CPoint cur_pos=GetScrollPosition(); 
	CPoint new_pos;
	// проверка на видимость
	int y1=foundItem->m_itemRect.top-m_wndHeader.m_sumItemsHeight;
	int y2=foundItem->m_itemRect.bottom;

	RECT rect;
	GetClientRect(&rect);
	int w_y=rect.bottom-rect.top;

	if(y1<cur_pos.y) 	new_pos.y=y1; //пункт выше верхнего
	else if(y2>cur_pos.y+w_y)new_pos.y=y2-w_y;//пункт ниже нижнего
	else return true;

	if(new_pos.y<0)new_pos.y=0;
	new_pos.x=cur_pos.x;
	ScrollToPosition(new_pos);
	Invalidate();
	return TRUE;
}

bool CaplSizingListCtrl::RecalcItemsTextRect(CDC *pDC, int nItem)
{
	if(GetColumnCount() == 0) return false;
	
	// размер списка
	CRect rcClient, tmpRect;
	GetClientRect(&rcClient);

	// текущий контекст для рисования
	bool bNeedReleaseDC= false;
	if(!pDC)
	{
		pDC = GetDC();
		pDC->SetMapMode(m_mode);
		bNeedReleaseDC= true;
	}

	// бывает, что сначала нужно один раз отрисовать,
	// чтобы там все пересчиталось
	if(m_wndHeader.m_sumItemsHeight == 0)
		m_wndHeader.PaintHeader(*pDC);

	// пересчитываем все строчки
	bool bRecalcAll = (nItem == -1) ? true : false;

	// начальная высота (сразу после заголовка)
	int j, cy = m_wndHeader.m_sumItemsHeight + m_yIndent - 1;
	int top = m_wndHeader.m_sumItemsHeight + m_yIndent - 1;

	// если указан номер элемента, то пересчитывать будем с него
	if(nItem > 0)
	{
		// получаем элемент
		CaplSizingListItem *lItem = 0;
		lItem = GetItem(nItem, 0);

		// новая граница
		CaplSizingListItem *lItemPrev = GetItem(nItem-1, 0);
		top = cy = lItemPrev->m_itemRect.bottom;
	}
	else 
	{
		nItem = 0;
	}	

	// идем по строкам
	for(int i= nItem; i<GetItemCount();i++)
	{
		// максимальная высота ячейки в строке
		int maxItemHeight=0;

		// обход начинаем слева
		int cx = rcClient.left + m_xIndent;

		// старая максимальаня высота
		int nOldMaxHeight = GetItem(i, 0)->m_itemRect.Height();

		// проходим по столбцам
		for(j=0;j<GetColumnCount();j++)
		{
			// получаем элемент
			CaplSizingListItem *lItem = GetItem(i, j);
			if(!lItem) continue;

			// вычисляем textRect
			DrawItemText(*pDC, lItem, cx, cy, false);

			// новая максимальная высота ячейки в строке
			if(maxItemHeight<lItem->m_textRect.Height())
				maxItemHeight=lItem->m_textRect.Height();

			// смещаемся на ширину столбца
			cx+=GetColumnWidth(j);
		}

		// максимальная высота не изменилась - значит и расчет дальше неактуален
		//if(i == nItem && nOldMaxHeight == maxItemHeight && !bRecalcAll) return true;

		int maxItemRectHeight = 0;
		cx = rcClient.left + m_xIndent;

		for(j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *lItem=GetItem(i,j);
			if(!lItem) continue;

			//расчитаем границы ячейки 
			lItem->m_itemRect.top=cy+1;
			if(cy==top) lItem->m_itemRect.top=cy;
			lItem->m_itemRect.left=cx;
			lItem->m_itemRect.right=cx+GetColumnWidth(j);
			lItem->m_itemRect.bottom=cy+maxItemHeight;

			//скорректируем границы текста по тексту
			int v_delta=(int)((lItem->m_itemRect.Height()-lItem->m_textRect.Height())/2);
			lItem->m_textRect.top+=v_delta;
			lItem->m_textRect.bottom=lItem->m_itemRect.bottom-lItem->m_cy;
			lItem->m_textRect.left+=lItem->m_cx;
			lItem->m_textRect.right=lItem->m_itemRect.right;

			//скорректируем границы текста по иконке (если она есть)
			if(lItem->m_iImage != -1 && !lItem->m_sText.IsEmpty() && m_cImageItemList!=NULL)
			{
				IMAGEINFO *pImageInfo = new IMAGEINFO;
				m_cImageItemList->GetImageInfo(lItem->m_iImage, pImageInfo);
				lItem->m_textRect.left += (pImageInfo->rcImage.right-pImageInfo->rcImage.left);

				delete pImageInfo;
			}

			cx+=GetColumnWidth(j);

			if(maxItemRectHeight<lItem->m_itemRect.Height())
				maxItemRectHeight=lItem->m_itemRect.Height();
		}

		// смещаемся на максимальную высоту ячейки в строке
		if(maxItemHeight < maxItemRectHeight) maxItemHeight = maxItemRectHeight;
		cy+=maxItemHeight;
	}
	if(bNeedReleaseDC) ReleaseDC(pDC);
	Invalidate();
	return true;
}

bool CaplSizingListCtrl::SetItemText(int nItem, int nSubItem,LPCTSTR lpszText,BOOL bInvalidate, BOOL bRecalcItemsRect)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_sText=lpszText;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_sText=lpszText;
	}
	
	if(bRecalcItemsRect) RecalcItemsTextRect(0, nItem);
	if(bInvalidate) Invalidate();

	return true;
}

bool CaplSizingListCtrl::SetItemData(DWORD dwData,int nItem, int nSubItem)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_dData=dwData;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_dData=dwData;
	}
		
	return true;
}

bool CaplSizingListCtrl::SetItemColor(COLORREF m_newColor,int nItem, int nSubItem,BOOL bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	
	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_itemColor=m_newColor;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_itemColor=m_newColor;
	}
	
	if(bInvalidate) Invalidate();
	return TRUE;
}

bool CaplSizingListCtrl::SetItemTextColor(COLORREF m_newColor,int nItem, int nSubItem,BOOL bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	
	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_textColor=m_newColor;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_textColor=m_newColor;
	}
	
	if(bInvalidate) Invalidate();
	return TRUE;
}

bool CaplSizingListCtrl::SetItemBkColor(COLORREF m_newColor,int nItem, int nSubItem,BOOL bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_bgrColor=m_newColor;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_bgrColor=m_newColor;
	}

	if(bInvalidate) Invalidate();
	return TRUE;
}
bool CaplSizingListCtrl::SetItemBold(int nItem, int nSubItem, BOOL bBold, BOOL bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_bBold=bBold;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_bBold=bBold;
	}

	if(bInvalidate) Invalidate();
	return TRUE;
}
bool CaplSizingListCtrl::SetItemItalic(int nItem, int nSubItem, BOOL bItalic, BOOL bInvalidate)
{
	if(nItem<0 || nItem>GetItemCount()) return false;
	if(nSubItem>GetColumnCount()) return false;

	CaplSizingListItem *foundItem=0;
	if(nSubItem<0) 
	{
		for(int i=0;i<GetColumnCount();i++)
		{
			foundItem=GetItem(nItem,i);
			if(foundItem==0) return false;
			foundItem->m_bItalic=bItalic;
		}
	}
	else
	{
		foundItem=GetItem(nItem,nSubItem);
		if(foundItem==0) return false;
		foundItem->m_bItalic=bItalic;
	}

	if(bInvalidate) Invalidate();
	return TRUE;
}

void CaplSizingListCtrl::DeselectAll(BOOL bInvalidate)
{
	m_oldSelItem=-1;
	m_oldSelSubItem=-1;
	OnSelChanged(-1,-1);
	if(!m_items) return;
	for(int i=0;i<m_nItemsCount;i++)
		m_items[i].m_bSelected=false;

	if(bInvalidate) Invalidate();
}
bool CaplSizingListCtrl::SelectItem(int nItem, int nSubItem,bool bSelect,BOOL bInvalidate)
{
	if(!m_items) return false;
	for(int i=0;i<GetItemCount();i++)
	{
		for(int j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *foundItem=GetItem(i,j);
			if(foundItem==0) return false;
			if(i==nItem)
			{
				if(j==nSubItem || (m_btSelectMode & HG_ENTIRE_ROW_SELECT))
				{
					foundItem->m_bSelected=bSelect;
				}
				else
				{
					if(bSelect && (m_btSelectMode & HG_SINGLE_ITEM_SELECT)) 
					{
						foundItem->m_bSelected=false;
					}
				}	
			}
			else
			{
				if(bSelect && (m_btSelectMode & HG_SINGLE_ITEM_SELECT))//снимаем выделение у всех строк кроме переданной
				{
					foundItem->m_bSelected=false;
				}
			}
		}
	}
	if(bSelect)
	{
		if(m_btSelectMode & HG_ENTIRE_ROW_SELECT)
		{
			if(m_oldSelItem!=nItem)
			{
				OnSelChanged(nItem,nSubItem);
			}
		}
		else
		{
			if(m_oldSelItem!=nItem || m_oldSelSubItem!=nSubItem)
			{
				OnSelChanged(nItem,nSubItem);
			}	
		}
		m_oldSelItem=nItem;
		m_oldSelSubItem=nSubItem;

	}	
		
	if(bInvalidate) Invalidate();
	return true;
}
bool CaplSizingListCtrl::SetSelectMode(BYTE flags)
{
	if((flags & HG_SINGLE_ITEM_SELECT) && (flags & HG_MULTI_ITEM_SELECT)) return false;
	if((flags & HG_ENTIRE_ROW_SELECT) && (flags & HG_SUB_ITEMS_SELECT)) return false;
	m_btSelectMode=flags;
	DeselectAll();
	return true;
}
bool CaplSizingListCtrl::GetListSelected(CUIntArray &nItemsSelected)
{
	if(!m_items) return false;
	for(int i=0;i<GetItemCount();i++)
	{
		for(int j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *foundItem=GetItem(i,j);
			if(foundItem==0) return false;
			if(foundItem->m_bSelected)
			{
				nItemsSelected.Add(i);
				break;
			}
		}
	}
	return true;
}

int CaplSizingListCtrl::GetFirstSelectedItem()
{
	if(!m_items) return -1;
	CUIntArray nItemsSelected;
	GetListSelected(nItemsSelected);
	if(!nItemsSelected.GetSize()) return -1;
	return nItemsSelected[0];
}

int CaplSizingListCtrl::GetSelectedItemsCount()
{
	if(!m_items) return 0;
	CUIntArray nItemsSelected;
	GetListSelected(nItemsSelected);
	return nItemsSelected.GetSize();
}

bool CaplSizingListCtrl::GetListSelected(CArray<CaplSizingListItem*,CaplSizingListItem*> &sItemsSelected)
{
	if(!m_items) return false;
	for(int i=0;i<m_nItemsCount;i++)
	{
		if(m_items[i].m_bSelected) sItemsSelected.Add(&m_items[i]);
	}
	if(sItemsSelected.GetSize()) return true;
	return false;
}

void CaplSizingListCtrl::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	m_ToolTip->Hide();
	CaplSizingListItem *lItem=GetItemByPoint(point);
	if(lItem)
	{
		CWnd *parentWnd=GetParent();
		if(parentWnd) 
		{
			NMLISTVIEW nmListView;
			memset(&nmListView, 0, sizeof(NMLISTVIEW));
			nmListView.hdr.idFrom = GetDlgCtrlID();
			nmListView.hdr.code = HDN_ITEMDBLCLICK;
			nmListView.hdr.hwndFrom = m_hWnd;
			
			nmListView.iItem = lItem->m_iItem;
			nmListView.iSubItem = lItem->m_iSubItem;
		
			parentWnd->SendMessage(WM_NOTIFY, (WPARAM)GetDlgCtrlID(), (LPARAM)&nmListView);
			//parentWnd->SendMessage(WM_NOTIFY,(WPARAM)HDN_ITEMDBLCLICK,(LPARAM)lItem);
		}
	}
	
	CScrollView::OnLButtonDblClk(nFlags, point);
}

void CaplSizingListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	m_ToolTip->Hide();
/*	перенесено в PreTranslateMessage
	int delta = 0;
	CPoint cur_pos = GetScrollPosition();
	
	if(m_btSelectMode & HG_SINGLE_ITEM_SELECT && m_btSelectMode &HG_ENTIRE_ROW_SELECT) 
	{
		int nItem=GetFirstSelectedItem();
		int nextItem = -1;

		CaplSizingListItem *foundItem=0;
		
		if(nChar==VK_UP)
		{
			foundItem = GetItem(nItem, 0);
			if(foundItem) delta += (-foundItem->m_itemRect.Height());

			nextItem=nItem-1;
		}
		else if(nChar==VK_DOWN)
		{
			nextItem=nItem+1;
			foundItem = GetItem(nItem, 0);
			if(foundItem) delta += foundItem->m_itemRect.Height();
		}
		else  if(nChar==VK_PRIOR ) //PgUp
		{
			nextItem=nItem-3;
			if(nextItem<0) nextItem=0;

		}
		else  if(nChar==VK_NEXT  ) //PgDn
		{
			nextItem=nItem+3;
			if(nextItem>=GetItemCount())nextItem=GetItemCount()-1;

		}
		else  if(nChar==VK_HOME   ) 
		{
			nextItem=0;
		}
		else  if(nChar==VK_END   ) 
		{
			nextItem=GetItemCount()-1;
		}

		if(nextItem>-1 && nextItem<GetItemCount())
		{
			SelectItem(nextItem);
			EnsureVisible(nextItem); 
		}
	}*/


	CScrollView::OnKeyDown(nChar, nRepCnt, nFlags);

	//cur_pos.y += delta;
	//ScrollToPosition(cur_pos);
}

BOOL CaplSizingListCtrl::PreTranslateMessage(MSG* pMsg)
{
	// TODO: Add your specialized code here and/or call the base class
	if(0!=pMsg)
	{
		if(pMsg->message==WM_KEYDOWN && pMsg->hwnd==m_hWnd)
		{
			m_ToolTip->Hide();
			UINT nChar=pMsg->wParam;
			if(nChar==VK_UP || nChar==VK_DOWN || nChar==VK_PRIOR  || nChar==VK_NEXT || nChar==VK_HOME ||  nChar==VK_END)
			{
				int nItem=GetFirstSelectedItem();
				int nextItem = -1;
				if(nChar==VK_UP)nextItem=nItem-1;
				else if(nChar==VK_DOWN) nextItem=nItem+1;
				else  if(nChar==VK_PRIOR ) nextItem=nItem-3;//PgUp
				else  if(nChar==VK_NEXT  ) nextItem=nItem+3; //PgDn
				else  if(nChar==VK_HOME   ) nextItem=0;
				else  if(nChar==VK_END) nextItem=GetItemCount()-1;

				if(nextItem<0) nextItem=0;
				if(nextItem>=GetItemCount())nextItem=GetItemCount()-1;

				SelectItem(nextItem);
				EnsureVisible(nextItem); 
				return TRUE;
			}
		}
	}
	return CScrollView::PreTranslateMessage(pMsg);
}

int CaplSizingListCtrl::InsertHeaderRow(int nPos,bool bInvalidate)
{
	int res=m_wndHeader.InsertRow(nPos);
	if(bInvalidate) Invalidate();
	return res;
}

bool CaplSizingListCtrl::SetHeaderItemText(int nRow,int nCol,LPCTSTR lpszText,bool bInvalidate)
{
	bool res=m_wndHeader.SetHeaderItemText(nRow,nCol,lpszText);
	if(bInvalidate) Invalidate();
	return res;
}

bool CaplSizingListCtrl::SetHeaderColumnColor(int nCol,COLORREF color,bool bInvalidate)
{
	bool res=m_wndHeader.SetHeaderColumnColor(nCol,color);
	if(bInvalidate) Invalidate();
	return res;
}

bool CaplSizingListCtrl::SetHeaderColumnTextColor(int nCol,COLORREF color,bool bInvalidate)
{
	bool res=m_wndHeader.SetHeaderColumnTextColor(nCol,color);
	if(bInvalidate) Invalidate();
	return res;
}

bool CaplSizingListCtrl::SetHeaderColumnTextBgrColor(int nCol,COLORREF color,bool bInvalidate)
{
	bool res=m_wndHeader.SetHeaderColumnTextBgrColor(nCol,color);
	if(bInvalidate) Invalidate();
	return res;
}

bool CaplSizingListCtrl::SetHeaderColumnSortType(int nCol,long sort_type)
{
	return m_wndHeader.SetHeaderColumnSortType(nCol,sort_type);
}

void CaplSizingListCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	m_ToolTip->Hide();
	SetFocus();
	CaplSizingListItem *fItem=GetItemByPoint(point);
	if(!fItem) return;
	if(m_btSelectMode & HG_SINGLE_ITEM_SELECT) 
	{
		if(!fItem->m_bSelected) SelectItem(fItem->m_iItem, fItem->m_iSubItem);
	}
	else
	{
		SelectItem(fItem->m_iItem, fItem->m_iSubItem,!fItem->m_bSelected);
	}
	
	CScrollView::OnRButtonDown(nFlags, point);
}



BOOL CaplSizingListCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	SetCursor(m_hCurCursor);
	return 0;
}

void CaplSizingListCtrl::GetOffsets(int &cx,int &cy)
{
	CPoint cur_pos=GetScrollPosition();
	cx=cur_pos.x;
	cy=cur_pos.y;

}

//**********************************************************************
void CaplSizingListCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(!IsWindow(m_hWnd)) return;
	m_ToolTip->Hide();

	CWnd::OnMouseMove(nFlags, point);

	CPoint cur_pos=GetScrollPosition();
	int x=point.x+cur_pos.x, y=point.y+cur_pos.y;

	if(m_resizingCol)
	{
		int width_delta=x-m_prev_drag_point_x;
		int new_width=m_resizingCol->m_nWidth+width_delta;
		if(new_width<m_wndHeader.m_minItemWidth) 
		{
			new_width=m_wndHeader.m_minItemWidth;
		}
		m_resizingCol->m_nWidth=new_width;
		m_prev_drag_point_x=x;
		RecalcColumnsWidth();		
	}
	else
	{
		HCURSOR hOldCursor=m_hCurCursor;
		m_hCurCursor=m_hDefCursor;
		CaplListHeaderCtrl::CaplHeaderItem *resizingCol=m_wndHeader.GetResizingColumn(point);
		if(resizingCol)
		{
			m_hCurCursor=0;
			CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
			if(0!=app) m_hCurCursor=app->LoadCursor(IDC_RESIZE_COLUMN_CUR);
		}
		if(hOldCursor!=m_hCurCursor) SetCursor(m_hCurCursor);

		if(!resizingCol)
		{
			bool bShowTooltip=false;
			CString tooltipText=_T("");
			POINT tooltip_point=point;
			tooltip_point.x+=10;
			tooltip_point.y+=10;
			CaplSizingListCtrl::CaplSizingListItem *listItem=GetItemByPoint(point);
			if(listItem)
			{
				if(listItem->m_bShowTooltip) bShowTooltip=true;
				tooltipText=listItem->m_sText;
			}
			else 
			{
				int nCol,nRow;
				if(m_wndHeader.GetActiveItem(point,nCol,nRow))
				{
					if(m_wndHeader.m_headerItems[nCol].m_bShowTooltip[nRow]) 
					{
						bShowTooltip=true;
						tooltipText=m_wndHeader.m_headerItems[nCol].m_rowText[nRow];
					}
				}
			}
			if(bShowTooltip)
			{
				ClientToScreen(&tooltip_point);
				m_ToolTip->Show(tooltip_point.x,tooltip_point.y, tooltipText);  
			}
		}
	}

	TRACKMOUSEEVENT		csTME;
	csTME.cbSize = sizeof(csTME);
	csTME.dwFlags = TME_LEAVE;
	csTME.hwndTrack = m_hWnd;
	::_TrackMouseEvent(&csTME);
}

LRESULT CaplSizingListCtrl::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
	m_ToolTip->Hide();
	return 1;
} 

int CaplSizingListCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message)
{
	return MA_ACTIVATE;
}
LRESULT CaplSizingListCtrl::OnNcHitTest(CPoint point)
{
	// TODO: Add your message handler code here and/or call default

	return CScrollView::OnNcHitTest(point);
}

bool CaplSizingListCtrl::SaveToFile(LPCSTR fname)
{
	if(GetItemCount()<=0) {AfxMessageBox(APL_T("Нет данных для сохраненеия!"),MB_ICONSTOP|MB_OK); return false;}
	
	CString fpath=fname;
	if(fpath==_T(""))
	{
		CFileDialog dlg(FALSE,_T("htm"),NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
			_T("HTML Files (*.htm*)|*.htm*|All Files (*.*)|*.*||"));
		if(dlg.DoModal()!=IDOK) return false;
		fpath=dlg.GetPathName();
	}

	CString buf,html=_T("");
	html =_T("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//RU\">\n")
		_T("<html>\n")
		_T("<head>\n")
		_T("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=Windows-1251\">\n")
		_T("<body>\n");

#ifdef _UNICODE
	html.Replace(_T("Windows-1251"),_T("UTF-8"));
#endif

	GetHtml(buf);
	html+=buf;

	html +=	_T("</body>\n</html>");

	CaplStringFile file;
	if(!file.Open(fpath,CFile::modeCreate|CFile::modeWrite))
	{AfxMessageBox(APL_T("Ошибка открытия файла!"),MB_ICONSTOP|MB_OK); return false;}
	file.WriteString(html);

#ifdef _UNICODE
	file.SetFileEncoding(aplUTF8);
#endif

	file.Close();
	if(IDYES==AfxMessageBox(APL_T("Файл сохранен! Открыть?"),MB_ICONQUESTION|MB_YESNO))
	{
		aplShellExecute(0,_T("open"),fpath);
	}
	return true;
}


bool CaplSizingListCtrl::GetHtml(CString &html)
{
	html=_T("<TABLE cellSpacing=\"0\" cellPadding=\"5\" border=\"1\">\n");

	int i,j;
	CString buf;

	int col_width,allwidth=m_wndHeader.GetColumnsWidth();

	html+=_T("<thead><TR>\n");

	// заголовок
	for(i=0; i<m_wndHeader.m_headerItems.GetSize(); i++)
	{
		col_width=m_wndHeader.GetColumnWidth(i);
		buf.Format(_T("<th valign=\"middle\" width=%i%%>"),(int)(100*col_width/allwidth) );
		html+=buf;
		
		//html+=">";

		buf=m_wndHeader.m_headerItems[i].m_lpszColumnHeading;
		buf.Replace(_T("\n"),_T("<br>"));
		html+=buf;
		html+=_T("</th>\n");

	}
	html+=_T("</TR></thead>\n");

	// данные
	for(i=0; i<GetItemCount(); i++)
	{
		html+=_T("<TR>\n");
		for(j=0;j<GetColumnCount();j++)
		{
			CaplSizingListItem *lItem=GetItem(i, j);
			if(!lItem) {html+=_T("<td>&nbsp;</td>\n"); continue;}

			int r=GetRValue(lItem->m_itemColor);
			int g=GetGValue(lItem->m_itemColor);
			int b=GetBValue(lItem->m_itemColor);
			buf.Format(_T("<td valign=\"middle\" bgColor=#%x%x%x "),r,g,b);
			html+=buf;

			int colAlign=GetColumnAlign(lItem->m_iSubItem);

			if(colAlign==DT_RIGHT)html+=_T(" ALIGN=\"right\"");
			else if(colAlign==DT_CENTER)html+=_T(" ALIGN=\"center\"");
			else html+=_T(" ALIGN=\"left\"");

			html+=_T(">");

			if(lItem->m_bBold)html+=_T("<b>");
			if(lItem->m_bItalic)html+=_T("<i>");

			if(lItem->m_sText==_T("")) html+=_T("&nbsp;");
			else html+=lItem->m_sText;

			if(lItem->m_bItalic)html+=_T("</i>");
			if(lItem->m_bBold)html+=_T("</b>");
			html+=_T("</td>\n");
		}
		html+=_T("</TR>\n");
	}
	html +=_T("</TABLE>\n");
	return true;
}



