Click here to Skip to main content
15,884,099 members
Articles / Desktop Programming / ATL

ATL Grid control

Rate me:
Please Sign up or sign in to vote.
4.67/5 (16 votes)
6 Feb 2000 396K   54.6K   116  
A grid control for displaying tabular data, based on Chris Maunder's grid control
// Grid.cpp : Implementation of CGrid
//
// ATL Grid Control
//
// Written by Mario Zucca 
//        mailto:mario@GenoaValley.org
//        http://www.GenoaValley.org
//
// Copyright (c) 2000.
//
// The code contained in this file is based on the original
// Grid control written by Chris Maunder,
//        mailto:chris@codeproject.com
//        http://www.codeproject.com
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed unmodified by any means PROVIDING it is 
// not sold for profit without the authors written consent, and 
// providing that this notice and the authors name and all copyright 
// notices remains intact. If the source code in this file is used in 
// any  commercial application then a statement along the lines of 
// "Portions copyright (c) Mario Zucca, 2000" must be included in 
// the startup banner, "About" box or printed documentation. An email 
// letting me know that you are using it would be nice as well. 
//
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability for any damage/loss of business that
// this product may cause.
//
// Expect bugs!
// 
// Please use and enjoy, and let me know of any bugs/mods/improvements 
// that you have found/implemented and I will fix/incorporate them into 
// this file. 
//

#include "stdafx.h"
#include "MemDC.h"

//#include "InPlaceEdit.h"

/////////////////////////////////////////////////////////////////////////////
// CGrid


// Get the number of lines to scroll with each mouse wheel notch
// Why doesn't windows give us this function???
UINT GetMouseScrollLines()
{
    int nScrollLines = 3;            // reasonable default
    HKEY hKey;

    if (RegOpenKeyEx(HKEY_CURRENT_USER,  _T("Control Panel\\Desktop"),
                     0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
    {
        TCHAR szData[128];
        DWORD dwKeyDataType;
        DWORD dwDataBufSize = sizeof(szData);

        if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
                           (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
        {
            nScrollLines = _tcstoul(szData, NULL, 10);
        }
        RegCloseKey(hKey);
    }

    return nScrollLines;
}

STDMETHODIMP CGrid::get_Image(int Row, int Col, short *pVal)
{
	CGridCell* pCell = GetCell(Row,Col);

	if(pCell)
		*pVal = pCell->GetImage();
	else
		*pVal = -1;

	return S_OK;
}

STDMETHODIMP CGrid::put_Image(int Row, int Col, short newVal)
{
	CGridCell* pCell = GetCell(Row,Col);

	if(pCell)
		pCell->SetImage(newVal);
	FireViewChange();
	return S_OK;
}

STDMETHODIMP CGrid::get_Text(int Row, int Col, BSTR *pVal)
{
	CGridCell* pCell = GetCell(Row,Col);

	if(pCell)
	*pVal = pCell->GetText();

	return S_OK;
}

STDMETHODIMP CGrid::put_Text(int Row, int Col, BSTR newVal)
{
	CGridCell* pCell = GetCell(Row,Col);

	if(pCell)
		pCell->put_Text(newVal);
	FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::InsertRow(int Row, BSTR caption)
{
	NewRow(caption,Row);
	FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::get_RowCount(int *pVal)
{
	*pVal = m_nRows;

	return S_OK;
}

STDMETHODIMP CGrid::put_RowCount(int newVal)
{
    ATLASSERT(newVal >= 0);

    if (newVal == m_nRows) return TRUE;

    if (newVal < m_nFixedRows) 
        m_nFixedRows = newVal;

    if (m_idCurrentCell.row >= newVal)
        SetFocusCell(-1,-1);

    int addedRows = newVal - m_nRows;

    // If we are about to lose rows, then we need to delete the GridCell objects 
    // in each column within each row
    if (addedRows < 0) {
        for (int row = newVal; row < m_nRows; row++)
        {
            // Delete cells
            for (int col = 0; col < m_nCols; col++) 
            {
                CGridCell* pCell = GetCell(row, col);
                if (pCell)
				{
//                    pCell->Empty();
		            EmptyCell(pCell, row, col);
                    delete pCell;
                }
            }
            // Delete rows
            GRID_ROW* pRow = m_RowData[row];
            if (pRow) delete pRow;
        }
    }

    // Change the number of rows.
    m_nRows = newVal;
    m_RowData.resize(m_nRows);
    m_arRow.resize(newVal);

    // If we have just added rows, we need toruct new elements for each cell
    // and set the default row height
    if (addedRows > 0) {
        // initialize row heights and data
        int startRow = newVal - addedRows;
        for (int row = startRow; row < newVal; row++) {
            m_arRow[row].Height = m_nDefCellHeight;
            m_RowData[row] = new GRID_ROW;
            m_RowData[row]->resize(m_nCols);
            for (int col = 0; col < m_nCols; col++)
            {
                GRID_ROW* pRow = m_RowData[row];
                if (pRow)
					pRow->at(col) = CreateCell(row, col);
            }
        }
    }
    //else
    //    ResetSelectedRange();
    
    if (m_bAllowDraw && m_hWnd)
    {
        ResetScrollBars();
        FireViewChange();
    }
    return TRUE;

	return S_OK;
}

STDMETHODIMP CGrid::get_ColumnCount(int *pVal)
{
	*pVal = m_nCols;

	return S_OK;
}

STDMETHODIMP CGrid::put_ColumnCount(int newVal)
{
	if (newVal < 0)
		return S_OK;

	if (newVal == m_nCols) return S_OK;

	if (newVal < m_nFixedCols) 
		m_nFixedCols = newVal;

	if (m_idCurrentCell.col >= newVal)
		SetFocusCell(-1,-1);

	int addedCols = newVal - m_nCols;

	// If we are about to lose columns, then we need to delete the GridCell objects 
	// within each column
	if (addedCols < 0) {
		for (int row = 0; row < m_nRows; row++)
			for (int col = newVal; col < m_nCols; col++)
			{
				CGridCell* pCell = GetCell(row, col);
				if (pCell) {
//					pCell->Empty();
		            EmptyCell(pCell, row, col);
					delete pCell;
				}
			}
	}

	// Change the number of columns.
	m_nCols = newVal;
	m_arCol.resize(newVal);

	// Change the number of columns in each row.
	for (int i = 0; i < m_nRows; i++)
		if (m_RowData[i]) m_RowData[i]->resize(newVal);

	// If we have just added columns, we need toruct new elements for each cell
	// and set the default column width
	if (addedCols > 0)
	{
		// initialized column widths
		int startCol = newVal - addedCols;
		for (int col = startCol; col < m_nCols; col++)
			m_arCol[col].Width = m_nDefCellWidth;

		// initialise column data
		for (int row = 0; row < m_nRows; row++)
			for (col = startCol; col < m_nCols; col++)
			{
				GRID_ROW* pRow = m_RowData[row];
				if (pRow) 
					pRow->at(col) = CreateCell(row,col);
			}
	}
	//else    // check for selected cell ranges
	//    ResetSelectedRange();

	if (m_bAllowDraw && m_hWnd)
	{
		ResetScrollBars();
		FireViewChange();
	}

	return S_OK;
}

STDMETHODIMP CGrid::get_RowHeight(int nRow, int *pVal)
{
	*pVal = GetRowHeight(nRow);

	return S_OK;
}

STDMETHODIMP CGrid::put_RowHeight(int nRow, int newVal)
{
	ATLASSERT(nRow >= 0 && nRow < m_nRows && newVal >= 0);
	if (nRow < 0 || nRow >= m_nRows || newVal < 0) return S_OK;

	m_arRow[nRow].Height = newVal;    
	FireViewChange();
	return S_OK;
}

STDMETHODIMP CGrid::get_ColumnWidth(int Col, int *pVal)
{
	*pVal = GetColumnWidth(Col);

	return S_OK;
}

STDMETHODIMP CGrid::put_ColumnWidth(int nCol, int width)
{
//ATLASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
	if (nCol < 0 || nCol >= m_nCols || width < 0) return S_OK;

	m_arCol[nCol].Width = width;
	return TRUE;
	FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::get_CellFont(int Row, int Col, IFontDisp **pVal)
{

	HRESULT hr = S_OK;
	CGridCell* pCell;
	pCell = GetCell(Row,Col);
	if (pCell)
		hr = pCell->get_Font(pVal);

	return hr;
}

STDMETHODIMP CGrid::put_CellFont(int Row, int Col, IFontDisp *newVal)
{
	HRESULT hr = S_OK;

	CGridCell* pCell = GetCell(Row,Col);
	if (pCell)
		hr = pCell->put_Font(newVal);

	return hr;
}

STDMETHODIMP CGrid::AutoSize()
{
	HDC hDC = GetDC();
	if (!hDC) return S_OK;

	int nNumColumns = m_nCols;

	// initialize column widths to zero
	for (int nCol = 0; nCol < nNumColumns; nCol++)
		m_arCol[nCol].Width = 0;

	// initialize row heights to zero
	for (int nRow = 0; nRow < m_nRows; nRow++)
		m_arRow[nRow].Height = 0;

	SIZE size;
	for (nCol = 0; nCol < nNumColumns; nCol++)
		for (nRow = 0; nRow < m_nRows; nRow++)
		{
			size = GetCellExtent(nRow, nCol, hDC);
			if (size.cx > (int) m_arCol[nCol].Width)  m_arCol[nCol].Width = size.cx;
			if (size.cy > (int) m_arRow[nRow].Height) m_arRow[nRow].Height = size.cy;
		}

	ReleaseDC(hDC);

	if (m_bAllowDraw && m_hWnd) {
		ResetScrollBars();
		FireViewChange();
	}

	return S_OK;
}
////////////////////////////////////////////////////////////
// Grid Operations
////////////////////////////////////////////////////////////

HRESULT CGrid::OnDraw(ATL_DRAWINFO& di)
{

		
//	PAINTSTRUCT ps; 
	HDC hdc; 


	RECT rc;
	HDC hdcMem;
	HBITMAP hbmMem, hbmOld;
	//
	// Get the size of the client rectangle
	//
	GetClientRect(&rc);
	CMemDC dc(di.hdcDraw,rc);
	DrawGrid(dc.GetDC(),rc);
	return S_OK;

	hdc = di.hdcDraw; 

	//
	// Create a compatible DC
	//

	hdcMem = CreateCompatibleDC(hdc);

	//
	// Create a bitmap big enough for our client rect
	//

	hbmMem = CreateCompatibleBitmap(hdc,
									rc.right-rc.left,
									rc.bottom-rc.top);

	//
	// Select the bitmap into the off-screen dc
	//

	hbmOld = (HBITMAP) SelectObject(hdcMem, hbmMem);

	DrawGrid(hdcMem,rc);
	//
	// Render the image into the offscreen dc
	//

	SetBkMode(hdcMem, TRANSPARENT);

	//
	// Blit the changes to the screen dc
	//

	BitBlt(hdc, 
		   rc.left, rc.top,
		   rc.right-rc.left, rc.bottom-rc.top,
		   hdcMem,
		   0, 0,
		   SRCCOPY);

	//
	// Done with off screen bitmap and dc
	//

	SelectObject(hdcMem, hbmOld);
	DeleteObject(hbmMem);
	DeleteDC(hdcMem);
//	EndPaint(&ps); 
	return S_OK;
}


// selects columns
void CGrid::SelectColumns(CCellID currentCell)
{
    if (!m_bEnableSelection)
        return;

    //if (currentCell.col == m_idCurrentCell.col) return;
    if (currentCell.col < m_nFixedCols)
        return;
    if (!IsValid(currentCell))
        return;

	int fixedRow;
	get_FixedRows(&fixedRow);

    SetSelectedRange(fixedRow, 
                     min(m_SelectionStartCell.col, currentCell.col), 
                     m_nRows-1,    
                     max(m_SelectionStartCell.col, currentCell.col)); 

}

// selects rows
void CGrid::SelectRows(CCellID currentCell)
{
	int fixedColumn;
	get_FixedCols(&fixedColumn);

    if (!m_bEnableSelection)
        return;

    //if (currentCell.row; == m_idCurrentCell.row) return;
    if (currentCell.row < m_nFixedRows)
        return;
    if (!IsValid(currentCell))
        return;

    if (m_bListMode && GetSingleRowSelection())
        SetSelectedRange(currentCell.row, fixedColumn,
                         currentCell.row, m_nCols-1);
    else 
        SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
                         fixedColumn, 
                         max(m_SelectionStartCell.row, currentCell.row), 
                         m_nCols-1); 

}

// selects cells
void CGrid::SelectCells(CCellID currentCell)
{
    if (!m_bEnableSelection) 
        return;

    int row = currentCell.row;
    int col = currentCell.col;
    if (row < m_nFixedRows || col < m_nFixedCols)
        return;
    if (!IsValid(currentCell))
        return;

    // Prevent unnecessary redraws
    //if (currentCell == m_LeftClickDownCell)  return;
    //else if (currentCell == m_idCurrentCell) return;

    SetSelectedRange(min(m_SelectionStartCell.row, row), 
                     min(m_SelectionStartCell.col, col), 
                     max(m_SelectionStartCell.row, row),
                     max(m_SelectionStartCell.col, col)); 

}

BOOL CGrid::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data, int low, int high)
{
	// Provvisorio sarebbe da usare i template
    if (nCol >= m_nCols) return FALSE;

    if (high == -1) high = m_nRows - 1;

    int lo = low;
    int hi = high;

    if( hi <= lo ) return FALSE;

    LPARAM midItem = GetCell( (lo+hi)/2, nCol )->GetData();

    // loop through the list until indices cross
    while( lo <= hi )
    {
        // Find the first element that is greater than or equal to the partition 
        // element starting from the left Index.
        if( bAscending )
            while (lo < high  && pfnCompare(GetCell(lo, nCol)->GetData(), midItem, data) < 0)
                ++lo;
        else
            while (lo < high && pfnCompare(GetCell(lo, nCol)->GetData(), midItem, data) > 0)
                ++lo;

        // Find an element that is smaller than or equal to  the partition 
        // element starting from the right Index.
        if( bAscending )
            while (hi > low && pfnCompare(GetCell(hi, nCol)->GetData(), midItem, data) > 0)
                --hi;
        else
            while (hi > low && pfnCompare(GetCell(hi, nCol)->GetData(), midItem, data) < 0)
                --hi;

        // If the indexes have not crossed, swap if the items are not equal
        if (lo <= hi)
        {
            // swap only if the items are not equal
            if (pfnCompare(GetCell(lo, nCol)->GetData(), GetCell(hi, nCol)->GetData(), data) != 0)
            {
                for (int col = 0; col < m_nCols; col++)
                {
                    CGridCell *pCell = GetCell(lo, col);
                    SetCell(lo, col, GetCell(hi, col));
                    SetCell(hi, col, pCell);
                }
                UINT nRowHeight = m_arRow[lo].Height;
                m_arRow[lo] = m_arRow[hi];
                m_arRow[hi].Height = nRowHeight;
            }

            ++lo;
            --hi;
        }
    }

    // If the right index has not reached the left side of array
    // must now sort the left partition.
    if( low < hi )
        SortItems(pfnCompare, nCol, bAscending, data, low, hi);

    // If the left index has not reached the right side of array
    // must now sort the right partition.
    if( lo < high )
        SortItems(pfnCompare, nCol, bAscending, data, lo, high);

    return TRUE;

}

BOOL CGrid::SetCell(int nRow, int nCol, CGridCell *pCell)
{
    if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) return FALSE;

    GRID_ROW* pRow = m_RowData[nRow];
    if (!pRow) return FALSE;

    pRow->at(nCol) = pCell;
    return TRUE;

}

BOOL CGrid::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /*= TRUE */)
{
    SCROLLINFO si;
    si.cbSize = sizeof(SCROLLINFO);
    si.fMask  = SIF_POS;
    si.nPos   = nPos;
    return SetScrollInfo(nBar, &si, bRedraw);

}

void CGrid::SetModified(BOOL bModified, int nRow, int nCol)
{
	CGridCell* pCell = GetCell(nRow,nCol);

    if (nRow > 0 && nCol > 0)
    {
        if (bModified)
        {
	        SetItemState(nRow,nCol,
				pCell->GetState() | GVIS_MODIFIED);
            m_bModified = TRUE; 
        }
        else
	        SetItemState(nRow,nCol,
				pCell->GetState() & ~GVIS_MODIFIED);
    }
    else
        m_bModified = bModified;

    if (!m_bModified)
    {
        for (int row = 0; row < m_nRows; row++)
            for (int col = 0; col < m_nCols; col++) 
			{
				pCell = GetCell(nRow,nCol);
				if(pCell)
					SetItemState(nRow,nCol,
						pCell->GetState() & ~GVIS_MODIFIED);
			}
    }

}

/////////////////////////////////////////////////////////////////////////////////////
// GridCtrl cell visibility tests and invalidation/redraw functions

// EnsureVisible supplied by Roelf Werkman
void CGrid::EnsureVisible(int nRow, int nCol)
{
    CCellRange VisibleCells = GetVisibleNonFixedCellRange(NULL);

    int right = nCol - VisibleCells.GetMaxCol();
    int left  = VisibleCells.GetMinCol() - nCol;
    int down  = nRow - VisibleCells.GetMaxRow();
    int up    = VisibleCells.GetMinRow() - nRow;

    while (right > 0)
    {
        SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
        right--;
    }
    while (left > 0)
    {
        SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
        left--;
    }
    while (down > 0)
    {
        SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
        down--;
   }
   while (up > 0)
   {
       SendMessage(WM_VSCROLL, SB_LINEUP, 0);
       up--;
   }

   // Move one more if we only see a snall bit of the cell
   RECT rectCell={0,0,0,0}, rectWindow={0,0,0,0};
   GetCellRect(nRow, nCol, &rectCell);
   GetClientRect(&rectWindow);
   if (rectCell.right > rectWindow.right)
        SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
   if (rectCell.bottom > rectWindow.bottom)
        SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
}

void CGrid::EnsureVisible(CCellID &cell)
{
	EnsureVisible(cell.row, cell.col);
}

void CGrid::OnFixedRowClick(CCellID &cell)
{
	int fixedColumn;
	get_FixedCols(&fixedColumn);

    if (!IsValid(cell)) 
        return;

    if (m_bListMode)
    {
        if (!m_bSortOnClick) 
            return;

        LoadCursor(_Module.m_hInst,IDC_WAIT);
        if (cell.col == m_SortColumn)
            m_bAscending = !m_bAscending;
        else 
        {
            m_bAscending = TRUE;
            m_SortColumn = cell.col;
        }
        SortTextItems(m_SortColumn, m_bAscending);
        FireViewChange();
    } 
    else if (cell.col < fixedColumn) 
    {
        m_MouseMode = MOUSE_SELECT_ALL;
        OnSelecting(cell);
    } 
    else 
    {
        m_MouseMode = MOUSE_SELECT_COL;
        OnSelecting(cell);
    }
   SetCursor(LoadCursor(_Module.m_hInst,IDC_ARROW));
 
}

void CGrid::OnFixedColumnClick(CCellID &cell)
{
    if (!IsValid(cell))
        return;

//    if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
//    {
//        OnEditCell(cell.row, cell.col, VK_LBUTTON);
//        return;
//    }

	int fixedRow;
	get_FixedRows(&fixedRow);

    if (cell.row < fixedRow) 
    {
        m_MouseMode = MOUSE_SELECT_ALL;
        OnSelecting(cell);
    }
    else 
    {
        m_MouseMode = MOUSE_SELECT_ROW;
        OnSelecting(cell);
    }

}

BOOL CGrid::MouseOverColumnResizeArea(POINT point)
{
    if (point.y >= GetFixedRowHeight())
        return FALSE;
    
    CCellID idCurrentCell = GetCellFromPt(point.x,point.y);
    POINT start;
    if (!GetCellOrigin(idCurrentCell, &start)) 
        return FALSE;
    
    int endx = start.x + GetColumnWidth(idCurrentCell.col);
    
    if ((point.x - start.x <= m_nResizeCaptureRange && idCurrentCell.col != 0) || 
        endx - point.x <= m_nResizeCaptureRange)
    {
        return TRUE;
    }
    else
        return FALSE;

}

BOOL CGrid::MouseOverRowResizeArea(POINT point)
{
    if (point.x >= GetFixedColumnWidth())
        return FALSE;
    
    CCellID idCurrentCell = GetCellFromPt(point.x,point.y);
    POINT start;
    if (!GetCellOrigin(idCurrentCell, &start)) 
        return FALSE;
    
    int endy = start.y + GetRowHeight(idCurrentCell.row);
    
    if ((point.y - start.y <= m_nResizeCaptureRange && idCurrentCell.row != 0) || 
        endy - point.y <= m_nResizeCaptureRange)
    {
        return TRUE;
    }
    else
        return FALSE;

}

void CGrid::OnSelecting(const CCellID &currentCell)
{
    if (!m_bEnableSelection) 
        return;

    switch(m_MouseMode)
    {
        case MOUSE_SELECT_ALL:   SelectAllCells();            break;
        case MOUSE_SELECT_COL:   SelectColumns(currentCell);  break;
        case MOUSE_SELECT_ROW:   SelectRows(currentCell);     break;
        case MOUSE_SELECT_CELLS: SelectCells(currentCell);    break;
    }

}

// Sorts on a given column using the cell text
BOOL CGrid::SortTextItems(int nCol, BOOL bAscending)
{
    ResetSelectedRange();
    SetFocusCell(-1,-1);
	int fixedRow;
	get_FixedRows(&fixedRow);

    return SortTextItems(nCol, bAscending, fixedRow,-1);
}

// recursive sort implementation
BOOL CGrid::SortTextItems(int nCol, BOOL bAscending, int low, int high)
{
    if (nCol >= m_nCols) return FALSE;

    if (high == -1) high = m_nRows - 1;

    int lo = low;
    int hi = high;

    if( hi <= lo ) return FALSE;

    _bstr_t midItem = GetCell( (lo+hi)/2, nCol )->GetText();

    // loop through the list until indices cross
    while( lo <= hi )
    {
        // Find the first element that is greater than or equal to the partition 
        // element starting from the left Index.
        if( bAscending )
            while (lo < high  && GetCell(lo, nCol)->GetText() < midItem)
                ++lo;
        else
            while (lo < high && GetCell(lo, nCol)->GetText() > midItem)
                ++lo;

        // Find an element that is smaller than or equal to  the partition 
        // element starting from the right Index.
        if( bAscending )
            while (hi > low && GetCell(hi, nCol)->GetText() > midItem)
                --hi;
        else
            while (hi > low && GetCell(hi, nCol)->GetText() < midItem)
                --hi;

        // If the indexes have not crossed, swap if the items are not equal
        if (lo <= hi)
        {
            // swap only if the items are not equal
            if (GetCell(lo, nCol)->GetText() != GetCell(hi, nCol)->GetText())
            {
                for (int col = 0; col < m_nCols; col++)
                {
                    CGridCell *pCell = GetCell(lo, col);
                    SetCell(lo, col, GetCell(hi, col));
                    SetCell(hi, col, pCell);
                }
                UINT nRowHeight = m_arRow[lo].Height;
                m_arRow[lo].Height = m_arRow[hi].Height;
                m_arRow[hi].Height = nRowHeight;
            }

            ++lo;
            --hi;
        }
    }

    // If the right index has not reached the left side of array
    // must now sort the left partition.
    if( low < hi )
        SortTextItems(nCol, bAscending, low, hi);

    // If the left index has not reached the right side of array
    // must now sort the right partition.
    if( lo < high )
        SortTextItems(nCol, bAscending, lo, high);

    return TRUE;

}

void CGrid::ResetSelectedRange()
{
    SetSelectedRange(-1,-1,-1,-1,FALSE);
    SetFocusCell(-1,-1);
}

// recursive sort implementation
BOOL CGrid::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data)
{
    ResetSelectedRange();
    SetFocusCell(-1,-1);
	int fixedRow;
	get_FixedRows(&fixedRow);

    return SortItems(pfnCompare, nCol, bAscending, data, fixedRow, -1);

}

void CGrid::SetSelectedRange(const CCellRange &Range, 
							 BOOL bForceRepaint /* = FALSE*/ )
{
    SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(), 
                     Range.GetMaxRow(), Range.GetMaxCol(),
                     bForceRepaint);
}

