Click here to Skip to main content
15,898,036 members
Articles / Desktop Programming / MFC

The ALXGrid Control Library.

Rate me:
Please Sign up or sign in to vote.
5.00/5 (29 votes)
10 Nov 20021 min read 201.4K   5.5K   85  
The ALXGrid Control Library is a set of classes for management of data as a table.
// ALXGridCore.cpp : implementation of the CALXGridCore class
//
#include "stdafx.h"
#include "resource.h"       // main symbols
#include "ALXGridCore.h"

#if _MSC_VER > 1200
#include <atlbase.h>
#endif // _MSC_VER > 1200

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

const DWORD maxScrollRange	=	SHRT_MAX;

// ������� ������ ������� ���������� � ������
BOOL DrawCellCtrl(CDC* pDC, CRect& rect, CELL_INFO& CellInfo, CELL_DATA& CellData)
{
	CRect rectText(rect), rectCtrl(rect);
	CString strText = CellData.m_strText;
	BOOL FirstDrawFrameCtrl = FALSE;
	UINT nState = CellInfo.m_nState;

	switch(CellInfo.m_nTypeCtrl)
	{
	case DFC_BUTTON:
		{
			// If it is the button DFCS_BUTTONPUSH
			if(nState & DFCS_BUTTONPUSH)
			{
				FirstDrawFrameCtrl = TRUE;
				rectCtrl.DeflateRect(1,0,0,1);
			}
			else
			{
				if(strText.GetLength()>0) // If it is necessary to output the text
				{
					strText = " " + strText;
					rectText.left	= min(rect.right,rect.left + 15);
				}
				else
				{
					rectText = CRect(0,0,0,0);
					rectCtrl.left	= max(rect.left,rect.left+(rect.Width()-13)/2);
				}
				rectCtrl.top	= max(rect.top,rect.top+(rect.Height()-13)/2);
				rectCtrl.right	= min(rect.right,rectCtrl.left + 13),
				rectCtrl.bottom = min(rect.bottom,rectCtrl.top + 13);

				switch(CellData.m_dwTag)
				{
				case 0:
					{
						nState =  nState & ~DFCS_CHECKED;
						break;
					}
				case 1:
					{
						if(nState == (nState | DFCS_BUTTON3STATE))
							nState =  (nState & ~DFCS_BUTTON3STATE) | DFCS_BUTTONCHECK | DFCS_CHECKED;
						else
							nState =  nState | DFCS_CHECKED;
						break;
					}
				case 2:
					{
						if(nState == (nState | DFCS_BUTTON3STATE))
							nState =  nState | DFCS_CHECKED;
						else
							nState =  nState & ~DFCS_CHECKED;
						break;
					}
				default:
						nState =  nState & ~DFCS_CHECKED;
				}
			}
			break;
		}
	case DFC_SCROLL:
		{
			if((nState & DFCS_SCROLLSIZEGRIPRIGHT) == DFCS_SCROLLSIZEGRIPRIGHT)
			{
				CRect rectCtrl1(rectCtrl), rectCtrl2(rectCtrl);
				rectCtrl1.left = max(rect.left,rect.right - ::GetSystemMetrics(SM_CXVSCROLL));
				rectCtrl1.bottom = rect.top + rect.Height()/2;
				rectCtrl2.top = rectCtrl1.bottom;
				rectCtrl2.left = rectCtrl1.left;
				rectText.right = rectCtrl.left;
				if(rectCtrl1.IsRectEmpty())
					return FALSE;
				return
					pDC->DrawText(strText, rectText, CellInfo.m_nFormat) &&
					pDC->DrawFrameControl(&rectCtrl1,CellInfo.m_nTypeCtrl,nState & ~ DFCS_SCROLLSIZEGRIPRIGHT | DFCS_SCROLLUP) &&
					pDC->DrawFrameControl(&rectCtrl2,CellInfo.m_nTypeCtrl,nState & ~ DFCS_SCROLLSIZEGRIPRIGHT | DFCS_SCROLLDOWN);
			}
			if((nState & DFCS_SCROLLSIZEGRIP) == DFCS_SCROLLSIZEGRIP)
			{
				FirstDrawFrameCtrl = TRUE;
				rectText.right = max(rect.left,rect.right - rect.Height()/2 - 1);
				break;
			}
			if((nState & DFCS_SCROLLCOMBOBOX) == DFCS_SCROLLCOMBOBOX)
			{
				rectCtrl.left = max(rect.left,rect.right - rect.Height());
				rectText.right = rectCtrl.left;
			}
			break;
		}
	case DFC_MENU:
		{
			FirstDrawFrameCtrl = TRUE;
			strText = " " + strText;
			rectCtrl.right	= min(rect.right,rect.left + 13);
			rectText.left	= min(rect.right,rectCtrl.right + 2); 
			break;
		}
	case DFC_CAPTION:
		{
			rectCtrl.left = max(rect.left,rect.right - rect.Height());
			rectText.right = rectCtrl.left; 
			break;
		}
	}

	if(rectCtrl.IsRectEmpty())
		return FALSE;
	if(FirstDrawFrameCtrl)
	{
		BOOL bResult =	pDC->DrawFrameControl(&rectCtrl,CellInfo.m_nTypeCtrl,nState);
						pDC->DrawText(strText, rectText, CellInfo.m_nFormat);

		return bResult;
/*		return
			pDC->DrawFrameControl(&rectCtrl,CellInfo.m_nTypeCtrl,nState) &&
			pDC->DrawText(strText, rectText, CellInfo.m_nFormat);
*/
	}
	else
	{
				pDC->DrawText(strText, rectText, CellInfo.m_nFormat);
		return	pDC->DrawFrameControl(&rectCtrl,CellInfo.m_nTypeCtrl,nState);
/*		return
			pDC->DrawText(strText, rectText, CellInfo.m_nFormat) &&
			pDC->DrawFrameControl(&rectCtrl,CellInfo.m_nTypeCtrl,nState);
*/	}
};

/////////////////////////////////////////////////////////////////////////////
// CALXGridCore

// �����������
CALXGridCore::CALXGridCore()
{
	m_pCellCtrl = NULL;

	m_bInsideUpdate = FALSE;

	m_curHResize = NULL;

	m_EnableResizeCol = FALSE;
	m_BeginResizeCol = FALSE;
		
	m_CountHeaderRows = 1;
	m_CountFrozenCols = 1;

	m_nHeaderColPressed = -1;
	m_nHeaderRowPressed = -1;

	m_nFrozenColPressed = -1;
	m_nFrozenRowPressed = -1;

	m_bSelAllBtnPressed = FALSE;

	m_nRowLineCount = 1;

	m_nActiveCol = m_CountFrozenCols;
	m_nActiveRow = m_CountHeaderRows;

	m_nSortOrder = None;
	m_nSortHeadCol = -1;
	m_nSortHeadRow = -1;

	m_nVScrollFactor = 1;
	m_nHScrollFactor = 1;

	m_CurScrollPos.x = 0;
	m_CurScrollPos.y = 0;

	m_sizeTotal = 0;
	m_sizePage = 0;
	m_sizeLine = 0;
	m_sizeExtArea = 0;

	// ��������� �� ����� ����
	m_pGridWnd = NULL;

	m_nRowHeight = 16;
	m_nHeadRowHeight = m_nRowHeight;
	m_FrozenColWidth = 8;

	// ��������� ������������ �����, ������������ ������
	LOGFONT	 logfont;
	memset(&logfont, 0, sizeof(logfont));
	CFont mFont;
	mFont.Attach(GetStockObject(DEFAULT_GUI_FONT));;
	mFont.GetLogFont(&logfont);
//	logfont.lfHeight = -11;
//	logfont.lfWeight = FW_NORMAL;
//	lstrcpy(logfont.lfFaceName, _T("Microsoft Sans Serif"));
//	logfont.lfCharSet = DEFAULT_CHARSET;//RUSSIAN_CHARSET;
//	logfont.lfOutPrecision = OUT_TT_PRECIS;
//	logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
//	logfont.lfQuality = PROOF_QUALITY;
//	logfont.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH;
//	logfont.lfItalic = FALSE;

	m_pHeadFont = &m_Font;

	if(!m_Font.CreateFontIndirect(&logfont))
	{
		TRACE0("Failed to create grid font\n");
		return;
	}

	m_MetricsCells.FillDefault();

	// �������� ���������� �����
	m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
	m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;

	m_nActiveSelCol = m_nActiveCol;
	m_nActiveSelRow = m_nActiveRow;
}

// ����������
CALXGridCore::~CALXGridCore()
{
	if(m_pCellCtrl != NULL)
		delete m_pCellCtrl;
	if(m_curHResize != NULL)
		DestroyCursor(m_curHResize);
}

// ������� ������ ���������� ����.
void CALXGridCore::OnGridDraw(CDC *pDC)
{
	CRect rectClip;
	// �������� ������� �����������.
	pDC->GetClipBox(&rectClip); 
	// ���� ���������� ������������ ?
	if (rectClip.IsRectEmpty())
		return;

	OnUpdateRect(pDC,rectClip);
}

// ������� ����������� ������� ���� � ������� �����.
CRect CALXGridCore::GetGridRect(CRect& rectPaint)
{
	CRect rectGrid = rectPaint;
	rectGrid.OffsetRect(m_CurScrollPos.x, m_CurScrollPos.y);
	return rectGrid;
}

// ������� ����������� ������� ���� � ������� �����.
CRect CALXGridCore::GetHeadRect(CRect& rectPaint)
{
	CRect rectHead = rectPaint;
	rectHead.OffsetRect(m_CurScrollPos.x,0); 
	return rectHead;
}

// ������� ����������� ������� ���� � ������� ����������� ��������.
CRect CALXGridCore::GetFrozenRect(CRect& rectPaint)
{
	CRect rectFrozen = rectPaint;
	rectFrozen.OffsetRect(0, m_CurScrollPos.y); 
	return rectFrozen;
}

// ������� �������� ��������� �� ����.
void CALXGridCore::SetGridWnd(CWnd *pGridWnd)
{
	m_pGridWnd = pGridWnd;
}

// ������� ���������� ������� ����.
void CALXGridCore::OnUpdateRect(CDC *pDC, CRect &rectClip)
{
	CFont* pOldFont = NULL;
	pOldFont = pDC->SelectObject(&m_Font);
	int OldBkMode =	pDC->SetBkMode(TRANSPARENT);

	COLORREF crOldText = pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
	CRect rectClient;
	m_pGridWnd->GetClientRect(&rectClient);
	CRgn rgnGrid;
	rgnGrid.CreateRectRgn(  m_CountFrozenCols > 0 ? m_FrozenColWidth * m_CountFrozenCols - offsetXY + 1: 0,
							m_CountHeaderRows > 0 ? m_nHeadRowHeight * m_CountHeaderRows - offsetXY + 1: 0,
							rectClient.right, rectClient.bottom );
	// ������������ ����� ������� ������ ���� ���������

	// ���� ����� �������������� �����
	if(m_CountHeaderRows > 0 && rectClip.top <= m_nHeadRowHeight * m_CountHeaderRows - offsetXY )
	{
		// ���� ����� �������������� ������������ ����� �������
		if(m_CountFrozenCols > 0 && rectClip.left<= m_FrozenColWidth * m_CountFrozenCols - offsetXY)
		{
			pDC->SelectClipRgn(&rgnGrid);
			OnUpdateGridRect(pDC, CRect(m_FrozenColWidth * m_CountFrozenCols,m_nHeadRowHeight * m_CountHeaderRows - offsetXY ,rectClip.right,rectClip.bottom));
			pDC->SelectClipRgn(NULL);
			OnUpdateFrozenRect(pDC, CRect(rectClip.left,m_nHeadRowHeight * m_CountHeaderRows,m_FrozenColWidth * m_CountFrozenCols,rectClip.bottom));
			OnUpdateHeaderRect(pDC, CRect(m_FrozenColWidth * m_CountFrozenCols,rectClip.top,rectClip.right,m_nHeadRowHeight * m_CountHeaderRows));
			OnUpdateFrozenHeaderRect(pDC, CRect(1,1,m_FrozenColWidth * m_CountFrozenCols+1,m_nHeadRowHeight * m_CountHeaderRows+1));
		}
		else
		{
			pDC->SelectClipRgn(&rgnGrid);
			OnUpdateGridRect(pDC, CRect(rectClip.left,m_nHeadRowHeight * m_CountHeaderRows - offsetXY ,rectClip.right,rectClip.bottom));
			pDC->SelectClipRgn(NULL);
			OnUpdateHeaderRect(pDC, CRect(rectClip.left,rectClip.top,rectClip.right,m_nHeadRowHeight * m_CountHeaderRows));
		}
			
	}
	else
	{
		// ���� ����� �������������� ������������ ����� �������
		if(m_CountFrozenCols > 0 && rectClip.left <= m_FrozenColWidth * m_CountFrozenCols - offsetXY )
		{
			pDC->SelectClipRgn(&rgnGrid);
			OnUpdateGridRect(pDC, CRect(m_FrozenColWidth * m_CountFrozenCols,rectClip.top,rectClip.right,rectClip.bottom));
			pDC->SelectClipRgn(NULL);
			OnUpdateFrozenRect(pDC, CRect(rectClip.left,rectClip.top,m_FrozenColWidth * m_CountFrozenCols,rectClip.bottom));
		}
		else
			OnUpdateGridRect(pDC, rectClip);
	}

	int nGridHeight = max(m_nHeadRowHeight * m_CountHeaderRows - offsetXY + 1,TopWndPos(GetAllRowCount())+1);

	// ���� ������ ���� ������ ������ �����
	if(rectClip.bottom > nGridHeight)
	{
		// ���� ������ ���� ������ ������ �����
		if(rectClip.right > m_nRowWidth - m_CurScrollPos.x - offsetXY)
		{
			CBrush brushBackground1,brushBackground2;
			CRect rectBackgrnd1(m_nRowWidth - m_CurScrollPos.x - offsetXY + 1,rectClip.top - offsetXY,rectClip.right,rectClip.bottom);
			if(brushBackground1.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)))
				pDC->FillRect(&rectBackgrnd1, &brushBackground1);
			CRect rectBackgrnd2(rectClip.left,nGridHeight - offsetXY + 1,rectClip.right,rectClip.bottom);
			if(brushBackground2.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)))
				pDC->FillRect(&rectBackgrnd2, &brushBackground2);
		}
		else
		{
			CBrush brushBackground;
			CRect rectBackgrnd(rectClip.left,nGridHeight - offsetXY + 1,rectClip.right,rectClip.bottom);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)))
				pDC->FillRect(&rectBackgrnd, &brushBackground);
		}
	}
	else
	{
		// ���� ������ ���� ������ ������ �����
		if(rectClip.right > m_nRowWidth - m_CurScrollPos.x - offsetXY)
		{
			CBrush brushBackground;
			CRect rectBackgrnd(m_nRowWidth - m_CurScrollPos.x - offsetXY + 1,rectClip.top,rectClip.right,rectClip.bottom);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_WINDOW)))
				pDC->FillRect(&rectBackgrnd, &brushBackground);
		}
	}
	if(pOldFont != NULL)
		pDC->SelectObject(pOldFont);

	pDC->SetBkMode(OldBkMode);
	pDC->SetTextColor(crOldText);
}