void CGrid::SetSelectedRange(int nMinRow, int nMinCol, 
					  int nMaxRow, int nMaxCol,
					  BOOL bForceRepaint /*= FALSE */)
{
    if (!m_bEnableSelection) return;

    HDC hDC = NULL;
	BOOL flg = FALSE;
    if (bForceRepaint) hDC = ::GetDC(m_hWnd);
    DWORD key;
    CCellID cell;
	CGridCell* pCell;

    // Unselect all previously selected cells
//    for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
	
	selMap::iterator it = m_SelectedCellMap.begin();
	try
	{
    while( it != m_SelectedCellMap.end())
    {
//        m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
		key = it->first;
		cell= it->second;

        // Reset the selection flag on the cell
        if (IsValid(cell))
		{
            pCell = GetCell(cell.row, cell.col);
			SetItemState(cell.row, cell.col, 
                         pCell->GetState() & ~GVIS_SELECTED,&flg);

            // If this is to be reselected, continue on past the redraw
            if (nMinRow <= cell.row && cell.row <= nMaxRow &&
                nMinCol <= cell.col && cell.col <= nMaxCol)
                    ;
			else
            if (bForceRepaint && hDC)                    // Redraw NOW
                RedrawCell(cell.row, cell.col, hDC);
            else
                InvalidateCellRect(cell);                // Redraw at leisure
        }
		if(flg == FALSE)
			it++;
		else
			it = m_SelectedCellMap.begin();

    }
	}
	catch(...)
	{
		;
    }
    // if any previous selected cells are to be retained (eg Ctrl is being held down)
    // then copy them to the newly created list, and mark all these cells as
    // selected
    if (!GetSingleRowSelection())
//    for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
    
	it = m_PrevSelectedCellMap.begin();
	while (	it != m_PrevSelectedCellMap.end())
    {
//        m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
        key = it->first;
		cell = it->second;

        if (IsValid(cell))
		{
			int nState = GetCell(cell.row, cell.col)->GetState();

			// Set state as Selected. This will add the cell to m_SelectedCells[]
			SetItemState(cell.row, cell.col, nState | GVIS_SELECTED,&flg);
			// Redraw (immediately or at leisure)
			if (bForceRepaint && hDC)
				RedrawCell(cell.row, cell.col, hDC);
			else
				InvalidateCellRect(cell);
		}
		if (flg == TRUE)
			it = m_PrevSelectedCellMap.begin();
		else
			++it;
    }

    // Now select all cells in the cell range specified. If the cell has already
    // been marked as selected (above) then ignore it.
    if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
        nMaxRow < m_nRows && nMaxCol < m_nCols &&
         nMinRow <= nMaxRow && nMinCol <= nMaxCol)
    {
        for (int row = nMinRow; row <= nMaxRow; row++)
            for (int col = nMinCol; col <= nMaxCol; col++) 
            {
                int nState = GetCell(row, col)->GetState();
                if (nState & GVIS_SELECTED)
                    continue;    // Already selected - ignore

                // Add to list of selected cells
                CCellID cell(row, col);

                // Set state as Selected. This will add the cell to m_SelectedCells[]
                SetItemState(row, col, nState | GVIS_SELECTED);

                // Redraw (immediately or at leisure)
                if (bForceRepaint && hDC)
                    RedrawCell(row, col, hDC);
                else
                    InvalidateCellRect(cell);
            }
    }
//    TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());

    if (hDC != NULL) 
        ::ReleaseDC(m_hWnd,hDC);

}

void CGrid::OnEditCell(int nRow, int nCol, UINT nChar)
{
    EnsureVisible(nRow, nCol);

    CCellID cell(nRow, nCol);
    if (!IsValid(cell) || !IsCellEditable(nRow, nCol) || !IsCellVisible(nRow, nCol)) 
        return;

    RECT rect;
    if (!GetCellRect(cell, &rect)) return;


/*    GV_ITEM Item;
    Item.mask = GVIF_TEXT | GVIF_FORMAT;
    Item.row = nRow;
    Item.col = nCol;
    if (!GetItem(&Item)) return;

    DWORD dwStyle = ES_LEFT;
    if (Item.nFormat & DT_RIGHT) dwStyle = ES_RIGHT;
    else if (Item.nFormat & DT_CENTER) dwStyle = ES_CENTER;
*/

//    SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT);
/*	VARIANT_BOOL cancel = VARIANT_FALSE;

	Fire_BeforeEdit(nRow,nCol,&cancel);
	if (cancel == VARIANT_TRUE) // Cancel Editing
		return; */
	// Editing the cell
	GetCell(nRow,nCol)->Edit(m_hWnd,&rect,nRow,nCol);
}

///////////////////////////////////////////////////////////////////////////////
// Message Handler
///////////////////////////////////////////////////////////////////////////////
LRESULT CGrid::OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    POINTS point;

	point = MAKEPOINTS(lParam);  // position of cursor 
	int fixedColumn;
	get_FixedCols(&fixedColumn);

	if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) 
    {
        CCellID cell = GetCellFromPt(point.x,point.y);
        ATLASSERT(IsValid(cell));

        POINT start;
        if (!GetCellOrigin(0, cell.col, &start)) return 0;

        if (point.x - start.x <= m_nResizeCaptureRange)     // Clicked right of border
            cell.col--;

        AutosizeColumn(cell.col);
        FireViewChange();
    } 
    else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
    {
        CCellID cell = GetCellFromPt(point.x,point.y);
        ATLASSERT(IsValid(cell));

        POINT start;
        if (!GetCellOrigin(0, cell.col, &start)) return 0;

        if (point.y - start.y <= m_nResizeCaptureRange)     // Clicked below border
            cell.row--;

        AutosizeRow(cell.row);
        FireViewChange();
    }
    else if (m_MouseMode == MOUSE_NOTHING)
    {
        if (m_LeftClickDownCell.row >= m_nFixedRows && 
            IsValid(m_LeftClickDownCell) &&
            m_LeftClickDownCell.col >= m_nFixedCols)
        {
            OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
        }
        else if (m_bListMode)
        {
            CCellID cell = GetCellFromPt(point.x,point.y);
            if (!IsValid(cell)) return 0;
            if (cell.row >= m_nFixedRows && cell.col < fixedColumn)
                OnEditCell(cell.row, cell.col, VK_LBUTTON);
        }
    }

	return 0;
}

LRESULT CGrid::OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    static BOOL bAlreadyInsideThisProcedure = FALSE;
    if (bAlreadyInsideThisProcedure)
        return DefWindowProc(uMsg,wParam,lParam);

    if (!::IsWindow(m_hWnd))
        return DefWindowProc(uMsg,wParam,lParam);;

    // Start re-entry blocking
    bAlreadyInsideThisProcedure = TRUE;

//    if (::IsWindow(GetSafeHwnd()) && GetFocus()->GetSafeHwnd() != GetSafeHwnd()) 
        SetFocus();        // Auto-destroy any InPlaceEdit's

    ResetScrollBars();    

    // End re-entry blocking
    bAlreadyInsideThisProcedure = FALSE;
	return 0;
}

LRESULT CGrid::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	POINT point;
	point.x = LOWORD(lParam);  // X position of cursor 
	point.y = HIWORD(lParam);  // Y position of cursor 

    HWND hOldFocusWnd = ::GetFocus();

    m_LeftClickDownPoint = point;
    m_LeftClickDownCell = GetCellFromPt(point.x,point.y);
    if (!IsValid(m_LeftClickDownCell)) return 0;
	

    m_SelectionStartCell = (wParam & MK_SHIFT)? m_idCurrentCell : m_LeftClickDownCell;

    SetFocus();        // Auto-destroy any InPlaceEdit's

    // If the user clicks on the current cell, then prepare to edit it.
    // (If the user moves the mouse, then dragging occurs)
    if (m_LeftClickDownCell == m_idCurrentCell)
    {
        m_MouseMode = MOUSE_PREPARE_EDIT;
        return 0;
    }   
    else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
             m_MouseMode != MOUSE_OVER_ROW_DIVIDE)        
    {
//        SetFocusCell(-1,-1);
        SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
                     max(m_LeftClickDownCell.col, m_nFixedCols));
    }

#ifndef GRIDCONTROL_NO_DRAGDROP
    // If the user clicks on a selected cell, then prepare to drag it.
    // (If the user moves the mouse, then dragging occurs)
    if (m_bAllowDragAndDrop && hOldFocusWnd == m_hWnd && 
        GetCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col)->GetState()
				& GVNI_SELECTED)
    {
        m_MouseMode = MOUSE_PREPARE_DRAG;
        return 0;
    }
#endif

    SetCapture();

    if (m_MouseMode == MOUSE_NOTHING)
    {
        if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
        {
            if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
            {
                SetCursor(LoadCursor(_Module.m_hInst,IDC_SIZEWE));
                m_MouseMode = MOUSE_OVER_COL_DIVIDE;
            }
        }
        else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
        {
            if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
            {
                SetCursor(LoadCursor(_Module.m_hInst,IDC_SIZENS));
                m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
            }
        }
        //else if (m_MouseMode != MOUSE_NOTHING)
        //{
        //    SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
        //    m_MouseMode = MOUSE_NOTHING;
        //}
    }

    if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
    {
        m_MouseMode = MOUSE_SIZING_COL;
        POINT start;
        if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start)) return 0;

        RECT rect;
        GetClientRect(&rect);

        RECT invertedRect;
		invertedRect.left = point.x;
		invertedRect.top = rect.top;
		invertedRect.right = point.x + 2;
		invertedRect.bottom = rect.bottom;


        HDC hDC = ::GetDC(m_hWnd);
        if (hDC) {
            InvertRect(hDC,&invertedRect);
            ::ReleaseDC(m_hWnd,hDC);
        }

        if (point.x - start.x <= m_nResizeCaptureRange)        // clicked right of border
            if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start)) return 0;

        rect.left = start.x;
        ClientToScreen(&rect);
#ifndef _WIN32_WCE_NO_CURSOR
        ClipCursor(&rect);
#endif
    }
    else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
    {
        m_MouseMode = MOUSE_SIZING_ROW;
        POINT start;
        if (!GetCellOrigin(m_LeftClickDownCell, &start)) return 0;

        RECT rect;
        GetClientRect(&rect);

        RECT invertedRect;
		invertedRect.left = rect.left;
		invertedRect.top = point.y;
		invertedRect.right = rect.right;
		invertedRect.bottom = point.y + 2;

        HDC hDC = ::GetDC(m_hWnd);
        if (hDC) {
            InvertRect(hDC,&invertedRect);
            ::ReleaseDC(m_hWnd,hDC);
        }

        if (point.y - start.y <= m_nResizeCaptureRange)            // clicked below border
            if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start)) return 0;

        rect.top = start.y;
        ClientToScreen(&rect);
#ifndef _WIN32_WCE_NO_CURSOR
        ClipCursor(&rect);
#endif
    }
    else // not sizing or editing -- selecting
    {    
        // If Ctrl pressed, save the current cell selection. This will get added
        // to the new cell selection at the end of the cell selection process
//        m_PrevSelectedCellMap.RemoveAll();
		Fire_SelChanging(); // Fire evnt SelChanging

        m_PrevSelectedCellMap.clear();
        if (wParam & MK_CONTROL) {
//            for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
            for (selMap::iterator it = m_SelectedCellMap.begin();
				it != m_SelectedCellMap.end();
				it++)
            {
                DWORD key;
                CCellID cell;
//                m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
                key = it->first;
				cell= it->second;
//                m_PrevSelectedCellMap[key] = cell;
                m_PrevSelectedCellMap.insert(ValuePair(key,cell));
            }
        }
        
		int fixedRow;
		int fixedColumn;
		get_FixedRows(&fixedRow);
		get_FixedCols(&fixedColumn);

        if (m_LeftClickDownCell.row < fixedRow)
            OnFixedRowClick(m_LeftClickDownCell);
        else if (m_LeftClickDownCell.col < fixedColumn)
            OnFixedColumnClick(m_LeftClickDownCell);
        else
        {
            m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
            OnSelecting(m_LeftClickDownCell);
        }
        m_nTimerID = ::SetTimer(m_hWnd,WM_LBUTTONDOWN, m_nTimerInterval, 0);

    }   
    m_LastMousePoint = point;
	return 0;
}

LRESULT CGrid::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{

	UINT nChar = (UINT) wParam;    // virtual-key code 

    if (!IsValid(m_idCurrentCell)) 
        return 0;

    CCellID next = m_idCurrentCell;
    BOOL bChangeLine = FALSE;

    if (IsCTRLpressed())
    {
        switch (nChar)
        {
           case 'A': SelectAllCells();  break;
#ifndef GRIDCONTROL_NO_CLIPBOARD
//           case 'X': OnEditCut();        break;
//           case 'C': OnEditCopy();       break;
//           case 'V': OnEditPaste();      break;
#endif
        }
    }

    switch (nChar)
    {
        case VK_DELETE: 
            if (IsCellEditable(m_idCurrentCell.row, m_idCurrentCell.col))
            {
				//SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_BEGINLABELEDIT);
				VARIANT_BOOL cancel;
				Fire_BeforeEdit(m_idCurrentCell.row, m_idCurrentCell.col,&cancel);
				if (cancel == VARIANT_TRUE) // Stop editing
					return 0; // Stop Editing
				_bstr_t t = _T("");
                GetCell(m_idCurrentCell.row, m_idCurrentCell.col)->put_Text(t);
                SetModified(TRUE, m_idCurrentCell.row, m_idCurrentCell.col);
 				//SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_ENDLABELEDIT);
				Fire_AfterEdit(m_idCurrentCell.row, m_idCurrentCell.col);
                RedrawCell(m_idCurrentCell);
            }
            break;

        case VK_TAB:    
            if (IsSHIFTpressed())
            {
                if (next.col > m_nFixedCols) 
                    next.col--;
                else if (next.col == m_nFixedCols && next.row > m_nFixedRows) 
                {
                    next.row--; 
                    next.col = m_nCols - 1; 
                    bChangeLine = TRUE;
                }
            }
            else
            {
                if (next.col < (m_nCols - 1)) 
                    next.col++;
                else if (next.col == (m_nCols - 1) && 
                         next.row < (m_nRows - 1) )
                {
                    next.row++; 
                    next.col = m_nFixedCols; 
                    bChangeLine = TRUE;
                }
            } 
            break;

        case VK_DOWN:   
            if (next.row < (m_nRows - 1))
                next.row++; 
            break;            
            
        case VK_UP:     
            if (next.row > m_nFixedRows)           
                next.row--; 
            break;

        case VK_RIGHT:  
            if (next.col < (m_nCols - 1)) 
                next.col++; 
            break;
            
        case VK_LEFT:   
            if (next.col > m_nFixedCols)           
                next.col--; 
            break;

        case VK_NEXT:   
            {
            CCellID idOldTopLeft = GetTopleftNonFixedCell();
            SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
            CCellID idNewTopLeft = GetTopleftNonFixedCell();

            int increment = idNewTopLeft.row - idOldTopLeft.row;
            if (increment) {
                next.row += increment;
                if (next.row > (m_nRows - 1)) 
                    next.row = m_nRows - 1;
            }
            else
                next.row = m_nRows - 1;
                break;
            }
    
            case VK_PRIOR:  
            {
            CCellID idOldTopLeft = GetTopleftNonFixedCell();
            SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
            CCellID idNewTopLeft = GetTopleftNonFixedCell();

            int increment = idNewTopLeft.row - idOldTopLeft.row;
            if (increment) 
            {
                next.row += increment;
                if (next.row < m_nFixedRows) 
                    next.row = m_nFixedRows;
            } else
                next.row = m_nFixedRows;
                break;
            }
    
        case VK_HOME:   
            SendMessage(WM_VSCROLL, SB_TOP, 0);
            next.row = m_nFixedRows;
            break;
        
        case VK_END:    
            SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
            next.row = m_nRows - 1;
            break;
                
        default:
            DefWindowProc(uMsg,wParam,lParam);
    }
  
    if (next != m_idCurrentCell) 
    {
        // While moving with the Cursorkeys the current ROW/CELL will get selected
        // OR Selection will get expanded when SHIFT is pressed
        // Cut n paste from OnLButtonDown - Franco Bez 
        // Added check for NULL mouse mode - Chris Maunder.
        if (m_MouseMode == MOUSE_NOTHING)
        {
//            m_PrevSelectedCellMap.RemoveAll();
            m_PrevSelectedCellMap.clear();
            m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
            if (!IsSHIFTpressed() || nChar == VK_TAB)
                m_SelectionStartCell = next;
            OnSelecting(next);
            m_MouseMode = MOUSE_NOTHING;
        }

        SetFocusCell(next);

        if (!IsCellVisible(next))
        {   
            EnsureVisible(next); // Make sure cell is visible

            switch (nChar) {
                case VK_RIGHT:  
                    SendMessage(WM_HSCROLL, SB_LINERIGHT, 0); 
                    break;

                case VK_LEFT:   
                    SendMessage(WM_HSCROLL, SB_LINELEFT, 0);  
                    break;

                case VK_DOWN:   
                    SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);  
                    break;
                
                case VK_UP:     
                    SendMessage(WM_VSCROLL, SB_LINEUP, 0);    
                    break;                
                
                case VK_TAB:    
                    if (IsSHIFTpressed())
                    {
                        if (bChangeLine) 
                        {
                            SendMessage(WM_VSCROLL, SB_LINEUP, 0);
                            SetScrollPos32(SB_HORZ, m_nHScrollMax);
                            break;
                        }
                        else 
                            SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
                    }
                    else
                    {
                        if (bChangeLine) 
                        {
                            SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
                            SetScrollPos32(SB_HORZ, 0);
                            break;
                        }
                        else 
                            SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
                    }
                    break;

            }
            FireViewChange();
        }
    }
	return 0;
}

LRESULT CGrid::OnChar(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
/////////////////////////
// Provvisorio serve per la creazione di CInPlaceEdit

	UINT nChar = wParam;
	if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING)
    {
        if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
            OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, nChar);
    }
	return 0;
}

LRESULT CGrid::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	UINT nFlags = wParam;
	POINT point;
	POINT p1;
	p1.x = LOWORD(lParam);
	p1.y = HIWORD(lParam);
	
	point = p1;

    RECT rect;
    GetClientRect(&rect);

#ifndef GRIDCONTROL_NO_DRAGDROP
    // If outside client area, return (unless we are drag n dropping)
    if (m_MouseMode != MOUSE_DRAGGING && !::PtInRect(&rect, p1))
        return 0;
#endif

    // If the left mouse button is up, then test to see if row/column sizing is imminent
    if (!(nFlags & MK_LBUTTON) 
        || (m_MouseMode == MOUSE_NOTHING && (nFlags & MK_LBUTTON)))
    {
        if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
        {
            if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
            {
                SetCursor(LoadCursor(NULL,IDC_SIZEWE));
                m_MouseMode = MOUSE_OVER_COL_DIVIDE;
				SetCapture(); // We have to capture the mouse Mario
            }
        }
        else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
        {
            if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
            {
                SetCursor(LoadCursor(NULL,IDC_SIZENS));
                m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
				SetCapture(); // We have to capture the mouse Mario
            }
        }
        else if (m_MouseMode != MOUSE_NOTHING)
        {
            SetCursor(LoadCursor(NULL,IDC_ARROW));
            m_MouseMode = MOUSE_NOTHING;
			ReleaseCapture();
        }

#ifndef GRIDCONTROL_NO_TITLETIPS
        if (m_MouseMode == MOUSE_NOTHING && m_bTitleTips)
        {
            CCellID idCurrentCell = GetCellFromPt(point);
            RECT TextRect, CellRect;
			CGridCell* pCell = GetCell(idCurrentCell.row, idCurrentCell.col);

            if (pCell && GetTextRect(idCurrentCell.row, idCurrentCell.col, &TextRect) &&
                GetCellRect(idCurrentCell.row, idCurrentCell.col, &CellRect))

               m_TitleTip->Show(TextRect, 
                                pCell->GetText(), 
                                0,
                                &CellRect,
                                pCell->GetFont());
        }
#endif

        m_LastMousePoint = point;
        return 0;
    }

    if (!IsValid(m_LeftClickDownCell))
    {
        m_LastMousePoint = point;
        return 0;
    }

    // If the left mouse button is down, then process appropriately
    if (nFlags & MK_LBUTTON) 
    {
        switch(m_MouseMode)
        {
            case MOUSE_SELECT_ALL:        
                break;

            case MOUSE_SELECT_COL:
            case MOUSE_SELECT_ROW:    
            case MOUSE_SELECT_CELLS:    
                {
                    CCellID idCurrentCell = GetCellFromPt(point.x,point.y);
                    if (!IsValid(idCurrentCell)) 
                        return 0;

                    if (idCurrentCell != m_idCurrentCell)
                    {
                        OnSelecting(idCurrentCell);
                        //SetFocusCell(max(idCurrentCell.row, m_nFixedRows),
                        //             max(idCurrentCell.col, m_nFixedCols));
                        if (idCurrentCell.row >= m_nFixedRows &&
                            idCurrentCell.col >= m_nFixedCols)
                        {
                            SetFocusCell(idCurrentCell);
                        }
                    }
                    break;
                }

            case MOUSE_SIZING_COL:   
                {
                    HDC hDC = ::GetDC(m_hWnd);
                    if (!hDC) break;
                    
					RECT oldInvertedRect;
					oldInvertedRect.left =m_LastMousePoint.x;
					oldInvertedRect.top = rect.top;
					oldInvertedRect.right = m_LastMousePoint.x + 2;
					oldInvertedRect.bottom = rect.bottom;

                    InvertRect(hDC,&oldInvertedRect);

					RECT newInvertedRect;
					newInvertedRect.left =point.x;
					newInvertedRect.top = rect.top;
					newInvertedRect.right = point.x + 2;
					newInvertedRect.bottom = rect.bottom;

                    InvertRect(hDC,&newInvertedRect);
                    ::ReleaseDC(m_hWnd,hDC);
                }
                break;
                
            case MOUSE_SIZING_ROW:        
                {
                    HDC hDC = ::GetDC(m_hWnd);
                    if (!hDC) break;
                    
					RECT oldInvertedRect;
					oldInvertedRect.left = rect.left;
					oldInvertedRect.top = m_LastMousePoint.y;
					oldInvertedRect.right = rect.right;
					oldInvertedRect.bottom = m_LastMousePoint.y + 2;


                    InvertRect(hDC,&oldInvertedRect);


					RECT newInvertedRect;
					newInvertedRect.left =rect.left;
					newInvertedRect.top = point.y;
					newInvertedRect.right = rect.right;
					newInvertedRect.bottom = point.y + 2;
                    InvertRect(hDC,&newInvertedRect);

                    ::ReleaseDC(m_hWnd,hDC);
                }
                break;

#ifndef GRIDCONTROL_NO_DRAGDROP
            case MOUSE_PREPARE_DRAG:   
                OnBeginDrag();    
                break;
#endif
        }    
    }

    m_LastMousePoint = point;
	return 0;
}