// ������� ���������� �������� ����� ���������� � ������ �������.
// �������� bIncludePartiallyShownRows ���������� ����� �� ��������
// ������ �������� �������� � �������.
void CALXGridCore::RectToRowRange(const CRect &GridRect, int &nFirstRow, int &nLastRow, BOOL bIncludePartiallyShownRows)
{
	CRect rect(GridRect);
	// ������� ����������	
	rect.DeflateRect(offsetXY,offsetXY,-offsetXY,-offsetXY);
	// ��������� ��������
	int nRounding = bIncludePartiallyShownRows ? 0 : m_nRowHeight;
	// ��������� ������ �����
	int nHeadHeight = m_CountHeaderRows * m_nHeadRowHeight;

	// ��������� �������� �����
	if(rect.top <= nHeadHeight)
		nFirstRow = max(0,(rect.top + nRounding) / m_nHeadRowHeight);
	else
		nFirstRow = max(m_CountHeaderRows, min(m_CountHeaderRows + (rect.top - nHeadHeight + nRounding) / m_nRowHeight,GetAllRowCount() - 1));

	if(rect.bottom <= nHeadHeight)
		nLastRow = max(0, min((rect.bottom - nRounding) / m_nHeadRowHeight,m_CountHeaderRows - 1));
	else
		nLastRow = max(m_CountHeaderRows, min(m_CountHeaderRows + (rect.bottom - nHeadHeight - nRounding) / m_nRowHeight,GetAllRowCount() - 1));
}

// ������� ���������� �������� �������� ���������� � ������ �������.
// �������� bIncludePartiallyShownRows ���������� ����� �� ��������
// ������� �������� �������� � �������.
void CALXGridCore::RectToColRange(const CRect &GridRect, int &nFirstCol, int &nLastCol, BOOL bIncludePartiallyShownCols, int nHeadRow)
{
	CRect rect(GridRect);
	// ������� ����������	
	rect.DeflateRect(offsetXY,offsetXY,-offsetXY,-offsetXY);
	// ��������� ��������
	nFirstCol = 0;
	int curwidth;
	// ������� �������� ���� �������� ���������� �������� rect
	if(bIncludePartiallyShownCols)
	{
		curwidth = GetColWidth(nFirstCol, nHeadRow);
		while(rect.left >= curwidth && nFirstCol<GetAllColCount(nHeadRow)-1)
			curwidth = curwidth + GetColWidth(++nFirstCol, nHeadRow);

		nLastCol = nFirstCol;

		while(rect.right > curwidth && nLastCol<GetAllColCount(nHeadRow)-1)
			curwidth = curwidth + GetColWidth(++nLastCol, nHeadRow);
	}
	// ������� �������� ��������, ������� ������� �������� �������� rect
	else
	{
		curwidth = 0;
		while(rect.left + LeftColPos(m_CountFrozenCols, nHeadRow) > curwidth && nFirstCol<GetAllColCount(nHeadRow)-1)
			curwidth = curwidth + GetColWidth(nFirstCol++, nHeadRow);

		nLastCol = nFirstCol;

		if(nLastCol<=GetAllColCount(nHeadRow)-1)
			curwidth = curwidth + GetColWidth(nLastCol, nHeadRow);

		while(rect.right > curwidth && nLastCol<GetAllColCount(nHeadRow)-1)
		{
			nLastCol++;
			curwidth = curwidth + GetColWidth(nLastCol, nHeadRow);
			if(rect.right <= curwidth)
			{
				nLastCol--;
				return;
			}
		}
	}
}

// ����������� �������. ��� ������ ���������� ���������� �����
// � ����� ��� ����� ����� �����.
// ��� ������� ���������������� � ������ CALXGrid.
int CALXGridCore::GetGridRowCount()
{
	return 0;
}

// ����������� �������. ��� ������ ���������� ���������� ��������
// � ����� ��� ����� ����������� ��������.
// ��� ������� ���������������� � ������ CALXGrid.
int CALXGridCore::GetHeadColCount(int nHeadRow)
{
	return 0;
}

// ����������� �������. ��� ������ ���������� ������ ������� �����.
// �������� nCol ������ ������������ � ������ ����������� ����� �������.
// ��� ������� ���������������� � ������ CALXGrid.
int CALXGridCore::GetColWidth(int nCol, int nHeadRow)
{
	if(nCol >= m_CountFrozenCols)
		return GetHeadColWidth(GetGridCol(nCol), nHeadRow);
	else
		return ( nCol < 0 ? 0 : m_FrozenColWidth);
}

// ����������� �������. ������� ������ ��
// ����������� ����� ����� � ����� ����������� �������.
// ������ - �������� ���.
void CALXGridCore::OnDrawFrozenHeaderBtn(CDC *pDC, CRect &rectCell)
{
	BOOL bFlat = (m_pGridWnd->GetStyle() & AGS_FLAT);
	COLORREF clrCellFrame = ::GetSysColor(bFlat ? COLOR_BTNSHADOW : COLOR_WINDOWFRAME);

	// ������� ���������� ������	
	rectCell.DeflateRect(-offsetXY,-offsetXY,offsetXY,offsetXY);
	// ������� �����
	rectCell.InflateRect(1,1,0,0);
	pDC->Draw3dRect(rectCell,clrCellFrame,clrCellFrame);
	rectCell.DeflateRect(1,1,0,0);
	// ���� � ���������� ������� ������ ������ �� ������
	if(rectCell.Height() <= 2 || rectCell.Width() <= 2 || m_bSelAllBtnPressed)
	{
		CBrush brushBackground;
		// ����������� ������
		rectCell.DeflateRect(0,0,1,1);
		if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
			pDC->FillRect(&rectCell, &brushBackground);
		return;
	}
	if(bFlat)
	{
		pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
		CBrush brushBackground;
		// ����������� ������
		rectCell.DeflateRect(1,1,1,1);
		if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
			pDC->FillRect(&rectCell, &brushBackground);
	}
	else
		// ������ ������
		pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
}

// ����������� �������. ������� ������ �����.
// �������� nRow ���������� � ������ ���������� ����� �����.
void CALXGridCore::OnDrawGridRow(CDC *pDC, int nRow, int y, CRect& rectGrid)
{
	int nFirstCol, nLastCol, x;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
	nFirstCol = max(nFirstCol, m_CountFrozenCols);
	// ���������� x ���������� ����� ����� ������
	x = LeftWndPos(nFirstCol);

	// ��������� ������ ������ � ������� �����������
	for (int nCol = nFirstCol; nCol <= nLastCol; x = x + GetColWidth(nCol), nCol++)
		OnDrawGridCell(pDC,nCol,nRow,x,y);
	if(nRow == m_nActiveRow && 	m_pGridWnd->GetStyle() & AGS_ROWSELECT)
	{
		CRect rcFocus(LeftWndPos(m_CountFrozenCols) + 1, y + 1, LeftWndPos(m_CountFrozenCols) + (m_nRowWidth - m_CountFrozenCols * m_FrozenColWidth), y + m_nRowHeight);
		rcFocus.left = max(m_CountFrozenCols * m_FrozenColWidth - offsetXY, rcFocus.left);
		rcFocus.right = max(rcFocus.left, rcFocus.right);
		m_MetricsCells.m_FocusRect.DrawFocusRect(pDC, rcFocus);
	}
}

// ������� ������� ������ �����.
void CALXGridCore::OnDrawHeadRow(CDC *pDC, int nRow, int y, CRect& rectHeader)
{
	int nFirstCol, nLastCol, x;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToColRange(rectHeader, nFirstCol, nLastCol, TRUE, nRow);
	nFirstCol = max(nFirstCol, m_CountFrozenCols);
	// ���������� x ���������� ����� ����� ������
	x = LeftWndPos(nFirstCol, nRow);

	// ��������� ������ ������ � ������� �����������
	for (int nCol = nFirstCol; nCol <= nLastCol; x = x + GetColWidth(nCol, nRow), nCol++)
		OnDrawHeadCell(pDC,nCol,nRow,x,y);
}

// ������� ������� ������ ����������� ����� ��������.
void CALXGridCore::OnDrawFrozenRow(CDC *pDC, int nRow, int y, CRect& rectFrozen)
{
	int nFirstCol, nLastCol, x;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToColRange(rectFrozen, nFirstCol, nLastCol, TRUE);
	nFirstCol = min(nFirstCol, m_CountFrozenCols - 1);
	nLastCol  = min(nLastCol,  m_CountFrozenCols - 1);
	// ���������� x ���������� ����� ����� ������
	x = LeftColPos(nFirstCol) - offsetXY;

	// ��������� ������ ������� � ������� �����������
	for (int nCol = nFirstCol; nCol <= nLastCol; x = x + GetColWidth(nCol), nCol++)
		OnDrawFrozenCell(pDC,nCol,nRow,x,y);
}

// ������� ��������� ����� ����������� ������� ���� �����
// � ��������� �������� ���������.
void CALXGridCore::UpdateScrollSizes()
{
	// ��������� ������� �����(������ � ������ ������)
	CalculateGridMetrics();

	CSize sizeTotal(m_nRowWidth - offsetXY + m_sizeExtArea.cx,(m_nHeadRowHeight * m_CountHeaderRows + m_nRowHeight * GetGridRowCount()) - offsetXY + m_sizeExtArea.cy);

	sizeTotal.cx = max(0,sizeTotal.cx);
	sizeTotal.cy = max(0,sizeTotal.cy);

	// �������� ������� Scroll Bars
	SetScrollSizes(sizeTotal);
	// ���� ����� ������ ������� �������
	if(m_CurScrollPos.y + m_sizePage.cy > m_sizeTotal.cy)
		m_CurScrollPos.y = max(0,m_sizeTotal.cy - m_sizePage.cy + 1);
	if(m_CurScrollPos.x + m_sizePage.cx > m_sizeTotal.cx)
		m_CurScrollPos.x = max(0,m_sizeTotal.cx - m_sizePage.cx + 1);
}

// ������� ������������� ����� ����������� ������� ��� ���������.
void CALXGridCore::SetScrollSizes(const SIZE &sizeTotal)
{
	ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);

	m_sizeTotal = sizeTotal;

	if(m_sizeTotal.cx < maxScrollRange)
		m_nHScrollFactor = 1;
	else
		m_nHScrollFactor = (float)((double)m_sizeTotal.cx/(double)maxScrollRange + 1);

	if(m_sizeTotal.cy < maxScrollRange)
		m_nVScrollFactor = 1;
	else
		m_nVScrollFactor = (float)((double)m_sizeTotal.cy/(double)maxScrollRange + 1);

	if (m_pGridWnd != NULL)
		UpdateBars();
}

// ������� ��������� �������� ���������
void CALXGridCore::UpdateBars()
{
	// UpdateBars ����� ��������� �������� ������� ���� - ������������ ��� ���������
	if (m_bInsideUpdate)
		return;         // ��������� ����������� ������

	// ���������� ��������
	m_bInsideUpdate = TRUE;

	// update the horizontal to reflect reality
	// ������������� �����������, ����� �������� ����������������
	// NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
	// ��������: ���./����. ����� ��������� �������� � ��������� ������� ��������� 'OnSize'
	ASSERT(m_sizeTotal.cx >= 0);

	CRect rectClient;
	BOOL bCalcClient = TRUE;

	// allow parent to do inside-out layout first
	CWnd* pParentWnd = m_pGridWnd->GetParent();
	if (pParentWnd != NULL)
	{
		// ���� ������������ ���� ����������� �� ��� ���������, ������������ ����������
		// ������� ����������� � ������ ������ ��������� - ����� ��� ���������� �������
		if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
			(LPARAM)(LPCRECT)&rectClient) != 0)
		{
			// ����������� rectClient ������ GetTrueClientSize ���
			// ���������� ������� ���������� �������.
			bCalcClient = FALSE;
		}
	}

	CSize sizeClient;
	CSize sizeSb;
	CRect rect;

	if (bCalcClient)
	{
		// ���������� ����� �� ������ ��������� � �������� ������ ������� �������
		if (!GetTrueClientSize(sizeClient, sizeSb))
		{
			// ��� ����� ��� ����� ���������
			m_pGridWnd->GetClientRect(&rect);
			if (rect.right > 0 && rect.bottom > 0)
			{
				// ���� ���������� ������� ������, �� ����� ������������ ������ ���������
				m_pGridWnd->EnableScrollBarCtrl(SB_BOTH, FALSE);
			}
			m_bInsideUpdate = FALSE;
			return;
		}
	}
	else
	{
		// ������������ ���� ���������� ���������� �������
		GetScrollBarSizes(sizeSb);
		sizeClient.cx = rectClient.Width();
		sizeClient.cy = rectClient.Height();
	}

	// ���������� �����, ����� �������� ������ ���������
	CSize sizeRange;
	CPoint ptMove;
	CSize needSb;

	// �������� ��������� ������ ��������� � ���������� �������
	GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);

	// first scroll the window as needed
	// ������������ ���� �� ������� ��� ����������
	ScrollToPos(ptMove); // ����� �������� �������

	// ��� ���������, ���������� ��� ���������� ��������� ������� ������ ���������
	SCROLLINFO info;
	info.fMask = SIF_PAGE|SIF_RANGE;
	info.nMin = 0;

	// ������ ������������ ������ ��� ���������
	m_pGridWnd->EnableScrollBarCtrl(SB_HORZ, needSb.cx);
	m_pGridWnd->EnableScrollBarCtrl(SB_VERT, needSb.cy);
	// �������� ������ ���������� ������� ����
	m_pGridWnd->GetClientRect(&rect);
	sizeClient.cx = rect.Width();
	sizeClient.cy = rect.Height();
	if (needSb.cx)
	{
		info.nPage = (int)((double)sizeClient.cx/m_nHScrollFactor);
		if(info.nPage<=0)
			info.nPage = 1;
		m_sizePage.cx = sizeClient.cx;
		m_sizeLine.cx = sizeClient.cx / 10;
		info.nMax = (int)((double)m_sizeTotal.cx/m_nHScrollFactor);
		if (!m_pGridWnd->SetScrollInfo(SB_HORZ, &info, TRUE))
			m_pGridWnd->SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
	}
	if (needSb.cy)
	{
		info.nPage = (int)((double)sizeClient.cy/m_nVScrollFactor);
		if(info.nPage<=0)
			info.nPage = 1;
		m_sizePage.cy = sizeClient.cy;
		m_sizeLine.cy = m_nRowHeight;
		info.nMax = (int)((double)m_sizeTotal.cy/m_nVScrollFactor);
		if (!m_pGridWnd->SetScrollInfo(SB_VERT, &info, TRUE))
			m_pGridWnd->SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
	}

	// ������� ���������� ��������
	m_bInsideUpdate = FALSE;
}

// ������� ���������� ������� ������������ ���� �����.
void CALXGridCore::GetScrollBarSizes(CSize &sizeSb)
{
	sizeSb.cx = sizeSb.cy = 0;
	DWORD dwStyle = m_pGridWnd->GetStyle();

	if (m_pGridWnd->GetScrollBarCtrl(SB_VERT) == NULL)
		// �� ��������� ������ ��������� ����� ����������� ���������� ����� ����
		sizeSb.cx = ::GetSystemMetrics(SM_CXVSCROLL);//afxData.cxVScroll;
	if (m_pGridWnd->GetScrollBarCtrl(SB_HORZ) == NULL)
		// �� ����������� ������ ��������� ����� ����������� ���������� ����� ����
		sizeSb.cy = ::GetSystemMetrics(SM_CXHSCROLL);//afxData.cyHScroll;
}

// ������� ���������� ��������� �������� ���������.
void CALXGridCore::GetScrollBarState(CSize sizeClient, CSize &needSb, CSize &sizeRange, CPoint &ptMove, BOOL bInsideClient)
{
	// �������� ������� ����� ��������� (�������� ��� ��������� � ���������� �������)
	CSize sizeSb;
	GetScrollBarSizes(sizeSb);

	// ���������� ����� ��� ����� ���������
	sizeRange.cx = (int)((double)(m_sizeTotal.cx + 1 - sizeClient.cx)/m_nHScrollFactor);
	sizeRange.cy = (int)((double)(m_sizeTotal.cy + 1 - sizeClient.cy)/m_nVScrollFactor);
		// > 0 => ������� ������ ��������������
	ptMove = m_CurScrollPos;
		// ����� ������� ��������� (������ � ������� �������)

	BOOL bNeedH = sizeRange.cx > 0;
	if (!bNeedH)
		ptMove.x = 0;                       // ������� � ������ ���������
	else if (bInsideClient)
		sizeRange.cy += sizeSb.cy;          // ����� ����������� ��� ���������

	BOOL bNeedV = sizeRange.cy > 0;
	if (!bNeedV)
		ptMove.y = 0;                       // ������� � ������ ���������
	else if (bInsideClient)
		sizeRange.cx += sizeSb.cx;          // ����� ����������� ��� ���������
	if (bNeedV && !bNeedH && sizeRange.cx > 0)
	{
		ASSERT(bInsideClient);
		// ����� �������������� ������ ���������
		bNeedH = TRUE;
		sizeRange.cy += sizeSb.cy;
	}

	// ���� ������� ������� ��������� ��������� ������ ������� ���������
	if (sizeRange.cx > 0 && ptMove.x/m_nHScrollFactor >= sizeRange.cx)
		ptMove.x = (int)(((double)sizeRange.cx)*m_nHScrollFactor);
	if (sizeRange.cy > 0 && ptMove.y/m_nVScrollFactor >= sizeRange.cy)
		ptMove.y = (int)(((double)sizeRange.cy)*m_nVScrollFactor);

	// ������ �������� ������������� �������
	needSb.cx = bNeedH;
	needSb.cy = bNeedV;

	// needSb, sizeRange, � ptMove ����� ��������
}

// ������� ������������ ����������� ���� ����� �� ��������� �������.
void CALXGridCore::ScrollToPos(POINT ptPos)
{
	ASSERT(ptPos.x >= 0);
	ASSERT(ptPos.y >= 0);

	int xOrig = m_CurScrollPos.x;
	m_pGridWnd->SetScrollPos(SB_HORZ, (int)(((double)ptPos.x)/m_nHScrollFactor));
	int yOrig = m_CurScrollPos.y;
	m_pGridWnd->SetScrollPos(SB_VERT, (int)(((double)ptPos.y)/m_nVScrollFactor));
	
	ScrollWindow(xOrig - ptPos.x, yOrig - ptPos.y);

	m_CurScrollPos.x = ptPos.x;
	m_CurScrollPos.y = ptPos.y;
}

// ������� ���������� TRUE ���� ����� ������ ���������.
BOOL CALXGridCore::GetTrueClientSize(CSize &size, CSize &sizeSb)
{
	CRect rect;
	m_pGridWnd->GetClientRect(&rect);
	ASSERT(rect.top == 0 && rect.left == 0);
	size.cx = rect.right;
	size.cy = rect.bottom;
	DWORD dwStyle = m_pGridWnd->GetStyle();

	// ������� ������� ������ ����� ��������� ��� ����� ����
	GetScrollBarSizes(sizeSb);

	// ������� �������� �������������� ������ ������ ���������
	// (�� �����������, ��� ������ ��������� ����� ���� ���\����)
	if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
	{
		// �� ��������� ������ ��������� ����� ����������� ���������� ����� ����
		size.cx += sizeSb.cx;   // ����� ���. - �������������
	}
	if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
	{
		// �� ����������� ������ ��������� ����� ����������� ���������� ����� ����
		size.cy += sizeSb.cy;   // ����� ���. - �������������
	}

	// ���������� TRUE ���� ���������� �����
	return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
}

// ������� ���������� ������� ������� ������ ������.
// �������� nRow ������ ������������ � ������ ������� �����.
int CALXGridCore::TopRowPos(int nRow)
{
	if(nRow > m_CountHeaderRows)
		return m_CountHeaderRows * m_nHeadRowHeight + (nRow - m_CountHeaderRows) * m_nRowHeight;
	else
		return nRow * m_nHeadRowHeight;
}

// ������� ���������� ����� ������� ������ �������.
// �������� nCol ������ ������������ � ������ ����������� ������� �����.
int CALXGridCore::LeftColPos(int nCol, int nHeadRow)
{
	int iWidth = 0;
	for(int i = 0; i < nCol; i++)
		iWidth = iWidth + GetColWidth(i, nHeadRow);
	return iWidth;
}

// ������� ���������� ����� ������� ������ ������� � ����.
// �������� nCol ������ ������������ � ������ ����������� ������� �����.
int CALXGridCore::LeftWndPos(int nCol, int nHeadRow)
{
	return (LeftColPos(nCol, nHeadRow) - m_CurScrollPos.x - offsetXY);
}

// ������� ���������� ������� ������� ������ ������.
// �������� nRow ������ ������������ � ������ ����� � �����.
int CALXGridCore::TopWndPos(int nRow)
{
	return (TopRowPos(nRow) - m_CurScrollPos.y - offsetXY);
}

// ����������� �������. ������� ������� ����� � ����.
void CALXGridCore::OnUpdateGridRect(CDC *pDC, CRect &rectClip)
{
	int nFirstRow, nLastRow, y;
	CRect rectGrid = GetGridRect(rectClip);
	// ���������� ������ ������ � ��������� ���������������� ������
	RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
	nFirstRow = max(nFirstRow, m_CountHeaderRows);
	nLastRow = min(nLastRow, GetGridRowCount() - 1 + m_CountHeaderRows);
	// ���������� y ���������� ����� ������� ������
	y = TopWndPos(nFirstRow);

	// ��������� ������ ������ � ������� �����������.
	for (int nRow = nFirstRow; nRow <= nLastRow; y += m_nRowHeight, nRow++)
		OnDrawGridRow(pDC,nRow,y,rectGrid);
}

// ������� ���������� ������� ���� ������������� ����������� ��������.
void CALXGridCore::OnUpdateFrozenRect(CDC *pDC, CRect &rectClip)
{
	int nFirstRow, nLastRow, y;
	CRect rectFrozen = GetFrozenRect(rectClip);
	// ���������� ������ ������ � ��������� ���������������� ������
	RectToRowRange(rectFrozen, nFirstRow, nLastRow, TRUE);
	nFirstRow = max(nFirstRow, m_CountHeaderRows);
	nLastRow = min(nLastRow, GetGridRowCount() - 1 + m_CountHeaderRows);
	// ���������� y ���������� ������� ������
	y = TopWndPos(nFirstRow);

	// ��������� ������ ������ � ������� �����������,
	for (int nRow = nFirstRow; nRow <= nLastRow; y += m_nRowHeight, nRow++)
		OnDrawFrozenRow(pDC,nRow,y,rectFrozen);
}

// ������� ����������(�����������) ������� ����
// �� ����������� �� � ����� �� � ����������� ��������.
void CALXGridCore::OnUpdateFrozenHeaderRect(CDC *pDC, CRect &rectCell)
{
	OnDrawFrozenHeaderBtn(pDC, rectCell);
}

// ������� ���������� ������� ���� ������������� �����.
void CALXGridCore::OnUpdateHeaderRect(CDC *pDC, CRect &rectClip)
{
	int nFirstRow, nLastRow, y;
	CRect rectHeader = GetHeadRect(rectClip);
	// ���������� ������ ������ � ��������� ���������������� ������
	RectToRowRange(rectHeader, nFirstRow, nLastRow, TRUE);
	nFirstRow = min(nFirstRow,m_CountHeaderRows - 1);
	nLastRow = min(nLastRow, m_CountHeaderRows - 1);
	// ���������� y ���������� ����� ������� ������
	y = TopRowPos(nFirstRow) - offsetXY;

	CFont* pOldFont = NULL;
	if(m_pHeadFont != &m_Font)
		pOldFont = pDC->SelectObject(m_pHeadFont);

	// ��������� ������ ������ � ������� �����������,
	for (int nRow = nFirstRow; nRow <= nLastRow; y += m_nHeadRowHeight, nRow++)
		OnDrawHeadRow(pDC,nRow,y,rectHeader);

	if(pOldFont != NULL)
		pDC->SelectObject(pOldFont);
}

// ������� ������������ ���� �����.
void CALXGridCore::ScrollWindow(int xAmount, int yAmount)
{
	CRect rectClient;
	m_pGridWnd->GetClientRect(&rectClient);
	// ���� � ����� ��� ��������� � ����������� ��������
	if(m_CountHeaderRows == 0 && m_CountFrozenCols == 0)
	{
		m_pGridWnd->ScrollWindow(xAmount, yAmount);
		return;
	}
	// ���� ����� �� ��� y
	if(yAmount != 0 )
	{
		if(xAmount != 0)// ���� ����� �� ��� x � �� ��� �
		{
			rectClient.left	=	m_CountFrozenCols * m_FrozenColWidth - offsetXY + 1;
			m_pGridWnd->ScrollWindow(xAmount, 0,NULL,&rectClient);
			rectClient.left	=	0;
			rectClient.top	=	m_CountHeaderRows * m_nHeadRowHeight - offsetXY + 1;
			m_pGridWnd->ScrollWindow(0, yAmount,NULL,&rectClient);
		}
		else			// ���� ����� ������ �� ��� �
		{
			rectClient.top	=	m_CountHeaderRows * m_nHeadRowHeight - offsetXY + 1;
			m_pGridWnd->ScrollWindow(xAmount, yAmount,NULL,&rectClient);
		}
	}
	else
	{
		if(xAmount != 0)// ���� ����� ������ �� ��� x
		{
			rectClient.left	=	m_CountFrozenCols * m_FrozenColWidth - offsetXY + 1;
			m_pGridWnd->ScrollWindow(xAmount, yAmount,NULL,&rectClient);
		}
		else
			m_pGridWnd->ScrollWindow(xAmount, yAmount);
	}
}

// ������� ������������ ���� �����.
void CALXGridCore::ScrollRow(int nRow, int yAmount)
{
	CRect rectScroll;
	m_pGridWnd->GetClientRect(&rectScroll);
	rectScroll.top = TopWndPos(nRow);
	if(m_CountHeaderRows * m_nHeadRowHeight - offsetXY > rectScroll.top)
	{
		m_pGridWnd->InvalidateRect(CRect(rectScroll.left,m_CountHeaderRows * m_nHeadRowHeight - offsetXY + 1,rectScroll.right,rectScroll.bottom));
		SetActiveCell(m_nActiveCol,m_nActiveRow);
		return;
	}
	if(rectScroll.IsRectEmpty())
	{
		SetActiveCell(m_nActiveCol,m_nActiveRow);
	}
	else
	{
		m_pGridWnd->ScrollWindow(0, yAmount,NULL,&rectScroll);
		if(yAmount >= 0)
			rectScroll.top += m_nRowHeight;
		m_pGridWnd->InvalidateRect(CRect(rectScroll.left,rectScroll.top,rectScroll.right,rectScroll.top + m_nRowHeight));
	}
}

// ������� ������������ ���� �����.
void CALXGridCore::ScrollCol(int nCol, int nHeadRow, int xAmount)
{
	CRect rectScroll;
	m_pGridWnd->GetClientRect(&rectScroll);
	rectScroll.left = LeftWndPos(nCol, nHeadRow);
	if(m_CountFrozenCols * m_FrozenColWidth - offsetXY > rectScroll.left)
		xAmount = m_CountFrozenCols * m_FrozenColWidth - offsetXY - rectScroll.left;
	if(!rectScroll.IsRectEmpty())
		m_pGridWnd->ScrollWindow(xAmount, 0,NULL,&rectScroll);
}