LRESULT CGrid::OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
    // wheel scrolls whole pages, not just lines.
	short zDelta = (short) HIWORD( wParam); // wheel rotation 
    if (m_nRowsPerWheelNotch == -1)
    {
        int nPagesScrolled = zDelta / 120;

        if (nPagesScrolled > 0)
            for (int i = 0; i < nPagesScrolled; i++)
                PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
        else
            for (int i = 0; i > nPagesScrolled; i--)
                PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
    }
    else
    {
        int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;

        if (nRowsScrolled > 0)
            for (int i = 0; i < nRowsScrolled; i++)
                PostMessage(WM_VSCROLL, SB_LINEUP, 0);
        else
            for (int i = 0; i > nRowsScrolled; i--)
                PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
    }

	return 0;
}

LRESULT CGrid::OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	POINT point;
	point.x = LOWORD(lParam);
	point.y = HIWORD(lParam);

#ifndef _WIN32_WCE_NO_CURSOR
    ClipCursor(NULL);
#endif

    if (GetCapture() == m_hWnd)
    {
        ReleaseCapture();
        KillTimer(m_nTimerID);
        m_nTimerID = 0;
    }

    // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
    // and then didn't move mouse before clicking up (releasing button)
    if (m_MouseMode == MOUSE_PREPARE_EDIT)    
    {
        OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
    }
#ifndef GRIDCONTROL_NO_DRAGDROP
    // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
    // and then didn't move mouse before clicking up (releasing button)
    else if (m_MouseMode == MOUSE_PREPARE_DRAG) 
    {
        ResetSelectedRange();
    }
#endif
    else if (m_MouseMode == MOUSE_SIZING_COL)
    {
        RECT rect;
        GetClientRect(&rect);

        RECT invertedRect;
		invertedRect.left = m_LastMousePoint.x;
		invertedRect.top = rect.top;
		invertedRect.right = m_LastMousePoint.x + 2;
		invertedRect.bottom = rect.bottom;

        HDC hDC = ::GetDC(m_hWnd);
        if (hDC) {
            InvertRect(hDC,&invertedRect);
            ::ReleaseDC(m_hWnd,hDC);
        }

        if ( (m_LeftClickDownPoint.x != point.x) && (m_LeftClickDownPoint.y != point.y)) 
        {   
            POINT start;
            if (!GetCellOrigin(m_LeftClickDownCell, &start)) 
				return DefWindowProc(uMsg,wParam,lParam);

            put_ColumnWidth(m_LeftClickDownCell.col, point.x - start.x);
            ResetScrollBars();
            FireViewChange();
        }
    }
    else if (m_MouseMode == MOUSE_SIZING_ROW)
    {
        RECT rect;
        GetClientRect(&rect);

        RECT invertedRect;
		invertedRect.left = rect.left;
		invertedRect.top = m_LastMousePoint.y;
		invertedRect.right = rect.right;
		invertedRect.bottom = m_LastMousePoint.y + 2;
    
        HDC hDC = GetDC();
        if (hDC)
		{
            InvertRect(hDC,&invertedRect);
            ReleaseDC(hDC);
        }
   
        if ((m_LeftClickDownPoint.x != point.x) && (m_LeftClickDownPoint.y != point.y)) 
        {
            POINT start;
            if (!GetCellOrigin(m_LeftClickDownCell, &start))
				return DefWindowProc(uMsg,wParam,lParam);

            put_RowHeight(m_LeftClickDownCell.row, point.y - start.y);
            ResetScrollBars();
            FireViewChange();
        }
    } 
	else 	// Not sizing ... => end selecting
		Fire_SelChanged();


    m_MouseMode = MOUSE_NOTHING;

//    SetCursor(LoadCursor(_Module.m_hInst,IDC_ARROW));

    if (!IsValid(m_LeftClickDownCell)) 
		return DefWindowProc(uMsg,wParam,lParam);

	return DefWindowProc(uMsg,wParam,lParam);
}

LRESULT CGrid::OnHScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	UINT nSBCode = (int) LOWORD(wParam);  // scroll bar value 
	UINT nPos = (short int) HIWORD(wParam);   // scroll box position 

	int fixedColumn;
	get_FixedCols(&fixedColumn);

    if (GetFocus()!= m_hWnd) 
        SetFocus();  // Auto-destroy any InPlaceEdit's

#ifndef GRIDCONTROL_NO_TITLETIPS
    m_TitleTip->Hide();  // hide any titletips
#endif

    int scrollPos = GetScrollPos32(SB_HORZ);

    CCellID idTopLeft = GetTopleftNonFixedCell();

    RECT rect;
    GetClientRect(&rect);

    switch (nSBCode)
    {
        case SB_LINERIGHT:
            if (scrollPos < m_nHScrollMax)
            {
                int xScroll = GetColumnWidth(idTopLeft.col);
                SetScrollPos32(SB_HORZ, scrollPos + xScroll);
                if (GetScrollPos32(SB_HORZ) == scrollPos) break;          // didn't work

                rect.left = GetFixedColumnWidth() + xScroll;
                ScrollWindow(-xScroll, 0, &rect);
                rect.left = rect.right - xScroll;
                InvalidateRect(&rect);
            }
            break;

        case SB_LINELEFT:
            if (scrollPos > 0 && idTopLeft.col > fixedColumn)
            {
                int xScroll = GetColumnWidth(idTopLeft.col-1);
                SetScrollPos32(SB_HORZ, max(0,scrollPos - xScroll));
                rect.left = GetFixedColumnWidth();
                ScrollWindow(xScroll, 0, &rect);
                rect.right = rect.left + xScroll;
                InvalidateRect(&rect);
            }
            break;

        case SB_PAGERIGHT:
            if (scrollPos < m_nHScrollMax)
            {
                rect.left = GetFixedColumnWidth();
                int offset = rect.right - rect.left;
                int pos = min(m_nHScrollMax, scrollPos + offset);
                SetScrollPos32(SB_HORZ, pos);
                rect.left = GetFixedColumnWidth();
                InvalidateRect(&rect);
            }
            break;

        case SB_PAGELEFT:
            if (scrollPos > 0)
            {
                rect.left = GetFixedColumnWidth();
                int offset = -(rect.right - rect.left);
                int pos = max(0, scrollPos + offset);
                SetScrollPos32(SB_HORZ, pos);
                rect.left = GetFixedColumnWidth();
                InvalidateRect(&rect);
            }
            break;

        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            {
                SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
                CCellID idNewTopLeft = GetTopleftNonFixedCell();
                if (idNewTopLeft != idTopLeft)
                {
                    rect.left = GetFixedColumnWidth();
                    InvalidateRect(&rect);
                }
            }
            break;

        case SB_LEFT:
            if (scrollPos > 0)
            {
                SetScrollPos32(SB_HORZ, 0);
                FireViewChange();
            }
            break;

        case SB_RIGHT:
            if (scrollPos < m_nHScrollMax)
            {
                SetScrollPos32(SB_HORZ, m_nHScrollMax);
                FireViewChange();
            }
            break;


        default: break;
    }
	return 0;
}

LRESULT CGrid::OnVScroll(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
    if (GetFocus() != m_hWnd) 
        SetFocus();        // Auto-destroy any InPlaceEdit's

#ifndef GRIDCONTROL_NO_TITLETIPS
    m_TitleTip->Hide();  // hide any titletips
#endif

    // Get the scroll position ourselves to ensure we get a 32 bit value
    int scrollPos = GetScrollPos32(SB_VERT);

    CCellID idTopLeft = GetTopleftNonFixedCell();

    RECT rect;
    GetClientRect(&rect);

	UINT nSBCode = (int) LOWORD(wParam);  // scroll bar value 
	UINT nPos = (short int) HIWORD(wParam);   // scroll box position 

	int fixedRow;
	get_FixedRows(&fixedRow);

    switch (nSBCode)
    {
        case SB_LINEDOWN:
            if (scrollPos < m_nVScrollMax)
            {
                int yScroll = GetRowHeight(idTopLeft.row);
                SetScrollPos32(SB_VERT, scrollPos + yScroll);
                if (GetScrollPos32(SB_VERT) == scrollPos) 
                    break;          // didn't work

                rect.top = GetFixedRowHeight() + yScroll;
                ScrollWindow( 0, -yScroll, &rect);
                rect.top = rect.bottom - yScroll;
                InvalidateRect(&rect);
            }
            break;

        case SB_LINEUP:
            if (scrollPos > 0 && idTopLeft.row > fixedRow)
            {
                int yScroll = GetRowHeight(idTopLeft.row-1);
                SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
                rect.top = GetFixedRowHeight();
                ScrollWindow(0, yScroll, &rect);
                rect.bottom = rect.top + yScroll;
                InvalidateRect(&rect);
            }
            break;

        case SB_PAGEDOWN:
            if (scrollPos < m_nVScrollMax)
            {
                rect.top = GetFixedRowHeight();
                scrollPos = min(m_nVScrollMax, scrollPos + (rect.bottom - rect.top));
                SetScrollPos32(SB_VERT, scrollPos);
                rect.top = GetFixedRowHeight();
                InvalidateRect(&rect);
            }
            break;

        case SB_PAGEUP:
            if (scrollPos > 0)
            {
                rect.top = GetFixedRowHeight();
                int offset = -(rect.bottom - rect.top);
                int pos = max(0, scrollPos + offset);
                SetScrollPos32(SB_VERT, pos);
                rect.top = GetFixedRowHeight();
                InvalidateRect(&rect);
            }
            break;

        case SB_THUMBPOSITION:
        case SB_THUMBTRACK:
            {
                SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
                CCellID idNewTopLeft = GetTopleftNonFixedCell();
                if (idNewTopLeft != idTopLeft)
                {
                    rect.top = GetFixedRowHeight();
                    InvalidateRect(&rect);
                }
            }
            break;

        case SB_TOP:
            if (scrollPos > 0)
            {
                SetScrollPos32(SB_VERT, 0);
                FireViewChange();
            }
            break;

        case SB_BOTTOM:
            if (scrollPos < m_nVScrollMax)
            {
                SetScrollPos32(SB_VERT, m_nVScrollMax);
                FireViewChange();
            }

        default: break;
    }
		return 0;
}

LRESULT CGrid::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
	UINT nIDEvent = wParam;
    ATLASSERT(nIDEvent == WM_LBUTTONDOWN);
    if (nIDEvent != WM_LBUTTONDOWN)
        return 0;

    POINT pt, origPt;

#ifdef _WIN32_WCE
    if (m_MouseMode == MOUSE_NOTHING)
        return;
    origPt = GetMessagePos();
#else
    if (!GetCursorPos(&origPt))
        return 0;
#endif

    ScreenToClient(&origPt);

    RECT rect;
    GetClientRect(&rect);

    int nFixedRowHeight = GetFixedRowHeight();
    int nFixedColWidth = GetFixedColumnWidth();

    pt = origPt;
    if (pt.y > rect.bottom)
    {
        //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
        SendMessage(WM_KEYDOWN, VK_DOWN, 0);

        if (pt.x < rect.left)  
            pt.x = rect.left;
        if (pt.x > rect.right) 
            pt.x = rect.right;
        pt.y = rect.bottom;
        OnSelecting(GetCellFromPt(pt.x,pt.y));
    }
    else if (pt.y < nFixedRowHeight)
    {
        //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
        SendMessage(WM_KEYDOWN, VK_UP, 0);

        if (pt.x < rect.left)  
            pt.x = rect.left;
        if (pt.x > rect.right) 
            pt.x = rect.right;
        pt.y = nFixedRowHeight + 1;
        OnSelecting(GetCellFromPt(pt.x,pt.y));
    }

    pt = origPt;
    if (pt.x > rect.right)
    {
        // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
        SendMessage(WM_KEYDOWN, VK_RIGHT, 0);

        if (pt.y < rect.top)    
            pt.y = rect.top;
        if (pt.y > rect.bottom) 
            pt.y = rect.bottom;
        pt.x = rect.right;
        OnSelecting(GetCellFromPt(pt.x,pt.y));
    } 
    else if (pt.x < nFixedColWidth)
    {
        //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
        SendMessage(WM_KEYDOWN, VK_LEFT, 0);

        if (pt.y < rect.top)    
            pt.y = rect.top;
        if (pt.y > rect.bottom)
            pt.y = rect.bottom;
        pt.x = nFixedColWidth + 1;
        OnSelecting(GetCellFromPt(pt.x,pt.y));
    }
	return 0;
}

////////////////////////////////////////////////////////////
// End Grid Operations
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Grid Drawing
////////////////////////////////////////////////////////////

BOOL CGrid::RedrawCell(const CCellID &cell, HDC hDC /*= NULL*/)
{
    return RedrawCell(cell.row, cell.col, hDC);
}

BOOL CGrid::RedrawCell(int nRow, int nCol, HDC hDC)
{
	BOOL bResult = TRUE;
    BOOL bMustReleaseDC = FALSE;

    if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
        return FALSE;

    RECT rect;
    if (!GetCellRect(nRow, nCol, &rect)) 
        return FALSE;

    if (!hDC) {
        hDC = ::GetDC(m_hWnd);
        if (hDC)
            bMustReleaseDC = TRUE;
    }

    if (hDC)
    {
        // Redraw cells directly
        if (nRow < m_nFixedRows || nCol < m_nFixedCols)
        {
            bResult = DrawFixedCell(hDC, nRow, nCol, rect, TRUE);
        }
        else
        {
            bResult = 
				GetCell(nRow,nCol)->DrawCell(hDC,
				m_pImageList,
				rect,
				m_crTextBkColour,
				m_crTextColour,
				m_nMargin,
				TRUE);
            
            // Since we have erased the background, we will need to redraw the gridlines
			HPEN pen = CreatePen(PS_SOLID, 0, m_crGridColour);;
			HPEN pOldPen =NULL;
			if(pen)
				HPEN pOldPen = (HPEN) SelectObject(hDC,(HPEN)pen);
			else
				return FALSE;

            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ) 
            {
                MoveToEx(hDC,rect.left, rect.bottom,NULL);
                LineTo(hDC,rect.right+1, rect.bottom);
            }
            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT) 
            {
                MoveToEx(hDC,rect.right, rect.top,NULL);
                LineTo(hDC,rect.right, rect.bottom+1);    
            }
            SelectObject(hDC,pOldPen);
			DeleteObject(pen);
//			DeleteObject(pOldPen);
        }
    } else
        InvalidateRect(&rect, TRUE);     // Could not get a DC - FireViewChange it anyway
                                        // and hope that OnPaint manages to get one

    if (bMustReleaseDC) 
        ::ReleaseDC(m_hWnd,hDC);

    return bResult;
}

BOOL CGrid::DrawFixedCell(HDC hDC, int nRow, int nCol, RECT rect, BOOL bEraseBk)
{
    if (!m_bAllowDraw) 
        return FALSE;
	
/*
    GV_ITEM Item;
    Item.mask = GVIF_TEXT | GVIF_FORMAT | GVIF_IMAGE | GVIF_BKCLR | GVIF_FGCLR;
    Item.row = nRow;
    Item.col = nCol;
    if (!GetItem(&Item))
        return FALSE;
*/
	CGridCell* Item = GetCell(nRow,nCol);
	if (Item== 0)
		return FALSE;

    // Force redraw of background if custom colour
    //if (Item.crBkClr != CLR_DEFAULT)
        bEraseBk = TRUE;

    if (bEraseBk)
    {
        HBRUSH brush;
		brush = CreateSolidBrush((Item->GetCRBkClr() == CLR_DEFAULT)? m_crFixedBkColour : Item->GetCRBkClr());
        FillRect(hDC,&rect, brush);
		DeleteObject(brush);
    }
    ::SetTextColor(hDC,(Item->GetCRFgClr() == CLR_DEFAULT)? m_crFixedTextColour : Item->GetCRFgClr());
    
    int nSavedDC = SaveDC(hDC);
    
    // Create the appropriate font and select into DC
	CGridCell* pCell;
	pCell = GetCell(nRow,nCol);
	LOGFONT cLF;

	if (pCell)
      cLF = *pCell->GetFont();
	else
		cLF = m_Logfont;

    CCellID FocusCell = m_idCurrentCell;

    // if (IsCellFixed(nRow, nCol) && (FocusCell.row == nRow || FocusCell.col == nCol))
    //{
    if (FocusCell.row == nRow || FocusCell.col == nCol)
    {
        static LOGFONT lf;
        memcpy(&lf, &cLF, sizeof(LOGFONT));
        lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
        cLF = lf;
    }
   
    HFONT Font;
    Font = CreateFontIndirect(&cLF);
    SelectObject(hDC,Font);

    if (IsValid(FocusCell) &&  (FocusCell.row == nRow || FocusCell.col == nCol))
    {
        rect.right++; rect.bottom++;
        DrawEdge(hDC,&rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT);
        InflateRect(&rect,-1,-1);
    }
    else
    {
        HPEN lightpen,
             darkpen,
             pOldPen ;

		lightpen = CreatePen(PS_SOLID, 1,  ::GetSysColor(COLOR_3DHIGHLIGHT));
		darkpen = CreatePen(PS_SOLID,  1, ::GetSysColor(COLOR_3DDKSHADOW));
    
		if (lightpen && darkpen)
		{
			pOldPen = (HPEN) SelectObject(hDC,lightpen);
			MoveToEx(hDC,rect.right, rect.top,NULL);
			LineTo(hDC,rect.left, rect.top);
			LineTo(hDC,rect.left, rect.bottom);

			SelectObject(hDC,darkpen);
			MoveToEx(hDC,rect.right, rect.top,NULL);
			LineTo(hDC,rect.right, rect.bottom);
			LineTo(hDC,rect.left, rect.bottom);

			SelectObject(hDC,pOldPen);
			InflateRect(&rect,-1,-1);

			DeleteObject(lightpen);
			DeleteObject(darkpen);
			DeleteObject(pOldPen);
		}
		else
		{
			LPTSTR lpMsgBuf;
			DWORD err = GetLastError();

			FormatMessage( 
				FORMAT_MESSAGE_ALLOCATE_BUFFER,
				NULL,
				err,
				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
				lpMsgBuf,
				0,
				NULL 
			);
			// Process any inserts in lpMsgBuf.
			// ...
			// Display the string.
			ATLTRACE( (LPCTSTR)lpMsgBuf);
			// Free the buffer.
			LocalFree( lpMsgBuf );
		}

    }

    SetBkMode(hDC,TRANSPARENT);
    InflateRect(&rect,-m_nMargin, 0);

    if (m_pImageList && Item->GetImage() >= 0)
    {
        IMAGEINFO Info;
        if (ImageList_GetImageInfo(m_pImageList,Item->GetImage(), &Info))
        {
            //CRgn rgn;
            //rgn.CreateRectRgnIndirect(rect);
            //pDC->SelectClipRgn(&rgn);
            //rgn.DeleteObject();
    
            int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
			
			IMAGELISTDRAWPARAMS iDP;
			iDP.cbSize = sizeof(iDP);
			iDP.cx = 0;
			iDP.cy = 0;
			iDP.dwRop = SRCCOPY ;
			iDP.fStyle = ILD_NORMAL;
			iDP.hdcDst = hDC;
			iDP.himl = m_pImageList;
			iDP.i = Item->GetImage();
			iDP.rgbBk = CLR_DEFAULT;
			iDP.rgbFg = CLR_DEFAULT;
			iDP.x = rect.left;
			iDP.y = rect.top;
			iDP.xBitmap = 0;
			iDP.yBitmap = 0;

            ImageList_DrawIndirect(&iDP);
            rect.left += nImageWidth+m_nMargin;
        }
    }

    DrawText(hDC, Item->GetText(), -1, &rect, Item->GetFormat());

    RestoreDC(hDC,nSavedDC);
    DeleteObject(Font);

    return TRUE;

}

void CGrid::DrawGrid(HDC hDC,RECT rc)
{
    RECT rect;
    int row,col;

    RECT clipRect=rc;

/*    if (GetClipBox(hDC,&clipRect) == ERROR) 
        return;
*/
    EraseBkgnd(hDC,rc);            // OnEraseBkgnd does nothing, so erase bkgnd here.
                                // This necessary since we may be using a Memory DC.

    int nFixedRowHeight = GetFixedRowHeight();
    int nFixedColWidth  = GetFixedColumnWidth();

    CCellID idTopLeft = GetTopleftNonFixedCell();
    int minVisibleRow = idTopLeft.row,
        minVisibleCol = idTopLeft.col;

    RECT VisRect;
    CCellRange VisCellRange = GetVisibleNonFixedCellRange(&VisRect);
    int maxVisibleRow = VisCellRange.GetMaxRow(),
        maxVisibleCol = VisCellRange.GetMaxCol();

    // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
    rect.bottom = -1;
    for (row = 0; row < m_nFixedRows; row++)
    {
        rect.top = rect.bottom+1;
        rect.bottom = rect.top + GetRowHeight(row)-1;
        rect.right = -1;
		if(GetRowHeight(row)>0)
        for (col = 0; col < m_nFixedCols; col++)
        {
            rect.left = rect.right+1;
            rect.right = rect.left + GetColumnWidth(col)-1;  
            
            DrawFixedCell(hDC, row, col, rect,FALSE);
        }
    }
     
    // draw fixed column cells:  m_nFixedRows..n, 0..m_nFixedCols-1
    rect.bottom = nFixedRowHeight-1;
    for (row = minVisibleRow; row <= maxVisibleRow; row++)
    {
        rect.top = rect.bottom+1;
        rect.bottom = rect.top + GetRowHeight(row)-1;

        // rect.bottom = bottom pixel of previous row
        if (rect.top > clipRect.bottom) 
            break;                // Gone past cliprect
        if (rect.bottom < clipRect.top)
            continue;             // Reached cliprect yet?

        rect.right = -1;
 		if(GetRowHeight(row)>0)
		for (col = 0; col < m_nFixedCols; col++)
		{
			rect.left = rect.right+1;
			rect.right = rect.left + GetColumnWidth(col)-1;

			if (rect.left > clipRect.right) 
				break;            // gone past cliprect
			if (rect.right < clipRect.left) 
				continue;         // Reached cliprect yet?

			DrawFixedCell(hDC, row, col, rect,FALSE);
		}
    }
    
    // draw fixed row cells  0..m_nFixedRows, m_nFixedCols..n
    rect.bottom = -1;
    for (row = 0; row < m_nFixedRows; row++)
    {
        rect.top = rect.bottom+1;
        rect.bottom = rect.top + GetRowHeight(row)-1;

        // rect.bottom = bottom pixel of previous row
        if (rect.top > clipRect.bottom) 
            break;                // Gone past cliprect
        if (rect.bottom < clipRect.top) 
            continue;             // Reached cliprect yet?

        rect.right = nFixedColWidth-1;
		if(GetRowHeight(row)>0)
        for (col = minVisibleCol; col <= maxVisibleCol; col++)
        {                                       
            rect.left = rect.right+1;
            rect.right = rect.left + GetColumnWidth(col)-1;

            if (rect.left > clipRect.right)
                break;        // gone past cliprect
            if (rect.right < clipRect.left) 
                continue;     // Reached cliprect yet?

            DrawFixedCell(hDC, row, col, rect,FALSE);
        }
    }
    
    // draw rest of non-fixed cells
    rect.bottom = nFixedRowHeight-1;
    for (row = minVisibleRow; row <= maxVisibleRow; row++)
    {
        rect.top = rect.bottom+1;
        rect.bottom = rect.top + GetRowHeight(row)-1;

        // rect.bottom = bottom pixel of previous row
        if (rect.top > clipRect.bottom) 
            break;                // Gone past cliprect
        if (rect.bottom < clipRect.top) 
            continue;             // Reached cliprect yet?

        rect.right = nFixedColWidth-1;
		if(GetRowHeight(row)>0)
        for (col = minVisibleCol; col <= maxVisibleCol; col++)
        {
            rect.left = rect.right+1;
            rect.right = rect.left + GetColumnWidth(col)-1;

            if (rect.left > clipRect.right)
                break;        // gone past cliprect
            if (rect.right < clipRect.left) 
                continue;     // Reached cliprect yet?

			GetCell(row,col)->DrawCell(hDC,
				m_pImageList,
				rect,
				m_crTextBkColour,
				m_crTextColour,
				m_nMargin,
				FALSE);
            //DrawCell(hDC, row, col, rect,FALSE);
        }
    }


	HPEN pen = CreatePen(PS_SOLID, 0, m_crGridColour);
	if (pen != NULL)
		SelectObject(hDC,(HPEN)pen);

    // draw vertical lines (drawn at ends of cells)
    if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT) 
    {
        int x = nFixedColWidth;
        for (col = minVisibleCol; col <= maxVisibleCol; col++) {
            x += GetColumnWidth(col);
            MoveToEx(hDC,x-1, nFixedRowHeight,NULL);
            LineTo(hDC,x-1, VisRect.bottom);   
        }
    }
    
    // draw horizontal lines (drawn at bottom of each cell)
    if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ) 
    {
        int y = nFixedRowHeight;
        for (row = minVisibleRow; row <= maxVisibleRow; row++) {
            y += GetRowHeight(row);
            MoveToEx(hDC,nFixedColWidth, y-1,NULL);    
            LineTo(hDC,VisRect.right,  y-1);
        }
    }

    SelectObject(hDC,
		GetStockObject(WHITE_PEN));

	//		CreatePen(PS_NULL,0,NULL));
	DeleteObject(pen);
}

////////////////// ERASE BACKGROUND //////////////////
void CGrid::EraseBkgnd(HDC hDC,RECT rc)
{

    RECT  VisRect, ClipRect, rect;

    HBRUSH FixedBack,
           TextBack,
           Back;

	FixedBack = CreateSolidBrush(m_crFixedBkColour);
	TextBack = CreateSolidBrush(m_crTextBkColour);
	Back = CreateSolidBrush(m_crBkColour);

/*    if (GetClipBox(hDC,&ClipRect) == ERROR) 
        return;
*/
	ClipRect = rc;

    GetVisibleNonFixedCellRange(&VisRect);

    // Draw Fixed columns background
    int nFixedColumnWidth = GetFixedColumnWidth();
    
	if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
	{
		RECT recF;
		recF.left =ClipRect.left;
		recF.top = ClipRect.top;
		recF.right = nFixedColumnWidth;
		recF.bottom = VisRect.bottom;

        FillRect(hDC,&recF,FixedBack);
	}
        
    // Draw Fixed rows background
    int nFixedRowHeight = GetFixedRowHeight();
    if (ClipRect.top < nFixedRowHeight && 
        ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
	{
        RECT recF;
		recF.left =nFixedColumnWidth-1;
		recF.top = ClipRect.top;
		recF.right = VisRect.right;
		recF.bottom = nFixedRowHeight;
		
		FillRect(hDC,&recF,FixedBack);
	}
    // Draw non-fixed cell background
    if (IntersectRect(&rect,&VisRect, &ClipRect)) 
    {
        RECT CellRect;
		CellRect.left=max(nFixedColumnWidth, rect.left);
		CellRect.top=max(nFixedRowHeight, rect.top);
		CellRect.right=rect.right;
		CellRect.bottom=rect.bottom;

        FillRect(hDC,&CellRect, TextBack);
    }

    // Draw right hand side of window outside grid
    if (VisRect.right < ClipRect.right) 
	{
		RECT recF;
		recF.left =VisRect.right;
		recF.top = ClipRect.top;
		recF.right = ClipRect.right;
		recF.bottom = ClipRect.bottom;

        FillRect(hDC,&recF,Back);
	}

    // Draw bottom of window below grid
    if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right) 
	{
		RECT recF;
		recF.left =ClipRect.left;
		recF.top = VisRect.bottom;
		recF.right = VisRect.right;
		recF.bottom = ClipRect.bottom;
        FillRect(hDC,&recF,Back);
	}
	DeleteObject(FixedBack);
	DeleteObject(TextBack);
	DeleteObject(Back);
}

BOOL CGrid::InvalidateCellRect(const CCellID &cell)
{
    if (!::IsWindow(m_hWnd) || !m_bAllowDraw)
        return FALSE;

    ATLASSERT(IsValid(cell));

    if (!IsCellVisible(cell.row, cell.col)) return FALSE;

    RECT rect;
    if (!GetCellRect(cell, &rect)) return FALSE;
    rect.right++; rect.bottom++;
    InvalidateRect(&rect, TRUE);

    return TRUE;

}

BOOL CGrid::InvalidateCellRect(const CCellRange &cellRange)
{
    ATLASSERT(IsValid(cellRange));
    if (!::IsWindow(m_hWnd) || !m_bAllowDraw) return FALSE;

    CCellRange visibleCellRange = GetVisibleNonFixedCellRange(NULL).Intersect(cellRange);

    RECT rect;
    if (!GetCellRangeRect(visibleCellRange, &rect)) return FALSE;

    rect.right++; rect.bottom++;
    InvalidateRect(&rect, TRUE);

    return TRUE;

}

////////////////////////////////////////////////////////////
// End Grid Drawing
////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////
// Grid Attributes
////////////////////////////////////////////////////////////

// Creates a new grid cell and performs any necessary initialisation
// Provvisorio deve farlo la cella.
CGridCell* CGrid::CreateCell(int nRow, int nCol)
{
    CGridCell* pCell = new CComObject<CGridCell>;
    if (!pCell)
        return NULL;
    
    pCell->AddRef();
	pCell->SetParent(this);

    // Make format same as cell above
    if (nRow > 0 && nCol >= 0 && nCol < m_nCols)
        pCell->SetFormat(GetCell(nRow-1, nCol)->GetFormat());
 
    // Make font default grid font
    pCell->put_Font(m_pFont);
    
    return pCell;

}

CCellID CGrid::SetFocusCell(int nRow, int nCol)
{
    return SetFocusCell(CCellID(nRow, nCol));
}