// ������� ������ ������ �����.
void CALXGridCore::OnDrawGridCell(CDC *pDC, int nCol, int nRow, int x, int y)
{
	CELL_INFO CellInfo;
	CELL_DATA CellData;
	CALXCellCtrl* pCellCtrl;
	DWORD dwStyle = m_pGridWnd->GetStyle();

	int nGridCol = GetGridCol(nCol); // ������ ������� ��� ����� ����������� �������
	int nGridRow = GetGridRow(nRow); // ������ ������ ��� ����� ����� �����

	// �������� ������� ������
	CALXCellMetrics* pCellMetrics = GetCellMetrics(nGridCol, nGridRow);

	ASSERT(pCellMetrics != NULL);

	// ���������� ������� �� ������
	BOOL bActiveCell = (nCol == m_nActiveCol && nRow == m_nActiveRow);
	// ���������� �������� �� ������
	BOOL bSelCell = (dwStyle & AGS_ROWSELECT) && nRow == m_nActiveRow;
	bSelCell = bSelCell || ((dwStyle & AGS_RANGESELECT) && m_SelRangeCell.InRange(nCol, nRow));

	// ���������� ���� ����
	COLORREF clrBackgrnd =  (bActiveCell ? pCellMetrics->m_ActiveCellColor.m_crBackgrnd : (bSelCell ? pCellMetrics->m_SelectCellColor.m_crBackgrnd : pCellMetrics->m_DefaultCellColor.m_crBackgrnd));
	// ���������� ���� ������
	COLORREF clrText =  (bActiveCell ? pCellMetrics->m_ActiveCellColor.m_crText : (bSelCell ? pCellMetrics->m_SelectCellColor.m_crText : pCellMetrics->m_DefaultCellColor.m_crText));

	// �������� ���������� � ������ ������
	CRect rectCell(x,y,x+GetColWidth(nCol)+1,y+m_nRowHeight+1);
	// ������� �����
	if(dwStyle & AGS_NOGRIDLINES)
	{
		COLORREF clrBackgrndHor =  (bSelCell || (bActiveCell && (dwStyle & AGS_ROWSELECT))) ? pCellMetrics->m_SelectCellColor.m_crBackgrnd : pCellMetrics->m_DefaultCellColor.m_crBackgrnd;
		COLORREF clrBackgrndVer =  pCellMetrics->m_DefaultCellColor.m_crBackgrnd;
		pCellMetrics->m_Borders.DrawBorders(pDC, rectCell,clrBackgrndHor,clrBackgrndVer,clrBackgrndHor,clrBackgrndVer,AOD_HOR_VERT);
	}
	else
		pCellMetrics->m_Borders.DrawBorders(pDC, rectCell);

	rectCell.DeflateRect(1,1,1,1); // ��������� ������� ���������
	
	if(rectCell.IsRectEmpty())
		return; // - ���� ������ ������ �������� �� �����

	// �������� ���������� � ���� ������
	CellInfo = GetCellInfo(nGridCol,nGridRow);

	// ���� ������ �������
	if(bActiveCell)
	{
		// �������� ��������� �� ������� ���������� �������
		pCellCtrl = GetCellCtrl(nGridCol,nGridRow);
		if(pCellCtrl != NULL)
			// �������� ���������� � ���������� ������ �� �������� ����������
			CellData = pCellCtrl->GetCellData();
		else
			// �������� ���������� � ���������� ������ �� ������������ ������
			CellData = GetCellData(nGridCol,nGridRow);
	}
	else
		// �������� ���������� � ���������� ������ �� ������������ ������
		CellData = GetCellData(nGridCol,nGridRow);


	CBrush brushBackgrnd;
	// ������� ������
	if(brushBackgrnd.CreateSolidBrush(clrBackgrnd))
		pDC->FillRect(&rectCell, &brushBackgrnd);

	// ���� ������ � ������������
	if(IsImage(nGridCol,nGridRow))
	{
		CPoint pt;
		CSize sz;

		// �������� ������ �����������
		GetSizeImage(nGridCol,nGridRow,sz);
		// ��������� ������ �����������, ���� ���������
		sz.cx = min(rectCell.Width(),sz.cx);
		sz.cy = min(rectCell.Height(),sz.cy);

		pt.x = rectCell.left+1;
		// ������� ����������� � ����� ������ �� ��� �
		pt.y = rectCell.top + (rectCell.Height() - sz.cy)/2;

		DrawImage(pDC,nGridCol,nGridRow,pt,sz,bActiveCell);

		// ������� ����� ������� ������
		rectCell.left = min(rectCell.right,rectCell.left+sz.cx+2);
	}

	// ���� ��� ������ �������
	if(bActiveCell && rectCell.Width() > 0 && rectCell.Height() > 0)
		// ������� ����� "������ �����"
		pCellMetrics->m_FocusRect.DrawFocusRect(pDC, rectCell);

	rectCell.DeflateRect(1,1,1,1); // ��������� ������� ���������

	// ������������� ���� ������
	COLORREF clrOldText = pDC->SetTextColor(clrText);

	CFont* pOldFont = NULL;
	if(bActiveCell)
	{
		// ���� ��� ������ ��������� �����
		if(pCellMetrics->pActiveFont != NULL)
			// ������������� �����
			pOldFont = pDC->SelectObject(pCellMetrics->pActiveFont);
	}	// ���� ��� ������ ��������� �����
	else if(pCellMetrics->pDefaultFont != NULL)
			// ������������� �����
			pOldFont = pDC->SelectObject(pCellMetrics->pDefaultFont);
	

	if(CellInfo.m_nTypeCtrl > 0)
		// ���� ����, ������ ������� ����������
		DrawCellCtrl(pDC,rectCell,CellInfo,CellData);
	else
		// ������� �����
		pDC->DrawText(CellData.m_strText, rectCell, CellInfo.m_nFormat);

	if(pOldFont != NULL)
		pDC->SelectObject(pOldFont);

	pDC->SetTextColor(clrOldText);
}

// ����������� �������. ������ ������ �����.
void CALXGridCore::OnDrawHeadCell(CDC *pDC, int nCol, int nRow, int x, int y)
{
	BOOL bFlat = (m_pGridWnd->GetStyle() & AGS_FLAT);
	CRect rectCell(x,y,x+GetColWidth(nCol, nRow)+1,y+m_nHeadRowHeight+1);
	COLORREF clrCellFrame = ::GetSysColor(bFlat ? COLOR_BTNSHADOW : COLOR_3DDKSHADOW);

	// ������� �����
	pDC->Draw3dRect(rectCell,clrCellFrame,clrCellFrame);

	// ���� � ���������� ������� ������ ������ �� ������ ��� ������ ������
	if((rectCell.Height() <= 3 || rectCell.Width() <= 3) || (nCol == m_nHeaderColPressed && nRow == m_nHeaderRowPressed))
	{
		CBrush brushBackground;
		// ����������� ������
		rectCell.DeflateRect(1,1,1,1);
		if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
			pDC->FillRect(&rectCell, &brushBackground);
		rectCell.DeflateRect(4,2,1,0);
	}
	else
	{
		rectCell.DeflateRect(1,1,0,0);
		if(bFlat)
		{
			pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
			CBrush brushBackground;
			// ����������� ������
			rectCell.DeflateRect(1,1,1,1);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
				pDC->FillRect(&rectCell, &brushBackground);
			rectCell.DeflateRect(2,0,2,1);
		}
		else
		{
			// ������ ������
			pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
			rectCell.DeflateRect(3,1,3,2);
		}
	}


	if(!rectCell.IsRectEmpty())
	{
		// �������� ����� � ����� 
		HEADCELL_INFO CellInfo = GetHeadCellInfo(GetGridCol(nCol),nRow);

		if(m_nSortHeadCol + m_CountFrozenCols != nCol || m_nSortHeadRow != nRow || m_nSortOrder == None)
		{
			pDC->DrawText(CellInfo.m_strText, rectCell, CellInfo.m_nFormat);
			return;
		}

		int nArrowW = min(7,rectCell.Width());
		int nArrowH = min(7,rectCell.Height());
		int nArrowTopPos = rectCell.top + (rectCell.Height()-nArrowH)/2;
		int nArrowMargin = min(5,(rectCell.Width() - nArrowW)/2);
		int nGap = pDC->GetTextExtent(" ").cx * 3;

		if(rectCell.Width() <= nGap + nArrowW + nArrowMargin)
		{
			DrawArrow(pDC,CPoint(rectCell.left+(rectCell.Width()-nArrowW)/2,nArrowTopPos),CSize(nArrowW, nArrowH));
			return;
		}

		CRect rc(rectCell);
		pDC->DrawText(CellInfo.m_strText,rc,CellInfo.m_nFormat| DT_CALCRECT);

		if(CellInfo.m_nFormat & DT_RIGHT)
		{
			// ���� ������ � ������� ��������� ���������� � ������
			if(rc.Width() + nGap + nArrowW + nArrowMargin < rectCell.Width())
			{
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectCell, CellInfo.m_nFormat);
				// ������ ������� ����� �� ������
				DrawArrow(pDC,CPoint(rectCell.right - rc.Width() - nGap - nArrowW, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
			else
			{
				CRect rectClipCell;
				rectClipCell.top = rectCell.top;
				rectClipCell.bottom = rectCell.bottom;
				rectClipCell.left = rectCell.left + (nArrowMargin + nArrowW + nGap);
				rectClipCell.right = rectCell.right;
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectClipCell, CellInfo.m_nFormat);
				// ������ ������� ����� �� ������
				DrawArrow(pDC,CPoint(rectCell.left + nArrowMargin, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
		}
		else if(CellInfo.m_nFormat & DT_CENTER)
		{
			// ���� ������ � ������� ��������� ���������� � ������
			if((rectCell.Width() - rc.Width())/2 >  nGap + nArrowW + nArrowMargin)
			{
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectCell, CellInfo.m_nFormat);
				// ������ ������� ������ �� ������
				DrawArrow(pDC,CPoint(rectCell.left + (rectCell.Width() - rc.Width())/2 + rc.Width() + nGap, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
			else
			{
				CRect rectClipCell;
				rectClipCell.top = rectCell.top;
				rectClipCell.bottom = rectCell.bottom;
				rectClipCell.left = rectCell.left;
				rectClipCell.right = rectCell.right - (nArrowMargin + nArrowW + nGap);
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectClipCell, CellInfo.m_nFormat);
				// ������ ������� ������ �� ������
				DrawArrow(pDC,CPoint(rectCell.right - nArrowW - nArrowMargin, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
		}
		else
		{
			// ���� ������ � ������� ��������� ���������� � ������
			if(rc.Width() + nGap + nArrowW + nArrowMargin < rectCell.Width())
			{
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectCell, CellInfo.m_nFormat);
				// ������ ������� ������ �� ������
				DrawArrow(pDC,CPoint(rectCell.left + rc.Width() + nGap, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
			else
			{
				CRect rectClipCell;
				rectClipCell.top = rectCell.top;
				rectClipCell.bottom = rectCell.bottom;
				rectClipCell.left = rectCell.left;
				rectClipCell.right = rectCell.right - (nArrowMargin + nArrowW + nGap);
				// ������� �����
				pDC->DrawText(CellInfo.m_strText, rectClipCell, CellInfo.m_nFormat);
				// ������ ������� ������ �� ������
				DrawArrow(pDC,CPoint(rectCell.right - nArrowW - nArrowMargin, nArrowTopPos),CSize(nArrowW, nArrowH));
			}
		}
	}
}

// ����������� �������. ������ ����� ����������� ������.
void CALXGridCore::OnDrawFrozenCell(CDC *pDC, int nCol, int nRow, int x, int y)
{
	int cx = GetColWidth(nCol) + 1;
	int cy = m_nRowHeight + 1;
	BOOL bPressed = (nCol == m_nFrozenColPressed && nRow == m_nFrozenRowPressed);
	BOOL bDrawArrow = (nCol == m_CountFrozenCols - 1) && (m_nActiveRow == nRow || (GetKeyState(VK_SHIFT) >= 0 && nRow == m_nFrozenRowPressed));
	BOOL bFlat = (m_pGridWnd->GetStyle() & AGS_FLAT);

	DrawFrozenBtn(pDC, x, y, cx, cy, bPressed, bDrawArrow, bFlat);

/*	BOOL bFlat = (m_pGridWnd->GetStyle() & AGS_FLAT);
	CRect rectCell(x,y,x+GetColWidth(nCol)+1,y+m_nRowHeight+1);
	COLORREF clrCellFrame = ::GetSysColor(bFlat ? COLOR_BTNSHADOW : COLOR_3DDKSHADOW);

	// ������� �����
	pDC->Draw3dRect(rectCell,clrCellFrame,clrCellFrame);
	rectCell.DeflateRect(1,1,0,0);

	// ���� � ���������� ������� ������ ������ �� ������
	if(rectCell.Height() <= 2 || rectCell.Width() <= 2 )
	{
		CBrush brushBackground;
		// ����������� ������
		rectCell.DeflateRect(0,0,1,1);
		if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
			pDC->FillRect(&rectCell, &brushBackground);
		return;
	}

	// ���� ��� ������ ������� � ��� ����� ������ ������ �� �����������
	if(m_nActiveRow == nRow && nCol == m_CountFrozenCols - 1)
	{
		// ���� ������ �� ������
		if(nCol != m_nFrozenColPressed || nRow != m_nFrozenRowPressed)
		{
			if(bFlat)
			{
				pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
				CBrush brushBackground;
				// ����������� ������
				rectCell.DeflateRect(1,1,1,1);
				if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
					pDC->FillRect(&rectCell, &brushBackground);
				rectCell.DeflateRect(1,1,1,1);
			}
			else
			{
				// ������ ������
				pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
				rectCell.DeflateRect(2,2,2,2);
			}
		}
		else
		{
			CBrush brushBackground;
			// ����������� ������
			rectCell.DeflateRect(0,0,1,1);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
				pDC->FillRect(&rectCell, &brushBackground);
			rectCell.DeflateRect(2,1,0,0);
		}
		// ������ �������
		CBrush brushBlack;
		if(brushBlack.CreateSolidBrush(::GetSysColor(COLOR_WINDOWFRAME)))
		{
			POINT ptTriangle[4];
			CRgn rgnTriangle;
			ptTriangle[0].x = rectCell.left + (rectCell.Width()-4)/2;
			ptTriangle[0].y = rectCell.top + (rectCell.Height()-7)/2 - 1;
			ptTriangle[1].x = ptTriangle[0].x+4;
			ptTriangle[1].y = ptTriangle[0].y+4;
			ptTriangle[2].x = ptTriangle[0].x;
			ptTriangle[2].y = ptTriangle[0].y+8;
			rgnTriangle.CreatePolygonRgn(ptTriangle,3,WINDING);
			pDC->FillRgn(&rgnTriangle,&brushBlack);
		}
	}
	else
	{
		// ���� ������ �� ������
		if(nCol != m_nFrozenColPressed || nRow != m_nFrozenRowPressed)
		{
			if(bFlat)
			{
				pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
				CBrush brushBackground;
				// ����������� ������
				rectCell.DeflateRect(1,1,1,1);
				if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
					pDC->FillRect(&rectCell, &brushBackground);
				rectCell.DeflateRect(1,1,1,1);
			}
			else
			{
				// ������ ������
				pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
				rectCell.DeflateRect(2,2,2,2);
			}
		}
		else
		{
			CBrush brushBackground;
			// ����������� ������
			rectCell.DeflateRect(0,0,1,1);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
				pDC->FillRect(&rectCell, &brushBackground);
		}
	}
*/
}

// ������� ��������� ������ � ������ ������
void CALXGridCore::CalculateGridMetrics()
{
	// �������� ����� �����
	DWORD dwStyle = m_pGridWnd->GetStyle();
	// ���������� ������ ������
	CSize sizeFont = GetFontSize(&m_Font);
	// ���������� ������ ������ �����
	m_nRowHeight = sizeFont.cy * m_nRowLineCount + 3; // 2 lines of text

	// ���� ������ ������ ����� ������ ���������� �� ������� ������
	if((dwStyle & AGS_CUSTOMHEAD_HEIGHT) == 0)
	{
		// ���� ������ ����� � ����� ���������
		if(m_pHeadFont != &m_Font)
		{
			ASSERT(m_pHeadFont != NULL);
			// ���������� ������ ������
			sizeFont = GetFontSize(m_pHeadFont);
			// ���������� ������ ������ �����
			m_nHeadRowHeight = sizeFont.cy + 3;
		}
		else
		// ���������� ������ ������ �����
			m_nHeadRowHeight = m_nRowHeight;
	}

	// ���� � ����� ���� ����������� �������, ���������� ������ ����������� ��������
	if(m_CountFrozenCols > 0)
		// ���� ������ ����������� ������� ������ ���������� �������������
		if((dwStyle & AGS_CUSTOMFROZEN_WIDTH) == 0)
				m_FrozenColWidth = m_nRowHeight/2;
	
	// ���������� ������ �����
	m_nRowWidth = 0;
	for(int i = 0; i < GetAllColCount(); i++)
		m_nRowWidth = m_nRowWidth + GetColWidth(i);
}

// ������� ���������� ������ ������.
CSize CALXGridCore::GetFontSize(CFont* pFont)
{
	CSize sizeFont;

	CFont* pOldFont = NULL;
	CClientDC dc(m_pGridWnd);

	pOldFont = dc.SelectObject(pFont);

	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);
	sizeFont.cx = tm.tmWeight;
	sizeFont.cy = tm.tmHeight;

	if(pOldFont != NULL)
		dc.SelectObject(pOldFont);

	return sizeFont;
}

// ������� ������������� �������� ������.
BOOL CALXGridCore::SetActiveCell(int nCol, int nRow)
{
	if(nCol < m_CountFrozenCols || nRow < m_CountHeaderRows || nCol >= GetAllColCount() || nRow >= GetAllRowCount())
		return FALSE;

	int nPrevActiveCol = m_nActiveCol;
	int nPrevActiveRow = m_nActiveRow;
	BOOL bRowSelect = (m_pGridWnd->GetStyle() & AGS_ROWSELECT);

	ALXSelRangeCell mPrevSelRangeCell = m_SelRangeCell;

	if(SaveModifyed(FALSE))
	{
		m_nActiveCol = nCol;
		m_nActiveRow = nRow;

		m_nActiveSelCol = m_nActiveCol;
		m_nActiveSelRow = m_nActiveRow;

		if(m_nActiveRow != nPrevActiveRow)
			OnChangeActiveRow(GetGridRow(m_nActiveRow));

		m_pGridWnd->SetFocus();
	}

	OnSetActiveCell(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));


	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	if(nPrevActiveRow != m_nActiveRow)
		// ��������� ���������� �������� ������ ����������� �������
		for(int i = 0; i < m_CountFrozenCols; i++)
			UpdateCell(pDC, i, nPrevActiveRow);
	if(bRowSelect && nPrevActiveRow != m_nActiveRow)
		// ��������� ���������� ������
		UpdateRow(pDC,nPrevActiveRow);
	else
	{
		m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
		m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;

		// ���� ����� �������� �������� �����
		if(m_pGridWnd->GetStyle() & AGS_RANGESELECT)
		{
			// ������� ��������� � ����������� ��������� ���������� �����
			CRect rectGrid = GetGridRect(rectClient);
			// ���������� �������� ������� � ���� ��������
			int nFirstCol, nLastCol;
			// ���������� ����� ������� � ���������� ����������������� �������
			RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
			nFirstCol = max(nFirstCol, mPrevSelRangeCell.m_LeftCol);
			nLastCol = min(nLastCol, mPrevSelRangeCell.m_RightCol);
			// ���������� �������� ������� � ���� �����
			int nFirstRow, nLastRow;
			// ���������� ����� ������� � ���������� ����������������� �������
			RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
			nFirstRow = max(nFirstRow, mPrevSelRangeCell.m_TopRow);
			nLastRow = min(nLastRow, mPrevSelRangeCell.m_BottomRow);
			// ������� ���������
			if(!mPrevSelRangeCell.IsEmpty())
				for(int i = nFirstRow; i <= nLastRow; i++)
					for(int j = nFirstCol; j <= nLastCol; j++)
						if(!m_SelRangeCell.InRange(j,i))
							UpdateCell(pDC, j, i);
		}

		// ��������� ���������� �������� ������
		UpdateCell(pDC, nPrevActiveCol, nPrevActiveRow);
		if(m_CountHeaderRows > 0 && nPrevActiveCol != m_nActiveCol)
			// ��������� ���������� �������� ������ �����
			UpdateCell(pDC, nPrevActiveCol, m_CountHeaderRows-1);
	}


	// ���� ����������, ������������ ���� ���,
	// ��� ����� ��������� ������ (�������) ���� �����.
	CPoint pt(m_CurScrollPos);
	BOOL bNeedToVScroll = TRUE;
	BOOL bNeedToHScroll = TRUE;

	// ������� ��������� ����� ?
	if(	LeftWndPos(m_nActiveCol) < m_CountFrozenCols * m_FrozenColWidth - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ������ ������� ��������.
		pt.x = LeftColPos(m_nActiveCol) - m_FrozenColWidth * m_CountFrozenCols;
	}
	else if ( LeftWndPos(m_nActiveCol + 1) - 1 > rectClient.right - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ��������� ������� ��������.
		pt.x = min(LeftColPos(m_nActiveCol) - m_FrozenColWidth * m_CountFrozenCols, LeftColPos(m_nActiveCol + 1) - rectClient.Width()) - offsetXY + 1;
	}
	else
		bNeedToHScroll = FALSE;

	// ������ ��������� ������ ?
	if(	TopWndPos(m_nActiveRow) < m_CountHeaderRows * m_nHeadRowHeight - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ������ ������� �������.
		pt.y = TopRowPos(m_nActiveRow) - m_nHeadRowHeight * m_CountHeaderRows;
	}
	else if ( TopWndPos(m_nActiveRow + 1) - 1 > rectClient.bottom - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ��������� ������� �������.
		pt.y = min(TopRowPos(m_nActiveRow) - m_nHeadRowHeight * m_CountHeaderRows, m_CountHeaderRows * m_nHeadRowHeight + (m_nActiveRow - m_CountHeaderRows + 1) * m_nRowHeight - rectClient.Height()) - offsetXY + 1;
	}
	else
		bNeedToVScroll = FALSE;

	// ���� ��������� ���������
	if(bNeedToHScroll || bNeedToVScroll)
		ScrollToPos(pt);
	
	// �������� ��������� �� ������� ���������� ������
	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl == NULL)
	{
		// ������� ������� ���������� ������
		pCellCtrl = CreateCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow),GetCellCtrlStyle(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow)));
		if(pCellCtrl != NULL)
		{
			SetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow), pCellCtrl);
			SetDataCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow), pCellCtrl);
		}
	}
	else if(m_nActiveCol != nPrevActiveCol || m_nActiveRow != nPrevActiveRow)
		SetDataCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow), pCellCtrl);


	if(nPrevActiveRow != m_nActiveRow || !bNeedToVScroll)
		// ��������� �������� ������ ����������� �������
		for(int i = 0; i < m_CountFrozenCols; i++)
			UpdateCell(pDC, i, m_nActiveRow);
	if(bRowSelect && nPrevActiveRow != m_nActiveRow)
		// ��������� �������� ������
		UpdateRow(pDC,m_nActiveRow);
	else
	{
		// ��������� �������� ������
		UpdateCell(pDC, m_nActiveCol, m_nActiveRow);
		if(m_CountHeaderRows > 0 && (nPrevActiveCol != m_nActiveCol || !bNeedToHScroll))
			// ��������� ���������� �������� ������ �����
			UpdateCell(pDC, m_nActiveCol, m_CountHeaderRows-1);
	}

	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);

	CWnd* pParentWnd = m_pGridWnd->GetParent();
	if(pParentWnd != NULL)
		pParentWnd->SendMessage(GWM_ACTCOLROWCHANGED,(WPARAM)m_pGridWnd->m_hWnd,0);

	ActivateCtrl(m_nActiveCol, m_nActiveRow);

	return TRUE;
}

// ������� ������������� ��������� ������.
BOOL CALXGridCore::SetSelectCell(int nCol, int nRow)
{
	if(nCol < m_CountFrozenCols || nRow < m_CountHeaderRows || nCol >= GetAllColCount() || nRow >= GetAllRowCount())
		return FALSE;
	// ���� ������ �������� �������� �����
	if(!(m_pGridWnd->GetStyle() & AGS_RANGESELECT))
		return SetActiveCell(nCol, nRow);

	int nPrevActiveSelCol = m_nActiveSelCol;
	int nPrevActiveSelRow = m_nActiveSelRow;
	BOOL bRowSelect = (m_pGridWnd->GetStyle() & AGS_ROWSELECT);

	ALXSelRangeCell mPrevSelRangeCell = m_SelRangeCell;

	if(SaveModifyed(FALSE))
	{
		m_nActiveSelCol = nCol;
		m_nActiveSelRow = nRow;
	}

	m_pGridWnd->SetFocus();

	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	// �������� �������� ���������� �����
	if(!m_SelRangeCell.IsEmpty())
	{
		// �������� �������� ���������� �������
		if(m_SelRangeCell.m_LeftCol > m_nActiveSelCol)
		{
			m_SelRangeCell.m_LeftCol = m_nActiveSelCol;
			m_SelRangeCell.m_RightCol = m_nActiveCol;
		}
		else if(m_SelRangeCell.m_RightCol < m_nActiveSelCol)
		{
			m_SelRangeCell.m_LeftCol = m_nActiveCol;
			m_SelRangeCell.m_RightCol = m_nActiveSelCol;
		}
		else if(m_nActiveSelCol >= m_SelRangeCell.m_LeftCol && m_nActiveSelCol <= m_SelRangeCell.m_RightCol)
		{
			if(m_nActiveSelCol > nPrevActiveSelCol)
				if(m_nActiveSelCol < m_nActiveCol)
					m_SelRangeCell.m_LeftCol = m_nActiveSelCol;
				else
					m_SelRangeCell.m_LeftCol = m_nActiveCol;
			else if(m_nActiveSelCol < nPrevActiveSelCol)
				if(m_nActiveSelCol > m_nActiveCol)
					m_SelRangeCell.m_RightCol = m_nActiveSelCol;
				else
					m_SelRangeCell.m_RightCol = m_nActiveCol;
		}
		// �������� �������� ���������� �����
		if(m_SelRangeCell.m_TopRow > m_nActiveSelRow)
		{
			m_SelRangeCell.m_TopRow = m_nActiveSelRow;
			m_SelRangeCell.m_BottomRow = m_nActiveRow;
		}
		else if(m_SelRangeCell.m_BottomRow < m_nActiveSelRow)
		{
			m_SelRangeCell.m_TopRow = m_nActiveRow;
			m_SelRangeCell.m_BottomRow = m_nActiveSelRow;
		}
		else if(m_nActiveSelRow >= m_SelRangeCell.m_TopRow && m_nActiveSelRow <= m_SelRangeCell.m_BottomRow)
		{
			if(m_nActiveSelRow > nPrevActiveSelRow)
				if(m_nActiveSelRow < m_nActiveRow)
					m_SelRangeCell.m_TopRow = m_nActiveSelRow;
				else
					m_SelRangeCell.m_TopRow = m_nActiveRow;
			else if(m_nActiveSelRow < nPrevActiveSelRow)
				if(m_nActiveSelRow > m_nActiveRow)
					m_SelRangeCell.m_BottomRow = m_nActiveSelRow;
				else
					m_SelRangeCell.m_BottomRow = m_nActiveRow;
		}
	}
	else
	{
		m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveSelCol;
		m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveSelRow;
	}
		// ������� ��������� � ����������� ��������� ���������� �����
		CRect rectGrid = GetGridRect(rectClient);
		// ���������� �������� ������� � ���� ��������
		int nFirstCol, nLastCol;
		// ���������� ����� ������� � ���������� ����������������� �������
		RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
		nFirstCol = max(nFirstCol, mPrevSelRangeCell.m_LeftCol);
		nLastCol = min(nLastCol, mPrevSelRangeCell.m_RightCol);
		// ���������� �������� ������� � ���� �����
		int nFirstRow, nLastRow;
		// ���������� ����� ������� � ���������� ����������������� �������
		RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
		nFirstRow = max(nFirstRow, mPrevSelRangeCell.m_TopRow);
		nLastRow = min(nLastRow, mPrevSelRangeCell.m_BottomRow);
		// ������� ���������
		if(!mPrevSelRangeCell.IsEmpty())
			for(int i = nFirstRow; i <= nLastRow; i++)
				for(int j = nFirstCol; j <= nLastCol; j++)
					if(!m_SelRangeCell.InRange(j,i))
						UpdateCell(pDC, j, i);

	// ��������� ���������� �������� ������
	UpdateCell(pDC, nPrevActiveSelCol, nPrevActiveSelRow);
	if(m_CountHeaderRows > 0 && nPrevActiveSelCol != m_nActiveSelCol)
		// ��������� ���������� �������� ������ �����
		UpdateCell(pDC, nPrevActiveSelCol, m_CountHeaderRows-1);

	// ���� ����������, ������������ ���� ���,
	// ��� ����� ��������� ������ (�������) ���� �����.
	CPoint pt(m_CurScrollPos);
	BOOL bNeedToVScroll = TRUE;
	BOOL bNeedToHScroll = TRUE;

	// ������� ��������� ����� ?
	if(	LeftWndPos(m_nActiveSelCol) < m_CountFrozenCols * m_FrozenColWidth - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ������ ������� ��������.
		pt.x = LeftColPos(m_nActiveSelCol) - m_FrozenColWidth * m_CountFrozenCols;
	}
	else if ( LeftWndPos(m_nActiveSelCol + 1) - 1 > rectClient.right - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ��������� ������� ��������.
		pt.x = min(LeftColPos(m_nActiveSelCol) - m_FrozenColWidth * m_CountFrozenCols, LeftColPos(m_nActiveSelCol + 1) - rectClient.Width()) - offsetXY + 1;
	}
	else
		bNeedToHScroll = FALSE;

	// ������ ��������� ������ ?
	if(	TopWndPos(m_nActiveSelRow) < m_CountHeaderRows * m_nHeadRowHeight - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ������ ������� �������.
		pt.y = TopRowPos(m_nActiveSelRow) - m_nHeadRowHeight * m_CountHeaderRows;
	}
	else if ( TopWndPos(m_nActiveSelRow + 1) - 1 > rectClient.bottom - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ��������� ������� �������.
		pt.y = min(TopRowPos(m_nActiveSelRow) - m_nHeadRowHeight * m_CountHeaderRows, m_CountHeaderRows * m_nHeadRowHeight + (m_nActiveSelRow - m_CountHeaderRows + 1) * m_nRowHeight - rectClient.Height()) - offsetXY + 1;
	}
	else
		bNeedToVScroll = FALSE;

	// ���� ��������� ���������
	if(bNeedToHScroll || bNeedToVScroll)
		ScrollToPos(pt);
	

	rectGrid = GetGridRect(rectClient);
	// ���������� �������� ������� � ���� ��������
	nFirstCol, nLastCol;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
	nFirstCol = max(nFirstCol, m_SelRangeCell.m_LeftCol);
	nLastCol = min(nLastCol, m_SelRangeCell.m_RightCol);
	// ���������� �������� ������� � ���� �����
	nFirstRow, nLastRow;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
	nFirstRow = max(nFirstRow, m_SelRangeCell.m_TopRow);
	nLastRow = min(nLastRow, m_SelRangeCell.m_BottomRow);
	// ��������� ���������� ������
	for(int i = nFirstRow; i <= nLastRow; i++)
		for(int j = nFirstCol; j <= nLastCol; j++)
			UpdateCell(pDC, j, i);

	// ��������� �������� ������
	UpdateCell(pDC, m_nActiveSelCol, m_nActiveSelRow);
	if(m_CountHeaderRows > 0 && (nPrevActiveSelCol != m_nActiveSelCol || !bNeedToHScroll))
		// ��������� ���������� �������� ������ �����
		UpdateCell(pDC, m_nActiveSelCol, m_CountHeaderRows-1);

	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);

	CWnd* pParentWnd = m_pGridWnd->GetParent();
	if(pParentWnd != NULL)
		pParentWnd->SendMessage(GWM_SELCOLROWRANGE,(WPARAM)m_pGridWnd->m_hWnd,0);

	return TRUE;
}