CCellID CGrid::SetFocusCell(CCellID cell)
{
    if (cell == m_idCurrentCell) 
        return m_idCurrentCell;

    CCellID idPrev = m_idCurrentCell;
    m_idCurrentCell = cell;

    if (IsValid(idPrev)) 
    {
//        SendMessageToParent(idPrev.row, idPrev.col, GVN_SELCHANGING);
		CGridCell* pCell = GetCell(idPrev.row,idPrev.col);
		if (pCell)
			pCell->SetState(pCell->GetState() & ~GVIS_FOCUSED);

		EnsureVisible(cell);

    if (IsValid(m_idCurrentCell)) //{
        SetItemState(m_idCurrentCell.row, m_idCurrentCell.col, 
                     GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
/*        RedrawCell(idPrev,NULL); ???? Serve ???

        if (idPrev.col != m_idCurrentCell.col)
            for (int row = 0; row < m_nFixedRows; row++)
//???                RedrawCell(row, idPrev.col,NULL);
        if (idPrev.row != m_idCurrentCell.row)
            for (int col = 0; col < m_nFixedCols; col++) 
//???                RedrawCell(idPrev.row, col,NULL);
    }

    if (IsValid(m_idCurrentCell)) {
        SetItemState(m_idCurrentCell.row, m_idCurrentCell.col, 
                     GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);

//???        RedrawCell(m_idCurrentCell,NULL);

        if (idPrev.col != m_idCurrentCell.col)
            for (int row = 0; row < m_nFixedRows; row++) 
                RedrawCell(row, m_idCurrentCell.col,NULL);
        if (idPrev.row != m_idCurrentCell.row)
            for (int col = 0; col < m_nFixedCols; col++) 
                RedrawCell(m_idCurrentCell.row, col,NULL);

//        SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED); 
    
*/
	
	}
	FireViewChange();
    return idPrev;

}

void CGrid::ResetScrollBars()
{
	if (!m_bAllowDraw || !::IsWindow(m_hWnd)) 
		return;

	RECT rect;
	GetClientRect(&rect);
	rect.left  += GetFixedColumnWidth();
	rect.top   += GetFixedRowHeight();
	if (rect.left >= rect.right || rect.top >= rect.bottom) return;

	RECT VisibleRect;
		VisibleRect.left =GetFixedColumnWidth();
		VisibleRect.top = GetFixedRowHeight();
		VisibleRect.right = rect.right;
		VisibleRect.bottom = rect.bottom;

	RECT VirtualRect;
		VirtualRect.left =GetFixedColumnWidth();
		VirtualRect.top = GetFixedRowHeight();
		VirtualRect.right = GetVirtualWidth();
		VirtualRect.bottom = GetVirtualHeight();


	CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
	if (!IsValid(visibleCells)) return;

	SCROLLINFO si;
	si.cbSize = sizeof(SCROLLINFO);
	si.fMask  = SIF_PAGE;
	si.nPage  = VisibleRect.right - VisibleRect.left;    SetScrollInfo(SB_HORZ, &si, FALSE); 
	si.nPage  = VisibleRect.bottom - VisibleRect.top;   SetScrollInfo(SB_VERT, &si, FALSE); 

	if ((VisibleRect.bottom - VisibleRect.top) < (VirtualRect.bottom - VirtualRect.top))
		m_nVScrollMax = (VirtualRect.bottom - VirtualRect.top)-1; //+ GetRowHeight(visibleCells.GetTopLeft().row);
	else
		m_nVScrollMax = 0;

	if ((VisibleRect.right - VisibleRect.left) < (VirtualRect.right - VirtualRect.left))
		m_nHScrollMax = VirtualRect.right - VirtualRect.left-1; //+ GetColumnWidth(visibleCells.GetTopLeft().col);
	else
		m_nHScrollMax = 0;

	ATLASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine :)
	SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
	SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);

}

SIZE CGrid::GetTextExtent(LPCTSTR str, BOOL bUseSelectedFont /*  = TRUE*/)
{
	HDC pDC = GetDC();

	SIZE size = {0,0};
	if (!pDC) return size;

	HFONT pOldFont, font;

	if (bUseSelectedFont)
	{
		LOGFONT lf;
		memcpy(&lf, &m_Logfont, sizeof(LOGFONT));
		lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
        
		font = CreateFontIndirect(&lf);

		pOldFont = (HFONT) SelectObject(pDC,font);
	}
	else
		pOldFont = (HFONT) SelectObject(pDC,m_Font);

	::GetTextExtentPoint32(pDC,
			   str, strlen(str), &size);

	SelectObject(pDC,pOldFont);
	ReleaseDC(pDC);
	size.cx += 2*m_nMargin;
	size.cy += 2*m_nMargin;

	return size;

}

////////////////////////////////////////////////////////////////////////////////////
// Row/Column count functions
int CGrid::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE*/)
{
	SCROLLINFO si;
	si.cbSize = sizeof(SCROLLINFO);

	if (bGetTrackPos)
	{
		si.fMask = SIF_TRACKPOS;
		if (GetScrollInfo(nBar, &si))
			return si.nTrackPos;
	}
	else 
	{
		si.fMask = SIF_POS;
		if (GetScrollInfo(nBar, &si))
			return si.nPos;
	}

	return 0;

}

SIZE CGrid::GetCellExtent(int nRow, int nCol, HDC hDC)
{
	CGridCell* pCell;
	pCell = GetCell(nRow,nCol);
	LOGFONT cLF;

	if (pCell)
      cLF = *pCell->GetFont();
	else
		cLF = m_Logfont;
    
    // use selected font since it's thicker   
    LOGFONT lf;
    memcpy(&lf, &cLF, sizeof(LOGFONT));
    
    if (nRow < m_nFixedRows || nCol < m_nFixedCols)
        lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
            
    HFONT font;
    font = CreateFontIndirect(&lf);
    
    HFONT pOldFont = (HFONT) SelectObject(hDC,font);

	SIZE size;
	LPCTSTR lpString;
	SIZE ret;

	lpString = (const char*) pCell->GetText();
	int len = 0;
	if(lpString)
		len = strlen(lpString);
	//VERIFY(
	BOOL bval = ::GetTextExtentPoint32(hDC,
		lpString,
		len,
		&size);
	if(bval == 0)
	{
		ret.cx = 0;
		ret.cy = 0;
		return ret;
	}

    SelectObject(hDC,pOldFont);

    size.cx += 4*m_nMargin;
	size.cy += 2*m_nMargin;

    SIZE ImageSize = {0,0};
    if (m_pImageList) {
        int nImage = pCell->GetImage();
        if (nImage >= 0) {
            IMAGEINFO Info;
            if (ImageList_GetImageInfo(m_pImageList,nImage, &Info))
                ImageSize.cx = Info.rcImage.right-Info.rcImage.left+1;
				ImageSize.cy = Info.rcImage.bottom-Info.rcImage.top+1;
        }
    }
    SIZE sz={0,0};
	if (pCell)
		sz = pCell->GetPictureSize();
		
	ret.cx = size.cx + ImageSize.cx + sz.cx;
	ret.cy = max(size.cy, ImageSize.cy);
	ret.cy = max(ret.cy,sz.cy);

	DeleteObject(font);
    return ret;
}

BOOL CGrid::GetCellRangeRect(const CCellRange &cellRange, LPRECT lpRect)
{
    POINT MinOrigin,MaxOrigin;

    if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin)) 
        return FALSE;
    if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin)) 
        return FALSE;

    lpRect->left   = MinOrigin.x;
    lpRect->top    = MinOrigin.y;
    lpRect->right  = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()-1);
    lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()-1);

    return TRUE;
}

CCellID CGrid::GetTopleftNonFixedCell()
{
    int nVertScroll = GetScrollPos(SB_VERT), 
		nHorzScroll = GetScrollPos(SB_HORZ);

    int nColumn = m_nFixedCols, nRight = 0;
    while (nRight < nHorzScroll && nColumn < (m_nRows-1))
        nRight += GetColumnWidth(nColumn++);

    int nRow = m_nFixedRows, nTop = 0;
    while (nTop < nVertScroll && nRow < (m_nRows-1))
        nTop += GetRowHeight(nRow++);

    //TRACE("TopLeft cell is row %d, col %d\n",nRow, nColumn);
    return CCellID(nRow, nColumn);

}

// This gets even partially visible cells
CCellRange CGrid::GetVisibleNonFixedCellRange(LPRECT pRect)
{
    RECT rect;
    GetClientRect(&rect);

    CCellID idTopLeft = GetTopleftNonFixedCell();

    // calc bottom
    int bottom = GetFixedRowHeight();
    for (int i = idTopLeft.row; i < m_nRows; i++)
    {
        bottom += GetRowHeight(i);
        if (bottom >= rect.bottom) {
            bottom = rect.bottom;
            break;
        }
    }                                
    int maxVisibleRow = min(i, m_nRows - 1);
    
    // calc right
    int right = GetFixedColumnWidth();
    for (i = idTopLeft.col; i < m_nCols; i++)
    {
        right += GetColumnWidth(i);
        if (right >= rect.right) {
            right = rect.right;
            break;
        }
    }
    int maxVisibleCol = min(i, m_nCols - 1);
    if (pRect) {
        pRect->left = pRect->top = 0;
        pRect->right = right;
        pRect->bottom = bottom;
    }

    return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
}

BOOL CGrid::IsCellVisible(CCellID cell)
{
    return IsCellVisible(cell.row, cell.col);

}

BOOL CGrid::IsCellVisible(int nRow, int nCol)
{
    if (!::IsWindow(m_hWnd))
        return FALSE;

    int x,y;

 	int fixedRow;
	int fixedColumn;
	get_FixedRows(&fixedRow);
	get_FixedCols(&fixedColumn);

   CCellID TopLeft;
    if (nCol >= fixedColumn || nRow >= fixedRow)
    {
        TopLeft = GetTopleftNonFixedCell();
        if (nCol >= fixedColumn && nCol < TopLeft.col) return FALSE;
        if (nRow >= fixedRow && nRow < TopLeft.row) return FALSE;
    }

    RECT rect;
    GetClientRect(&rect);
    if (nCol < fixedColumn)
    {
        x = 0;
        for (int i = 0; i <= nCol; i++) 
        {
            if (x >= rect.right) return FALSE;
            x += GetColumnWidth(i);    
        }
    } 
    else 
    {
        x = GetFixedColumnWidth();
        for (int i = TopLeft.col; i <= nCol; i++) 
        {
            if (x >= rect.right) return FALSE;
            x += GetColumnWidth(i);    
        }
    }

    if (nRow < fixedRow)
    {
        y = 0;
        for (int i = 0; i <= nRow; i++) 
        {
            if (y >= rect.bottom) return FALSE;
            y += GetRowHeight(i);    
        }
    } 
    else 
    {
        if (nRow < TopLeft.row) return FALSE;
        y = GetFixedRowHeight();
        for (int i = TopLeft.row; i <= nRow; i++) 
        {
            if (y >= rect.bottom) return FALSE;
            y += GetRowHeight(i);    
        }
    }

    return TRUE;
}

BOOL CGrid::GetCellOrigin(int nRow, int nCol, LPPOINT p)
{
    int i;

    if (!IsValid(nRow, nCol)) return FALSE;

    CCellID idTopLeft;
    if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
        idTopLeft = GetTopleftNonFixedCell();

    if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
        (nCol>= m_nFixedCols && nCol < idTopLeft.col))
        return FALSE;

    p->x = 0;
    if (nCol < m_nFixedCols)                      // is a fixed column
        for (i = 0; i < nCol; i++)
            p->x += GetColumnWidth(i);
    else {                                        // is a scrollable data column
        for (i = 0; i < m_nFixedCols; i++)
            p->x += GetColumnWidth(i);
        for (i = idTopLeft.col; i < nCol; i++)
            p->x += GetColumnWidth(i);
    }

    p->y = 0;
    if (nRow < m_nFixedRows)                      // is a fixed row
        for (i = 0; i < nRow; i++)
            p->y += GetRowHeight(i);
    else {                                        // is a scrollable data row
        for (i = 0; i < m_nFixedRows; i++)
            p->y += GetRowHeight(i);
        for (i = idTopLeft.row; i < nRow; i++)
            p->y += GetRowHeight(i);
    }

    return TRUE;
}

BOOL CGrid::GetCellOrigin(const CCellID &cell, LPPOINT p)
{
    return GetCellOrigin(cell.row, cell.col, p);
}

BOOL CGrid::GetCellRect(const CCellID &cell, LPRECT pRect)
{
    return GetCellRect(cell.row, cell.col, pRect);

}

BOOL CGrid::GetCellRect(int nRow, int nCol, LPRECT pRect)
{
    POINT CellOrigin;
    if (!GetCellOrigin(nRow, nCol, &CellOrigin)) return FALSE;

    pRect->left   = CellOrigin.x;
    pRect->top    = CellOrigin.y;
    pRect->right  = CellOrigin.x + GetColumnWidth(nCol)-1;
    pRect->bottom = CellOrigin.y + GetRowHeight(nRow)-1;

    //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d:  %d,%d - %d,%d\n",
    //      nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
    //      pRect->left, pRect->top, pRect->right, pRect->bottom);

    return TRUE;
}

BOOL CGrid::IsCellEditable(CCellID &cell)
{
    return IsCellEditable(cell.row, cell.col); 
}

BOOL CGrid::IsCellEditable(int nRow, int nCol)
{
	VARIANT_BOOL IsEditable;
	CGridCell* pCell = GetCell(nRow,nCol);

	get_Editable(&IsEditable);
	if(pCell)
		return IsEditable && ((pCell->GetState() & GVIS_READONLY) != GVIS_READONLY);
	else
		return IsEditable;
}

// used by ResetScrollBars() - This gets only fully visible cells
CCellRange CGrid::GetUnobstructedNonFixedCellRange()
{
	RECT rect;
	GetClientRect(&rect);

	CCellID idTopLeft = GetTopleftNonFixedCell();

	// calc bottom
	int bottom = GetFixedRowHeight();
	for (int i = idTopLeft.row; i < m_nRows; i++)
	{
		bottom += GetRowHeight(i);
		if (bottom >= rect.bottom) break;
	}
	int maxVisibleRow = min(i, m_nRows - 1);
	if (maxVisibleRow > 0 && bottom > rect.bottom) maxVisibleRow--;

	// calc right
	int right = GetFixedColumnWidth();
	for (i = idTopLeft.col; i < m_nCols; i++)
	{
		right += GetColumnWidth(i);
		if (right >= rect.right) break;
	}
	int maxVisibleCol = min(i, m_nCols - 1);
	if (maxVisibleCol > 0 && right > rect.right) maxVisibleCol--;


	return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
}

CCellID CGrid::GetCellFromPt(long x,long y,
					  BOOL bAllowFixedCellCheck /*= TRUE*/)
{
	// Modified to adapt to POINTS e POINT

    CCellID idTopLeft = GetTopleftNonFixedCell();
    CCellID cellID; // return value

    // calculate column index
    int fixedColWidth = GetFixedColumnWidth();

    if (x < 0 || (!bAllowFixedCellCheck && x < fixedColWidth)) // not in window
        cellID.col = -1;
    else if (x < fixedColWidth) // in fixed col
    {
        int xpos = 0;
        for (int col = 0; col < m_nFixedCols; col++)
        {
            xpos += GetColumnWidth(col);
            if (xpos > x) break;
        }
        cellID.col = col;
    }
    else    // in non-fixed col
    {
        int xpos = fixedColWidth;
        for (int col = idTopLeft.col; col < m_nCols; col++)
        {
            xpos += GetColumnWidth(col);
            if (xpos > x) break;
        }

        if (col >= m_nCols)
            cellID.col = -1;
        else
            cellID.col = col;
    }
    
    // calculate row index
    int fixedRowHeight = GetFixedRowHeight();
    if (y < 0 || (!bAllowFixedCellCheck && y < fixedRowHeight)) // not in window
        cellID.row = -1;
    else if (y < fixedRowHeight) // in fixed col
    {
        int ypos = 0;
        for (int row = 0; row < m_nFixedRows; row++)
        {
            ypos += GetRowHeight(row);
            if (ypos > y) break;
        }
        cellID.row = row;
    }
    else
    {
        int ypos = fixedRowHeight;
        for (int row = idTopLeft.row; row < m_nRows; row++)
        {
            ypos += GetRowHeight(row);
            if (ypos > y) break;
        }

        if (row >= m_nRows)
            cellID.row = -1;
        else
            cellID.row = row;
    }

    return cellID;
}
/*
BOOL CGrid::SetFont(LOGFONT lf)
{

    // Store font as the global default
    memcpy(&m_Logfont, &lf, sizeof(LOGFONT));

    // reset all cells' fonts
    for (int row = 0; row < m_nRows; row++)
        for (int col = 0; col < m_nCols; col++)
            GetCell(row, col)->SetFont(lf);

    // Get the font size and hence the default cell size
	if (m_hWnd == NULL)
		return TRUE;
    HDC hDC = GetDC();
    if (hDC) 
    {
		if (m_Font)
			DeleteObject(m_Font);
        m_Font=CreateFontIndirect(&m_Logfont);
        HFONT pOldFont = (HFONT) SelectObject(hDC,m_Font);
        
        TEXTMETRIC tm;
        GetTextMetrics(hDC,&tm);
        
		SIZE size;
		::GetTextExtentPoint32(hDC, _T(" "), 1, &size);

        m_nMargin = size.cx;
        SelectObject(hDC,pOldFont);
        ReleaseDC(hDC);

        m_nDefCellHeight = tm.tmHeight+tm.tmExternalLeading + 2*m_nMargin;
        m_nDefCellWidth  = tm.tmAveCharWidth*12 + 2*m_nMargin;
    }

    if (m_hWnd) 
        FireViewChange();

    return TRUE;

}
*/
int CGrid::NewRow(_bstr_t strHeading, int nRow)
{
    // If the insertion is for a specific row, check it's within range.
    if (nRow >= 0 && nRow >= m_nRows)
        return -1;

//??    ResetSelectedRange();

    // Gotta be able to at least _see_ some of the row.
    if (m_nCols < 1) 
        put_ColumnCount(1);    

    // Adding a row to the bottom
	if (nRow<0)
		nRow = m_nRows;
    m_nRows++;
	
//	m_arRow.resize(m_nRows);
	m_RowData.insert(
		m_RowData.begin()+nRow);

	m_arRow.insert(
		m_arRow.begin()+nRow);

    m_RowData[nRow]= new GRID_ROW;
    
    m_RowData[nRow]->resize(m_nCols);

    // Initialise cell data
    for (int col = 0; col < m_nCols; col++)
    {
        GRID_ROW* pRow = m_RowData[nRow];
        if (!pRow) return -1;
        pRow->at(col) = CreateCell(nRow, col);
    }

    // Set row title
    GetCell(nRow, 0)->put_Text(strHeading);

    // initialized row height
    m_arRow[nRow].Height = GetTextExtent(strHeading).cy;

    if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
        m_idCurrentCell.row++;
    
    ResetScrollBars();

    return nRow;
}