// ������� �������������� ������ �����.
void CALXGridCore::UpdateCell(CDC* pDC, int nCol, int nRow)
{
	// ���������� ������� ������� ����� ��������
	CRect rectCell;
	if(nCol < m_CountFrozenCols)
	{
		rectCell.left = m_FrozenColWidth * nCol - offsetXY;
		rectCell.right = m_FrozenColWidth * (nCol + 1) - offsetXY - 1;
	}
	else
	{
		rectCell.left = LeftWndPos(nCol, nRow < m_CountHeaderRows ? nRow : -1);
		rectCell.right = LeftWndPos(nCol+1, nRow < m_CountHeaderRows ? nRow : -1)-1;
	}
	if(nRow < m_CountHeaderRows)
	{
		rectCell.top = m_nHeadRowHeight * nRow - offsetXY;
		rectCell.bottom = m_nHeadRowHeight * (nRow + 1) - offsetXY - 1;
	}
	else
	{
		rectCell.top = TopWndPos(nRow);
		rectCell.bottom = TopWndPos(nRow+1)-1;
	}

	// ���� ������� ������ � pDC �� NULL
	if(rectCell.right > 0 && rectCell.bottom > 0 && pDC != NULL)
		OnUpdateRect(pDC,rectCell); // ��������� ������� ���� 
}

// ������� �������� ����, ��� ������� ������ ����� ������������.
void CALXGridCore::InvalidateCell(int nCol, int nRow)
{
	CRect rectCell;
	rectCell.left = LeftWndPos(nCol);
	rectCell.right = rectCell.left + GetColWidth(nCol);
	rectCell.top = TopWndPos(nRow);
	rectCell.bottom = rectCell.top + m_nRowHeight;
	m_pGridWnd->InvalidateRect(rectCell);
}

// ������� �������������� ������ �����.
void CALXGridCore::UpdateRow(CDC* pDC, int nRow)
{
	// ���������� ������� ������� ����� ��������
	CRect rectCell;
	m_pGridWnd->GetClientRect(&rectCell);
	rectCell.left = 0;

	if(nRow < m_CountHeaderRows)
	{
		rectCell.top = m_nHeadRowHeight * nRow - offsetXY;
		rectCell.bottom = m_nHeadRowHeight * (nRow + 1) - offsetXY - 1;
	}
	else
	{
		rectCell.top = TopWndPos(nRow);
		rectCell.bottom = TopWndPos(nRow+1)-1;
	}

	// ���� ������� ������ � pDC �� NULL
	if(rectCell.right > 0 && rectCell.bottom > 0 && pDC != NULL)
		OnUpdateRect(pDC,rectCell); // ��������� ������� ���� 
}

// ������� �������� ����, ��� ������� ������ ����� ������������.
void CALXGridCore::InvalidateRow(int nRow)
{
	CRect rectRow;
	m_pGridWnd->GetClientRect(&rectRow);
	rectRow.top = TopWndPos(nRow);
	rectRow.bottom = rectRow.top + m_nRowHeight;
	m_pGridWnd->InvalidateRect(rectRow);
}

// ������� ���������� TRUE ���� ������ ��������� ����� ��������� �����.
BOOL CALXGridCore::IsCursorBetweenCols(int x, int& ResizeCol, int& ResizeRow)
{
	x = x + m_CurScrollPos.x;
	int i = 0;
	int iPrevWidth = 0, iNextWidth = GetColWidth(i,ResizeRow);
	while( (x < iPrevWidth  || x > iNextWidth) && i < GetAllColCount(ResizeRow)-1)
	{
		i++;
		iPrevWidth = iNextWidth;
		iNextWidth = iNextWidth + GetColWidth(i,ResizeRow);
	}

	if(x <= iPrevWidth + 2 || x >= iNextWidth - 2)
	{
		if(x <= iPrevWidth + 2)
			ResizeCol = i-1;
		else
			ResizeCol = i;
		if(ResizeCol < m_CountFrozenCols && !(m_pGridWnd->GetStyle() & AGS_CUSTOMFROZEN_WIDTH))
			return FALSE;
		return TRUE;
	}
	else
		return FALSE;
}

// ������� ���������� ��� ���������� ��������� ������ �������
void CALXGridCore::EndResizeCol(int x)
{
	// ����������� �����. ���� � �����. �����
	x = x + m_CurScrollPos.x;

	// �������� ����� ������ �������
	int nNewWidth = x - LeftColPos(m_ResizeCol,m_ResizeRow);
	int nOldWidth = GetColWidth(m_ResizeCol,m_ResizeRow);
	if(nNewWidth < 0)
		nNewWidth = 0;

	if(m_ResizeCol >= m_CountFrozenCols)
	{
		SetHeadColWidth(GetGridCol(m_ResizeCol), m_ResizeRow, nNewWidth);
		ScrollCol(m_ResizeCol, m_ResizeRow, nOldWidth - nNewWidth);
	}
	else
		m_FrozenColWidth = nNewWidth;

	BOOL bActiveCtrl = FALSE;
	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl != NULL)
	{
		bActiveCtrl = pCellCtrl->IsActive();
		// ������������ �������� ������� ���������� 
		pCellCtrl->DeactivateCtrl();
	}

	// ��������� Scroll Bars
	UpdateScrollSizes();

	CWnd* pParentWnd = m_pGridWnd->GetParent();
	if(pParentWnd != NULL)
		pParentWnd->SendMessage(GWM_COLWIDTHCHANGED,(WPARAM)m_pGridWnd,0);

	m_pGridWnd->SetFocus();

	if(m_ResizeCol < m_CountFrozenCols)
		m_pGridWnd->Invalidate();

	if(bActiveCtrl)
		ActivateCtrl(m_nActiveCol, m_nActiveRow);
}

// ������� ������������� �������� ������ �����.
BOOL CALXGridCore::SetActiveCell(CPoint point)
{
	int nCol = 0, nRow = 0;
	if(point.x <= m_CountFrozenCols*m_FrozenColWidth)
		nCol = m_nActiveCol;
	else
		nCol = XToCol(point.x + m_CurScrollPos.x);

	if(point.y <= m_CountHeaderRows*m_nHeadRowHeight)
		nRow = m_nActiveRow;
	else
		nRow = YToRow(point.y + m_CurScrollPos.y);

	return SetActiveCell(nCol, nRow);
}

// ������� ������������� ���������� ������.
BOOL CALXGridCore::SetSelectCell(CPoint point)
{
	int nCol = 0, nRow = 0;
	if(point.x <= m_CountFrozenCols*m_FrozenColWidth)
		nCol = m_nActiveSelCol;
	else
		nCol = XToCol(point.x + m_CurScrollPos.x);

	if(point.y <= m_CountHeaderRows*m_nHeadRowHeight)
		nRow = m_nActiveSelRow;
	else
		nRow = YToRow(point.y + m_CurScrollPos.y);

	return SetSelectCell(nCol, nRow);
}

// ������� ���������� ����� ������� ������� ����������� ���������� x.
int CALXGridCore::XToCol(int x, int nHeadRow)
{
	int nCol = 0;
	int iPrevWidth = 0, iNextWidth = GetColWidth(nCol, nHeadRow);
	while( (x < iPrevWidth  || x > iNextWidth) && nCol < GetAllColCount(nHeadRow)-1)
	{
		nCol++;
		iPrevWidth = iNextWidth;
		iNextWidth = iNextWidth + GetColWidth(nCol,nHeadRow);
	}
	return (x > iNextWidth) ? ++nCol : nCol;
}

// ������� ���������� ����� ������ ������� ����������� ���������� y.
int CALXGridCore::YToRow(int y)
{
	if(y < m_CountHeaderRows * m_nHeadRowHeight)
		return y / m_nHeadRowHeight;
	else
		return m_CountHeaderRows + (y - m_CountHeaderRows * m_nHeadRowHeight) / m_nRowHeight;
}

// ����������� �������. ���������� ��������� �� ������� ���������� ������.
// ��� ������� ���������������� � ������ CALXGrid
CALXCellCtrl* CALXGridCore::GetCellCtrl(int nCol, int nRow)
{
	return m_pCellCtrl;
}

// ����������� �������. ������������� ������� ���������� ��� ������.
// ��� ������� ���������������� � ������ CALXGrid
void CALXGridCore::SetCellCtrl(int nCol, int nRow, CALXCellCtrl* pCellCtrl)
{
}

// ����������� �������. �������� ������ �������� ���������� �������.
// ��� ������� ����� �������������� � ����� ���������������� ������.
void CALXGridCore::SetDataCtrl(int nCol, int nRow, CALXCellCtrl* pCellCtrl)
{
	pCellCtrl->SetData(GetCellData(nCol,nRow));
}

// ����������� �������. ��� ������ ��������� ������� ���������� ��� ������.
// ��� ������� ���������������� � ������ CALXGrid
CALXCellCtrl* CALXGridCore::CreateCellCtrl(int nCol, int nRow, DWORD dwStyle, UINT nID)
{
	CALXCellCtrl* pCellCtrl = new CALXCellCtrl;
	pCellCtrl->CreateCtrl(dwStyle,m_pGridWnd,IDC_CELLCTRL+nCol);
	pCellCtrl->EnableCtrl(FALSE);
	pCellCtrl->SetFontCtrl(&m_Font);
	return pCellCtrl;
}

// ����������� �������. ��� ������ ���������� ������ ������.
// ��� ������� ������ ��������������� � �������� ������ ����������� �� CALXGridView ��� CALXGridCtrl.
CELL_DATA CALXGridCore::GetCellData(int nCol, int nRow)
{
	CELL_DATA CtrlData;
	CtrlData.m_strText.Format("%u - %u",nCol,nRow);
	return CtrlData;
}

// ����������� �������. ��� ������ ���������� ���������� � ����� ������.
// ��� ������� ���������������� � ������ CALXGrid.
CELL_INFO CALXGridCore::GetCellInfo(int nCol, int nRow)
{
	CELL_INFO CellInfo;
	CellInfo.m_nFormat = DT_CENTER | DT_VCENTER;
	CellInfo.m_nTypeCtrl = 0;
	return CellInfo;
}

// ����������� �������. ��� ������ ���������� ���������� � ����� �������� ���������� �������.
// ��� ������� ���������������� � ������ CALXGrid.
DWORD CALXGridCore::GetCellCtrlStyle(int nCol, int nRow)
{
	return WS_CHILD;
}

// ������� ���������� ��������� �� ���� �����.
CWnd* CALXGridCore::GetGridWnd()
{
	return m_pGridWnd;
}

// ����������� �������. ��� ���������� ������� ������.
// ��� ������� ����� ��������������� � �������� ������ ����������� �� CALXGridView ��� CALXGridCtrl.
CALXCellMetrics* CALXGridCore::GetCellMetrics(int nCol, int nRow)
{
	return &m_MetricsCells;
}

// ����������� �������. ��� ���������� ���������� �� ��� ������ �����������.
// ��� ������� ���������������� � ������ CALXGrid.
BOOL CALXGridCore::IsImage(int nCol, int nRow)
{
	return FALSE;
}

// ����������� �������. ��� ���������� ��� ����������� ��� ������.
// ��� ������� ���������������� � ������ CALXGrid.
UINT CALXGridCore::GetTypeImage(int nCol, int nRow)
{
	return NULL;
}

// ����������� �������. ��� ������ ���������� ������ ����������� ��� ������ ������.
// ��� ������� ���������������� � ������ CALXGrid.
BOOL CALXGridCore::GetSizeImage(int nCol, int nRow, CSize& sz)
{
	sz.cx = 0;
	sz.cy = 0;
	return FALSE;
}

// ����������� �������. ��� ������ ���������� ��������� �� �����������.
// ��� ������� ���������������� � ������ CALXGrid.
LPARAM CALXGridCore::GetImage(int nCol, int nRow, BOOL bSelected)
{
	return NULL;
}

// ����������� �������. ��� ������ ���������� ���������� � �����������.
// ��� ������� ������ ��������������� � �������� ������ ����������� �� CALXGridView ��� CALXGridCtrl.
void CALXGridCore::GetImageListDrawParams(int nCol, int nRow, IMAGELISTDRAWPARAMS* pimldp, BOOL bSelected)
{

}

// ������������� ����� � ���� ����� "����� �����"
void CALXGridCore::SetFocusRect(COLORREF crFaceColor, COLORREF crBkColor/* = ::GetSysColor(COLOR_WINDOW)*/, BOOL bSolid/* = TRUE*/)
{
	m_MetricsCells.m_FocusRect.m_crFaceColor =	crFaceColor;
	m_MetricsCells.m_FocusRect.m_crBackColor = crBkColor;
	m_MetricsCells.m_FocusRect.m_bSolid = bSolid;
}

// ������� �������� ��������� �������� ���������� ������� � ������� ����� ������ ����.
// ������������ ��� ����������� �������� ���������� �������.
void CALXGridCore::SendLButtonDown(UINT nFlags, CPoint point)
{
	CPoint pointClick;
	// ����������� ���������� ���� � ���������� �������� ����������.
	pointClick.x = point.x + m_CurScrollPos.x - LeftColPos(m_nActiveCol);
	pointClick.y = point.y + m_CurScrollPos.y - TopRowPos(m_nActiveRow);
	if(pointClick.x < 0 || pointClick.y < 0)
		return;
	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl != NULL)
		pCellCtrl->SendLButtonDown(nFlags, pointClick);
}

// ������� ��������� � ������������� �������
// � ������ �������� ���������� �������.
void CALXGridCore::ActivateCtrl(int nCol, int nRow)
{
	if(nRow < m_CountHeaderRows)
		return;

	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(nCol),GetGridRow(nRow));
	if(pCellCtrl != NULL)
	{
		// ���� ������ � ������������
		if(IsImage(GetGridCol(nCol),GetGridRow(nRow)))
		{
			CSize sz;
			// �������� ������ �����������, ����� ������� ������ ������
			GetSizeImage(GetGridCol(nCol),GetGridRow(nRow),sz);
			sz.cx += 2;
			pCellCtrl->ActivateCtrl(LeftWndPos(nCol)+sz.cx,TopWndPos(nRow),GetColWidth(nCol)-sz.cx,m_nRowHeight);
		}
		else
			pCellCtrl->ActivateCtrl(LeftWndPos(nCol),TopWndPos(nRow),GetColWidth(nCol),m_nRowHeight);
	}
}

// ������� ������� ������� � ������.
void CALXGridCore::DrawImage(CDC *pDC, int nCol, int nRow, CPoint& pt, CSize& sz, BOOL bSelected)
{

	switch(GetTypeImage(nCol,nRow))
	{
	case DIT_BITMAP :
		{
			LPARAM hBitmap = GetImage(nCol,nRow,bSelected);
			if(hBitmap != NULL)
				DrawState(pDC->m_hDC,NULL,NULL, hBitmap,0,pt.x,pt.y,sz.cx,sz.cy,DST_BITMAP);
			break;
		}
	case DIT_ICON :
		{
			HICON hIcon = (HICON)GetImage(nCol,nRow,bSelected);
			if(hIcon != NULL)
				DrawIconEx(pDC->m_hDC,pt.x,pt.y,hIcon,sz.cx,sz.cy,NULL,NULL,DI_NORMAL | DI_DEFAULTSIZE);
			break;
		}
	case DIT_IMGLIST :
		{
			IMAGELISTDRAWPARAMS imldp;
			memset(&imldp, 0, sizeof(imldp));
			imldp.cbSize = sizeof(imldp);
			imldp.hdcDst = pDC->m_hDC;
			imldp.rgbBk = CLR_DEFAULT;
			imldp.rgbFg = CLR_DEFAULT;
			imldp.fStyle = ILD_TRANSPARENT;
			imldp.himl = NULL;
			imldp.cx = sz.cx;
			imldp.cy = sz.cy;
			imldp.x = pt.x;
			imldp.y = pt.y;

#if _MSC_VER > 1200
			DWORD dwMajor = 0, dwMinor = 0;
			AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
			if (dwMajor < 6)
				imldp.cbSize = IMAGELISTDRAWPARAMS_V3_SIZE;
#endif // _MSC_VER > 1200

			GetImageListDrawParams(nCol,nRow,&imldp,bSelected);

			if(imldp.himl != NULL)
				ImageList_DrawIndirect(&imldp);

			break;
		}
	}
}

// ������� �������������� ����� ���������
void CALXGridCore::RedrawFocusRect()
{
	CRect rectCell,rectRow(0,0,0,0);
	CRect rectClient;
	CRgn rgnGrid;
	int nActGridCol = GetGridCol(m_nActiveCol); // ������ ������� ��� ����� ����������� �������
	int nActGridRow = GetGridRow(m_nActiveRow); // ������ ������ ��� ����� ����� �����

	m_pGridWnd->GetClientRect(&rectClient);

	rectCell.left = LeftWndPos(m_nActiveCol) + 1;
	rectCell.right = rectCell.left + GetColWidth(m_nActiveCol) - 1;
	rectCell.top = TopWndPos(m_nActiveRow) + 1;
	rectCell.bottom = rectCell.top + m_nRowHeight - 1;

	// ���� ������ � ������������
	if(IsImage(nActGridCol,nActGridRow))
	{
		CSize sz;
		// �������� ������ �����������
		GetSizeImage(nActGridCol,nActGridRow,sz);
		// ��������� ������ �����������, ���� ���������
		sz.cx = min(rectCell.Width(),sz.cx);
		// ������� ����� ������� ������
		rectCell.left = min(rectCell.right,rectCell.left+sz.cx+2);
	}
	if(m_pGridWnd->GetStyle() & AGS_ROWSELECT)
	{
		rectRow.left = LeftWndPos(m_CountFrozenCols) + 1;
		rectRow.right = rectRow.left + (m_nRowWidth - m_CountFrozenCols * m_FrozenColWidth) - 1;
		rectRow.top = rectCell.top;
		rectRow.bottom = rectCell.bottom;
	}
	else
	{
		if(rectCell.IsRectEmpty())
			return;
	}

	rgnGrid.CreateRectRgn(  m_CountFrozenCols > 0 ? m_FrozenColWidth * m_CountFrozenCols - offsetXY + 1: 0,
							m_CountHeaderRows > 0 ? m_nHeadRowHeight * m_CountHeaderRows - offsetXY + 1: 0,
							rectClient.right,rectClient.bottom  );

	// �������� ������� ������
	CALXCellMetrics* pCellMetrics = GetCellMetrics(nActGridCol, nActGridRow);

	ASSERT(pCellMetrics != NULL);

	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	pDC->SelectClipRgn(&rgnGrid);
		pCellMetrics->m_FocusRect.DrawFocusRect(pDC, rectCell);
		if(!rectRow.IsRectEmpty())
			m_MetricsCells.m_FocusRect.DrawFocusRect(pDC, rectRow);
	pDC->SelectClipRgn(NULL);

	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);
}

void CALXGridCore::ScrollAndSetActCol(int HPos, int nCol, BOOL RedrawCells /* = TRUE*/)
{
	if(nCol < m_CountFrozenCols || nCol >= GetAllColCount())
		return;

	HPos = min(HPos,m_sizeTotal.cx - m_sizePage.cx + 1);
	HPos = HPos > 0 ? HPos : 0;

	int nPrevActiveCol = m_nActiveCol;
	int nPrevActiveRow = m_nActiveRow;
	BOOL bRowSelect = (m_pGridWnd->GetStyle() & AGS_ROWSELECT);

	ALXSelRangeCell mPrevSelRangeCell = m_SelRangeCell;

	SaveModifyed();

	m_nActiveCol = nCol;

	m_nActiveSelCol = m_nActiveCol;
	m_nActiveSelRow = m_nActiveRow;
	
	m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
	m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;

	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl != NULL)
		SetDataCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow), pCellCtrl);

	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	// ���� ����� �������������� ������
	if(RedrawCells)
	{
		// ���� ����� �������� �������� �����
		if(m_pGridWnd->GetStyle() & AGS_RANGESELECT)
		{
			// ������� ��������� � ����������� ��������� ���������� �����
			CRect rectGrid = GetGridRect(rectClient);
			// ���������� �������� ������� � ���� ��������
			int nFirstCol, nLastCol;
			// ���������� ����� ������� � ���������� ����������������� �������
			RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
			nFirstCol = max(nFirstCol, mPrevSelRangeCell.m_LeftCol);
			nLastCol = min(nLastCol, mPrevSelRangeCell.m_RightCol);
			// ���������� �������� ������� � ���� �����
			int nFirstRow, nLastRow;
			// ���������� ����� ������� � ���������� ����������������� �������
			RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
			nFirstRow = max(nFirstRow, mPrevSelRangeCell.m_TopRow);
			nLastRow = min(nLastRow, mPrevSelRangeCell.m_BottomRow);
			// ������� ���������
			if(!mPrevSelRangeCell.IsEmpty())
				for(int i = nFirstRow; i <= nLastRow; i++)
					for(int j = nFirstCol; j <= nLastCol; j++)
						if(!m_SelRangeCell.InRange(j,i))
							UpdateCell(pDC, j, i);
		}

		// ��������� ���������� �������� ������
		UpdateCell(pDC, nPrevActiveCol, nPrevActiveRow);
		if(m_CountHeaderRows > 0)
			// ��������� ���������� �������� ������ �����
			UpdateCell(pDC, nPrevActiveCol, m_CountHeaderRows-1);
	}

	// ���� ����������, ������������ ���� ���, ��� ����� ���������
	// ������ (�������) ���� �����.
	
	// ���� ��������� ���������
	if(m_CurScrollPos.x != HPos)
	{
		CPoint pt(HPos,m_CurScrollPos.y);
		ScrollToPos(pt);
	}

	// ���� ����� �������������� ������
	if(RedrawCells)
	{

		if(!bRowSelect)
			// ��������� �������� ������
			UpdateCell(pDC, m_nActiveCol, m_nActiveRow);
		else
			// ��������� �������� ������
			UpdateRow(pDC,m_nActiveRow);

		if(m_CountHeaderRows > 0)
			// ��������� �������� ������ �����
			UpdateCell(pDC, m_nActiveCol, m_CountHeaderRows-1);
	}

	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);

	return;
}

void CALXGridCore::ScrollAndSetActRow(int VPos, int nRow, BOOL RedrawCells /*= TRUE*/)
{
	if(nRow < m_CountHeaderRows || nRow >= GetAllRowCount())
		return;
	VPos = min(VPos,m_sizeTotal.cy - m_sizePage.cy + 1);
	VPos = VPos > 0 ? VPos : 0;

	int nPrevActiveCol = m_nActiveCol;
	int nPrevActiveRow = m_nActiveRow;
	BOOL bRowSelect = (m_pGridWnd->GetStyle() & AGS_ROWSELECT);

	ALXSelRangeCell mPrevSelRangeCell = m_SelRangeCell;

	SaveModifyed();

	m_nActiveRow = nRow;

	m_nActiveSelCol = m_nActiveCol;
	m_nActiveSelRow = m_nActiveRow;
	
	m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
	m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;

	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl != NULL)
		SetDataCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow), pCellCtrl);

	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	// ���� ����� �������������� ������
	if(RedrawCells)
	{
		if(bRowSelect)
			// ��������� ���������� ������
			UpdateRow(pDC,nPrevActiveRow);
		else
		{
			m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
			m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;

			// ���� ����� �������� �������� �����
			if(m_pGridWnd->GetStyle() & AGS_RANGESELECT)
			{
				// ������� ��������� � ����������� ��������� ���������� �����
				CRect rectGrid = GetGridRect(rectClient);
				// ���������� �������� ������� � ���� ��������
				int nFirstCol, nLastCol;
				// ���������� ����� ������� � ���������� ����������������� �������
				RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
				nFirstCol = max(nFirstCol, mPrevSelRangeCell.m_LeftCol);
				nLastCol = min(nLastCol, mPrevSelRangeCell.m_RightCol);
				// ���������� �������� ������� � ���� �����
				int nFirstRow, nLastRow;
				// ���������� ����� ������� � ���������� ����������������� �������
				RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
				nFirstRow = max(nFirstRow, mPrevSelRangeCell.m_TopRow);
				nLastRow = min(nLastRow, mPrevSelRangeCell.m_BottomRow);
				// ������� ���������
				if(!mPrevSelRangeCell.IsEmpty())
					for(int i = nFirstRow; i <= nLastRow; i++)
						for(int j = nFirstCol; j <= nLastCol; j++)
							if(!m_SelRangeCell.InRange(j,i))
								UpdateCell(pDC, j, i);
			}

			// ��������� ���������� �������� ������
			UpdateCell(pDC, nPrevActiveCol, nPrevActiveRow);
			if(m_CountFrozenCols > 0)
				// ��������� ���������� �������� ������ ����������� �������
				for(int i = 0; i < m_CountFrozenCols; i++)
					UpdateCell(pDC, i, nPrevActiveRow);
		}
	}

	// ���� ����������, ������������ ���� ���, ��� ����� ���������
	// ������ (�������) ���� �����.

	// ���� ��������� ���������
	if(m_CurScrollPos.y != VPos)
	{
		CPoint pt(m_CurScrollPos.x,VPos);
		ScrollToPos(pt);
	}
	
	if(RedrawCells)
	{// ���� ����� �������������� ������

		if(bRowSelect)
			// ��������� �������� ������
			UpdateRow(pDC,m_nActiveRow);
		else
		{
			// ��������� �������� ������
			UpdateCell(pDC, m_nActiveCol, m_nActiveRow);
			if(m_CountFrozenCols > 0)
				// ��������� �������� ������ ����������� �������
				UpdateCell(pDC, m_CountFrozenCols-1, m_nActiveRow);
		}
	}
	
	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);

	return;
}