long CGrid::GetVirtualWidth()
{
	long lVirtualWidth = 0;
	int iColCount = m_nCols;
	for (int i = 0; i < iColCount; i++)
		lVirtualWidth += m_arCol[i].Width;

	return lVirtualWidth;
}

long CGrid::GetVirtualHeight()
{
	long lVirtualHeight = 0;

	for (int i = 0; i < m_nRows; i++)
		lVirtualHeight += m_arRow[i].Height;

	return lVirtualHeight;
}

int CGrid::GetFixedRowHeight()
{
	int nHeight = 0;
	for (int i = 0; i < m_nFixedRows; i++)
		nHeight += GetRowHeight(i);

	return nHeight;
}

BOOL CGrid::IsValid(int nRow, int nCol)
{
	return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
}

BOOL CGrid::IsValid(const CCellID &cell)
{
	return IsValid(cell.row, cell.col);
}

BOOL CGrid::IsValid(const CCellRange &range)
{
	 return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 && 
			range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
			range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
			 range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
}

BOOL CGrid::SetItemState(int nRow, int nCol, UINT state, BOOL* itInv /*= NULL*/) // Indica se l'iteratore delle celle selezionate viene o meno invalidato
{
	// itInv vale TRUE se cancello l'elemento e quindi invalido
	// l'iteratore 

    CGridCell* pCell = GetCell(nRow, nCol);
    ATLASSERT(pCell);

	if (itInv)
		*itInv = FALSE;
    if (!pCell)
        return FALSE;

    // If the cell is being unselected, remove it from the selected list
    if ((pCell->GetState() & GVIS_SELECTED) && !(state & GVIS_SELECTED))
    {
        CCellID cell;
        DWORD key = MAKELONG(nRow, nCol);

//        if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
		selMap::iterator it = m_SelectedCellMap.find(key);

        if (it != m_SelectedCellMap.end())
		{
            m_SelectedCellMap.erase(it); //Invalida l'iteratore
			if (itInv)
				*itInv=TRUE;
		}
    }

    // If cell is being selected, add it to the list of selected cells
    else if (!(pCell->GetState() & GVIS_SELECTED) && (state & GVIS_SELECTED))
    {
        CCellID cell(nRow, nCol);
        m_SelectedCellMap.insert(ValuePair(MAKELONG(nRow, nCol), cell));
		if (itInv)
			*itInv=TRUE;
    }

    // Set the cell's state
    pCell->SetState(state);

    return TRUE;
}

int CGrid::GetRowHeight(int nRow)
{
    ATLASSERT(nRow >= 0 && nRow < m_nRows);
    if (nRow < 0 || nRow >= m_nRows)
		return -1;

    return m_arRow[nRow].Height;
}

int CGrid::GetFixedColumnWidth()
{
    int nWidth = 0;
    for (int i = 0; i < m_nFixedCols; i++)
        nWidth += GetColumnWidth(i);

    return nWidth;
}

int CGrid::GetColumnWidth(int nCol)
{
    ATLASSERT(nCol >= 0 && nCol < m_nCols);
    if (nCol < 0 || nCol >= m_nCols) return -1;

    return m_arCol[nCol].Width;

}

CGridCell* CGrid::GetCell(int nRow, int nCol)
{
    if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) return NULL;

    GRID_ROW* pRow = m_RowData[nRow];
    if (!pRow) return NULL;
//    return pRow->GetAt(nCol);
    return pRow->at(nCol);
}
/*
BOOL GetItem(GV_ITEM* pItem)
{
    if (!pItem)
        return FALSE;
    CGridCell* pCell = GetCell(pItem->row, pItem->col);
    if (!pCell) 
        return FALSE;

    if (pItem->mask & GVIF_TEXT)   pItem->szText  = pCell->GetText();
    if (pItem->mask & GVIF_PARAM)  pItem->lParam  = pCell->lParam;
    if (pItem->mask & GVIF_IMAGE)  pItem->iImage  = pCell->iImage;
    if (pItem->mask & GVIF_STATE)  pItem->state   = pCell->state;
    if (pItem->mask & GVIF_FORMAT) pItem->nFormat = pCell->nFormat;
    if (pItem->mask & GVIF_BKCLR)  pItem->crBkClr = pCell->crBkClr;
    if (pItem->mask & GVIF_FGCLR)  pItem->crFgClr = pCell->crFgClr;
    if (pItem->mask & GVIF_FONT)   memcpy(&(pItem->lfFont), &(pCell->lfFont), sizeof(LOGFONT));

    return TRUE;
}
*/

////////////////////////////////////////////////////////////
// End Grid Attributes
////////////////////////////////////////////////////////////