void CALXGridCore::ScrollAndSetActCell(int nCol, int nRow, BOOL RedrawCells /*= TRUE*/)
{
	int nPrevActiveCol = m_nActiveCol;
	int nPrevActiveRow = m_nActiveRow;

	// ���� ����������, ������������ ���� ���,
	// ��� ����� ��������� ������ (�������) ���� �����.
	CPoint pt(m_CurScrollPos);
	BOOL bNeedToVScroll = TRUE;
	BOOL bNeedToHScroll = TRUE;

	nCol += m_CountFrozenCols;
	nRow += m_CountHeaderRows;

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	// ������� ��������� ����� ?
	if(	LeftWndPos(nCol) < m_CountFrozenCols * m_FrozenColWidth - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ������ ������� ��������.
		pt.x = LeftColPos(nCol) - m_FrozenColWidth * m_CountFrozenCols;
	}
	else if ( LeftWndPos(nCol + 1) - 1 > rectClient.right - offsetXY)
	{
		// ����� ��������� �������� �� ����� ��� ����� �����������.
		// ���� ����������, ��� ����� �� ��� ����� ��������� ������� ��������.
		pt.x = min(LeftColPos(nCol) - m_FrozenColWidth * m_CountFrozenCols, LeftColPos(nCol + 1) - rectClient.Width()) - offsetXY + 1;
	}
	else
		bNeedToHScroll = FALSE;

	// ������ ��������� ������ ?
	if(	TopWndPos(nRow) < m_CountHeaderRows * m_nHeadRowHeight - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ������ ������� �������.
		pt.y = TopRowPos(nRow) - m_nHeadRowHeight * m_CountHeaderRows;
	}
	else if ( TopWndPos(nRow + 1) - 1 > rectClient.bottom - offsetXY)
	{
		// ����� ��������� ������ �� ������ ��� ������ �����������.
		// ���� ����������, ��� ����� ��� ���� ����� ��������� ������� �������.
		pt.y = min(TopRowPos(nRow) - m_nHeadRowHeight * m_CountHeaderRows, m_CountHeaderRows * m_nHeadRowHeight + (nRow - m_CountHeaderRows + 1) * m_nRowHeight - rectClient.Height()) - offsetXY + 1;
	}
	else
		bNeedToVScroll = FALSE;

	// ���� ��������� ���������
	if(bNeedToHScroll || bNeedToVScroll)
		ScrollToPos(pt);

	ScrollAndSetActCol(pt.x, nCol, RedrawCells);
	ScrollAndSetActRow(pt.y, nRow, RedrawCells);

	OnSetActiveCell(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));

	if(m_nActiveRow != nPrevActiveRow)
		OnChangeActiveRow(GetGridRow(m_nActiveRow));
}

void CALXGridCore::ScrollToCol(int HPos, int nCol)
{
	if(nCol < m_CountFrozenCols || nCol >= GetAllColCount())
		return;

	HPos = min(HPos,m_sizeTotal.cx - m_sizePage.cx + 1);
	HPos = HPos > 0 ? HPos : 0;

	// ���� ����������, ������������ ���� ���, ����� ��������
	// ������ (�������) ���� �����.
	
	// ���� ��������� ���������
	if(m_CurScrollPos.x != HPos)
	{
		CPoint pt(HPos,m_CurScrollPos.y);
		ScrollToPos(pt);
	}

	return;
}

void CALXGridCore::ScrollToRow(int VPos, int nRow)
{
	if(nRow < m_CountHeaderRows || nRow >= GetAllRowCount())
		return;
	VPos = min(VPos,m_sizeTotal.cy - m_sizePage.cy + 1);
	VPos = VPos > 0 ? VPos : 0;

	// ���� ����������, ������������ ���� ���, ����� ��������
	// ������ (�������) ���� �����.
	
	// ���� ��������� ���������
	if(m_CurScrollPos.y != VPos)
	{
		CPoint pt(m_CurScrollPos.x,VPos);
		ScrollToPos(pt);
	}

	return;
}

// ������� ��������� ��������� ��������� � �������� �������� ����������
// ������� � �������������� ���� ������� ����������.
BOOL CALXGridCore::SaveModifyed(BOOL bSkipErrors /*= TRUE*/)
{
	CALXCellCtrl* pCellCtrl = GetCellCtrl(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow));
	if(pCellCtrl != NULL)
	{
		if(pCellCtrl->IsModifyed())
		{// ���� ���� ���������
			if(pCellCtrl->OnValidate())
			{// ���� ��������� ���������
				if(OnSaveCellData(GetGridCol(m_nActiveCol),GetGridRow(m_nActiveRow)))
				{// ���� ��������� ���������
					pCellCtrl->SetModify(FALSE);
					pCellCtrl->DeactivateCtrl();
					return TRUE;
				}
				else if(bSkipErrors)
				{// ���� ����� ��������������� ������
					pCellCtrl->SetModify(FALSE);
					pCellCtrl->DeactivateCtrl();
					return FALSE;
				}
				else
					return FALSE;
			}
			else if(bSkipErrors)
			{// ���� ����� ��������������� ������
				pCellCtrl->SetModify(FALSE);
				pCellCtrl->DeactivateCtrl();
				return FALSE;
			}
			else
				return FALSE;
		}
		pCellCtrl->DeactivateCtrl();
	}
	return TRUE;
}

// ������� ������ ������� � ������ �����
// ������� �� �������� ������������� ������.
void CALXGridCore::DrawArrow(CDC *pDC, CPoint pos, CSize sz)
{
	if(sz.cx <= 3 || sz.cy <= 3)
		return;

	CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
	CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
	CPen* pOldPen;


	if(m_nSortOrder == Descending)		
	{
		// Draw triangle pointing downwords
		pOldPen = pDC->SelectObject(&penShadow);
		pDC->MoveTo(pos.x + sz.cx,	pos.y);
		pDC->LineTo(pos.x, pos.y);
		pDC->LineTo(pos.x + sz.cx/2, pos.y + sz.cy);
		pDC->SelectObject(&penLight);
		pDC->MoveTo(pos.x + sz.cx/2 + 1, pos.y + sz.cy - 1);
		pDC->LineTo(pos.x + sz.cx, pos.y);
	}
	else		
	{
		// Draw triangle pointing upwards
		pOldPen = pDC->SelectObject(&penLight);
		pDC->MoveTo(pos.x,	pos.y + sz.cy);
		pDC->LineTo(pos.x + sz.cx, pos.y + sz.cy);
		pDC->LineTo(pos.x + sz.cx/2 + 1, pos.y);		
		pDC->SelectObject(&penShadow);
		pDC->MoveTo(pos.x,	pos.y + sz.cy - 1);
		pDC->LineTo(pos.x + sz.cx/2,pos.y);
	}
	// Restore the pen
	pDC->SelectObject( pOldPen );	
}

// ������� ������ ������ ����������� �������
void CALXGridCore::DrawFrozenBtn(CDC *pDC, int x, int y, int cx, int cy, BOOL bCellPressed, BOOL bDrawArrow, BOOL bFlat)
{
	// �������� ������ ���������
	CRect rectCell(x,y,max(x,x+cx),max(y,y+cy));
	// �������� ���� �����
	COLORREF clrCellFrame = ::GetSysColor(bFlat ? COLOR_BTNSHADOW : COLOR_3DDKSHADOW);

	// ������ �����
	pDC->Draw3dRect(rectCell,clrCellFrame,clrCellFrame);
	rectCell.DeflateRect(1,1,0,0);

	//
	if(rectCell.Height() <= 2 || rectCell.Width() <= 2 )
	{
		CBrush brushBackground;
		// fill cell
		rectCell.DeflateRect(0,0,1,1);
		if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
			pDC->FillRect(&rectCell, &brushBackground);
	}	 // if active row && first from right frozen cell
	else if(bDrawArrow) 
	{
		// if not press
		if(!bCellPressed)
		{
			if(bFlat)
			{
				pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
				CBrush brushBackground;
				// fill cell
				rectCell.DeflateRect(1,1,1,1);
				if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
					pDC->FillRect(&rectCell, &brushBackground);
				rectCell.DeflateRect(1,1,1,1);
			}
			else
			{
				// draw button
				pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
				rectCell.DeflateRect(2,2,2,2);
			}
		}
		else
		{
			CBrush brushBackground;
			// fill cell
			rectCell.DeflateRect(0,0,1,1);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
				pDC->FillRect(&rectCell, &brushBackground);
			rectCell.DeflateRect(2,1,0,0);
		}
		// draw arrow
		CBrush brushBlack;
		if(brushBlack.CreateSolidBrush(::GetSysColor(COLOR_WINDOWFRAME)))
		{
			POINT ptTriangle[4];
			CRgn rgnTriangle;
			ptTriangle[0].x = rectCell.left + (rectCell.Width()-4)/2;
			ptTriangle[0].y = rectCell.top+(rectCell.Height()-9)/2;
			ptTriangle[1].x = ptTriangle[0].x+4;
			ptTriangle[1].y = ptTriangle[0].y+4;
			ptTriangle[2].x = ptTriangle[0].x;
			ptTriangle[2].y = ptTriangle[0].y+8;
			rgnTriangle.CreatePolygonRgn(ptTriangle,3,WINDING);
			pDC->FillRgn(&rgnTriangle,&brushBlack);
		}
	}
	else
	{
		// if not press
		if(!bCellPressed)
		{
			if(bFlat)
			{
				pDC->Draw3dRect(rectCell,::GetSysColor(COLOR_BTNHIGHLIGHT),::GetSysColor(COLOR_BTNSHADOW));
				CBrush brushBackground;
				// fill cell
				rectCell.DeflateRect(1,1,1,1);
				if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
					pDC->FillRect(&rectCell, &brushBackground);
				rectCell.DeflateRect(1,1,1,1);
			}
			else
			{
				// draw button
				pDC->DrawFrameControl(rectCell,DFC_BUTTON,DFCS_BUTTONPUSH);
				rectCell.DeflateRect(2,2,2,2);
			}
		}
		else
		{
			CBrush brushBackground;
			// fill cell
			rectCell.DeflateRect(0,0,1,1);
			if(brushBackground.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)))
				pDC->FillRect(&rectCell, &brushBackground);
		}
	}
}

void CALXGridCore::SetSelectRange(int nLeftCol, int nRightCol, int nTopRow, int nButtonRow)
{
	// ���� ������ �������� �������� �����
	if(!(m_pGridWnd->GetStyle() & AGS_RANGESELECT))
		return;

	SaveModifyed(FALSE);

	ALXSelRangeCell mPrevSelRangeCell = m_SelRangeCell;

	m_pGridWnd->SetFocus();

	// �������� �������� ����������
	CDC* pDC = m_pGridWnd->GetDC();

	CRect rectClient;
	m_pGridWnd->GetClientRect(rectClient);

	// ����� ��������
	m_SelRangeCell.m_LeftCol = nLeftCol;
	m_SelRangeCell.m_RightCol = nRightCol;
	m_SelRangeCell.m_TopRow = nTopRow;
	m_SelRangeCell.m_BottomRow =  nButtonRow;
	// ���� ������ �������
	if(m_SelRangeCell.IsEmpty())
	{
		m_SelRangeCell.m_LeftCol = m_SelRangeCell.m_RightCol = m_nActiveCol;
		m_SelRangeCell.m_TopRow = m_SelRangeCell.m_BottomRow = m_nActiveRow;
	}

	m_nActiveSelCol = m_SelRangeCell.m_LeftCol;
	m_nActiveSelRow = m_SelRangeCell.m_TopRow;

	// ����� �������� �������
	if(m_nActiveCol > m_SelRangeCell.m_RightCol)
		m_nActiveCol = m_SelRangeCell.m_RightCol;
	else if(m_nActiveCol < m_SelRangeCell.m_LeftCol)
		m_nActiveCol = m_SelRangeCell.m_LeftCol;
	// ����� �������� ������
	if(m_nActiveRow > m_SelRangeCell.m_BottomRow)
		m_nActiveRow = m_SelRangeCell.m_BottomRow;
	else if(m_nActiveRow < m_SelRangeCell.m_TopRow)
		m_nActiveRow = m_SelRangeCell.m_TopRow;

	// ������� ��������� � ����������� ��������� ���������� �����
	CRect rectGrid = GetGridRect(rectClient);
	// ���������� �������� ������� � ���� ��������
	int nFirstCol, nLastCol;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToColRange(rectGrid, nFirstCol, nLastCol, TRUE);
	nFirstCol = max(nFirstCol, mPrevSelRangeCell.m_LeftCol);
	nLastCol = min(nLastCol, mPrevSelRangeCell.m_RightCol);
	// ���������� �������� ������� � ���� �����
	int nFirstRow, nLastRow;
	// ���������� ����� ������� � ���������� ����������������� �������
	RectToRowRange(rectGrid, nFirstRow, nLastRow, TRUE);
	nFirstRow = max(nFirstRow, mPrevSelRangeCell.m_TopRow);
	nLastRow = min(nLastRow, mPrevSelRangeCell.m_BottomRow);
	// ������� ���������
	if(!mPrevSelRangeCell.IsEmpty())
		for(int i = nFirstRow; i <= nLastRow; i++)
			for(int j = nFirstCol; j <= nLastCol; j++)
				if(!m_SelRangeCell.InRange(j,i))
					UpdateCell(pDC, j, i);

// ��������
	SetSelectCell(m_nActiveSelCol, m_nActiveSelRow);

//	m_pGridWnd->Invalidate();
	// ����������� �������� ����������
	m_pGridWnd->ReleaseDC(pDC);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
Year of birth - 1974.
Eeducation - was ended by Kaliningrad State University in 1997.
Now I work as the engineer-programmer in Kaliningrad (RUSSIA).

Comments and Discussions