STDMETHODIMP CGrid::get_ColumnResizing(VARIANT_BOOL *pVal)
{
	if (m_bAllowColumnResize == TRUE)
		*pVal = VARIANT_TRUE;
	else
		*pVal = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::put_ColumnResizing(VARIANT_BOOL newVal)
{
	if (newVal == VARIANT_TRUE)
		m_bAllowColumnResize = TRUE;
	else
		m_bAllowColumnResize = FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::get_RowResizing(VARIANT_BOOL *pVal)
{
	if (m_bAllowRowResize == TRUE)
		*pVal = VARIANT_TRUE;
	else
		*pVal = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::put_RowResizing(VARIANT_BOOL newVal)
{
	if (newVal == VARIANT_TRUE)
		m_bAllowRowResize = TRUE;
	else
		m_bAllowRowResize = FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::get_GridLines(grGridLines *pVal)
{
	*pVal = m_nGridLines;

	return S_OK;
}

STDMETHODIMP CGrid::put_GridLines(grGridLines newVal)
{
	m_nGridLines = newVal;
	if (m_hWnd)
		FireViewChange();
	return S_OK;
}

STDMETHODIMP CGrid::get_Editable(VARIANT_BOOL *pVal)
{
	if (m_bEditable == TRUE)
		*pVal = VARIANT_TRUE;
	else
		*pVal = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::put_Editable(VARIANT_BOOL newVal)
{
	if (newVal == VARIANT_TRUE)
		m_bEditable = TRUE;
	else
		m_bEditable = FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::get_FixedRows(int *pVal)
{
	*pVal = m_nFixedRows;
	return S_OK;
}

STDMETHODIMP CGrid::put_FixedRows(int newVal)
{
	if (newVal < 0)
		return S_OK;

	if (newVal > m_nRows) 
		if (!put_RowCount(newVal)) return FALSE;

	if (m_idCurrentCell.row < newVal)
		SetFocusCell(-1,-1);

	m_nFixedRows = newVal;

	if (m_bAllowDraw && m_hWnd)
		FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::get_FixedCols(int *pVal)
{
	*pVal = m_nFixedCols;
	return S_OK;
}

STDMETHODIMP CGrid::put_FixedCols(int newVal)
{
    ATLASSERT(newVal >= 0);
    if (newVal > m_nCols)
        if (put_ColumnCount(newVal) != S_OK) return FALSE;

    if (m_idCurrentCell.col < newVal)
        SetFocusCell(-1,-1);

    m_nFixedCols = newVal;

    if (m_bAllowDraw && m_hWnd)
        FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::AutosizeColumn(int col)
{
	if (col <0)
	{
		BOOL stopDraw = m_bAllowDraw;
		m_bAllowDraw = FALSE;
		int nNumColumns = m_nCols;
		for (int nCol = 0; nCol < nNumColumns; nCol++)
			AutosizeColumn(nCol);
		
		m_bAllowDraw = stopDraw;

	}
	else
	{
		if ( col >= m_nCols) return FALSE;

		SIZE size;
		HDC hDC = GetDC();
		if (!hDC) return FALSE;

		int nWidth = 0;

		for (int nRow = 0; nRow < m_nRows; nRow++)
		{
			size = GetCellExtent(nRow, col, hDC);
			if (size.cx > nWidth) nWidth = size.cx;
		}

		m_arCol[col].Width = nWidth;

		::ReleaseDC(m_hWnd,hDC);
		ResetScrollBars();
	}

    if (m_bAllowDraw && m_hWnd)
        FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::AutosizeRow(int row)
{
	if(row < 0)
	{
		BOOL stopDraw = m_bAllowDraw;
		m_bAllowDraw = FALSE;

		for (int nRow = 0; nRow < m_nRows; nRow++)
			AutosizeRow(nRow);
		m_bAllowDraw = stopDraw;
	}
	else
	{
		if (row >= m_nRows) return FALSE;

		SIZE size;
		HDC hDC = ::GetDC(m_hWnd);
		if (!hDC) return FALSE;

		int nHeight = 0;
		int nNumColumns = m_nCols;
		for (int nCol = 0; nCol < nNumColumns; nCol++)
		{  
			size = GetCellExtent(row, nCol, hDC);
			if (size.cy > nHeight) nHeight = size.cy;
		}  
		m_arRow[row].Height = nHeight;

		::ReleaseDC(m_hWnd,hDC);
		ResetScrollBars();

	}
    if (m_bAllowDraw && m_hWnd)
        FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::get_CellEnabled(int row, int col, VARIANT_BOOL *pVal)
{
	*pVal = (GetItemState(row,col) & GVIS_READONLY);

	return S_OK;
}

STDMETHODIMP CGrid::put_CellEnabled(int row, int col, VARIANT_BOOL newVal)
{
    if (newVal == FALSE)
        SetItemState(row,col, GetItemState(row,col) | GVIS_READONLY);
    else
        SetItemState(row,col, GetItemState(row,col) & ~GVIS_READONLY);
	return S_OK;
}

STDMETHODIMP CGrid::get_AllowSelection(VARIANT_BOOL *pVal)
{
	*pVal = m_bEnableSelection;
	return S_OK;
}

STDMETHODIMP CGrid::put_AllowSelection(VARIANT_BOOL newVal)
{
	ResetSelectedRange();
	m_bEnableSelection = newVal;
	ResetSelectedRange();
	return S_OK;
}

STDMETHODIMP CGrid::get_ListMode(VARIANT_BOOL *pVal)
{
	if (m_bListMode)
		*pVal = VARIANT_TRUE;
	else
		*pVal = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::put_ListMode(VARIANT_BOOL newVal)
{
	if(newVal == VARIANT_TRUE)
		m_bListMode = TRUE;
	else
		m_bListMode = FALSE;


	return S_OK;
}

UINT CGrid::GetItemState(int nRow, int nCol)
{
    CGridCell* pCell = GetCell(nRow, nCol);
    ATLASSERT(pCell);
    if (!pCell)
        return 0;

    return pCell->GetState();
}

STDMETHODIMP CGrid::get_CurrentRow(int *pVal)
{
	*pVal = m_idCurrentCell.row;

	return S_OK;
}

STDMETHODIMP CGrid::put_CurrentRow(int newVal)
{
	SetFocusCell(newVal, m_idCurrentCell.col);

	return S_OK;
}

STDMETHODIMP CGrid::get_CurrentCol(int *pVal)
{
	*pVal = m_idCurrentCell.col;
	return S_OK;
}

STDMETHODIMP CGrid::put_CurrentCol(int newVal)
{
	SetFocusCell(m_idCurrentCell.row,newVal);
	return S_OK;
}

STDMETHODIMP CGrid::DeleteRow(int row)
{

    if ( row < 0 || row >= m_nRows)
        return S_OK;

    GRID_ROW* pRow = m_RowData[row];
    if (!pRow) return S_OK;

    ResetSelectedRange();

    for (int col = 0; col < m_nCols; col++) 
    {
        CGridCell* pCell = pRow->at(col);
        if (pCell) {
            EmptyCell(pCell, row, col);
            delete pCell;
        }
    }
//    delete pRow;
    m_RowData.erase(m_RowData.begin()+row);
    m_arRow.erase(m_arRow.begin()+row);

    m_nRows--;
    if (row < m_nFixedRows) m_nFixedRows--;

    if (row == m_idCurrentCell.row)
        m_idCurrentCell.row = m_idCurrentCell.col = -1;
    else if (row < m_idCurrentCell.row)
        m_idCurrentCell.row--;

    ResetScrollBars();

	FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::DeleteColumn(int col)
{
    if (col < 0 || col >= m_nCols)
        return S_OK;

    ResetSelectedRange();

    for (int row = 0; row < m_nRows; row++) 
    {
        GRID_ROW* pRow = m_RowData[row];
        if (!pRow) return FALSE;

        CGridCell* pCell = pRow->at(col);
        if (pCell) {
            EmptyCell(pCell, row, col);
            delete pCell;
        }
        pRow->erase(pRow->begin()+col);
    }
    m_arCol.erase(m_arCol.begin()+col);
    m_nCols--;
    if (col < m_nFixedCols) m_nFixedCols--;

    if (col == m_idCurrentCell.col)
        m_idCurrentCell.row = m_idCurrentCell.col = -1;
    else if (col < m_idCurrentCell.col)
        m_idCurrentCell.col--;

    ResetScrollBars();
	FireViewChange();

	return S_OK;
}

STDMETHODIMP CGrid::get_HeaderSort(VARIANT_BOOL *pVal)
{
	*pVal = m_bSortOnClick;
	return S_OK;
}

STDMETHODIMP CGrid::put_HeaderSort(VARIANT_BOOL newVal)
{
	m_bSortOnClick = newVal;
	return S_OK;
}

STDMETHODIMP CGrid::get_SingleRowSelection(VARIANT_BOOL *pVal)
{
	*pVal = m_bSingleRowSelection;
	return S_OK;
}

STDMETHODIMP CGrid::put_SingleRowSelection(VARIANT_BOOL newVal)
{
	m_bSingleRowSelection = newVal;
	return S_OK;
}
BOOL CGrid::GetSingleRowSelection()
{
	VARIANT_BOOL pVal;
	get_SingleRowSelection(&pVal);
	if(pVal == VARIANT_TRUE)
		return TRUE;
	else
		return FALSE;
}
// Performs any cell cleanup necessary to maintain grid integrity
void CGrid::EmptyCell(CGridCell *pCell, int nRow, int nCol)
{
    // Set the cells state to 0. If the cell is selected, this
    // will remove the cell from the selected list.
    SetItemState(nRow, nCol, 0);

    // Empty strings
//    pCell->szText;
}


STDMETHODIMP CGrid::get_BackColor(OLE_COLOR *pVal)
{
	*pVal = (OLE_COLOR) m_crBkColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_BackColor(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crBkColour = cr;

	if (m_hWnd)
		FireViewChange();


	return S_OK;
}

STDMETHODIMP CGrid::get_FixedBackColor(OLE_COLOR *pVal)
{
	*pVal = (OLE_COLOR) m_crFixedBkColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_FixedBackColor(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crFixedBkColour = cr;

	if (m_hWnd)
		FireViewChange();


	return S_OK;
}

STDMETHODIMP CGrid::get_TextColor(OLE_COLOR *pVal)
{
	*pVal = (OLE_COLOR) m_crTextColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_TextColor(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crTextColour = cr;

	if (m_hWnd)
		FireViewChange();


	return S_OK;
}

STDMETHODIMP CGrid::get_TextBackColor(OLE_COLOR *pVal)
{
	*pVal = m_crTextBkColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_TextBackColor(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crTextBkColour = cr;

	if (m_hWnd)
		FireViewChange();


	return S_OK;
}

STDMETHODIMP CGrid::get_Color(OLE_COLOR *pVal)
{
	*pVal = (OLE_COLOR) m_crGridColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_Color(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crGridColour = cr;

	if (m_hWnd)
		FireViewChange();



	return S_OK;
}

STDMETHODIMP CGrid::get_FixedTextColor(OLE_COLOR *pVal)
{
	*pVal = (OLE_COLOR) m_crFixedTextColour;

	return S_OK;
}

STDMETHODIMP CGrid::put_FixedTextColor(OLE_COLOR newVal)
{
	COLORREF cr;
	int i = OleTranslateColor(newVal,
					NULL,
					&cr);
	if ( i == S_OK)
		m_crFixedTextColour = cr;

	if (m_hWnd)
		FireViewChange();


	return S_OK;
}

STDMETHODIMP CGrid::get_CellFgColor(int Row, int Col, OLE_COLOR *pVal)
{
	CGridCell* pCell = GetCell(Row,Col);
	if (pCell)
		*pVal = (OLE_COLOR) pCell->GetCRFgClr();
	else
		*pVal = NULL;

	return S_OK;
}

STDMETHODIMP CGrid::put_CellFgColor(int Row, int Col, OLE_COLOR newVal)
{
	CGridCell* pCell = GetCell(Row,Col);
	if (pCell)
	{
		COLORREF cr;
		int i = OleTranslateColor(newVal,
					NULL,
					&cr);
		if ( i == S_OK)
			pCell->SetFgColour(cr);

		if (m_hWnd)
			FireViewChange();

	}

	return S_OK;
}

STDMETHODIMP CGrid::get_CellBgColor(int Row, int Col, OLE_COLOR *pVal)
{
	CGridCell* pCell = GetCell(Row,Col);
	if (pCell)
		*pVal = (OLE_COLOR) pCell->GetCRBkClr();
	else
		*pVal = NULL;

	return S_OK;
}

STDMETHODIMP CGrid::put_CellBgColor(int Row, int Col, OLE_COLOR newVal)
{
	CGridCell* pCell = GetCell(Row,Col);
	if (pCell)
	{
		COLORREF cr;
		int i = OleTranslateColor(newVal,
					NULL,
					&cr);
		if ( i == S_OK)
			pCell->SetBkColour(cr);

		if (m_hWnd)
			FireViewChange();

	}

	return S_OK;
}

void CGrid::SetFont(IFontDisp *font)
{
	CComQIPtr<IFont> pFont(font);
	if (pFont)
	{
		HFONT hf;
		LOGFONT lf;
		memset(&lf,0,sizeof(LOGFONT));
		HRESULT hr = pFont->get_hFont(&hf);
		if SUCCEEDED(hr)
		{
			pFont->AddRefHfont(hf);
			int bytes;
			DWORD err;
			if(hf)
				bytes = GetObject(hf, sizeof(LOGFONT), &lf);
			if(bytes == 0)
			{
				err = GetLastError();
			}

		// Store font as the global default
		memcpy(&m_Logfont, &lf, sizeof(LOGFONT));

  
		// reset all cells' fonts
		for (int row = 0; row < m_nRows; row++)
			for (int col = 0; col < m_nCols; col++)
				GetCell(row, col)->put_Font(font);

		// Get the font size and hence the default cell size
		if (m_hWnd == NULL)
			return;
		HDC hDC = GetDC();
		if (hDC) 
		{
			if (m_Font)
				DeleteObject(m_Font);
			m_Font=CreateFontIndirect(&m_Logfont);
			HFONT pOldFont = (HFONT) SelectObject(hDC,m_Font);
        
			TEXTMETRIC tm;
			GetTextMetrics(hDC,&tm);
        
			SIZE size;
			::GetTextExtentPoint32(hDC, _T(" "), 1, &size);

			m_nMargin = size.cx;
			SelectObject(hDC,pOldFont);
			ReleaseDC(hDC);

			m_nDefCellHeight = tm.tmHeight+tm.tmExternalLeading + 2*m_nMargin;
			m_nDefCellWidth  = tm.tmAveCharWidth*12 + 2*m_nMargin;
		}

		if (m_hWnd) 
			FireViewChange();

			pFont->ReleaseHfont(hf);
		}
	}
	return ;

}

STDMETHODIMP CGrid::SimpleConf()
{
		//// Semplice codice di inizializzazione della grid per TEST

				// Gestione del Font
		LOGFONT lf;                        // Used to create the CFont.

	   memset(&lf, 0, sizeof(LOGFONT));   // Clear out structure.

	   lf.lfHeight = 14;
	   lf.lfWidth = 0;
	   lf.lfEscapement = 0;
	   lf.lfOrientation = 0;
	   lf.lfWeight = FW_NORMAL;
	   lf.lfItalic = FALSE;
	   lf.lfUnderline = FALSE;
	   lf.lfStrikeOut = FALSE;
	   lf.lfCharSet = ANSI_CHARSET;
	   lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
	   lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
	   lf.lfQuality = DEFAULT_QUALITY;
	   lf.lfPitchAndFamily = FF_DONTCARE;
	   strcpy(lf.lfFaceName, "MS Sans Serif");
   
//		SetFont(lf); // Provvisorio deve diventare una property

//		static CImageList list1;
//		list1.Create(MAKEINTRESOURCE(IDB_IMAGES), 16, 1, RGB(255,255,255));
//		SetImageList(list1.m_hImageList);

		put_FixedRows(1);
		put_FixedCols(1);

		put_RowCount(10);
		put_ColumnCount(10);
		put_TextBackColor(RGB(0xFF, 0xFF, 0xE0));
		DWORD dwTextStyle = DT_RIGHT|DT_VCENTER|DT_SINGLELINE;
		#ifndef _WIN32_WCE
			dwTextStyle |= DT_END_ELLIPSIS;
		#endif
	// fill rows/cols with text
	char buffer[200] = "\0";
	_bstr_t tmp;
	
	CGridCell* pCell;

	for (int row = 0; row < 10; row++)
		for (int col = 0; col < m_nCols; col++)
		{ 
			pCell = GetCell(row,col);
			if(pCell)
			{
//			Item.mask = GVIF_TEXT|GVIF_FORMAT;
				if (row < 1)
				{
					pCell->SetFormat(DT_LEFT|DT_WORDBREAK);
					sprintf(buffer,"Column %d",col);
					tmp = buffer;
					pCell->put_Text(tmp);
				}
				else if (col < 1) 
				{
					sprintf(buffer,"Row %d",row);
					pCell->SetFormat(dwTextStyle);
					tmp = buffer;
					pCell->put_Text(tmp);
				}
				else 
				{
					sprintf(buffer,"%d",row*col);
					pCell->SetFormat(dwTextStyle);
					tmp = buffer;
					pCell->put_Text(tmp);
				}

				int fixedColumn;
				get_FixedCols(&fixedColumn);
				if (col == (fixedColumn-1) )//&& row >= m_Grid.GetFixedRowCount())
					GetCell(row, col)->SetImage(
					rand()%ImageList_GetImageCount(m_pImageList));	

				//else if (rand() % 10 == 1)
				//	m_Grid.SetItemImage(row, col, 0);

				if (rand() % 10 == 1)
				{
					COLORREF clr = RGB(rand() % 128+128, rand() % 128+128, rand() % 128+128);
					pCell->SetBkColour(clr);
					pCell->SetFgColour(RGB(255,0,0));
				}
			}
		}
	AutoSize();

	int height;
	get_RowHeight(0,&height);
	put_RowHeight(0, 3*height/2);

	return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// IOleControl method overrides

STDMETHODIMP CGrid::GetMiscStatus (DWORD dwAspect, DWORD *pdwStatus)
{
    if (NULL == pdwStatus) return E_POINTER;

    *pdwStatus = 
           OLEMISC_SETCLIENTSITEFIRST |
           OLEMISC_ACTIVATEWHENVISIBLE |
           OLEMISC_INSIDEOUT |
           OLEMISC_CANTLINKINSIDE |
           OLEMISC_RECOMPOSEONRESIZE;/* |
           OLEMISC_NOUIACTIVATE ;*/

    return S_OK;
}

STDMETHODIMP CGrid::get_Cell(int Row, int Col, IGridCell **pVal)
{
	
	CGridCell* pCell = GetCell(Row,Col);
	
	if(pCell)
		pCell->AddRef();
	*pVal = pCell;

	return S_OK;
}

STDMETHODIMP CGrid::put_Cell(int Row, int Col, IGridCell *newVal)
{
	// TODO: Add your implementation code here

	return S_OK;
}
BOOL CGrid::GetTextRect(int nRow, int nCol, LPRECT pRect)
{
/* TODO: i've to get image information
    GV_ITEM Item;
    Item.mask = GVIF_IMAGE;
    Item.row = nRow;
    Item.col = nCol;
    if (!GetItem(&Item))
        return FALSE;
*/
    if (!GetCellRect(nRow, nCol, pRect))
        return FALSE;

    //pRect->left += m_nMargin;
    //pRect->right -= m_nMargin;
/*
    if (m_pImageList && Item.iImage >= 0) {
        IMAGEINFO Info;
        if (m_pImageList->GetImageInfo(Item.iImage, &Info)) {
            int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
            pRect->left += nImageWidth+m_nMargin;
        }
    }
*/
    return TRUE;
}
// Get cell from point
CCellID CGrid::GetCellFromPt(POINT point, BOOL bAllowFixedCellCheck /*=TRUE*/)
{  
    CCellID idTopLeft = GetTopleftNonFixedCell();
    CCellID cellID; // return value

    // calculate column index
    int fixedColWidth = GetFixedColumnWidth();

    if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
        cellID.col = -1;
    else if (point.x < fixedColWidth) // in fixed col
    {
        int xpos = 0;
        for (int col = 0; col < m_nFixedCols; col++)
        {
            xpos += GetColumnWidth(col);
            if (xpos > point.x) break;
        }
        cellID.col = col;
    }
    else    // in non-fixed col
    {
        int xpos = fixedColWidth;
        for (int col = idTopLeft.col; col < m_nCols; col++)
        {
            xpos += GetColumnWidth(col);
            if (xpos > point.x) break;
        }

        if (col >= m_nCols)
            cellID.col = -1;
        else
            cellID.col = col;
    }
    
    // calculate row index
    int fixedRowHeight = GetFixedRowHeight();
    if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
        cellID.row = -1;
    else if (point.y < fixedRowHeight) // in fixed col
    {
        int ypos = 0;
        for (int row = 0; row < m_nFixedRows; row++)
        {
            ypos += GetRowHeight(row);
            if (ypos > point.y) break;
        }
        cellID.row = row;
    }
    else
    {
        int ypos = fixedRowHeight;
        for (int row = idTopLeft.row; row < m_nRows; row++)
        {
            ypos += GetRowHeight(row);
            if (ypos > point.y) break;
        }

        if (row >= m_nRows)
            cellID.row = -1;
        else
            cellID.row = row;
    }

    return cellID;
}

STDMETHODIMP CGrid::get_ToolTip(VARIANT_BOOL *pVal)
{
	if(m_bTitleTips ==TRUE)
		*pVal = VARIANT_TRUE;
	else
		*pVal = VARIANT_FALSE;

	return S_OK;
}

STDMETHODIMP CGrid::put_ToolTip(VARIANT_BOOL newVal)
{
	if(newVal == VARIANT_TRUE)
		m_bTitleTips = TRUE;
	else
		m_bTitleTips = FALSE;
	return S_OK;
}

STDMETHODIMP CGrid::Refresh()
{

	FireViewChange();
	return S_OK;
}

STDMETHODIMP CGrid::SelectAllCells()
{
// selects all cells
	if (!m_bEnableSelection)
		return S_OK;

	SetSelectedRange(m_nFixedRows, m_nFixedCols, m_nRows-1, m_nCols-1);


	return S_OK;
}

BOOL CGrid::PreTranslateAccelerator(LPMSG pMsg, HRESULT &hRet)
{
	 BOOL bHandled;
      if(pMsg->message == WM_KEYDOWN && pMsg->hwnd == m_hWnd &&
         (pMsg->wParam == VK_LEFT || 
         pMsg->wParam == VK_RIGHT ||
         pMsg->wParam == VK_UP ||
         pMsg->wParam == VK_DOWN))
      {
         hRet = S_OK; 
		 OnKeyDown(pMsg->message,pMsg->wParam,pMsg->lParam,bHandled);
//         m_ctlEdit.SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
         return TRUE;
      }
      //TODO: Add your additional accelerator handling code here
      if(pMsg->message == WM_KEYDOWN && 
         ((pMsg->wParam == VK_ESCAPE) || (pMsg->wParam == VK_UP) ||
         (pMsg->wParam == VK_DOWN) ))
	  {
		  hRet = S_OK; // Stop an eventual in place action
		  ::PostMessage(pMsg->hwnd,WM_KILLFOCUS,0,0);
		  return TRUE;
	  }
      if(pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_TAB)
	  {
		  // special case: use TAB
		  if(pMsg->hwnd == m_hWnd) // The grid has the focus, so delegate to OnKeyDown
		  {
			if (m_vbKeepTab == VARIANT_FALSE)
				 return FALSE;

			OnKeyDown(pMsg->message,pMsg->wParam,pMsg->lParam,bHandled);
			 return TRUE;
		  }
		  else
		  {
//		  SendMessage(pMsg->hwnd,WM_KILLFOCUS,0,0);
			// Move to next cell
			int row = m_idCurrentCell.row,col=m_idCurrentCell.col+1;
			if(col>=m_nCols)
			{
				col = m_nFixedCols;
				row +=1;
				if (row>=m_nRows)
					row = m_nFixedRows;
			}
/*			VARIANT_BOOL cancel = VARIANT_FALSE;

			Fire_BeforeEdit(row,col,&cancel);
			if (cancel == VARIANT_TRUE) // Cancel Editing
				return FALSE;*/
			// Editing the cell
			RECT rect;
			CCellID cellID(row,col);
			SetFocusCell(cellID);
			GetCellRect(cellID,&rect);
			GetCell(row,col)->Edit(m_hWnd,&rect,row,col);
			return TRUE;
		  }
	  }
      return FALSE;

}

STDMETHODIMP CGrid::get_KeepTab(VARIANT_BOOL *pVal)
{
	*pVal = m_vbKeepTab;

	return S_OK;
}

STDMETHODIMP CGrid::put_KeepTab(VARIANT_BOOL newVal)
{
	m_vbKeepTab = newVal;

	return S_OK;
}

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
Italy Italy
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions