From 0e9b642c051a3546777873d6e4f31bdbd8b57be1 Mon Sep 17 00:00:00 2001
From: mrDarker <mr.darker@163.com>
Date: 星期二, 27 五月 2025 11:47:06 +0800
Subject: [PATCH] 1. 添加自定义网格控件和Port设置类

---
 SourceCode/Bond/Servo/Servo.vcxproj                                 |   30 
 SourceCode/Bond/Servo/resource.h                                    |    0 
 SourceCode/Bond/Servo/Servo.vcxproj.user                            |    4 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h        |   55 
 SourceCode/Bond/Servo/GridControl/GridCell.cpp                      |  294 +
 SourceCode/Bond/Servo/GridControl/GridCtrl.cpp                      | 8428 +++++++++++++++++++++++++++++++++++
 SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h                 |   83 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp  |   42 
 SourceCode/Bond/Servo/PortConfigurationDlg.h                        |   27 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp      |  212 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp |  268 +
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h      |   68 
 SourceCode/Bond/Servo/GridControl/GridDropTarget.h                  |   82 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp    |  510 ++
 SourceCode/Bond/Servo/Servo.rc                                      |    0 
 SourceCode/Bond/Servo/GridControl/CellRange.h                       |  156 
 SourceCode/Bond/Servo/GridControl/GridCell.h                        |  143 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp    |  185 
 SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp               |  262 +
 SourceCode/Bond/Servo/GridControl/TitleTip.h                        |   87 
 SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp                |  156 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h   |   92 
 SourceCode/Bond/Servo/GridControl/GridCellButton.h                  |   28 
 SourceCode/Bond/Servo/GridControl/GridCellBase.cpp                  |  773 +++
 SourceCode/Bond/Servo/GridControl/GridMemDC.h                       |  106 
 SourceCode/Bond/Servo/PortConfigurationDlg.cpp                      |   74 
 SourceCode/Bond/Servo/Servo.vcxproj.filters                         |   86 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h    |   26 
 SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h      |  178 
 SourceCode/Bond/Servo/GridControl/GridCellBase.h                    |  172 
 SourceCode/Bond/Servo/GridControl/GridCellButton.cpp                |   46 
 SourceCode/Bond/Servo/GridControl/GridCtrl.h                        | 1090 ++++
 SourceCode/Bond/Servo/GridControl/TitleTip.cpp                      |  341 +
 33 files changed, 14,101 insertions(+), 3 deletions(-)

diff --git a/SourceCode/Bond/Servo/GridControl/CellRange.h b/SourceCode/Bond/Servo/GridControl/CellRange.h
new file mode 100644
index 0000000..5fd2004
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/CellRange.h
@@ -0,0 +1,156 @@
+///////////////////////////////////////////////////////////////////////
+// CellRange.h: header file
+//
+// MFC Grid Control - interface for the CCellRange class.
+//
+// Written by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+// The code contained in this file is based on the original
+// WorldCom Grid control written by Joe Willcoxson,
+//      mailto:chinajoe@aol.com
+//      http://users.aol.com/chinajoe
+
+#ifndef max
+#define max(a,b)            (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b)            (((a) < (b)) ? (a) : (b))
+#endif
+
+class CCellID
+{    
+// Attributes
+public:
+    int row, col;
+
+// Operations
+public:
+    explicit CCellID(int nRow = -1, int nCol = -1) : row(nRow), col(nCol) {}
+
+    int IsValid() const { return (row >= 0 && col >= 0); }
+    int operator==(const CCellID& rhs) const { return (row == rhs.row && col == rhs.col); }
+    int operator!=(const CCellID& rhs) const { return !operator==(rhs); }
+};
+
+class CCellRange
+{ 
+public:
+    
+    CCellRange(int nMinRow = -1, int nMinCol = -1, int nMaxRow = -1, int nMaxCol = -1)
+    {
+        Set(nMinRow, nMinCol, nMaxRow, nMaxCol);
+    }
+
+    void Set(int nMinRow = -1, int nMinCol = -1, int nMaxRow = -1, int nMaxCol = -1);
+    
+    int  IsValid() const;
+    int  InRange(int row, int col) const;
+    int  InRange(const CCellID& cellID) const;
+    int  Count() { return (m_nMaxRow - m_nMinRow + 1) * (m_nMaxCol - m_nMinCol + 1); }
+    
+    CCellID  GetTopLeft() const;
+    CCellRange  Intersect(const CCellRange& rhs) const;
+    
+    int GetMinRow() const {return m_nMinRow;}
+    void SetMinRow(int minRow) {m_nMinRow = minRow;}
+    
+    int GetMinCol() const {return m_nMinCol;}
+    void SetMinCol(int minCol) {m_nMinCol = minCol;}
+    
+    int GetMaxRow() const {return m_nMaxRow;}
+    void SetMaxRow(int maxRow) {m_nMaxRow = maxRow;}
+    
+    int GetMaxCol() const {return m_nMaxCol;}
+    void SetMaxCol(int maxCol) {m_nMaxCol = maxCol;}
+
+    int GetRowSpan() const {return m_nMaxRow - m_nMinRow + 1;}
+    int GetColSpan() const {return m_nMaxCol - m_nMinCol + 1;}
+    
+    void operator=(const CCellRange& rhs);
+    int  operator==(const CCellRange& rhs);
+    int  operator!=(const CCellRange& rhs);
+    
+protected:
+    int m_nMinRow;
+    int m_nMinCol;
+    int m_nMaxRow;
+    int m_nMaxCol;
+};
+
+inline void CCellRange::Set(int minRow, int minCol, int maxRow, int maxCol)
+{
+     m_nMinRow = minRow;
+     m_nMinCol = minCol;
+     m_nMaxRow = maxRow;
+     m_nMaxCol = maxCol;
+}
+
+inline void CCellRange::operator=(const CCellRange& rhs)
+{
+    if (this != &rhs) Set(rhs.m_nMinRow, rhs.m_nMinCol, rhs.m_nMaxRow, rhs.m_nMaxCol);
+}
+
+inline int CCellRange::operator==(const CCellRange& rhs)
+{
+     return ((m_nMinRow == rhs.m_nMinRow) && (m_nMinCol == rhs.m_nMinCol) &&
+             (m_nMaxRow == rhs.m_nMaxRow) && (m_nMaxCol == rhs.m_nMaxCol));
+}
+
+inline int CCellRange::operator!=(const CCellRange& rhs)
+{
+     return !operator==(rhs);
+}
+
+inline int CCellRange::IsValid() const
+{
+     return (m_nMinRow >= 0 && m_nMinCol >= 0 && m_nMaxRow >= 0 && m_nMaxCol >= 0 &&
+             m_nMinRow <= m_nMaxRow && m_nMinCol <= m_nMaxCol);
+}
+
+inline int CCellRange::InRange(int row, int col) const
+{
+     return (row >= m_nMinRow && row <= m_nMaxRow && col >= m_nMinCol && col <= m_nMaxCol);
+}
+
+inline int CCellRange::InRange(const CCellID& cellID) const
+{
+     return InRange(cellID.row, cellID.col);
+}
+
+inline CCellID CCellRange::GetTopLeft() const
+{
+     return CCellID(m_nMinRow, m_nMinCol);
+}
+
+inline CCellRange CCellRange::Intersect(const CCellRange& rhs) const
+{
+     return CCellRange(max(m_nMinRow,rhs.m_nMinRow), max(m_nMinCol,rhs.m_nMinCol),
+                       min(m_nMaxRow,rhs.m_nMaxRow), min(m_nMaxCol,rhs.m_nMaxCol));
+}
+
+#endif // !defined(AFX_CELLRANGE_H__F86EF761_725A_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCell.cpp b/SourceCode/Bond/Servo/GridControl/GridCell.cpp
new file mode 100644
index 0000000..370413c
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCell.cpp
@@ -0,0 +1,294 @@
+// GridCell.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for the "default" cell type of the
+// grid control. Adds in cell editing.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.20+
+//
+// History:
+// Eric Woodruff - 20 Feb 2000 - Added PrintCell() plus other minor changes
+// Ken Bertelson - 12 Apr 2000 - Split CGridCell into CGridCell and CGridCellBase
+// <kenbertelson@hotmail.com>
+// C Maunder     - 17 Jun 2000 - Font handling optimsed, Added CGridDefaultCell
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridInPlaceEdit.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridCell, CGridCellBase)
+IMPLEMENT_DYNCREATE(CGridDefaultCell, CGridCell)
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell
+
+CGridCell::CGridCell()
+{
+    m_plfFont = NULL;
+	CGridCell::Reset();
+}
+
+CGridCell::~CGridCell()
+{
+	if (m_plfFont)
+	{
+		delete m_plfFont;
+		m_plfFont = NULL;
+	}
+	
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell Attributes
+
+void CGridCell::operator=(const CGridCell& cell)
+{
+    if (this != &cell) CGridCellBase::operator=(cell);
+}
+
+void CGridCell::Reset()
+{
+    CGridCellBase::Reset();
+
+    m_strText.Empty();
+    m_nImage   = -1;
+    m_lParam   = NULL;           // BUG FIX J. Bloggs 20/10/03
+    m_pGrid    = NULL;
+    m_bEditing = FALSE;
+    m_pEditWnd = NULL;
+
+    m_nFormat = (DWORD)-1;       // Use default from CGridDefaultCell
+    m_crBkClr = CLR_DEFAULT;     // Background colour (or CLR_DEFAULT)
+    m_crFgClr = CLR_DEFAULT;     // Forground colour (or CLR_DEFAULT)
+    m_nMargin = (UINT)-1;        // Use default from CGridDefaultCell
+
+	if (m_plfFont)
+	{
+		delete m_plfFont;
+		m_plfFont = NULL;
+	}
+    m_plfFont = NULL;            // Cell font
+}
+
+void CGridCell::SetFont(const LOGFONT* plf)
+{
+    if (plf == NULL)
+    {
+		if (m_plfFont)
+		{
+			delete m_plfFont;
+			m_plfFont = NULL;
+		}
+    }
+    else
+    {
+        if (!m_plfFont)
+            m_plfFont = new LOGFONT;
+        if (m_plfFont)
+            memcpy(m_plfFont, plf, sizeof(LOGFONT)); 
+    }
+}
+
+LOGFONT* CGridCell::GetFont() const
+{
+    if (m_plfFont == NULL)
+    {
+        CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+        if (!pDefaultCell)
+            return NULL;
+
+        return pDefaultCell->GetFont();
+    }
+
+    return m_plfFont; 
+}
+
+CFont* CGridCell::GetFontObject() const
+{
+    // If the default font is specified, use the default cell implementation
+    if (m_plfFont == NULL)
+    {
+        CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+        if (!pDefaultCell)
+            return NULL;
+
+        return pDefaultCell->GetFontObject();
+    }
+    else
+    {
+        static CFont Font;
+        Font.DeleteObject();
+        Font.CreateFontIndirect(m_plfFont);
+        return &Font;
+    }
+}
+
+DWORD CGridCell::GetFormat() const
+{
+    if (m_nFormat == (DWORD)-1)
+    {
+        CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+        if (!pDefaultCell)
+            return 0;
+
+        return pDefaultCell->GetFormat();
+    }
+
+    return m_nFormat; 
+}
+
+UINT CGridCell::GetMargin() const           
+{
+    if (m_nMargin == (UINT)-1)
+    {
+        CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+        if (!pDefaultCell)
+            return 0;
+
+        return pDefaultCell->GetMargin();
+    }
+
+    return m_nMargin; 
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCell Operations
+
+BOOL CGridCell::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+    if ( m_bEditing )
+	{      
+        if (m_pEditWnd)
+		    m_pEditWnd->SendMessage ( WM_CHAR, nChar );    
+    }  
+	else  
+	{   
+		DWORD dwStyle = ES_LEFT;
+		if (GetFormat() & DT_RIGHT) 
+			dwStyle = ES_RIGHT;
+		else if (GetFormat() & DT_CENTER) 
+			dwStyle = ES_CENTER;
+		
+		m_bEditing = TRUE;
+		
+		// InPlaceEdit auto-deletes itself
+		CGridCtrl* pGrid = GetGrid();
+		m_pEditWnd = new CGridInPlaceEdit(pGrid, rect, dwStyle, nID, nRow, nCol, GetText(), nChar);
+    }
+    return TRUE;
+}
+
+void CGridCell::EndEdit()
+{
+    if (m_pEditWnd)
+        ((CGridInPlaceEdit*)m_pEditWnd)->EndEdit();
+}
+
+void CGridCell::OnEndEdit()
+{
+    m_bEditing = FALSE;
+    m_pEditWnd = NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDefaultCell
+
+CGridDefaultCell::CGridDefaultCell() 
+{
+#ifdef _WIN32_WCE
+    m_nFormat = DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX;
+#else
+    m_nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX | DT_END_ELLIPSIS;
+#endif
+    m_crFgClr = CLR_DEFAULT;
+    m_crBkClr = CLR_DEFAULT;
+    m_Size    = CSize(30,10);
+    m_dwStyle = 0;
+
+#ifdef _WIN32_WCE
+    LOGFONT lf;
+    GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
+    SetFont(&lf);
+#else // not CE
+    NONCLIENTMETRICS ncm;
+	memset(&ncm,0,sizeof(NONCLIENTMETRICS));
+    ncm.cbSize = sizeof(NONCLIENTMETRICS);
+    //VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
+	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
+    SetFont(&(ncm.lfMessageFont));
+#endif
+}
+
+CGridDefaultCell::~CGridDefaultCell()
+{
+    m_Font.DeleteObject(); 
+}
+
+void CGridDefaultCell::SetFont(const LOGFONT* plf)
+{
+//    ASSERT(plf);
+
+    if (!plf) return;
+
+    m_Font.DeleteObject();
+    m_Font.CreateFontIndirect(plf);
+
+    CGridCell::SetFont(plf);
+
+    // Get the font size and hence the default cell size
+    CDC* pDC = CDC::FromHandle(::GetDC(NULL));
+    if (pDC)
+    {
+        CFont* pOldFont = pDC->SelectObject(&m_Font);
+
+        SetMargin(pDC->GetTextExtent(_T(" "), 1).cx);
+        m_Size = pDC->GetTextExtent(_T(" XXXXXXXXXXXX "), 14);
+        m_Size.cy = (m_Size.cy * 3) / 2;
+
+        pDC->SelectObject(pOldFont);
+        ReleaseDC(NULL, pDC->GetSafeHdc());
+    }
+    else
+    {
+        SetMargin(3);
+        m_Size = CSize(40,16);
+    }
+}
+
+LOGFONT* CGridDefaultCell::GetFont() const
+{
+//    ASSERT(m_plfFont);  // This is the default - it CAN'T be NULL!
+    return m_plfFont;
+}
+
+CFont* CGridDefaultCell::GetFontObject() const
+{
+//    ASSERT(m_Font.GetSafeHandle());
+    return (CFont*) &m_Font; 
+}
diff --git a/SourceCode/Bond/Servo/GridControl/GridCell.h b/SourceCode/Bond/Servo/GridControl/GridCell.h
new file mode 100644
index 0000000..11664fd
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCell.h
@@ -0,0 +1,143 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCell.h : header file
+//
+// MFC Grid Control - Grid cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridCtrl;
+#include "GridCellBase.h"
+
+// Each cell contains one of these. Fields "row" and "column" are not stored since we
+// will usually have acces to them in other ways, and they are an extra 8 bytes per
+// cell that is probably unnecessary.
+
+class CGridCell : public CGridCellBase
+{
+    friend class CGridCtrl;
+    DECLARE_DYNCREATE(CGridCell)
+
+// Construction/Destruction
+public:
+    CGridCell();
+    virtual ~CGridCell();
+
+// Attributes
+public:
+    void operator=(const CGridCell& cell);
+
+    virtual void  SetText(LPCTSTR szText)        { m_strText = szText;  }                       
+    virtual void  SetImage(int nImage)           { m_nImage = nImage;   }                        
+    virtual void  SetData(LPARAM lParam)         { m_lParam = lParam;   }      
+    virtual void  SetGrid(CGridCtrl* pGrid)      { m_pGrid = pGrid;     }                          
+    // virtual void SetState(const DWORD nState);  -  use base class version   
+    virtual void  SetFormat(DWORD nFormat)       { m_nFormat = nFormat; }                      
+    virtual void  SetTextClr(COLORREF clr)       { m_crFgClr = clr;     }                          
+    virtual void  SetBackClr(COLORREF clr)       { m_crBkClr = clr;     }                          
+    virtual void  SetFont(const LOGFONT* plf);
+    virtual void  SetMargin(UINT nMargin)        { m_nMargin = nMargin; }
+    virtual CWnd* GetEditWnd() const             { return m_pEditWnd;   }
+    virtual void  SetCoords(int /*nRow*/, int /*nCol*/) {}  // don't need to know the row and
+                                                            // column for base implementation
+
+    virtual LPCTSTR     GetText() const             { return (m_strText.IsEmpty())? _T("") : LPCTSTR(m_strText); }
+    virtual int         GetImage() const            { return m_nImage;  }
+    virtual LPARAM      GetData() const             { return m_lParam;  }
+    virtual CGridCtrl*  GetGrid() const             { return m_pGrid;   }
+    // virtual DWORD    GetState() const - use base class
+    virtual DWORD       GetFormat() const;
+    virtual COLORREF    GetTextClr() const          { return m_crFgClr; } // TODO: change to use default cell
+    virtual COLORREF    GetBackClr() const          { return m_crBkClr; }
+    virtual LOGFONT*    GetFont() const;
+    virtual CFont*      GetFontObject() const;
+    virtual UINT        GetMargin() const;
+
+    virtual BOOL        IsEditing() const           { return m_bEditing; }
+    virtual BOOL        IsDefaultFont() const       { return (m_plfFont == NULL); }
+    virtual void        Reset();
+
+// editing cells
+public:
+    virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+    virtual void EndEdit();
+protected:
+    virtual void OnEndEdit();
+
+protected:
+    CString    m_strText;      // Cell text (or binary data if you wish...)
+    LPARAM     m_lParam;       // 32-bit value to associate with item
+    int        m_nImage;       // Index of the list view item抯 icon
+    DWORD      m_nFormat;
+    COLORREF   m_crFgClr;
+    COLORREF   m_crBkClr;
+    LOGFONT*   m_plfFont;
+    UINT       m_nMargin;
+
+    BOOL       m_bEditing;     // Cell being edited?
+
+    CGridCtrl* m_pGrid;        // Parent grid control
+    CWnd*      m_pEditWnd;
+};
+
+// This class is for storing grid default values. It's a little heavy weight, so
+// don't use it in bulk 
+class CGridDefaultCell : public CGridCell
+{
+    DECLARE_DYNCREATE(CGridDefaultCell)
+
+// Construction/Destruction
+public:
+    CGridDefaultCell();
+    virtual ~CGridDefaultCell();
+
+public:
+    virtual DWORD GetStyle() const                      { return m_dwStyle;      }
+    virtual void  SetStyle(DWORD dwStyle)               { m_dwStyle = dwStyle;   }
+    virtual int   GetWidth() const                      { return m_Size.cx;      }
+    virtual int   GetHeight() const                     { return m_Size.cy;      }
+    virtual void  SetWidth(int nWidth)                  { m_Size.cx = nWidth;    }
+    virtual void  SetHeight(int nHeight)                { m_Size.cy = nHeight;   }
+
+    // Disable these properties
+    virtual void     SetData(LPARAM /*lParam*/)             { ASSERT(FALSE);         }      
+    virtual void     SetState(DWORD /*nState*/)             { ASSERT(FALSE);         }
+    virtual DWORD    GetState() const                       { return CGridCell::GetState()|GVIS_READONLY; }
+    virtual void     SetCoords( int /*row*/, int /*col*/)   { /*ASSERT(FALSE);*/         }
+    virtual void     SetFont(const LOGFONT* /*plf*/);
+    virtual LOGFONT* GetFont() const;   
+    virtual CFont*   GetFontObject() const;
+
+protected:
+    CSize m_Size;       // Default Size
+    CFont m_Font;       // Cached font
+    DWORD m_dwStyle;    // Cell Style - unused
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp b/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp
new file mode 100644
index 0000000..4b426fd
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellBase.cpp
@@ -0,0 +1,773 @@
+// GridCellBase.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell base class
+//
+// Provides the implementation for the base cell type of the
+// grid control. No data is stored (except for state) but default
+// implementations of drawing, printingetc provided. MUST be derived
+// from to be used.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// Ken Bertelson - 12 Apr 2000 - Split CGridCell into CGridCell and CGridCellBase
+// C Maunder     - 19 May 2000 - Fixed sort arrow drawing (Ivan Ilinov)
+// C Maunder     - 29 Aug 2000 - operator= checks for NULL font before setting (Martin Richter)
+// C Maunder     - 15 Oct 2000 - GetTextExtent fixed (Martin Richter)
+// C Maunder     -  1 Jan 2001 - Added ValidateEdit
+// Yogurt        - 13 Mar 2004 - GetCellExtent fixed
+//
+// NOTES: Each grid cell should take care of it's own drawing, though the Draw()
+//        method takes an "erase background" paramter that is called if the grid
+//        decides to draw the entire grid background in on hit. Certain ambient
+//        properties such as the default font to use, and hints on how to draw
+//        fixed cells should be fetched from the parent grid. The grid trusts the
+//        cells will behave in a certain way, and the cells trust the grid will
+//        supply accurate information.
+//        
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellBase.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNAMIC(CGridCellBase, CObject)
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase
+
+CGridCellBase::CGridCellBase()
+{
+    Reset();
+}
+
+CGridCellBase::~CGridCellBase()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase Operations
+
+void CGridCellBase::Reset()
+{
+    m_nState  = 0;
+}
+
+void CGridCellBase::operator=(const CGridCellBase& cell)
+{
+	if (this == &cell) return;
+
+    SetGrid(cell.GetGrid());    // do first in case of dependencies
+
+    SetText(cell.GetText());
+    SetImage(cell.GetImage());
+    SetData(cell.GetData());
+    SetState(cell.GetState());
+    SetFormat(cell.GetFormat());
+    SetTextClr(cell.GetTextClr());
+    SetBackClr(cell.GetBackClr());
+    SetFont(cell.IsDefaultFont()? NULL : cell.GetFont());
+    SetMargin(cell.GetMargin());
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Attributes
+
+// Returns a pointer to a cell that holds default values for this particular type of cell
+CGridCellBase* CGridCellBase::GetDefaultCell() const
+{
+    if (GetGrid())
+        return GetGrid()->GetDefaultCell(IsFixedRow(), IsFixedCol());
+    return NULL;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Operations
+
+// EFW - Various changes to make it draw cells better when using alternate
+// color schemes.  Also removed printing references as that's now done
+// by PrintCell() and fixed the sort marker so that it doesn't draw out
+// of bounds.
+BOOL CGridCellBase::Draw(CDC* pDC, int nRow, int nCol, CRect rect,  BOOL bEraseBkgnd /*=TRUE*/)
+{
+    // Note - all through this function we totally brutalise 'rect'. Do not
+    // depend on it's value being that which was passed in.
+
+    CGridCtrl* pGrid = GetGrid();
+//    ASSERT(pGrid);
+
+    if (!pGrid || !pDC)
+        return FALSE;
+
+    if( rect.Width() <= 0 || rect.Height() <= 0)  // prevents imagelist item from drawing even
+        return FALSE;                             //  though cell is hidden
+
+    //TRACE3("Drawing %scell %d, %d\n", IsFixed()? _T("Fixed ") : _T(""), nRow, nCol);
+
+    int nSavedDC = pDC->SaveDC();
+    pDC->SetBkMode(TRANSPARENT);
+
+    // Get the default cell implementation for this kind of cell. We use it if this cell
+    // has anything marked as "default"
+    CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+    if (!pDefaultCell)
+        return FALSE;
+
+    // Set up text and background colours
+    COLORREF TextClr, TextBkClr;
+
+    TextClr = (GetTextClr() == CLR_DEFAULT)? pDefaultCell->GetTextClr() : GetTextClr();
+    if (GetBackClr() == CLR_DEFAULT)
+        TextBkClr = pDefaultCell->GetBackClr();
+    else
+    {
+        bEraseBkgnd = TRUE;
+        TextBkClr = GetBackClr();
+    }
+
+    // Draw cell background and highlighting (if necessary)
+    if ( IsFocused() || IsDropHighlighted() )
+    {
+        // Always draw even in list mode so that we can tell where the
+        // cursor is at.  Use the highlight colors though.
+        if(GetState() & GVIS_SELECTED)
+        {
+            TextBkClr = ::GetSysColor(COLOR_HIGHLIGHT);
+            TextClr = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
+            bEraseBkgnd = TRUE;
+        }
+
+        rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom
+        if (bEraseBkgnd)
+        {
+            TRY 
+            {
+                CBrush brush(TextBkClr);
+                pDC->FillRect(rect, &brush);
+            } 
+            CATCH(CResourceException, e)
+            {
+                //e->ReportError();
+            }
+            END_CATCH
+        }
+
+        // Don't adjust frame rect if no grid lines so that the
+        // whole cell is enclosed.
+        if(pGrid->GetGridLines() != GVL_NONE)
+        {
+            rect.right--;
+            rect.bottom--;
+        }
+
+        if (pGrid->GetFrameFocusCell())
+        {
+                // Use same color as text to outline the cell so that it shows
+                // up if the background is black.
+            TRY 
+            {
+                CBrush brush(TextClr);
+                pDC->FrameRect(rect, &brush);
+            }
+            CATCH(CResourceException, e)
+            {
+                //e->ReportError();
+            }
+            END_CATCH
+        }
+        pDC->SetTextColor(TextClr);
+
+        // Adjust rect after frame draw if no grid lines
+        if(pGrid->GetGridLines() == GVL_NONE)
+        {
+            rect.right--;
+            rect.bottom--;
+        }
+
+		//rect.DeflateRect(0,1,1,1);  - Removed by Yogurt
+    }
+    else if ((GetState() & GVIS_SELECTED))
+    {
+        rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom
+        pDC->FillSolidRect(rect, ::GetSysColor(COLOR_HIGHLIGHT));
+        rect.right--; rect.bottom--;
+        pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
+    }
+    else
+    {
+        if (bEraseBkgnd)
+        {
+            rect.right++; rect.bottom++;    // FillRect doesn't draw RHS or bottom
+            CBrush brush(TextBkClr);
+            pDC->FillRect(rect, &brush);
+            rect.right--; rect.bottom--;
+        }
+        pDC->SetTextColor(TextClr);
+    }
+
+    // Draw lines only when wanted
+    if (IsFixed() && pGrid->GetGridLines() != GVL_NONE)
+    {
+        CCellID FocusCell = pGrid->GetFocusCell();
+
+        // As above, always show current location even in list mode so
+        // that we know where the cursor is at.
+        BOOL bHiliteFixed = pGrid->GetTrackFocusCell() && pGrid->IsValid(FocusCell) &&
+                            (FocusCell.row == nRow || FocusCell.col == nCol);
+
+        // If this fixed cell is on the same row/col as the focus cell,
+        // highlight it.
+        if (bHiliteFixed)
+        {
+            rect.right++; rect.bottom++;
+            pDC->DrawEdge(rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT);
+            rect.DeflateRect(1,1);
+        }
+        else
+        {
+            CPen lightpen(PS_SOLID, 1,  ::GetSysColor(COLOR_3DHIGHLIGHT)),
+                darkpen(PS_SOLID,  1, ::GetSysColor(COLOR_3DDKSHADOW)),
+                *pOldPen = pDC->GetCurrentPen();
+
+            pDC->SelectObject(&lightpen);
+            pDC->MoveTo(rect.right, rect.top);
+            pDC->LineTo(rect.left, rect.top);
+            pDC->LineTo(rect.left, rect.bottom);
+
+            pDC->SelectObject(&darkpen);
+            pDC->MoveTo(rect.right, rect.top);
+            pDC->LineTo(rect.right, rect.bottom);
+            pDC->LineTo(rect.left, rect.bottom);
+
+            pDC->SelectObject(pOldPen);
+            rect.DeflateRect(1,1);
+        }
+    }
+
+    // Draw Text and image
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+    if (!pDC->m_bPrinting)
+#endif
+    {
+        CFont *pFont = GetFontObject();
+//		ASSERT(pFont);
+        if (pFont)
+            pDC->SelectObject(pFont);
+    }
+
+    //rect.DeflateRect(GetMargin(), 0); - changed by Yogurt
+    rect.DeflateRect(GetMargin(), GetMargin());    
+    rect.right++;    
+    rect.bottom++;
+
+    if (pGrid->GetImageList() && GetImage() >= 0)
+    {
+        IMAGEINFO Info;
+        if (pGrid->GetImageList()->GetImageInfo(GetImage(), &Info))
+        {
+            //  would like to use a clipping region but seems to have issue
+            //  working with CMemDC directly.  Instead, don't display image
+            //  if any part of it cut-off
+            //
+            // CRgn rgn;
+            // rgn.CreateRectRgnIndirect(rect);
+            // pDC->SelectClipRgn(&rgn);
+            // rgn.DeleteObject();
+
+            /*
+            // removed by Yogurt
+            int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
+            int nImageHeight = Info.rcImage.bottom-Info.rcImage.top+1;
+            if( nImageWidth + rect.left <= rect.right + (int)(2*GetMargin())
+                && nImageHeight + rect.top <= rect.bottom + (int)(2*GetMargin())  )
+            {
+                pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+            }
+            */
+            // Added by Yogurt
+            int nImageWidth = Info.rcImage.right-Info.rcImage.left;            
+            int nImageHeight = Info.rcImage.bottom-Info.rcImage.top;            
+            if ((nImageWidth + rect.left <= rect.right) && (nImageHeight + rect.top <= rect.bottom))                
+                pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+
+            //rect.left += nImageWidth+GetMargin();
+        }
+    }
+
+    // Draw sort arrow
+    if (pGrid->GetSortColumn() == nCol && nRow == 0)
+    {
+        CSize size = pDC->GetTextExtent(_T("M"));
+        int nOffset = 2;
+
+        // Base the size of the triangle on the smaller of the column
+        // height or text height with a slight offset top and bottom.
+        // Otherwise, it can get drawn outside the bounds of the cell.
+        size.cy -= (nOffset * 2);
+
+        if (size.cy >= rect.Height())
+            size.cy = rect.Height() - (nOffset * 2);
+
+        size.cx = size.cy;      // Make the dimensions square
+
+        // Kludge for vertical text
+        BOOL bVertical = (GetFont()->lfEscapement == 900);
+
+        // Only draw if it'll fit!
+        //if (size.cx + rect.left < rect.right + (int)(2*GetMargin())) - changed / Yogurt
+        if (size.cx + rect.left < rect.right)
+        {
+            int nTriangleBase = rect.bottom - nOffset - size.cy;    // Triangle bottom right
+            //int nTriangleBase = (rect.top + rect.bottom - size.cy)/2; // Triangle middle right
+            //int nTriangleBase = rect.top + nOffset;                 // Triangle top right
+
+            //int nTriangleLeft = rect.right - size.cx;                 // Triangle RHS
+            //int nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle
+            //int nTriangleLeft = rect.left;                            // Triangle LHS
+
+            int nTriangleLeft;
+            if (bVertical)
+                nTriangleLeft = (rect.right + rect.left - size.cx)/2; // Triangle middle
+            else
+                nTriangleLeft = rect.right - size.cx;               // Triangle RHS
+
+            CPen penShadow(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));
+            CPen penLight(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));
+            if (pGrid->GetSortAscending())
+            {
+                // Draw triangle pointing upwards
+                CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight);
+                pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1);
+                pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + 1 );
+                pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + size.cy + 1);
+                pDC->LineTo( nTriangleLeft + 1, nTriangleBase + size.cy + 1);
+
+                pDC->SelectObject(&penShadow);
+                pDC->MoveTo( nTriangleLeft, nTriangleBase + size.cy );
+                pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase );
+                pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase + size.cy );
+                pDC->LineTo( nTriangleLeft, nTriangleBase + size.cy );
+                pDC->SelectObject(pOldPen);
+            }
+            else
+            {
+                // Draw triangle pointing downwards
+                CPen *pOldPen = (CPen*) pDC->SelectObject(&penLight);
+                pDC->MoveTo( nTriangleLeft + 1, nTriangleBase + 1 );
+                pDC->LineTo( nTriangleLeft + (size.cx / 2) + 1, nTriangleBase + size.cy + 1 );
+                pDC->LineTo( nTriangleLeft + size.cx + 1, nTriangleBase + 1 );
+                pDC->LineTo( nTriangleLeft + 1, nTriangleBase + 1 );
+    
+                pDC->SelectObject(&penShadow);
+                pDC->MoveTo( nTriangleLeft, nTriangleBase );
+                pDC->LineTo( nTriangleLeft + (size.cx / 2), nTriangleBase + size.cy );
+                pDC->LineTo( nTriangleLeft + size.cx, nTriangleBase );
+                pDC->LineTo( nTriangleLeft, nTriangleBase );
+                pDC->SelectObject(pOldPen);
+            }
+            
+            if (!bVertical)
+                rect.right -= size.cy;
+        }
+    }
+
+    // We want to see '&' characters so use DT_NOPREFIX
+    GetTextRect(rect);
+    rect.right++;    
+    rect.bottom++;
+
+    DrawText(pDC->m_hDC, GetText(), -1, rect, GetFormat() | DT_NOPREFIX);
+
+    pDC->RestoreDC(nSavedDC);
+
+    return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Mouse and Cursor events
+
+// Not yet implemented
+void CGridCellBase::OnMouseEnter()
+{
+//    TRACE0("Mouse entered cell\n");
+}
+
+void CGridCellBase::OnMouseOver()
+{
+    //TRACE0("Mouse over cell\n");
+}
+
+// Not Yet Implemented
+void CGridCellBase::OnMouseLeave()
+{
+//    TRACE0("Mouse left cell\n");
+}
+
+void CGridCellBase::OnClick( CPoint PointCellRelative)
+{
+    UNUSED_ALWAYS(PointCellRelative);
+//    TRACE2("Mouse Left btn up in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnClickDown( CPoint PointCellRelative)
+{
+    UNUSED_ALWAYS(PointCellRelative);
+ //   TRACE2("Mouse Left btn down in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnRClick( CPoint PointCellRelative)
+{
+    UNUSED_ALWAYS(PointCellRelative);
+ //   TRACE2("Mouse right-clicked in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+void CGridCellBase::OnDblClick( CPoint PointCellRelative)
+{
+    UNUSED_ALWAYS(PointCellRelative);
+//    TRACE2("Mouse double-clicked in cell at x=%i y=%i\n", PointCellRelative.x, PointCellRelative.y);
+}
+
+// Return TRUE if you set the cursor
+BOOL CGridCellBase::OnSetCursor()
+{
+#ifndef _WIN32_WCE_NO_CURSOR
+    SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+    return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase editing
+
+void CGridCellBase::OnEndEdit() 
+{
+//	ASSERT( FALSE); 
+}
+
+BOOL CGridCellBase::ValidateEdit(LPCTSTR str)
+{
+    UNUSED_ALWAYS(str);
+	return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellBase Sizing
+
+BOOL CGridCellBase::GetTextRect( LPRECT pRect)  // i/o:  i=dims of cell rect; o=dims of text rect
+{
+    if (GetImage() >= 0)
+    {
+        IMAGEINFO Info;
+
+        CGridCtrl* pGrid = GetGrid();
+        CImageList* pImageList = pGrid->GetImageList();
+        
+        if (pImageList && pImageList->GetImageInfo( GetImage(), &Info))
+        {
+            int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
+            pRect->left += nImageWidth + GetMargin();
+        }
+    }
+
+    return TRUE;
+}
+
+// By default this uses the selected font (which is a bigger font)
+CSize CGridCellBase::GetTextExtent(LPCTSTR szText, CDC* pDC /*= NULL*/)
+{
+    CGridCtrl* pGrid = GetGrid();
+//    ASSERT(pGrid);
+
+    BOOL bReleaseDC = FALSE;
+    if (pDC == NULL || szText == NULL)
+    {
+        if (szText)
+			pDC = pGrid->GetDC();
+        if (pDC == NULL || szText == NULL) 
+        {
+            CGridDefaultCell* pDefCell = (CGridDefaultCell*) GetDefaultCell();
+//            ASSERT(pDefCell);
+            return CSize(pDefCell->GetWidth(), pDefCell->GetHeight());
+        }
+        bReleaseDC = TRUE;
+    }
+
+    CFont *pOldFont = NULL,
+          *pFont = GetFontObject();
+    if (pFont)
+        pOldFont = pDC->SelectObject(pFont);
+
+    CSize size;
+    int nFormat = GetFormat();
+
+    // If the cell is a multiline cell, then use the width of the cell
+    // to get the height
+    if ((nFormat & DT_WORDBREAK) && !(nFormat & DT_SINGLELINE))
+    {
+        CString str = szText;
+        int nMaxWidth = 0;
+        while (TRUE)
+        {
+            int nPos = str.Find(_T('\n'));
+            CString TempStr = (nPos < 0)? str : str.Left(nPos);
+            int nTempWidth = pDC->GetTextExtent(TempStr).cx;
+            if (nTempWidth > nMaxWidth)
+                nMaxWidth = nTempWidth;
+
+            if (nPos < 0)
+                break;
+            str = str.Mid(nPos + 1);    // Bug fix by Thomas Steinborn
+        }
+        
+        CRect rect;
+        rect.SetRect(0,0, nMaxWidth+1, 0);
+        pDC->DrawText(szText, -1, rect, nFormat | DT_CALCRECT);
+        size = rect.Size();
+    }
+    else
+        size = pDC->GetTextExtent(szText, (int)_tcslen(szText));
+
+    // Removed by Yogurt
+    //TEXTMETRIC tm;
+    //pDC->GetTextMetrics(&tm);
+    //size.cx += (tm.tmOverhang);
+
+    if (pOldFont)
+        pDC->SelectObject(pOldFont);
+    
+    size += CSize(2*GetMargin(), 2*GetMargin());
+
+    // Kludge for vertical text
+    LOGFONT *pLF = GetFont();
+    if (pLF->lfEscapement == 900 || pLF->lfEscapement == -900)
+    {
+        int nTemp = size.cx;
+        size.cx = size.cy;
+        size.cy = nTemp;
+        size += CSize(0, 4*GetMargin());
+    }
+    
+    if (bReleaseDC)
+        pGrid->ReleaseDC(pDC);
+
+    return size;
+}
+
+
+CSize CGridCellBase::GetCellExtent(CDC* pDC)
+{    
+    CSize size = GetTextExtent(GetText(), pDC);    
+    CSize ImageSize(0,0);    
+    
+    int nImage = GetImage();    
+    if (nImage >= 0)    
+    {        
+        CGridCtrl* pGrid = GetGrid();        
+//        ASSERT(pGrid);        
+        IMAGEINFO Info;        
+        if (pGrid->GetImageList() && pGrid->GetImageList()->GetImageInfo(nImage, &Info))         
+        {            
+            ImageSize = CSize(Info.rcImage.right-Info.rcImage.left,                                 
+                Info.rcImage.bottom-Info.rcImage.top);            
+            if (size.cx > 2*(int)GetMargin ())                
+                ImageSize.cx += GetMargin();            
+            ImageSize.cy += 2*(int)GetMargin ();        
+        }    
+    }    
+    size.cx += ImageSize.cx + 1;    
+    size.cy = max(size.cy, ImageSize.cy) + 1;    
+    if (IsFixed())    
+    {        
+        size.cx++;        
+        size.cy++;    
+    }    
+    return size;
+}
+
+// EFW - Added to print cells so that grids that use different colors are
+// printed correctly.
+BOOL CGridCellBase::PrintCell(CDC* pDC, int /*nRow*/, int /*nCol*/, CRect rect)
+{
+#if defined(_WIN32_WCE_NO_PRINTING) || defined(GRIDCONTROL_NO_PRINTING)
+    return FALSE;
+#else
+    COLORREF crFG, crBG;
+    GV_ITEM Item;
+
+    CGridCtrl* pGrid = GetGrid();
+    if (!pGrid || !pDC)
+        return FALSE;
+
+    if( rect.Width() <= 0
+        || rect.Height() <= 0)  // prevents imagelist item from drawing even
+        return FALSE;           //  though cell is hidden
+
+    int nSavedDC = pDC->SaveDC();
+
+    pDC->SetBkMode(TRANSPARENT);
+
+    if (pGrid->GetShadedPrintOut())
+    {
+        // Get the default cell implementation for this kind of cell. We use it if this cell
+        // has anything marked as "default"
+        CGridDefaultCell *pDefaultCell = (CGridDefaultCell*) GetDefaultCell();
+        if (!pDefaultCell)
+            return FALSE;
+
+        // Use custom color if it doesn't match the default color and the
+        // default grid background color.  If not, leave it alone.
+        if(IsFixed())
+            crBG = (GetBackClr() != CLR_DEFAULT) ? GetBackClr() : pDefaultCell->GetBackClr();
+        else
+            crBG = (GetBackClr() != CLR_DEFAULT && GetBackClr() != pDefaultCell->GetBackClr()) ?
+                GetBackClr() : CLR_DEFAULT;
+
+        // Use custom color if the background is different or if it doesn't
+        // match the default color and the default grid text color.  
+        if(IsFixed())
+            crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr();
+        else
+            crFG = (GetBackClr() != CLR_DEFAULT) ? GetTextClr() : pDefaultCell->GetTextClr();
+
+        // If not printing on a color printer, adjust the foreground color
+        // to a gray scale if the background color isn't used so that all
+        // colors will be visible.  If not, some colors turn to solid black
+        // or white when printed and may not show up.  This may be caused by
+        // coarse dithering by the printer driver too (see image note below).
+        if(pDC->GetDeviceCaps(NUMCOLORS) == 2 && crBG == CLR_DEFAULT)
+            crFG = RGB(GetRValue(crFG) * 0.30, GetGValue(crFG) * 0.59,
+                GetBValue(crFG) * 0.11);
+
+        // Only erase the background if the color is not the default
+        // grid background color.
+        if(crBG != CLR_DEFAULT)
+        {
+            CBrush brush(crBG);
+            rect.right++; rect.bottom++;
+            pDC->FillRect(rect, &brush);
+            rect.right--; rect.bottom--;
+        }
+    }
+    else
+    {
+        crBG = CLR_DEFAULT;
+        crFG = RGB(0, 0, 0);
+    }
+
+    pDC->SetTextColor(crFG);
+
+    CFont *pFont = GetFontObject();
+    if (pFont)
+        pDC->SelectObject(pFont);
+
+    /*
+    // ***************************************************
+    // Disabled - if you need this functionality then you'll need to rewrite.
+    // Create the appropriate font and select into DC.
+    CFont Font;
+    // Bold the fixed cells if not shading the print out.  Use italic
+    // font it it is enabled.
+    const LOGFONT* plfFont = GetFont();
+    if(IsFixed() && !pGrid->GetShadedPrintOut())
+    {
+        Font.CreateFont(plfFont->lfHeight, 0, 0, 0, FW_BOLD, plfFont->lfItalic, 0, 0,
+            ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+#ifndef _WIN32_WCE
+            PROOF_QUALITY,
+#else
+            DEFAULT_QUALITY,
+#endif
+            VARIABLE_PITCH | FF_SWISS, plfFont->lfFaceName);
+    }
+    else
+        Font.CreateFontIndirect(plfFont);
+
+    pDC->SelectObject(&Font);
+    // ***************************************************
+    */
+
+    // Draw lines only when wanted on fixed cells.  Normal cell grid lines
+    // are handled in OnPrint.
+    if(pGrid->GetGridLines() != GVL_NONE && IsFixed())
+    {
+        CPen lightpen(PS_SOLID, 1,  ::GetSysColor(COLOR_3DHIGHLIGHT)),
+             darkpen(PS_SOLID,  1, ::GetSysColor(COLOR_3DDKSHADOW)),
+            *pOldPen = pDC->GetCurrentPen();
+
+        pDC->SelectObject(&lightpen);
+        pDC->MoveTo(rect.right, rect.top);
+        pDC->LineTo(rect.left, rect.top);
+        pDC->LineTo(rect.left, rect.bottom);
+
+        pDC->SelectObject(&darkpen);
+        pDC->MoveTo(rect.right, rect.top);
+        pDC->LineTo(rect.right, rect.bottom);
+        pDC->LineTo(rect.left, rect.bottom);
+
+        rect.DeflateRect(1,1);
+        pDC->SelectObject(pOldPen);
+    }
+
+    rect.DeflateRect(GetMargin(), 0);
+
+    if(pGrid->GetImageList() && GetImage() >= 0)
+    {
+        // NOTE: If your printed images look like fuzzy garbage, check the
+        //       settings on your printer driver.  If it's using coarse
+        //       dithering and/or vector graphics, they may print wrong.
+        //       Changing to fine dithering and raster graphics makes them
+        //       print properly.  My HP 4L had that problem.
+
+        IMAGEINFO Info;
+        if(pGrid->GetImageList()->GetImageInfo(GetImage(), &Info))
+        {
+            int nImageWidth = Info.rcImage.right-Info.rcImage.left;
+            pGrid->GetImageList()->Draw(pDC, GetImage(), rect.TopLeft(), ILD_NORMAL);
+            rect.left += nImageWidth+GetMargin();
+        }
+    }
+
+    // Draw without clipping so as not to lose text when printed for real
+	// DT_NOCLIP removed 01.01.01. Slower, but who cares - we are printing!
+    DrawText(pDC->m_hDC, GetText(), -1, rect,
+        GetFormat() | /*DT_NOCLIP | */ DT_NOPREFIX);
+
+    pDC->RestoreDC(nSavedDC);
+
+    return TRUE;
+#endif
+}
+
+/*****************************************************************************
+Callable by derived classes, only
+*****************************************************************************/
+LRESULT CGridCellBase::SendMessageToParent(int nRow, int nCol, int nMessage)
+{
+    CGridCtrl* pGrid = GetGrid();
+    if( pGrid)
+        return pGrid->SendMessageToParent(nRow, nCol, nMessage);
+    else
+        return 0;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellBase.h b/SourceCode/Bond/Servo/GridControl/GridCellBase.h
new file mode 100644
index 0000000..d038c82
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellBase.h
@@ -0,0 +1,172 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCellBase.h : header file
+//
+// MFC Grid Control - Grid cell base class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridCtrl;
+
+// Cell states
+#define GVIS_FOCUSED            0x0001
+#define GVIS_SELECTED           0x0002
+#define GVIS_DROPHILITED        0x0004
+#define GVIS_READONLY           0x0008
+#define GVIS_FIXED              0x0010
+#define GVIS_FIXEDROW           0x0020
+#define GVIS_FIXEDCOL           0x0040
+#define GVIS_MODIFIED           0x0080
+
+// Cell data mask
+#define GVIF_TEXT               LVIF_TEXT
+#define GVIF_IMAGE              LVIF_IMAGE
+#define GVIF_PARAM              LVIF_PARAM
+#define GVIF_STATE              LVIF_STATE
+#define GVIF_BKCLR              (GVIF_STATE<<1)
+#define GVIF_FGCLR              (GVIF_STATE<<2)
+#define GVIF_FORMAT             (GVIF_STATE<<3)
+#define GVIF_FONT               (GVIF_STATE<<4)
+#define GVIF_MARGIN             (GVIF_STATE<<5)
+#define GVIF_ALL                (GVIF_TEXT|GVIF_IMAGE|GVIF_PARAM|GVIF_STATE|GVIF_BKCLR|GVIF_FGCLR| \
+                                 GVIF_FORMAT|GVIF_FONT|GVIF_MARGIN)
+
+// Used for Get/SetItem calls.
+typedef struct _GV_ITEM {
+    int      row,col;     // Row and Column of item
+    UINT     mask;        // Mask for use in getting/setting cell data
+    UINT     nState;      // cell state (focus/hilighted etc)
+    DWORD    nFormat;     // Format of cell
+    int      iImage;      // index of the list view item抯 icon
+    COLORREF crBkClr;     // Background colour (or CLR_DEFAULT)
+    COLORREF crFgClr;     // Forground colour (or CLR_DEFAULT)
+    LPARAM   lParam;      // 32-bit value to associate with item
+    LOGFONT  lfFont;      // Cell font
+    UINT     nMargin;     // Internal cell margin
+    CString  strText;     // Text in cell
+} GV_ITEM;
+
+
+// Each cell contains one of these. Fields "row" and "column" are not stored since we
+// will usually have acces to them in other ways, and they are an extra 8 bytes per
+// cell that is probably unnecessary.
+
+class CGridCellBase : public CObject
+{
+    friend class CGridCtrl;
+    DECLARE_DYNAMIC(CGridCellBase)
+
+// Construction/Destruction
+public:
+    CGridCellBase();
+    virtual ~CGridCellBase();
+
+// Attributes
+public:
+    virtual void SetText(LPCTSTR /* szText */)              = 0 ;
+    virtual void SetImage(int /* nImage */)                 = 0 ;
+    virtual void SetData(LPARAM /* lParam */)               = 0 ;
+    virtual void SetState(DWORD nState)                     { m_nState = nState; }
+    virtual void SetFormat(DWORD /* nFormat */)             = 0 ;
+    virtual void SetTextClr(COLORREF /* clr */)             = 0 ;
+    virtual void SetBackClr(COLORREF /* clr */)             = 0 ;
+    virtual void SetFont(const LOGFONT* /* plf */)          = 0 ;
+    virtual void SetMargin( UINT /* nMargin */)             = 0 ;
+    virtual void SetGrid(CGridCtrl* /* pGrid */)            = 0 ;
+    virtual void SetCoords( int /* nRow */, int /* nCol */) = 0 ;
+
+    virtual LPCTSTR    GetText()       const                = 0 ;
+    virtual LPCTSTR    GetTipText()    const                { return GetText(); } // may override TitleTip return
+    virtual int        GetImage()      const                = 0 ;
+    virtual LPARAM     GetData()       const                = 0 ;
+    virtual DWORD      GetState()      const                { return m_nState;  }
+    virtual DWORD      GetFormat()     const                = 0 ;
+    virtual COLORREF   GetTextClr()    const                = 0 ;
+    virtual COLORREF   GetBackClr()    const                = 0 ;
+    virtual LOGFONT  * GetFont()       const                = 0 ;
+    virtual CFont    * GetFontObject() const                = 0 ;
+    virtual CGridCtrl* GetGrid()       const                = 0 ;
+    virtual CWnd     * GetEditWnd()    const                = 0 ;
+    virtual UINT       GetMargin()     const                = 0 ;
+
+    virtual CGridCellBase* GetDefaultCell() const;
+
+    virtual BOOL IsDefaultFont()       const                = 0 ;
+    virtual BOOL IsEditing()           const                = 0 ;
+    virtual BOOL IsFocused()           const                { return (m_nState & GVIS_FOCUSED);  }
+    virtual BOOL IsFixed()             const                { return (m_nState & GVIS_FIXED);    }
+    virtual BOOL IsFixedCol()          const                { return (m_nState & GVIS_FIXEDCOL); }
+    virtual BOOL IsFixedRow()          const                { return (m_nState & GVIS_FIXEDROW); }
+    virtual BOOL IsSelected()          const                { return (m_nState & GVIS_SELECTED); }
+    virtual BOOL IsReadOnly()          const                { return (m_nState & GVIS_READONLY); }
+    virtual BOOL IsModified()          const                { return (m_nState & GVIS_MODIFIED); }
+    virtual BOOL IsDropHighlighted()   const                { return (m_nState & GVIS_DROPHILITED); }
+
+// Operators
+public:
+    virtual void operator=(const CGridCellBase& cell);
+
+// Operations
+public:
+    virtual void Reset();
+
+    virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+    virtual BOOL GetTextRect( LPRECT pRect);    // i/o:  i=dims of cell rect; o=dims of text rect
+    virtual BOOL GetTipTextRect( LPRECT pRect) { return GetTextRect( pRect); }  // may override for btns, etc.
+    virtual CSize GetTextExtent(LPCTSTR str, CDC* pDC = NULL);
+    virtual CSize GetCellExtent(CDC* pDC);
+
+    // Editing
+    virtual BOOL Edit( int /* nRow */, int /* nCol */, CRect /* rect */, CPoint /* point */, 
+                       UINT /* nID */, UINT /* nChar */) { return FALSE;}
+	virtual BOOL ValidateEdit(LPCTSTR str);
+    virtual void EndEdit() {}
+
+    // EFW - Added to print cells properly
+    virtual BOOL PrintCell(CDC* pDC, int nRow, int nCol, CRect rect);
+
+    // add additional protected grid members required of cells
+    LRESULT SendMessageToParent(int nRow, int nCol, int nMessage);
+
+protected:
+    virtual void OnEndEdit();
+    virtual void OnMouseEnter();
+    virtual void OnMouseOver();
+    virtual void OnMouseLeave();
+    virtual void OnClick( CPoint PointCellRelative);
+    virtual void OnClickDown( CPoint PointCellRelative);
+    virtual void OnRClick( CPoint PointCellRelative);
+    virtual void OnDblClick( CPoint PointCellRelative);
+    virtual BOOL OnSetCursor();
+
+protected:
+    DWORD    m_nState;      // Cell state (selected/focus etc)
+};
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLBASE_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp b/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp
new file mode 100644
index 0000000..f922942
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellButton.cpp
@@ -0,0 +1,46 @@
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellButton.h"  
+
+#ifdef _DEBUG  
+#define new DEBUG_NEW  
+#undef THIS_FILE  
+static const char* THIS_FILE = __FILE__;
+#endif  
+
+IMPLEMENT_DYNCREATE(CGridCellButton, CGridCell)
+	CGridCellButton::CGridCellButton(void)
+{
+	m_bPushing = FALSE;
+}
+
+CGridCellButton::~CGridCellButton(void)
+{
+}
+
+BOOL CGridCellButton::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd /* = TRUE */)
+{
+	m_rect = rect;
+	pDC->SetBkMode(TRANSPARENT);
+	rect.DeflateRect(GetMargin(), 0);
+	CFont* pOldFont = pDC->SelectObject(GetFontObject());
+	pDC->DrawFrameControl(rect, DFC_BUTTON, m_bPushing ? DFCS_BUTTONPUSH | DFCS_PUSHED : DFCS_BUTTONPUSH);
+	COLORREF ColorCurrent = pDC->GetTextColor();
+	pDC->SetTextColor(::GetSysColor(COLOR_BTNTEXT));
+	pDC->DrawText(GetText(), -1, rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);
+	pDC->SetTextColor(ColorCurrent);
+	return TRUE;
+}
+
+void CGridCellButton::OnClick(CPoint PointCellRelative)
+{
+	m_bPushing = !m_bPushing;
+	GetGrid()->InvalidateRect(m_rect);
+}
+
+void CGridCellButton::OnMouseLeave()
+{
+	m_bPushing = FALSE;
+	GetGrid()->InvalidateRect(m_rect);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCellButton.h b/SourceCode/Bond/Servo/GridControl/GridCellButton.h
new file mode 100644
index 0000000..ef4f410
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCellButton.h
@@ -0,0 +1,28 @@
+#ifndef __GRID_CELL_BUTTON__
+#define __GRID_CELL_BUTTON__
+
+#include "GridCell.h"
+
+class CGridCellButton : public CGridCell
+{
+	friend class CGridCtrl;
+	DECLARE_DYNCREATE(CGridCellButton)
+
+public:
+	CGridCellButton(void);
+	virtual ~CGridCellButton(void);
+
+	void SetPushing(BOOL bPush) {m_bPushing = bPush;}
+
+public:
+	virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+protected:
+	virtual void OnClick(CPoint PointCellRelative);
+	virtual void OnMouseLeave();
+
+protected:
+	CRect m_rect;
+	BOOL m_bPushing;
+};
+#endif
diff --git a/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp b/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp
new file mode 100644
index 0000000..2ad4846
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCtrl.cpp
@@ -0,0 +1,8428 @@
+// GridCtrl.cpp : implementation file
+//
+// MFC Grid Control v2.26
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// The code contained in this file was based on the original
+// WorldCom Grid control written by Joe Willcoxson,
+//        mailto:chinajoe@aol.com
+//        http://users.aol.com/chinajoe
+// (These addresses may be out of date) The code has gone through 
+// so many modifications that I'm not sure if there is even a single 
+// original line of code. In any case Joe's code was a great 
+// framework on which to build.
+//
+// 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. 
+//
+// An email letting me know how 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. 
+//
+//  History:
+//  --------
+//  This control is constantly evolving, sometimes due to new features that I
+//  feel are necessary, and sometimes due to existing bugs. Where possible I
+//  have credited the changes to those who contributed code corrections or
+//  enhancements (names in brackets) or code suggestions (suggested by...)
+//
+//          1.0 - 1.13   20 Feb 1998 - 6 May 1999
+//                          First release version. Progressed from being a basic
+//                          grid based on the original WorldCom Grid control
+//                          written by Joe Willcoxson (mailto:chinajoe@aol.com,
+//                          http://users.aol.com/chinajoe) to something a little
+//                          more feature rich. Rewritten so many times I doubt
+//                          there is a single line of Joe's code left. Many, many,
+//                          MANY people sent in bug reports and fixes. Thank you
+//                          all.
+//
+//          2.0         1 Feb 2000
+//                          Rewritten to make the grid more object oriented, in
+//                          that the CGridCell class now takes care of cell-specific
+//                          tasks. This makes the code more robust, but more
+//                          importantly it allows the simple insertion of other
+//                          types of cells.
+//                          
+//          2.10       11 Mar 2000 - Ken Bertelson and Chris Maunder
+//                          - Additions for virtual CGridCell support of embedded tree 
+//                            & cell buttons implementation
+//                          - Optional WYSIWYG printing
+//                          - Awareness of hidden (0 width/height) rows and columns for 
+//                            key movements,  cut, copy, paste, and autosizing
+//                          - CGridCell can make title tips display any text rather than 
+//                            cell text only
+//                          - Minor vis bug fixes
+//                          - CGridCtrl now works with CGridCellBase instead of CGridCell
+//                            This is a taste of things to come.
+//
+//          2.20       30 Jul 2000 - Chris Maunder
+//                          - Font storage optimised (suggested by Martin Richter)
+//                          - AutoSizeColumn works on either column header, data or both
+//                          - EnsureVisible. The saga continues... (Ken)
+//                          - Rewrote exception handling
+//                          - Added TrackFocusCell and FrameFocusCell properties, as well as
+//                            ExpandLastColumn (suggested by Bruce E. Stemplewski).
+//                          - InsertColumn now allows you to insert columns at the end of the
+//                            column range (David Weibel)
+//                          - Shift-cell-selection more intuitive
+//                          - API change: Set/GetGridColor now Set/GetGridLineColor
+//                          - API change: Set/GetBkColor now Set/GetGridBkColor
+//                          - API change: Set/GetTextColor, Set/GetTextBkColor depricated 
+//                          - API change: Set/GetFixedTextColor, Set/GetFixedBkColor depricated 
+//                          - Stupid DDX_GridControl workaround removed.
+//                          - Added "virtual mode" via Set/GetVirtualMode
+//                          - Added SetCallbackFunc to allow callback functions in virtual mode
+//                          - Added Set/GetAutoSizeStyle
+//                          - AutoSize() bug fixed
+//                          - added GVIS_FIXEDROW, GVIS_FIXEDCOL states
+//                          - added Get/SetFixed[Row|Column]Selection
+//                          - cell "Get" methods now const'd. Sorry folks...
+//                          - GetMouseScrollLines now uses win98/W2K friendly code
+//                          - WS_EX_CLIENTEDGE style now implicit
+//
+//                          [ Only the latest version and major version changes will be shown ]
+////
+//          2.25       13 Mar 2004 - Chris Maunder
+//                                 - Minor changes so it will compile in VS.NET (inc. Whidbey)
+//                                 - Fixed minor bug in EnsureVisible - Junlin Xu
+//                                 - Changed AfxGetInstanceHandle for AfxGetResourceHandle in RegisterWindowClass
+//					               - Various changes thanks to Yogurt
+//
+//          2.26       13 Dec 2005 - Pierre Couderc
+//                                 - Added sort in Virtual mode
+//                                 - Change row/column order programatically or via drag and drop
+//                                 - Added save/restore layer (for undoing row/column order changes)
+//
+// TODO:   1) Implement sparse grids (super easy now)
+//         2) Fix it so that as you drag select, the speed of selection increases
+//            with time.
+//         3) Scrolling is still a little dodgy (too much grey area). I know there
+//            is a simple fix but it's been a low priority
+//
+// ISSUES: 1) WindowFromPoint seems to do weird things in W2K. Causing problems for
+//            the rigt-click-on-titletip code.
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridMemDC.h"
+#include "GridCtrl.h"
+#include <algorithm>
+
+// OLE stuff for clipboard operations
+#include <afxadv.h>            // For CSharedFile
+#include <afxconv.h>           // For LPTSTR -> LPSTR macros
+
+// OLE stuff for drag and drop
+#include <VersionHelpers.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+// Spit out some messages as a sanity check for programmers
+#ifdef GRIDCONTROL_NO_TITLETIPS
+#pragma message(" -- CGridCtrl: No titletips for cells with large data")
+#endif
+#ifdef GRIDCONTROL_NO_DRAGDROP
+#pragma message(" -- CGridCtrl: No OLE drag and drop")
+#endif
+#ifdef GRIDCONTROL_NO_CLIPBOARD
+#pragma message(" -- CGridCtrl: No clipboard support")
+#endif
+#ifdef GRIDCONTROL_NO_PRINTING
+#pragma message(" -- CGridCtrl: No printing support")
+#endif
+
+
+IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
+
+
+// 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
+
+#ifndef _WIN32_WCE
+    // Do things the hard way in win95
+    OSVERSIONINFO VersionInfo = { 0 };
+    VersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+    if (!IsWindowsXPOrGreater() || (VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS && VersionInfo.dwMinorVersion == 0))
+    {
+        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);
+        }
+    }
+    // win98 or greater
+    else
+           SystemParametersInfo (SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
+#endif
+
+    return nScrollLines;
+}
+
+CRect  CGridCtrl::rectNull(0, 0, 0, 0);
+CCellID CGridCtrl::cellNull(0, 0);
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl
+
+CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
+{
+    RegisterWindowClass();
+
+#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
+    _AFX_THREAD_STATE* pState = AfxGetThreadState();
+    if (!pState->m_bNeedTerm && !AfxOleInit())
+        AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
+#endif
+
+    // Store the system colours in case they change. The gridctrl uses
+    // these colours, and in OnSysColorChange we can check to see if
+    // the gridctrl colours have been changed from the system colours.
+    // If they have, then leave them, otherwise change them to reflect
+    // the new system colours.
+    m_crWindowText        = ::GetSysColor(COLOR_WINDOWTEXT);
+    m_crWindowColour      = ::GetSysColor(COLOR_WINDOW);
+    m_cr3DFace            = ::GetSysColor(COLOR_3DFACE);
+    m_crShadow            = ::GetSysColor(COLOR_3DSHADOW);
+    m_crGridLineColour    = RGB(192,192,192);
+
+    m_nRows               = 0;
+    m_nCols               = 0;
+    m_nFixedRows          = 0;
+    m_nFixedCols          = 0;
+	m_InDestructor        = false;
+
+    m_bVirtualMode        = FALSE;
+    m_pfnCallback         = NULL;
+
+    m_nVScrollMax         = 0;          // Scroll position
+    m_nHScrollMax         = 0;
+    m_nRowsPerWheelNotch  = GetMouseScrollLines(); // Get the number of lines
+                                                   // per mouse wheel notch to scroll
+    m_nBarState           = GVL_NONE;
+    m_MouseMode           = MOUSE_NOTHING;
+    m_nGridLines          = GVL_BOTH;
+    m_bEditable           = TRUE;
+    m_bListMode           = FALSE;
+    m_bSingleRowSelection = FALSE;
+    m_bSingleColSelection = FALSE;
+    m_bLMouseButtonDown   = FALSE;
+    m_bRMouseButtonDown   = FALSE;
+    m_bAllowDraw          = TRUE;       // allow draw updates
+    m_bEnableSelection    = TRUE;
+    m_bFixedColumnSelection = TRUE;
+    m_bFixedRowSelection  = TRUE;
+    m_bAllowRowResize     = TRUE;
+    m_bAllowColumnResize  = TRUE;
+    m_bSortOnClick        = FALSE;      // Sort on header row click
+    m_bHandleTabKey       = TRUE;
+#ifdef _WIN32_WCE
+    m_bDoubleBuffer       = FALSE;      // Use double buffering to avoid flicker?
+#else
+    m_bDoubleBuffer       = TRUE;       // Use double buffering to avoid flicker?
+#endif
+    m_bTitleTips          = TRUE;       // show cell title tips
+
+    m_bWysiwygPrinting    = FALSE;      // use size-to-width printing
+
+    m_bHiddenColUnhide    = TRUE;       // 0-width columns can be expanded via mouse
+    m_bHiddenRowUnhide    = TRUE;       // 0-Height rows can be expanded via mouse
+
+    m_bAllowColHide       = TRUE;       // Columns can be contracted to 0-width via mouse
+    m_bAllowRowHide       = TRUE;       // Rows can be contracted to 0-height via mouse
+
+    m_bAscending          = TRUE;       // sorting stuff
+    m_nSortColumn         = -1;
+	m_pfnCompare		  = NULL;
+	m_pfnVirtualCompare   = NULL;
+    m_nAutoSizeColumnStyle = GVS_BOTH;  // Autosize grid using header and data info
+
+    m_nTimerID            = 0;          // For drag-selection
+    // LUC
+	m_nTimerInterval      = 150;         // (in milliseconds)
+    m_nResizeCaptureRange = 3;          // When resizing columns/row, the cursor has to be
+                                        // within +/-3 pixels of the dividing line for
+                                        // resizing to be possible
+    m_pImageList          = NULL;       // Images in the grid
+    m_bAllowDragAndDrop   = FALSE;      // for drag and drop - EFW - off by default
+    m_bTrackFocusCell     = FALSE;       // Track Focus cell?
+    m_bFrameFocus         = TRUE;       // Frame the selected cell?
+	m_AllowReorderColumn	= false;
+	m_QuitFocusOnTab = false;
+	m_AllowSelectRowInFixedCol = false;
+	m_bDragRowMode = TRUE; // allow to drop a line over another one to change row order
+    m_pRtcDefault = RUNTIME_CLASS(CGridCell);
+
+    SetupDefaultCells();
+    SetGridBkColor(m_crShadow);
+
+    // Set up the initial grid size
+    SetRowCount(nRows);
+    SetColumnCount(nCols);
+    SetFixedRowCount(nFixedRows);
+    SetFixedColumnCount(nFixedCols);
+	// LUC
+	m_nFreezedRows = 0;
+	m_nFreezedCols = 0;
+
+	// LUC
+	m_bExcludeFreezedRowsFromSelection = FALSE;
+	m_bExcludeFreezedColsFromSelection = FALSE;
+
+    SetTitleTipTextClr(CLR_DEFAULT);  //FNA
+    SetTitleTipBackClr(CLR_DEFAULT); 
+
+    // set initial selection range (ie. none)
+    m_SelectedCellMap.RemoveAll();
+    m_PrevSelectedCellMap.RemoveAll();
+
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+    // EFW - Added to support shaded/unshaded printout and
+    // user-definable margins.
+    m_bShadedPrintOut = TRUE;
+    SetPrintMarginInfo(2, 2, 4, 4, 1, 1, 1);
+#endif	
+
+	// LUC
+	m_bDrawingMergedCell = FALSE;
+	m_nCurrentMergeID = -1;
+	// LUC
+	m_bShowHorzNonGridArea = FALSE;
+}
+
+CGridCtrl::~CGridCtrl()
+{
+	m_InDestructor = true;
+    DeleteAllItems();
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+    if (m_bTitleTips && ::IsWindow(m_TitleTip.GetSafeHwnd())) 
+        m_TitleTip.DestroyWindow();
+#endif
+
+    DestroyWindow();
+
+#if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
+    // BUG FIX - EFW
+    COleDataSource *pSource = COleDataSource::GetClipboardOwner();
+    if(pSource)
+        COleDataSource::FlushClipboard();
+#endif
+}
+
+// Register the window class if it has not already been registered.
+BOOL CGridCtrl::RegisterWindowClass()
+{
+    WNDCLASS wndcls;
+    //HINSTANCE hInst = AfxGetInstanceHandle();
+    HINSTANCE hInst = AfxGetResourceHandle();
+
+    if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
+    {
+        // otherwise we need to register a new class
+        wndcls.style            = CS_DBLCLKS;
+        wndcls.lpfnWndProc      = ::DefWindowProc;
+        wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
+        wndcls.hInstance        = hInst;
+        wndcls.hIcon            = NULL;
+#ifndef _WIN32_WCE_NO_CURSOR
+        wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
+#else
+        wndcls.hCursor          = 0;
+#endif
+        wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
+        wndcls.lpszMenuName     = NULL;
+        wndcls.lpszClassName    = GRIDCTRL_CLASSNAME;
+
+        if (!AfxRegisterClass(&wndcls))
+        {
+            AfxThrowResourceException();
+            return FALSE;
+        }
+    }
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::Initialise()
+{
+    // Stop re-entry problems
+    static BOOL bInProcedure = FALSE;
+    if (bInProcedure)
+        return FALSE;
+    bInProcedure = TRUE;
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+    m_TitleTip.SetParentWnd(this);
+#endif
+
+	// This would be a good place to register the droptarget but
+	// unfortunately this causes problems if you are using the 
+	// grid in a view. 
+	// Moved from OnSize.
+//#ifndef GRIDCONTROL_NO_DRAGDROP
+//    m_DropTarget.Register(this);
+//#endif
+
+    if (::IsWindow(m_hWnd))
+        ModifyStyleEx(0, WS_EX_CLIENTEDGE);
+
+	// Kludge: Make sure the client edge shows
+	// This is so horrible it makes my eyes water.
+	CRect rect;
+	GetWindowRect(rect);
+	CWnd* pParent = GetParent();
+	if (pParent != NULL)
+		pParent->ScreenToClient(rect);
+	rect.InflateRect(1,1);	MoveWindow(rect);
+	rect.DeflateRect(1,1);  MoveWindow(rect);
+ 
+    bInProcedure = FALSE;
+    return TRUE;
+}
+
+// creates the control - use like any other window create control
+BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
+{
+//    ASSERT(pParentWnd->GetSafeHwnd());
+
+    if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
+        return FALSE;
+
+    //Initialise(); - called in PreSubclassWnd
+
+    // The number of rows and columns will only be non-zero if the constructor
+    // was called with non-zero initialising parameters. If this window was created
+    // using a dialog template then the number of rows and columns will be 0 (which
+    // means that the code below will not be needed - which is lucky 'cause it ain't
+    // gonna get called in a dialog-template-type-situation.
+
+    TRY
+    {
+        m_arRowHeights.SetSize(m_nRows);    // initialize row heights
+        m_arColWidths.SetSize(m_nCols);     // initialize column widths
+    }
+    CATCH (CMemoryException, e)
+    {
+        e->ReportError();
+        return FALSE;
+    }
+    END_CATCH
+
+    int i;
+    for (i = 0; i < m_nRows; i++)
+        m_arRowHeights[i] = m_cellDefault.GetHeight();
+    for (i = 0; i < m_nCols; i++)
+        m_arColWidths[i] = m_cellDefault.GetWidth();
+
+    return TRUE;
+}
+
+
+
+
+void CGridCtrl::SetupDefaultCells()
+{
+    m_cellDefault.SetGrid(this);            // Normal editable cell
+    m_cellFixedColDef.SetGrid(this);        // Cell for fixed columns
+    m_cellFixedRowDef.SetGrid(this);        // Cell for fixed rows
+    m_cellFixedRowColDef.SetGrid(this);     // Cell for area overlapped by fixed columns/rows
+
+    m_cellDefault.SetTextClr(m_crWindowText);   
+    m_cellDefault.SetBackClr(m_crWindowColour); 
+    m_cellFixedColDef.SetTextClr(m_crWindowText);
+    m_cellFixedColDef.SetBackClr(m_cr3DFace);
+    m_cellFixedRowDef.SetTextClr(m_crWindowText);
+    m_cellFixedRowDef.SetBackClr(m_cr3DFace);
+    m_cellFixedRowColDef.SetTextClr(m_crWindowText);
+    m_cellFixedRowColDef.SetBackClr(m_cr3DFace);
+}
+
+void CGridCtrl::PreSubclassWindow()
+{
+    CWnd::PreSubclassWindow();
+
+    //HFONT hFont = ::CreateFontIndirect(m_cellDefault.GetFont());
+    //OnSetFont((LPARAM)hFont, 0);
+    //DeleteObject(hFont);
+
+    Initialise();
+}
+
+// Sends a message to the parent in the form of a WM_NOTIFY message with
+// a NM_GRIDVIEW structure attached
+LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage) const
+{
+    if (!IsWindow(m_hWnd))
+        return 0;
+
+    NM_GRIDVIEW nmgv;
+    nmgv.iRow         = nRow;
+    nmgv.iColumn      = nCol;
+    nmgv.hdr.hwndFrom = m_hWnd;
+    nmgv.hdr.idFrom   = GetDlgCtrlID();
+    nmgv.hdr.code     = nMessage;
+
+    CWnd *pOwner = GetOwner();
+    if (pOwner && IsWindow(pOwner->m_hWnd))
+        return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
+    else
+        return 0;
+}
+
+// Send a request to the parent to return information on a given cell
+LRESULT CGridCtrl::SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const
+{
+    if (!IsWindow(m_hWnd))
+        return 0;
+
+    // Fix up the message headers
+    pDisplayInfo->hdr.hwndFrom = m_hWnd;
+    pDisplayInfo->hdr.idFrom   = GetDlgCtrlID();
+    pDisplayInfo->hdr.code     = GVN_GETDISPINFO;
+
+    // Send the message
+    CWnd *pOwner = GetOwner();
+    if (pOwner && IsWindow(pOwner->m_hWnd))
+        return pOwner->SendMessage(WM_NOTIFY, pDisplayInfo->hdr.idFrom, (LPARAM)pDisplayInfo);
+    else
+        return 0;
+}
+
+// Send a hint to the parent about caching information
+LRESULT CGridCtrl::SendCacheHintToParent(const CCellRange& range) const
+{
+    if (!IsWindow(m_hWnd))
+        return 0;
+
+    GV_CACHEHINT CacheHint;
+
+    // Fix up the message headers
+    CacheHint.hdr.hwndFrom = m_hWnd;
+    CacheHint.hdr.idFrom   = GetDlgCtrlID();
+    CacheHint.hdr.code     = GVN_ODCACHEHINT;
+
+    CacheHint.range = range;
+
+    // Send the message
+    CWnd *pOwner = GetOwner();
+    if (pOwner && IsWindow(pOwner->m_hWnd))
+        return pOwner->SendMessage(WM_NOTIFY, CacheHint.hdr.idFrom, (LPARAM)&CacheHint);
+    else
+        return 0;
+}
+
+#define LAYER_SIGNATURE (0x5FD4E64)
+int CGridCtrl::GetLayer(int** pLayer) // used to save and restore order of columns
+{ //  gives back the size of the area (do not forget to delete pLayer)
+	int Length = 2+GetColumnCount()*2;
+	int *Layer = new int[Length];	// the caller is supposed to delete it
+	Layer[0]= LAYER_SIGNATURE;
+	Layer[1]= GetColumnCount();
+	memcpy(&Layer[2], &m_arColOrder[0], GetColumnCount()*sizeof(int));
+	memcpy(&Layer[2+GetColumnCount()], &m_arColWidths[0], GetColumnCount()*sizeof(int));
+	*pLayer = Layer;
+	return Length;
+}
+void CGridCtrl::SetLayer(int* pLayer)
+{ // coming from a previous GetLayer (ignored if not same number of column, or the same revision number)
+	if(pLayer[0] != LAYER_SIGNATURE) return;
+	if(pLayer[1] != GetColumnCount()) return;
+/*	TRACE("  %d == %d \n",m_arColOrder[0],pLayer[2]);
+	TRACE("  %d == %d \n",m_arColOrder[1],pLayer[3]);
+	TRACE("  %d == %d \n",m_arColOrder[2],pLayer[4]);
+	TRACE("  %d == %d \n",m_arColWidths[0],pLayer[2+3]);
+	TRACE("  %d == %d \n",m_arColWidths[1],pLayer[3+3]);
+	TRACE("  %d == %d \n",m_arColWidths[2],pLayer[4+3]);
+	TRACE("  %d == %d \n",GetColumnCount(),3);
+
+	
+	ASSERT(m_arColOrder[0]==pLayer[2]);
+	ASSERT(m_arColOrder[1]==pLayer[3]);
+	ASSERT(m_arColOrder[2]==pLayer[4]);
+	ASSERT(m_arColWidths[0]==pLayer[2+3]);
+	ASSERT(m_arColWidths[1]==pLayer[3+3]);
+	ASSERT(m_arColWidths[2]==pLayer[4+3]);
+	ASSERT(GetColumnCount()==3);
+*/	memcpy(&m_arColOrder[0],&pLayer[2], GetColumnCount()*sizeof(int));
+	memcpy(&m_arColWidths[0],&pLayer[2+GetColumnCount()], GetColumnCount()*sizeof(int));
+}
+
+BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
+//EFW - Added ON_WM_RBUTTONUP
+//{{AFX_MSG_MAP(CGridCtrl)
+    ON_WM_PAINT()
+    ON_WM_HSCROLL()
+    ON_WM_VSCROLL()
+    ON_WM_SIZE()
+    ON_WM_LBUTTONUP()
+    ON_WM_LBUTTONDOWN()
+    ON_WM_MOUSEMOVE()
+    ON_WM_TIMER()
+    ON_WM_GETDLGCODE()
+    ON_WM_KEYDOWN()
+    ON_WM_CHAR()
+    ON_WM_LBUTTONDBLCLK()
+    ON_WM_ERASEBKGND()
+    ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
+    ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
+    ON_WM_SYSKEYDOWN()
+//}}AFX_MSG_MAP
+#ifndef _WIN32_WCE_NO_CURSOR
+    ON_WM_SETCURSOR()
+#endif
+#ifndef _WIN32_WCE
+    ON_WM_RBUTTONUP()
+    ON_WM_SYSCOLORCHANGE()
+    ON_WM_CAPTURECHANGED()
+#endif
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+    ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
+    ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
+    ON_COMMAND(ID_EDIT_CUT, OnEditCut)
+    ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
+    ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
+    ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
+#endif
+#if (_WIN32_WCE >= 210)
+    ON_WM_SETTINGCHANGE()
+#endif
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+    ON_WM_MOUSEWHEEL()
+#endif
+    ON_MESSAGE(WM_SETFONT, OnSetFont)
+    ON_MESSAGE(WM_GETFONT, OnGetFont)
+    ON_MESSAGE(WM_IME_CHAR, OnImeChar)
+    ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
+	ON_NOTIFY(GVN_COMBOSELCHANGE, IDC_INPLACE_CONTROL, OnComboSelChange)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl message handlers
+
+void CGridCtrl::OnPaint()
+{
+    CPaintDC dc(this);      // device context for painting
+
+    if (m_bDoubleBuffer)    // Use a memory DC to remove flicker
+    {
+        CGridMemDC MemDC(&dc);
+        OnDraw(&MemDC);
+    }
+    else                    // Draw raw - this helps in debugging vis problems.
+        OnDraw(&dc);
+}
+
+BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
+{
+    return TRUE;    // Don't erase the background.
+}
+
+// Custom background erasure. This gets called from within the OnDraw function,
+// since we will (most likely) be using a memory DC to stop flicker. If we just
+// erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
+// selected bitmap with colour, then all sorts of vis problems would occur
+void CGridCtrl::EraseBkgnd(CDC* pDC)
+{	
+    CRect  VisRect, ClipRect, rect;
+    CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
+           FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
+           FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
+           TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
+    CBrush Back(GetGridBkColor()); 
+    
+    if (pDC->GetClipBox(ClipRect) == ERROR)
+        return;
+    GetVisibleNonFixedCellRange(VisRect);
+
+    int nFixedColumnWidth = GetFixedColumnWidth();
+    int nFixedRowHeight = GetFixedRowHeight();
+
+    // Draw Fixed row/column background
+    if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
+        pDC->FillRect(CRect(ClipRect.left, ClipRect.top, 
+                      nFixedColumnWidth, nFixedRowHeight),
+                      &FixedRowColBack);
+
+    // Draw Fixed columns background
+    if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
+        pDC->FillRect(CRect(ClipRect.left, ClipRect.top, 
+                      nFixedColumnWidth, VisRect.bottom),
+                      &FixedColBack);
+        
+    // Draw Fixed rows background
+    if (ClipRect.top < nFixedRowHeight && 
+        ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
+        pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
+                      VisRect.right, nFixedRowHeight),
+                      &FixedRowBack);
+
+    // Draw non-fixed cell background
+    if (rect.IntersectRect(VisRect, ClipRect)) 
+    {
+        CRect CellRect(__max(nFixedColumnWidth, rect.left), 
+                       __max(nFixedRowHeight, rect.top),
+                       rect.right, rect.bottom);
+        pDC->FillRect(CellRect, &TextBack);
+    }
+
+    // Draw right hand side of window outside grid
+    if (VisRect.right < ClipRect.right) 
+        pDC->FillRect(CRect(VisRect.right, ClipRect.top, 
+                      ClipRect.right, ClipRect.bottom),
+                      &Back);
+
+    // Draw bottom of window below grid
+    if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right) 
+        pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
+                      VisRect.right, ClipRect.bottom),
+                      &Back);
+}
+
+void CGridCtrl::OnSize(UINT nType, int cx, int cy)
+{  
+    static BOOL bAlreadyInsideThisProcedure = FALSE;
+    if (bAlreadyInsideThisProcedure)
+        return;
+
+    if (!::IsWindow(m_hWnd))
+        return;
+
+	// This is not the ideal place to register the droptarget
+#ifndef GRIDCONTROL_NO_DRAGDROP
+	m_DropTarget.Register(this);
+#endif
+
+    // Start re-entry blocking
+    bAlreadyInsideThisProcedure = TRUE;
+
+    EndEditing();        // destroy any InPlaceEdit's
+    CWnd::OnSize(nType, cx, cy);
+    ResetScrollBars();
+
+    // End re-entry blocking
+    bAlreadyInsideThisProcedure = FALSE;
+}
+
+UINT CGridCtrl::OnGetDlgCode()
+{
+    UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
+
+    if (m_bHandleTabKey && !IsCTRLpressed())
+        nCode |= DLGC_WANTTAB;
+
+    return nCode;
+}
+
+#ifndef _WIN32_WCE
+// If system colours change, then redo colours
+void CGridCtrl::OnSysColorChange()
+{
+    CWnd::OnSysColorChange();
+
+    if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetGridBkColor() == m_crShadow)
+        SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
+
+    m_crWindowText   = ::GetSysColor(COLOR_WINDOWTEXT);
+    m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
+    m_cr3DFace       = ::GetSysColor(COLOR_3DFACE);
+    m_crShadow       = ::GetSysColor(COLOR_3DSHADOW);
+}
+#endif
+
+#ifndef _WIN32_WCE_NO_CURSOR
+// If we are drag-selecting cells, or drag and dropping, stop now
+void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
+{
+    if (pWnd->GetSafeHwnd() == GetSafeHwnd())
+        return;
+
+    // kill timer if active
+    if (m_nTimerID != 0)
+    {
+        KillTimer(m_nTimerID);
+        m_nTimerID = 0;
+    }
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+    // Kill drag and drop if active
+    if (m_MouseMode == MOUSE_DRAGGING)
+        m_MouseMode = MOUSE_NOTHING;
+#endif
+}
+#endif
+
+#if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
+// If system settings change, then redo colours
+void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
+{
+    CWnd::OnSettingChange(uFlags, lpszSection);
+
+    if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText)                   // Still using system colours
+        GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT));      // set to new system colour
+    if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
+        GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
+
+    if (GetGridBkColor() == m_crShadow)
+        SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
+
+    m_crWindowText   = ::GetSysColor(COLOR_WINDOWTEXT);
+    m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
+    m_cr3DFace       = ::GetSysColor(COLOR_3DFACE);
+    m_crShadow       = ::GetSysColor(COLOR_3DSHADOW);
+
+    m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
+}
+#endif
+
+// For drag-selection. Scrolls hidden cells into view
+// TODO: decrease timer interval over time to speed up selection over time
+void CGridCtrl::OnTimer(UINT_PTR nIDEvent)
+{
+//    ASSERT(nIDEvent == WM_LBUTTONDOWN);
+    if (nIDEvent != WM_LBUTTONDOWN)
+        return;
+
+    CPoint pt, origPt;
+
+#ifdef _WIN32_WCE
+    if (m_MouseMode == MOUSE_NOTHING)
+        return;
+    origPt = GetMessagePos();
+#else
+    if (!GetCursorPos(&origPt))
+        return;
+#endif
+
+    ScreenToClient(&origPt);
+
+    CRect rect;
+    GetClientRect(rect);
+
+	// LUC		
+	CCellID cell = GetCellFromPt(origPt);
+
+	CCellID idTopLeft = GetTopleftNonFixedCell();
+	if(idTopLeft.row == GetFixedRowCount(TRUE))
+	{
+		m_bExcludeFreezedRowsFromSelection = FALSE;
+	}
+	else if((cell.row > idTopLeft.row) || (m_LeftClickDownCell.row >= idTopLeft.row))
+	{
+		m_bExcludeFreezedRowsFromSelection = TRUE;
+
+	}	
+	if(idTopLeft.col == GetFixedColumnCount(TRUE))
+	{
+		m_bExcludeFreezedColsFromSelection = FALSE;
+	}
+	else if((cell.col > idTopLeft.col)	|| (m_LeftClickDownCell.col >= idTopLeft.col))
+	{
+		m_bExcludeFreezedColsFromSelection = TRUE;
+	}
+	
+	int nFixedRowHeight = GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection);
+    int nFixedColWidth = GetFixedColumnWidth(m_bExcludeFreezedColsFromSelection);
+	
+    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));
+    }
+    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));
+    }
+
+    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));
+    }
+    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));
+    }
+	
+}
+
+// move about with keyboard
+void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    if (!IsValid(m_idCurrentCell))
+    {
+        CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+        return;
+    }
+    CCellID next = m_idCurrentCell;
+    BOOL bChangeLine = FALSE;
+	BOOL bHorzScrollAction = FALSE;
+	BOOL bVertScrollAction = FALSE;
+
+    if (IsCTRLpressed())
+    {
+        switch (nChar)
+        {
+        case 'A':
+            OnEditSelectAll();
+            break;
+        case 'k':		// This is ctrl+ on french keyboard, may need to be better processed for other locales
+            AutoSizeColumns();
+			Invalidate();
+            break;
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+        case 'X':
+            OnEditCut();
+            break;
+        case VK_INSERT:
+        case 'C':
+            OnEditCopy();
+            break;
+        case 'V':
+            OnEditPaste();
+            break;
+#endif
+        }
+    }
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+    if (IsSHIFTpressed() &&(nChar == VK_INSERT))
+        OnEditPaste();
+#endif
+
+    BOOL bFoundVisible;
+    int iOrig;
+
+    if (nChar == VK_DELETE)
+    {
+		CutSelectedText();
+    }
+    else if (nChar == VK_DOWN)
+    {
+        // don't let user go to a hidden row
+        bFoundVisible = FALSE;
+        iOrig = next.row;
+        next.row++;
+        while( next.row < GetRowCount())
+        {
+            if( GetRowHeight( next.row) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            next.row++;
+        }
+        if( !bFoundVisible)
+            next.row = iOrig;
+    }
+    else if (nChar == VK_UP)
+    {
+        // don't let user go to a hidden row
+        bFoundVisible = FALSE;
+        iOrig = next.row;
+        next.row--;
+		// LUC
+		//while( next.row >= m_nFixedRows)
+		while( next.row >= GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+        {
+            if( GetRowHeight( next.row) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            next.row--;
+        }
+        if( !bFoundVisible)
+            next.row = iOrig;
+    }
+    else if (nChar == VK_RIGHT || (nChar == VK_TAB && !IsSHIFTpressed()) )
+    {
+		if( (nChar == VK_TAB) &&  m_QuitFocusOnTab )
+		{
+			CDialog* p= (CDialog*) GetParent();
+			if(p) p->NextDlgCtrl();
+			return;
+
+		}
+        // don't let user go to a hidden column
+        bFoundVisible = FALSE;
+        iOrig = next.col;
+        next.col++;
+
+        if (nChar == VK_TAB)
+        {
+			// If we're at the end of a row, go down a row till we find a non-hidden row
+            if (next.col == (GetColumnCount()) && next.row < (GetRowCount() - 1))
+            {
+				next.row++;
+				while( next.row < GetRowCount())
+				{
+					if( GetRowHeight(next.row) > 0)
+					{
+						bFoundVisible = TRUE;
+						break;
+					}
+					next.row++; 
+				}
+
+				// LUC
+                //next.col = m_nFixedCols;	// Place focus on first non-fixed column
+				next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);	// Place focus on first non-fixed column
+                bChangeLine = TRUE;
+            }
+            else
+                CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+        }
+
+		// We're on a non-hidden row, so look across for the next non-hidden column
+        while( next.col < GetColumnCount())
+        {
+            if( GetColumnWidth( next.col) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            next.col++;
+        }
+
+		// If nothing worked then don't bother
+        if( !bFoundVisible)
+            next.col = iOrig;
+    }
+    else if (nChar == VK_LEFT || (nChar == VK_TAB && IsSHIFTpressed()) )
+    {
+        // don't let user go to a hidden column
+        bFoundVisible = FALSE;
+        iOrig = next.col;
+        next.col--;
+
+        if (nChar == VK_TAB)
+        {
+			// LUC
+            if (next.col == (GetFixedColumnCount(m_bExcludeFreezedColsFromSelection)-1) 
+				&& next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+            {
+                next.row--;
+				while( next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+				{
+					if( GetRowHeight(next.row) > 0)
+					{
+						bFoundVisible = TRUE;
+						break;
+					}
+					next.row--; 
+				}
+
+                next.col = GetColumnCount() - 1; 
+                bChangeLine = TRUE;
+            }
+            else
+                CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+        }
+
+		// LUC
+        //while( next.col >= m_nFixedCols)
+		while(next.col >= GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+        {
+            if( GetColumnWidth( next.col) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            next.col--;
+        }
+        if( !bFoundVisible)
+            next.col = iOrig;
+    }
+    else if (nChar == VK_NEXT)
+    {
+        CCellID idOldTopLeft = GetTopleftNonFixedCell();
+        SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
+		bVertScrollAction = TRUE;
+        CCellID idNewTopLeft = GetTopleftNonFixedCell();
+
+        int increment = idNewTopLeft.row - idOldTopLeft.row;
+        if (increment)
+        {
+            next.row += increment;
+            if (next.row >(GetRowCount() - 1))
+                next.row = GetRowCount() - 1;
+        }
+        else
+            next.row = GetRowCount() - 1;
+    }
+    else if (nChar == VK_PRIOR)
+    {
+        CCellID idOldTopLeft = GetTopleftNonFixedCell();
+        SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
+		bVertScrollAction = TRUE;
+        CCellID idNewTopLeft = GetTopleftNonFixedCell();
+            
+        int increment = idNewTopLeft.row - idOldTopLeft.row;
+        if (increment) 
+        {
+            next.row += increment;
+			// LUC
+            if (next.row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection)) 
+                next.row = GetFixedRowCount(m_bExcludeFreezedColsFromSelection);
+        }
+        else
+			// LUC
+            next.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+    }
+    else if (nChar == VK_HOME)
+    {
+        // Home and Ctrl-Home work more like Excel
+        //  and don't let user go to a hidden cell
+        if (IsCTRLpressed())
+        {
+            SendMessage(WM_VSCROLL, SB_TOP, 0);
+            SendMessage(WM_HSCROLL, SB_LEFT, 0);
+			bVertScrollAction = TRUE;
+			bHorzScrollAction = TRUE;
+            //next.row = m_nFixedRows;
+            //next.col = m_nFixedCols;
+			// LUC
+			next.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+			next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+        }
+        else
+        {
+            SendMessage(WM_HSCROLL, SB_LEFT, 0);
+ 			bHorzScrollAction = TRUE;
+            // LUC
+			//next.col = m_nFixedCols;
+			next.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+        }
+        // adjust column to avoid hidden columns and rows
+        while( next.col < GetColumnCount() - 1)
+        {
+            if( GetColumnWidth( next.col) > 0)
+                break;
+            next.col++;
+        }
+        while( next.row < GetRowCount() - 1)
+        {
+            if( GetRowHeight( next.row) > 0)
+                break;
+            next.row++;
+        }
+    }
+    else if (nChar == VK_END)
+    {
+        // End and Ctrl-End work more like Excel
+        //  and don't let user go to a hidden cell
+        if (IsCTRLpressed())
+        {
+            SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
+            SendMessage(WM_HSCROLL, SB_RIGHT, 0);
+			bHorzScrollAction = TRUE;
+			bVertScrollAction = TRUE;
+            next.row = GetRowCount() - 1;
+            next.col = GetColumnCount() - 1;
+        }
+        else
+        {
+            SendMessage(WM_HSCROLL, SB_RIGHT, 0);
+			bHorzScrollAction = TRUE;
+            next.col = GetColumnCount() - 1;
+        }
+        // adjust column to avoid hidden columns and rows
+        //while( next.col > m_nFixedCols + 1)
+		while(next.col > GetFixedColumnCount(m_bExcludeFreezedColsFromSelection) + 1)
+        {
+            if( GetColumnWidth( next.col) > 0)
+                break;
+            next.col--;
+        }
+        //while( next.row > m_nFixedRows + 1)
+		while( next.row > GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) + 1)
+        {
+            if( GetRowHeight( next.row) > 0)
+                break;
+            next.row--;
+        }
+    }
+    else if (nChar == VK_F2)
+    {
+        OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), VK_LBUTTON);
+    }
+    else
+    {
+        CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
+        return;
+    }
+
+    if (next != m_idCurrentCell)
+    {
+		// LUC
+
+		int nNextRow = next.row;
+		int nNextCol = next.col;
+
+		int nCurRow = m_idCurrentCell.row;
+		int nCurCol = m_idCurrentCell.col;
+
+		BOOL bMerged = GetTopLeftMergedCell(nCurRow, nCurCol, rectNull);
+
+		switch(nChar)
+		{
+			case VK_LEFT:
+			{
+				if(GetTopLeftMergedCell(nNextRow, nNextCol, rectNull))
+				{					
+					next.col = nNextCol;					
+					if(bMerged)
+					{
+						// if already in a merged cell make sure the next column is not the leftmost column of the merged cell
+						next.col--;	
+					}
+				}
+				break;
+			}
+
+			case VK_RIGHT:
+			{
+				if(GetBottomRightMergedCell(nNextRow, nNextCol, rectNull))
+				{
+					next.col = nNextCol;
+					if(bMerged)
+					{
+						// if already in a merged cell make sure the next column is not the rightmost column of the merged cell						
+						next.col++;	
+					}
+				}
+				break;
+			}
+
+			case VK_UP:
+			{
+				if(GetTopLeftMergedCell(nNextRow, nNextCol, rectNull))
+				{
+					next.row = nNextRow;
+					if(bMerged)
+					{
+						// if already in a merged cell make sure the next row is not the topmost row of the merged cell						
+						next.row--;	
+					}
+				}
+				break;
+			}
+
+			case VK_DOWN:
+			{
+				if(GetBottomRightMergedCell(nNextRow, nNextCol, rectNull))
+				{
+					next.row = nNextRow;
+					if(bMerged)
+					{
+						// if already in a merged cell make sure the next row is not the bottommost row of the merged cell						
+						next.row++;	
+					}
+				}
+				break;
+			}
+		}
+		
+        // 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_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
+            if (!IsSHIFTpressed() || nChar == VK_TAB)
+                m_SelectionStartCell = next;
+
+			// Notify parent that selection is changing - Arthur Westerman/Scot Brennecke 
+            SendMessageToParent(next.row, next.col, GVN_SELCHANGING);
+			OnSelecting(next);
+			SendMessageToParent(next.row, next.col, GVN_SELCHANGED);
+
+            m_MouseMode = MOUSE_NOTHING;
+        }
+
+        SetFocusCell(next);
+
+        if (!IsCellVisible(next))
+        {
+
+            switch (nChar)
+            {
+            case VK_RIGHT:  
+                SendMessage(WM_HSCROLL, SB_LINERIGHT, 0); 
+				bHorzScrollAction = TRUE;
+                break;
+                
+            case VK_LEFT:   
+                SendMessage(WM_HSCROLL, SB_LINELEFT, 0);  
+				bHorzScrollAction = TRUE;
+                break;
+                
+            case VK_DOWN:   
+                SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);  
+				bVertScrollAction = TRUE;
+                break;
+                
+            case VK_UP:     
+                SendMessage(WM_VSCROLL, SB_LINEUP, 0);    
+				bVertScrollAction = TRUE;
+                break;                
+                
+            case VK_TAB:    
+                if (IsSHIFTpressed())
+                {
+                    if (bChangeLine) 
+                    {
+                        SendMessage(WM_VSCROLL, SB_LINEUP, 0);
+						bVertScrollAction = TRUE;
+                        SetScrollPos32(SB_HORZ, m_nHScrollMax);
+                        break;
+                    }
+                    else 
+					{
+                        SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
+						bHorzScrollAction = TRUE;
+					}
+                }
+                else
+                {
+                    if (bChangeLine) 
+                    {
+                        SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+						bVertScrollAction = TRUE;
+                        SetScrollPos32(SB_HORZ, 0);
+                        break;
+                    }
+                    else 
+					{
+						SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+						bHorzScrollAction = TRUE;
+					}
+                }
+                break;
+            }
+            EnsureVisible(next); // Make sure cell is visible
+            Invalidate();
+        }
+        EnsureVisible(next); // Make sure cell is visible
+
+		if (bHorzScrollAction)
+			SendMessage(WM_HSCROLL, SB_ENDSCROLL, 0);
+		if (bVertScrollAction)
+			SendMessage(WM_VSCROLL, SB_ENDSCROLL, 0);
+    }
+}
+
+void CGridCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+void CGridCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+#ifdef GRIDCONTROL_USE_TITLETIPS
+    m_TitleTip.Hide();  // hide any titletips
+#endif
+
+    CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// Instant editing of cells when keys are pressed
+void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    // EFW - BUG FIX
+    if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && nChar != VK_ESCAPE)
+    {
+        if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
+            OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), nChar);
+    }
+
+    CWnd::OnChar(nChar, nRepCnt, nFlags);
+}
+
+// Added by KiteFly
+LRESULT CGridCtrl::OnImeChar(WPARAM wCharCode, LPARAM)
+{
+    // EFW - BUG FIX
+    if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && wCharCode != VK_ESCAPE) 
+        OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), (UINT)wCharCode);
+    return 0;
+}
+
+// Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
+// refreshes the edited cell and moves onto next cell if the return character
+// from the edit says we should.
+void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
+{
+    GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
+    GV_ITEM     *pgvItem = &pgvDispInfo->item;
+
+    // In case OnEndInPlaceEdit called as window is being destroyed
+    if (!IsWindow(GetSafeHwnd()))
+        return;
+
+    OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
+    //InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
+
+    switch (pgvItem->lParam)
+    {
+    case VK_TAB:
+    case VK_DOWN:
+    case VK_UP:
+    case VK_RIGHT:
+    case VK_LEFT:
+    case VK_NEXT:
+    case VK_PRIOR:
+    case VK_HOME:
+    case VK_END:
+        OnKeyDown((UINT)pgvItem->lParam, 0, 0);
+        OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint( -1, -1), (UINT)pgvItem->lParam);
+    }
+
+    *pResult = 0;
+}
+
+
+void CGridCtrl::OnComboSelChange(NMHDR* pNMHDR, LRESULT* pResult)
+{
+	GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
+	GV_ITEM     *pgvItem = &pgvDispInfo->item;
+
+	// In case OnEndInPlaceEdit called as window is being destroyed
+	if (!IsWindow(GetSafeHwnd()))
+		return;
+
+	OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
+
+	SendMessageToParent(pgvItem->row, pgvItem->col, GVN_COMBOSELCHANGE);
+
+	*pResult = 0;
+}
+
+// Handle horz scrollbar notifications
+void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
+{
+    EndEditing();
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+    m_TitleTip.Hide();  // hide any titletips
+#endif
+
+    int scrollPos = GetScrollPos32(SB_HORZ);
+
+    CCellID idTopLeft = GetTopleftNonFixedCell();
+
+    CRect rect;
+    GetClientRect(rect);
+
+	// LUC
+	BOOL bIncludeFreezedCells = FALSE;
+
+    switch (nSBCode)
+    {
+    case SB_LINERIGHT:
+        if (scrollPos < m_nHScrollMax)
+        {
+            // may have contiguous hidden columns.  Blow by them
+            while (idTopLeft.col < (GetColumnCount()-1)
+                    && GetColumnWidth( idTopLeft.col) < 1 )
+            {
+                idTopLeft.col++;
+            }
+            int xScroll = GetColumnWidth(idTopLeft.col);
+            SetScrollPos32(SB_HORZ, scrollPos + xScroll);
+            if (GetScrollPos32(SB_HORZ) == scrollPos)
+                break;          // didn't work
+
+			// LUC
+            rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+            //rect.left = GetFixedColumnWidth() + xScroll;
+            //ScrollWindow(-xScroll, 0, rect);
+            //rect.left = rect.right - xScroll;
+            InvalidateRect(rect);
+        }
+        break;
+
+    case SB_LINELEFT:
+        if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount(TRUE))
+        {
+            int iColToUse = idTopLeft.col-1;
+            // may have contiguous hidden columns.  Blow by them
+            while(  iColToUse > GetFixedColumnCount(TRUE)
+                    && GetColumnWidth( iColToUse) < 1 )
+            {
+                iColToUse--;
+            }
+
+            int xScroll = GetColumnWidth(iColToUse);
+            SetScrollPos32(SB_HORZ, __max(0, scrollPos - xScroll));
+			// LUC
+            rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+            //ScrollWindow(xScroll, 0, rect);
+            //rect.right = rect.left + xScroll;
+            InvalidateRect(rect);
+        }
+        break;
+
+    case SB_PAGERIGHT:
+        if (scrollPos < m_nHScrollMax)
+        {
+			// LUC
+            rect.left = GetFixedColumnWidth(TRUE);
+            int offset = rect.Width();
+            int pos = min(m_nHScrollMax, scrollPos + offset);
+            SetScrollPos32(SB_HORZ, pos);
+			// LUC
+            rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_PAGELEFT:
+        if (scrollPos > 0)
+        {
+			// LUC
+            rect.left = GetFixedColumnWidth(TRUE);
+            int offset = -rect.Width();
+            int pos = __max(0, scrollPos + offset);
+            SetScrollPos32(SB_HORZ, pos);
+			// LUC
+            rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_THUMBPOSITION:
+    case SB_THUMBTRACK:
+        {
+            SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
+            m_idTopLeftCell.row = -1;
+            CCellID idNewTopLeft = GetTopleftNonFixedCell();
+            if (idNewTopLeft != idTopLeft)
+            {
+				// LUC
+                rect.left = GetFixedColumnWidth(bIncludeFreezedCells);
+                InvalidateRect(rect);
+            }
+        }
+        break;
+        
+    case SB_LEFT:
+        if (scrollPos > 0)
+        {
+            SetScrollPos32(SB_HORZ, 0);
+            Invalidate();
+        }
+        break;
+        
+    case SB_RIGHT:
+        if (scrollPos < m_nHScrollMax)
+        {
+            SetScrollPos32(SB_HORZ, m_nHScrollMax);
+            Invalidate();
+        }
+        break;
+        
+        
+    default: 
+        break;
+    }
+}
+
+// Handle vert scrollbar notifications
+void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
+{
+    EndEditing();
+
+#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();
+
+    CRect rect;
+    GetClientRect(rect);
+
+	// LUC
+	BOOL bIncludeFreezedCells = FALSE;
+
+    switch (nSBCode)
+    {
+    case SB_LINEDOWN:
+        if (scrollPos < m_nVScrollMax)
+        {
+            // may have contiguous hidden rows.  Blow by them
+            while(  idTopLeft.row < (GetRowCount()-1)
+                    && GetRowHeight( idTopLeft.row) < 1 )
+            {
+                idTopLeft.row++;
+            }
+
+            int yScroll = GetRowHeight(idTopLeft.row);
+            SetScrollPos32(SB_VERT, scrollPos + yScroll);
+            if (GetScrollPos32(SB_VERT) == scrollPos)
+                break;          // didn't work
+
+			// LUC
+            rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+            //rect.top = GetFixedRowHeight() + yScroll;
+            //ScrollWindow(0, -yScroll, rect);
+            //rect.top = rect.bottom - yScroll;
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_LINEUP:
+        if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount(TRUE))
+        {
+            int iRowToUse = idTopLeft.row-1;
+            // may have contiguous hidden rows.  Blow by them
+            while(  iRowToUse > GetFixedRowCount(TRUE)
+                    && GetRowHeight( iRowToUse) < 1 )
+            {
+                iRowToUse--;
+            }
+
+            int yScroll = GetRowHeight( iRowToUse);
+            SetScrollPos32(SB_VERT, __max(0, scrollPos - yScroll));
+            // LUC
+			rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+            //ScrollWindow(0, yScroll, rect);
+            //rect.bottom = rect.top + yScroll;
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_PAGEDOWN:
+        if (scrollPos < m_nVScrollMax)
+        {
+			// LUC
+            rect.top = GetFixedRowHeight(TRUE);
+            scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
+            SetScrollPos32(SB_VERT, scrollPos);
+			// LUC
+            rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_PAGEUP:
+        if (scrollPos > 0)
+        {
+			// LUC
+            rect.top = GetFixedRowHeight(TRUE);
+            int offset = -rect.Height();
+            int pos = __max(0, scrollPos + offset);
+            SetScrollPos32(SB_VERT, pos);
+			// LUC
+            rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+            InvalidateRect(rect);
+        }
+        break;
+        
+    case SB_THUMBPOSITION:
+    case SB_THUMBTRACK:
+        {
+            SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
+            m_idTopLeftCell.row = -1;
+            CCellID idNewTopLeft = GetTopleftNonFixedCell();
+            if (idNewTopLeft != idTopLeft)
+            {
+				// LUC
+                rect.top = GetFixedRowHeight(bIncludeFreezedCells);
+                InvalidateRect(rect);
+            }
+        }
+        break;
+        
+    case SB_TOP:
+        if (scrollPos > 0)
+        {
+            SetScrollPos32(SB_VERT, 0);
+            Invalidate();
+        }
+        break;
+        
+    case SB_BOTTOM:
+        if (scrollPos < m_nVScrollMax)
+        {
+            SetScrollPos32(SB_VERT, m_nVScrollMax);
+            Invalidate();
+        }
+        
+    default: 
+        break;
+    }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl implementation functions
+
+void CGridCtrl::OnDraw(CDC* pDC)
+{
+    if (!m_bAllowDraw)
+        return;
+
+    CRect clipRect;
+    if (pDC->GetClipBox(&clipRect) == ERROR)
+        return;
+
+    EraseBkgnd(pDC);            // OnEraseBkgnd does nothing, so erase bkgnd here.
+    // This necessary since we may be using a Memory DC.
+
+#ifdef _DEBUG
+	LARGE_INTEGER iStartCount;
+	QueryPerformanceCounter(&iStartCount);
+#endif
+	
+	CRect rc;
+	GetClientRect(rc);
+
+    CRect rect;
+    int row, col;
+    CGridCellBase* pCell;
+
+	// LUC
+    int nFixedRowHeight = GetFixedRowHeight(TRUE);
+    int nFixedColWidth  = GetFixedColumnWidth(TRUE);
+
+    CCellID idTopLeft = GetTopleftNonFixedCell();
+    int minVisibleRow = idTopLeft.row,
+        minVisibleCol = idTopLeft.col;
+
+    CRect VisRect;
+    CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
+    int maxVisibleRow = VisCellRange.GetMaxRow(),
+        maxVisibleCol = VisCellRange.GetMaxCol();
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(VisCellRange);
+
+    // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
+    rect.bottom = -1;
+	int nFixedRows = m_nFixedRows + m_nFreezedRows;
+	int nFixedCols = m_nFixedCols + m_nFreezedCols;
+    for (row = 0; row < nFixedRows; row++)
+    {
+        if (GetRowHeight(row) <= 0) continue;
+
+        rect.top = rect.bottom+1;
+        rect.bottom = rect.top + GetRowHeight(row)-1;
+        rect.right = -1;
+
+        for (col = 0; col < nFixedCols; col++)
+        {
+            if (GetColumnWidth(col) <= 0) continue;
+
+            rect.left = rect.right+1;
+            rect.right = rect.left + GetColumnWidth(col)-1;
+
+            pCell = GetCell(row, col);
+            if (pCell)
+			{
+				pCell->SetCoords(row,col);
+                pCell->Draw(pDC, 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++)
+    {
+        if (GetRowHeight(row) <= 0) continue;
+
+        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;
+        for (col = 0; col < nFixedCols; col++)
+        {
+            if (GetColumnWidth(col) <= 0) continue;
+
+            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?
+
+            pCell = GetCell(row, col);
+            if (pCell)
+			{
+				pCell->SetCoords(row,col);
+                pCell->Draw(pDC, row, col, rect, FALSE);
+			}
+        }
+    }
+
+
+    // draw fixed row cells  0..m_nFixedRows, m_nFixedCols..n
+    rect.bottom = -1;
+    for (row = 0; row < nFixedRows; row++)
+    {
+        if (GetRowHeight(row) <= 0) continue;
+
+        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;
+        for (col = minVisibleCol; col <= maxVisibleCol; col++)
+        {
+            if (GetColumnWidth(col) <= 0) continue;
+
+            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?
+
+            pCell = GetCell(row, col);
+            if (pCell)
+			{
+				pCell->SetCoords(row,col);
+				// LUC
+				if(!m_bShowHorzNonGridArea && (col == m_nCols - 1))
+				{
+					pCell->Draw(pDC, row, col, rect, FALSE);
+
+					if(rect.right < rc.right)
+					{
+						CRect rcFill(rect.right + 1, rect.top, rc.right - 2, rect.bottom);
+						
+						CGridCell cell;
+						cell.SetGrid(this);
+
+						DWORD dwState = pCell->GetState() & ~(GVIS_SELECTED | GVIS_FOCUSED);
+						cell.SetState(dwState);
+
+						int nSortColumn = GetSortColumn();
+						m_nSortColumn = -1;
+
+						cell.Draw(pDC, row, col, rcFill, TRUE);
+						
+						if(!(pCell->GetState() & GVIS_FIXED))
+						{
+							rcFill.right++;
+							rcFill.bottom++;
+							pDC->Draw3dRect(rcFill, GetTextBkColor(), m_crGridLineColour);
+						}
+
+						m_nSortColumn = nSortColumn;
+					}
+				}
+				else
+				{
+					pCell->Draw(pDC, row, col, rect, FALSE);
+				}
+			}			
+        }
+    }
+
+    // draw rest of non-fixed cells
+    rect.bottom = nFixedRowHeight-1;
+    for (row = minVisibleRow; row <= maxVisibleRow; row++)
+    {
+        if (GetRowHeight(row) <= 0) continue;
+
+        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;
+        for (col = minVisibleCol; col <= maxVisibleCol; col++)
+        {
+            if (GetColumnWidth(col) <= 0) continue;
+
+            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?
+
+            pCell = GetCell(row, col);
+            // TRACE(_T("Cell %d,%d type: %s\n"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
+            if (pCell)
+			{
+				pCell->SetCoords(row,col);
+				// LUC
+				if(!m_bShowHorzNonGridArea && (col == m_nCols - 1))
+				{			
+					if(rect.right < rc.right)
+					{
+						pCell->Draw(pDC, row, col, rect, FALSE);
+
+						CRect rcFill(rect.right + 1, rect.top, rc.right - 1, rect.bottom);
+						pDC->FillSolidRect(rcFill, GetTextBkColor());
+
+						rcFill.right++;
+						rcFill.bottom++;
+						pDC->Draw3dRect(rcFill, GetTextBkColor(), m_crGridLineColour);
+					}
+
+				}
+				else
+				{
+					pCell->Draw(pDC, row, col, rect, FALSE);
+				}
+			}			
+        }
+    }	
+
+	CPen pen;
+    pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
+    pDC->SelectObject(&pen);
+
+    // draw vertical lines (drawn at ends of cells)
+    if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+    {
+		// LUC
+        //int x = nFixedColWidth;
+		int x = GetFixedColumnWidth(); 
+		
+		// LUC
+        //for (col = minVisibleCol; col < maxVisibleCol; col++)
+		int nFixedRowHeightExcludingFreezedRows = GetFixedRowHeight();
+		for (col = m_nFixedCols; col <= maxVisibleCol; col++)
+        {
+            if (GetColumnWidth(col) <= 0) continue;
+
+			if(col == (m_nFixedCols + m_nFreezedCols))
+			{
+				col = minVisibleCol;
+			}
+
+            x += GetColumnWidth(col);
+            //pDC->MoveTo(x-1, nFixedRowHeight);
+			pDC->MoveTo(x-1, nFixedRowHeightExcludingFreezedRows);
+            pDC->LineTo(x-1, VisRect.bottom);
+        }
+    }
+
+    // draw horizontal lines (drawn at bottom of each cell)
+    if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+    {
+		// LUC
+        //int y = nFixedRowHeight;
+		int y = GetFixedRowHeight();
+        //for (row = minVisibleRow; row <= maxVisibleRow; row++)
+		int nFixedColumnWidthExcludingFreezedColumns = GetFixedColumnWidth();
+		for (row = m_nFixedRows; row <= maxVisibleRow; row++)
+        {
+            if (GetRowHeight(row) <= 0) continue;
+			
+			if(row == (m_nFixedRows + m_nFreezedRows))
+			{
+				row = minVisibleRow;
+			}
+
+            y += GetRowHeight(row);
+            //pDC->MoveTo(nFixedColWidth, y-1);
+			pDC->MoveTo(nFixedColumnWidthExcludingFreezedColumns, y-1);
+			// LUC
+            pDC->LineTo(VisRect.right,  y-1);			
+        }
+    }
+
+	// LUC : Merge Cell
+	m_bDrawingMergedCell = TRUE;
+	INT_PTR size = m_arMergedCells.GetSize();
+	if(size > 0)
+	{	
+		CRect rcMergeRect;
+		for(INT_PTR i = 0; i < size; i++)
+		{
+			m_nCurrentMergeID = i;
+			if(GetMergedCellRect(m_arMergedCells[i], rcMergeRect))
+			{
+				rcMergeRect.right--;
+				rcMergeRect.bottom--;
+				
+				pCell = GetCell(m_arMergedCells[i].GetMinRow(), m_arMergedCells[i].GetMinCol());
+				if (pCell)
+				{				
+					pCell->Draw(pDC, m_arMergedCells[i].GetMinRow(), m_arMergedCells[i].GetMinCol(), rcMergeRect, TRUE);
+				}
+			}
+		}
+	}
+	m_bDrawingMergedCell = FALSE;	
+	m_nCurrentMergeID = -1;
+
+	// LUC: 
+	// Finally we can draw a line for the Freezed Frame
+	////
+	pen.DeleteObject();
+	pen.CreatePen(PS_SOLID, 0, RGB(0, 0, 255));
+    pDC->SelectObject(&pen);
+	if(m_nFreezedRows > 0)
+	{
+		pDC->MoveTo(0, nFixedRowHeight);
+		pDC->LineTo(rc.right, nFixedRowHeight);
+	}
+	if(m_nFreezedCols > 0)
+	{
+		pDC->MoveTo(nFixedColWidth, 0);
+		pDC->LineTo(nFixedColWidth, rc.bottom);
+	}
+
+    pDC->SelectStockObject(NULL_PEN);
+
+    // Let parent know it can discard it's data if it needs to.
+    if (GetVirtualMode())
+       SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+#ifdef _DEBUG
+	LARGE_INTEGER iEndCount;
+	QueryPerformanceCounter(&iEndCount);
+	//TRACE1("Draw counter ticks: %d\n", iEndCount.LowPart-iStartCount.LowPart);
+#endif
+
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// CGridCtrl Cell selection stuff
+
+// Is a given cell designation valid (ie within the bounds of our number
+// of columns/rows)?
+BOOL CGridCtrl::IsValid(int nRow, int nCol) const
+{
+    return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
+}
+
+BOOL CGridCtrl::IsValid(const CCellID& cell) const
+{
+    return IsValid(cell.row, cell.col);
+}
+
+// Is a given cell range valid (ie within the bounds of our number
+// of columns/rows)?
+BOOL CGridCtrl::IsValid(const CCellRange& range) const
+{
+    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());
+}
+
+// Enables/Disables redraw for certain operations like columns auto-sizing etc,
+// but not for user caused things such as selection changes.
+void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
+{
+//    TRACE(_T("%s: Setting redraw to %s\n"),
+//             GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
+
+    if (bAllowDraw && !m_bAllowDraw)
+    {
+        m_bAllowDraw = TRUE;
+        Refresh();
+    }
+
+    m_bAllowDraw = bAllowDraw;
+    if (bResetScrollBars)
+        ResetScrollBars();
+}
+
+// Forces a redraw of a cell immediately (using a direct DC construction,
+// or the supplied dc)
+BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
+{
+    return RedrawCell(cell.row, cell.col, pDC);
+}
+
+BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
+{	
+    BOOL bResult = TRUE;
+    BOOL bMustReleaseDC = FALSE;
+
+    if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
+        return FALSE;
+
+    CRect rect;	
+	if (!GetCellRect(nRow, nCol, rect))
+        return FALSE;
+    
+	// LUC	
+	BOOL bIsMergeCell = GetTopLeftMergedCell(nRow, nCol, rect);
+
+    if (!pDC)
+    {
+        pDC = GetDC();
+        if (pDC)
+            bMustReleaseDC = TRUE;
+    }
+
+    if (pDC)
+    {
+        // Redraw cells directly
+        if (nRow < m_nFixedRows || nCol < m_nFixedCols)
+        {
+            CGridCellBase* pCell = GetCell(nRow, nCol);
+            if (pCell)
+                bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
+        }
+        else
+        {
+            CGridCellBase* pCell = GetCell(nRow, nCol);
+            if (pCell)
+                bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
+
+            // Since we have erased the background, we will need to redraw the gridlines
+            CPen pen;
+            pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
+
+            CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+            {
+                pDC->MoveTo(rect.left,    rect.bottom);
+                pDC->LineTo(rect.right + 1, rect.bottom);
+            }
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+            {
+                pDC->MoveTo(rect.right, rect.top);
+                pDC->LineTo(rect.right, rect.bottom + 1);
+            }
+            pDC->SelectObject(pOldPen);
+        }
+    } else
+        InvalidateRect(rect, TRUE);     // Could not get a DC - invalidate it anyway
+    // and hope that OnPaint manages to get one
+
+    if (bMustReleaseDC)
+        ReleaseDC(pDC);
+
+	// LUC : if this is a merge cell then we have to make sure there are no drawing problem becoz of direct redraw of cell
+	// specially becoz of the freeze pane lines
+	if(bIsMergeCell)
+	{
+		InvalidateRect(rect, TRUE);
+	}
+    
+	return bResult;
+}
+
+// redraw a complete row
+BOOL CGridCtrl::RedrawRow(int row)
+{
+    BOOL bResult = TRUE;
+
+    CDC* pDC = GetDC();
+    for (int col = 0; col < GetColumnCount(); col++)
+        bResult = RedrawCell(row, col, pDC) && bResult;
+    if (pDC)
+        ReleaseDC(pDC);
+
+    return bResult;
+}
+
+// redraw a complete column
+BOOL CGridCtrl::RedrawColumn(int col)
+{
+    BOOL bResult = TRUE;
+
+    CDC* pDC = GetDC();
+    for (int row = 0; row < GetRowCount(); row++)
+        bResult = RedrawCell(row, col, pDC) && bResult;
+    if (pDC)
+        ReleaseDC(pDC);
+
+    return bResult;
+}
+
+
+// Sets the currently selected cell, returning the previous current cell
+CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
+{
+    return SetFocusCell(CCellID(nRow, nCol));
+}
+
+CCellID CGridCtrl::SetFocusCell(CCellID cell)
+{
+    if (cell == m_idCurrentCell)
+        return m_idCurrentCell;
+
+    CCellID idPrev = m_idCurrentCell;
+
+    // EFW - Bug Fix - Force focus to be in a non-fixed cell
+    if (cell.row != -1 && cell.row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+        cell.row = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+    if (cell.col != -1 && cell.col < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+        cell.col = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+
+    m_idCurrentCell = cell;
+
+    if (IsValid(idPrev))
+    {
+        SetItemState(idPrev.row, idPrev.col,
+            GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
+        RedrawCell(idPrev); // comment to reduce flicker
+
+        if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
+            for (int row = 0; row < m_nFixedRows; row++)
+                RedrawCell(row, idPrev.col);
+        if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
+            for (int col = 0; col < m_nFixedCols; col++)
+                RedrawCell(idPrev.row, col);
+    }
+
+    if (IsValid(m_idCurrentCell))
+    {
+        SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
+            GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
+
+        RedrawCell(m_idCurrentCell); // comment to reduce flicker
+
+        if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
+            for (int row = 0; row < m_nFixedRows; row++)
+                RedrawCell(row, m_idCurrentCell.col);
+        if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
+            for (int col = 0; col < m_nFixedCols; col++)
+                RedrawCell(m_idCurrentCell.row, col);
+
+        // EFW - New addition.  If in list mode, make sure the selected
+        // row highlight follows the cursor.
+        // Removed by C Maunder 27 May
+        //if (m_bListMode)
+        //{
+        //    m_PrevSelectedCellMap.RemoveAll();
+        //    m_MouseMode = MOUSE_SELECT_ROW;
+        //    OnSelecting(m_idCurrentCell);
+
+            // Leave this off so that you can still drag the highlight around
+            // without selecting rows.
+            // m_MouseMode = MOUSE_NOTHING;
+        //}
+
+	}
+
+    return idPrev;
+}
+
+// Sets the range of currently selected cells
+void CGridCtrl::SetSelectedRange(const CCellRange& Range,
+                                 BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
+{
+    SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
+                     Range.GetMaxRow(), Range.GetMaxCol(),
+                     bForceRepaint, bSelectCells);
+}
+
+void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
+                                 BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
+{
+    if (!m_bEnableSelection)
+        return;
+
+	CWaitCursor wait; // Thomas Haase 
+	
+
+    CDC* pDC = NULL;
+    if (bForceRepaint)
+        pDC = GetDC();
+
+	// Only redraw visible cells
+    CCellRange VisCellRange, FixedVisCellRange;
+	if (IsWindow(GetSafeHwnd()))
+
+	{
+		VisCellRange = GetVisibleNonFixedCellRange(NULL, 0);
+		FixedVisCellRange = GetVisibleFixedCellRange();
+	}
+   
+    // EFW - Bug fix - Don't allow selection of fixed rows
+	// LUC    
+	int Left= (m_AllowSelectRowInFixedCol ? 0 : GetFixedColumnCount(m_bExcludeFreezedColsFromSelection));
+
+	if(nMinRow >= 0 && nMinRow < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+        nMinRow = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+    if(nMaxRow >= 0 && nMaxRow < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection))
+        nMaxRow = GetFixedRowCount(m_bExcludeFreezedRowsFromSelection);
+    if(nMinCol >= 0 && nMinCol < Left)
+        nMinCol = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+    if(nMaxCol >= 0 && nMaxCol < Left)
+        nMaxCol = GetFixedColumnCount(m_bExcludeFreezedColsFromSelection);
+
+	// LUC
+	for(int row = nMinRow; row <= nMaxRow; row++)
+	{
+		for(int col = nMinCol; col <= nMaxCol; col++)
+		{				
+			int nMergedMinRow = row, nMergedMinCol = col;
+			if(GetTopLeftMergedCell(nMergedMinRow, nMergedMinCol, rectNull))
+			{	
+				if(nMinRow > nMergedMinRow)
+				{
+					nMinRow = nMergedMinRow;
+				}
+				if(nMinCol > nMergedMinCol)
+				{
+					nMinCol = nMergedMinCol;
+				}								
+			}
+			int nMergedMaxRow = row, nMergedMaxCol = col;			
+			
+			if(GetBottomRightMergedCell(nMergedMaxRow, nMergedMaxCol, rectNull))
+			{
+				if(nMaxRow < nMergedMaxRow)
+				{
+					nMaxRow = nMergedMaxRow;
+				}
+				if(nMaxCol < nMergedMaxCol)
+				{
+					nMaxCol = nMergedMaxCol;
+				}
+			
+				// let's try to make it a bit efficient
+				row = nMergedMaxRow;
+				col = nMergedMaxCol;
+			}
+									
+		}
+	}		
+	////
+    // If we are selecting cells, then first clear out the list of currently selected cells, then
+    if (bSelectCells)
+    {
+        POSITION pos;
+
+        // Unselect all previously selected cells
+        for (pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+        {
+            DWORD key;
+            CCellID cell;
+            m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+            // Reset the selection flag on the cell
+            if (IsValid(cell))
+            {
+                // This will remove the cell from the m_SelectedCellMap map
+                SetItemState(cell.row, cell.col,
+                    GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
+
+                // If this is to be reselected, continue on past the redraw
+                if (nMinRow <= cell.row && cell.row <= nMaxRow &&
+                    nMinCol <= cell.col && cell.col <= nMaxCol)
+                    continue;
+
+				if ( (VisCellRange.IsValid() && VisCellRange.InRange( cell )) || FixedVisCellRange.InRange( cell ) )
+				{
+					if (bForceRepaint && pDC)                    // Redraw NOW
+						RedrawCell(cell.row, cell.col, pDC);
+					else
+						InvalidateCellRect(cell);                // Redraw at leisure
+				}
+            }
+            else
+            {
+                m_SelectedCellMap.RemoveKey( key);  // if it's not valid, get rid of it!
+            }
+        }
+
+        // if we are selecting cells, and there are previous selected cells to be retained 
+        // (eg Ctrl is being held down) then copy them to the newly created list, and mark 
+        // all these cells as selected
+        // Note that if we are list mode, single row selection, then we won't be adding 
+        // the previous cells. Only the current row of cells will be added (see below)
+        if (!GetSingleRowSelection() &&
+            nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0)
+        {
+            for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
+            {
+                DWORD key;
+                CCellID cell;
+                m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+                if (!IsValid(cell))
+                    continue;
+
+                int nState = GetItemState(cell.row, cell.col);
+
+                // Set state as Selected. This will add the cell to m_SelectedCellMap
+                SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
+
+				if (( VisCellRange.IsValid() && VisCellRange.InRange( cell ))  || FixedVisCellRange.InRange( cell )  )
+				{
+					// Redraw (immediately or at leisure)
+					if (bForceRepaint && pDC)
+					    RedrawCell(cell.row, cell.col, pDC);
+					else
+					    InvalidateCellRect(cell);
+				}
+            }
+        }
+    }
+
+    // Now select/deselect all cells in the cell range specified. If selecting, and the cell 
+    // has already been marked as selected (above) then ignore it. If we are deselecting and
+    // the cell isn't selected, then ignore
+    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++)
+            {
+                BOOL bCellSelected = IsCellSelected(row, col);
+                if (bSelectCells == bCellSelected)
+                    continue;    // Already selected or deselected - ignore
+
+                // Set the selected state. This will add/remove the cell to m_SelectedCellMap
+                if (bSelectCells)
+                    SetItemState(row, col, GetItemState(row, col) | GVIS_SELECTED);
+                else
+                    SetItemState(row, col, GetItemState(row, col) & ~GVIS_SELECTED);
+
+				if ( (VisCellRange.IsValid() && VisCellRange.InRange(row, col))  || FixedVisCellRange.InRange(row, col) )
+				{
+	                // Redraw (immediately or at leisure)
+	                if (bForceRepaint && pDC)
+	                    RedrawCell(row, col, pDC);
+	                else
+	                    InvalidateCellRect(row, col);
+				}
+            }
+    }
+    //    TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
+
+    if (pDC != NULL)
+        ReleaseDC(pDC);
+}
+
+// selects all cells
+void CGridCtrl::SelectAllCells()
+{
+    if (!m_bEnableSelection)
+        return;
+
+    SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount()-1, GetColumnCount()-1);
+}
+
+// selects columns
+void CGridCtrl::SelectColumns(CCellID currentCell, 
+                              BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+    if (!m_bEnableSelection)
+        return;
+
+    //if (currentCell.col == m_idCurrentCell.col) return;
+    if (currentCell.col < m_nFixedCols)
+        return;
+    if (!IsValid(currentCell))
+        return;
+
+    if (GetSingleColSelection())
+        SetSelectedRange(GetFixedRowCount(), currentCell.col,
+                         GetRowCount()-1,    currentCell.col,
+                         bForceRedraw, bSelectCells);
+    else
+        SetSelectedRange(GetFixedRowCount(),
+                         min(m_SelectionStartCell.col, currentCell.col),
+                         GetRowCount()-1,
+                         max(m_SelectionStartCell.col, currentCell.col),
+                         bForceRedraw, bSelectCells);
+}
+
+// selects rows
+void CGridCtrl::SelectRows(CCellID currentCell, 
+                           BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+    if (!m_bEnableSelection)
+        return;
+
+    //if (currentCell.row; == m_idCurrentCell.row) return;
+    if (currentCell.row < m_nFixedRows)
+        return;
+    if (!IsValid(currentCell))
+        return;
+	int Left = ( m_AllowSelectRowInFixedCol ? 0 : GetFixedColumnCount());
+    if (GetSingleRowSelection())
+        SetSelectedRange(currentCell.row, Left ,
+                         currentCell.row, GetColumnCount()-1, 
+                         bForceRedraw, bSelectCells);
+    else
+        SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
+                         Left,
+                         __max(m_SelectionStartCell.row, currentCell.row),
+                         GetColumnCount()-1,
+                         bForceRedraw, bSelectCells);
+}
+
+// selects cells
+void CGridCtrl::SelectCells(CCellID currentCell, 
+                            BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
+{
+    if (!m_bEnableSelection)
+        return;
+
+    int row = currentCell.row;
+    int col = currentCell.col;
+	// LUC
+    if (row < GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) || col < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection))
+		if (row < GetFixedRowCount() || col < GetFixedColumnCount())
+	{
+		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),
+                     bForceRedraw, bSelectCells);
+}
+
+// Called when mouse/keyboard selection is a-happening.
+void CGridCtrl::OnSelecting(const CCellID& currentCell)
+{
+    if (!m_bEnableSelection)
+        return;
+
+    switch (m_MouseMode)
+    {
+    case MOUSE_SELECT_ALL:
+        SelectAllCells();
+        break;
+    case MOUSE_SELECT_COL:
+        SelectColumns(currentCell, FALSE);
+        break;
+    case MOUSE_SELECT_ROW:
+        SelectRows(currentCell, FALSE);
+        break;
+    case MOUSE_SELECT_CELLS:
+        SelectCells(currentCell, FALSE);
+        break;
+    }
+
+    // EFW - Bug fix [REMOVED CJM: this will cause infinite loop in list mode]
+    // SetFocusCell(max(currentCell.row, m_nFixedRows), max(currentCell.col, m_nFixedCols));
+}
+
+void CGridCtrl::ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText)
+{
+    if (!IsCellEditable(nRow, nCol))
+        return;
+
+    if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
+    {
+        CString strCurrentText = GetItemText(nRow, nCol);
+        if (strCurrentText != strText)
+        {
+            SetItemText(nRow, nCol, strText);
+            if (ValidateEdit(nRow, nCol, strText) && 
+                SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
+            {
+                SetModified(TRUE, nRow, nCol);
+                RedrawCell(nRow, nCol);
+            }
+            else
+            {
+                SetItemText(nRow, nCol, strCurrentText);
+            }
+        }
+    }
+}
+
+void CGridCtrl::ClearCells(CCellRange Selection)
+{
+    for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
+    {
+        for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
+        {
+            // don't clear hidden cells
+            if ( m_arRowHeights[row] > 0 && m_arColWidths[col] > 0 )
+            {
+                ValidateAndModifyCellContents(row, col, _T(""));
+            }
+		}
+	}
+    Refresh();
+}
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+
+////////////////////////////////////////////////////////////////////////////////////////
+// Clipboard functions
+
+// Deletes the contents from the selected cells
+void CGridCtrl::CutSelectedText()
+{
+    if (!IsEditable())
+        return;
+
+    for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+    {
+		DWORD key;
+        CCellID cell;
+        m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+        ValidateAndModifyCellContents(cell.row, cell.col, _T(""));
+    }
+}
+
+// Copies text from the selected cells to the clipboard
+COleDataSource* CGridCtrl::CopyTextFromGrid()
+{
+    USES_CONVERSION;
+
+    CCellRange Selection = GetSelectedCellRange();
+    if (!IsValid(Selection))
+        return NULL;
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(Selection);
+
+    // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
+    CSharedFile sf(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
+
+    // Get a tab delimited string to copy to cache
+    CString str;
+    CGridCellBase *pCell;
+    for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
+    {
+        // don't copy hidden cells
+        if( m_arRowHeights[row] <= 0 )
+            continue;
+
+        str.Empty();
+        for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
+        {
+            // don't copy hidden cells
+            if( m_arColWidths[col] <= 0 )
+                continue;
+
+            pCell = GetCell(row, col);
+            if (pCell &&(pCell->GetState() & GVIS_SELECTED))
+            {
+                // if (!pCell->GetText())
+                //    str += _T(" ");
+                // else 
+                str += pCell->GetText();
+            }
+            if (col != Selection.GetMaxCol()) 
+                str += _T("\t");
+        }
+
+        if (row != Selection.GetMaxRow()) 
+            str += _T("\r\n");
+        
+        sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
+        str.ReleaseBuffer();
+    }
+    
+    char c = '\0';
+    sf.Write(&c, 1);
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+    DWORD dwLen = (DWORD) sf.GetLength();
+    HGLOBAL hMem = sf.Detach();
+    if (!hMem)
+        return NULL;
+
+    hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
+    if (!hMem)
+        return NULL;
+
+    // Cache data
+    COleDataSource* pSource = new COleDataSource();
+    pSource->CacheGlobalData(CF_TEXT, hMem);
+
+    return pSource;
+}
+
+// Pastes text from the clipboard to the selected cells
+BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject, 
+								BOOL bSelectPastedCells /*=TRUE*/)
+{
+    if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
+        return FALSE;
+
+    // Get the text from the COleDataObject
+    HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
+    CMemFile sf((BYTE*) ::GlobalLock(hmem), (UINT)::GlobalSize(hmem));
+
+    // CF_TEXT is ANSI text, so we need to allocate a char* buffer
+    // to hold this.
+	//LPTSTR szBuffer = new TCHAR[::GlobalSize(hmem)];
+    char* szBuffer = new char[::GlobalSize(hmem)];
+    if (!szBuffer)
+        return FALSE;
+
+    sf.Read(szBuffer, (UINT)::GlobalSize(hmem));
+    ::GlobalUnlock(hmem);
+
+    // Now store in generic TCHAR form so we no longer have to deal with
+    // ANSI/UNICODE problems
+    CString strText = szBuffer;
+    delete szBuffer;
+
+    // Parse text data and set in cells...
+    strText.LockBuffer();
+    CString strLine = strText;
+    int nLine = 0;
+
+    // Find the end of the first line
+	CCellRange PasteRange(cell.row, cell.col,-1,-1);
+    int nIndex;
+    do
+    {
+        int nColumn = 0;
+        nIndex = strLine.Find(_T("\n"));
+
+        // Store the remaining chars after the newline
+        CString strNext = (nIndex < 0)? _T("")  : strLine.Mid(nIndex + 1);
+
+        // Remove all chars after the newline
+        if (nIndex >= 0)
+            strLine = strLine.Left(nIndex);
+
+        int nLineIndex = strLine.FindOneOf(_T("\t,"));
+        CString strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
+
+        // skip hidden rows
+        int iRowVis = cell.row + nLine;
+        while( iRowVis < GetRowCount())
+        {
+            if( GetRowHeight( iRowVis) > 0)
+                break;
+            nLine++;
+            iRowVis++;
+        }
+
+        while (!strLine.IsEmpty())
+        {
+            // skip hidden columns
+            int iColVis = cell.col + nColumn;
+            while( iColVis < GetColumnCount())
+            {
+                if( GetColumnWidth( iColVis) > 0)
+                    break;
+                nColumn++;
+                iColVis++;
+            }
+
+            CCellID TargetCell(iRowVis, iColVis);
+            if (IsValid(TargetCell))
+            {
+                strCellText.TrimLeft();
+                strCellText.TrimRight();
+
+                ValidateAndModifyCellContents(TargetCell.row, TargetCell.col, strCellText);
+
+                // Make sure cell is not selected to avoid data loss
+                SetItemState(TargetCell.row, TargetCell.col,
+                    GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
+
+				if (iRowVis > PasteRange.GetMaxRow()) PasteRange.SetMaxRow(iRowVis);
+				if (iColVis > PasteRange.GetMaxCol()) PasteRange.SetMaxCol(iColVis);
+            }
+
+            strLine = (nLineIndex >= 0)? strLine.Mid(nLineIndex + 1) : _T("");
+            nLineIndex = strLine.FindOneOf(_T("\t,"));
+            strCellText = (nLineIndex >= 0)? strLine.Left(nLineIndex) : strLine;
+
+            nColumn++;
+        }
+
+        strLine = strNext;
+        nLine++;
+    } while (nIndex >= 0);
+
+    strText.UnlockBuffer();
+
+	if (bSelectPastedCells)
+		SetSelectedRange(PasteRange, TRUE);
+	else
+	{
+		ResetSelectedRange();
+		Refresh();
+	}
+
+    return TRUE;
+}
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+
+// Start drag n drop
+void CGridCtrl::OnBeginDrag()
+{
+    COleDataSource* pSource = NULL;
+    if (!m_bAllowDragAndDrop && m_CurCol==-1)
+        return;
+
+    if (m_CurCol>=0)	pSource = new COleDataSource();
+    if (!pSource && m_bAllowDragAndDrop) pSource = CopyTextFromGrid();
+    if (pSource)
+    {
+        SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
+            GetSelectedCellRange().GetTopLeft().col,
+            GVN_BEGINDRAG);
+
+        m_MouseMode = MOUSE_DRAGGING;
+        m_bLMouseButtonDown = FALSE;
+
+        DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);
+
+        if (dropEffect & DROPEFFECT_MOVE)
+            CutSelectedText();
+
+        if (pSource)
+            delete pSource;    // Did not pass source to clipboard, so must delete
+
+    }
+}
+
+// Handle drag over grid
+DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
+                                 CPoint point)
+{
+    // Find which cell we are over and drop-highlight it
+    CCellID cell = GetCellFromPt(point, FALSE);
+	bool Valid;
+    // Any text data available for us?
+	if(m_CurCol==-1)
+	{
+		if(m_bDragRowMode)
+		{
+			Valid = cell.col>=GetFixedColumnCount() && cell.row>=GetFixedRowCount();
+		}
+		else
+		{
+    if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
+        return DROPEFFECT_NONE;
+			Valid = IsValid(cell)!=0;
+		}
+	}
+	else
+	{
+		Valid = cell.col>=GetFixedColumnCount() &&   cell.row<GetFixedRowCount() ;
+	}
+
+
+    // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
+    if (!Valid)
+    {
+        OnDragLeave();
+        m_LastDragOverCell = CCellID(-1,-1);
+        return DROPEFFECT_NONE;
+    }
+	if(m_CurCol==-1)
+	{
+		if (!m_bDragRowMode && !IsCellEditable(cell))
+        return DROPEFFECT_NONE;
+	}
+
+    // Have we moved over a different cell than last time?
+    if (cell != m_LastDragOverCell)
+    {
+        // Set the previously drop-highlighted cell as no longer drop-highlighted
+        if (IsValid(m_LastDragOverCell))
+        {
+            UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+            SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+                nState & ~GVIS_DROPHILITED);
+            RedrawCell(m_LastDragOverCell);
+        }
+
+        m_LastDragOverCell = cell;
+
+        // Set the new cell as drop-highlighted
+        if (IsValid(m_LastDragOverCell))
+        {
+            UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+            SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+                nState | GVIS_DROPHILITED);
+            RedrawCell(m_LastDragOverCell);
+        }
+    }
+
+    // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
+    if (dwKeyState & MK_CONTROL)
+        return DROPEFFECT_COPY;
+    else
+        return DROPEFFECT_MOVE;
+}
+
+// Something has just been dragged onto the grid
+DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
+                                  CPoint point)
+{
+    // Any text data available for us?
+    m_LastDragOverCell = GetCellFromPt(point, m_CurCol>=0);
+	bool Valid;
+	if(m_CurCol==-1)
+	{
+    if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
+        return DROPEFFECT_NONE;
+
+    // Find which cell we are over and drop-highlight it
+    if (!IsValid(m_LastDragOverCell))
+        return DROPEFFECT_NONE;
+
+    if (!IsCellEditable(m_LastDragOverCell))
+        return DROPEFFECT_NONE;
+		Valid = IsValid(m_LastDragOverCell)!=0;
+
+	}
+	else
+	{
+		Valid = m_LastDragOverCell.row>=0 && m_LastDragOverCell.row<GetFixedRowCount() && m_LastDragOverCell.col>=GetFixedColumnCount();
+	}
+
+    if (Valid)
+    {
+        UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+        SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+            nState | GVIS_DROPHILITED);
+        RedrawCell(m_LastDragOverCell);
+    }
+
+    // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
+    if (dwKeyState & MK_CONTROL)
+        return DROPEFFECT_COPY;
+    else
+        return DROPEFFECT_MOVE;
+}
+
+// Something has just been dragged away from the grid
+void CGridCtrl::OnDragLeave()
+{
+    // Set the previously drop-highlighted cell as no longer drop-highlighted
+    if (IsValid(m_LastDragOverCell))
+    {
+        UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
+        SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
+            nState & ~GVIS_DROPHILITED);
+        RedrawCell(m_LastDragOverCell);
+    }
+}
+
+// Something has just been dropped onto the grid
+BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
+                       CPoint /* point */)
+{
+    m_MouseMode = MOUSE_NOTHING;
+    if(m_CurCol ==-1)
+	{
+		if (!m_bAllowDragAndDrop || (!IsCellEditable(m_LastDragOverCell) && !m_bDragRowMode))
+        return FALSE;
+	}
+
+    OnDragLeave();
+    if (m_CurCol>=0)
+	{
+		if(m_LastDragOverCell.col == m_CurCol || m_LastDragOverCell.row >= GetFixedRowCount()) 
+			return FALSE;
+		else
+		{
+			int New = m_arColOrder[m_CurCol];
+			m_arColOrder.erase(m_arColOrder.begin()+m_CurCol);
+			m_arColOrder.insert(m_arColOrder.begin()+m_LastDragOverCell.col, New);
+			m_CurCol=-1;
+			Invalidate();
+			return TRUE;
+		}
+	}
+	else
+	{
+		if(m_bDragRowMode)
+		{
+			Reorder(m_CurRow,m_LastDragOverCell.row);
+			Invalidate();
+			return TRUE;
+		}
+		else
+    return PasteTextToGrid(m_LastDragOverCell, pDataObject, FALSE);
+}
+}
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+void CGridCtrl::OnEditCut()
+{
+    if (!IsEditable())
+        return;
+
+    COleDataSource* pSource = CopyTextFromGrid();
+    if (!pSource)
+        return;
+
+    pSource->SetClipboard();
+    CutSelectedText();
+}
+
+void CGridCtrl::OnEditCopy()
+{
+    COleDataSource* pSource = CopyTextFromGrid();
+    if (!pSource)
+        return;
+
+    pSource->SetClipboard();
+}
+
+void CGridCtrl::OnEditPaste()
+{
+    if (!IsEditable())
+        return;
+
+	CCellRange cellRange = GetSelectedCellRange();
+
+	// Get the top-left selected cell, or the Focus cell, or the topleft (non-fixed) cell
+	CCellID cell;
+	if (cellRange.IsValid())
+	{
+		cell.row = cellRange.GetMinRow();
+		cell.col = cellRange.GetMinCol();
+	}
+	else
+	{
+		cell = GetFocusCell();
+		if (!IsValid(cell))
+			cell = GetTopleftNonFixedCell();
+		if (!IsValid(cell))
+			return;
+	}
+
+	// If a cell is being edited, then call it's edit window paste function.
+    if ( IsItemEditing(cell.row, cell.col) )
+    {
+        CGridCellBase* pCell = GetCell(cell.row, cell.col);
+//        ASSERT(pCell);
+        if (!pCell) return;
+
+		CWnd* pEditWnd = pCell->GetEditWnd();
+		if ( pEditWnd && pEditWnd->IsKindOf(RUNTIME_CLASS(CEdit)) )
+		{
+			((CEdit*)pEditWnd)->Paste();
+			return;
+		}
+    }
+
+    // Attach a COleDataObject to the clipboard and paste the data to the grid
+    COleDataObject obj;
+    if (obj.AttachClipboard())
+        PasteTextToGrid(cell, &obj);
+}
+#endif
+
+void CGridCtrl::OnEditSelectAll()
+{
+    SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+    SelectAllCells();
+    SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+}
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
+{
+	pCmdUI->Enable(GetSelectedCount() > 0); // - Thomas Haase 
+    //CCellRange Selection = GetSelectedCellRange();
+    //pCmdUI->Enable(Selection.Count() && IsValid(Selection));
+}
+
+void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
+{
+	pCmdUI->Enable(IsEditable() && GetSelectedCount() > 0); // - Thomas Haase 
+    //CCellRange Selection = GetSelectedCellRange();
+    //pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
+}
+
+void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
+{
+    CCellID cell = GetFocusCell();
+
+    BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
+        ::IsClipboardFormatAvailable(CF_TEXT);
+
+    pCmdUI->Enable(bCanPaste);
+}
+#endif
+
+void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
+{
+    pCmdUI->Enable(m_bEnableSelection);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////
+// hittest-like functions
+
+// TRUE if the mouse is over a row resize area
+BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point)
+{
+    if (point.x >= GetFixedColumnWidth())
+        return FALSE;
+
+    CCellID idCurrentCell = GetCellFromPt(point);
+    CPoint 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;
+}
+
+// TRUE if the mouse is over a column resize area. point is in Client coords
+BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point)
+{
+    if (point.y >= GetFixedRowHeight())
+        return FALSE;
+
+    CCellID idCurrentCell = GetCellFromPt(point);
+    CPoint 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;
+}
+
+// Get cell from point.
+// point - client coordinates
+// bAllowFixedCellCheck - if TRUE then fixed cells are checked
+CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck/* =TRUE*/, CCellID& cellOriginal/*= cellNull*/)
+{
+    CCellID cellID; // return value
+
+    CCellID idTopLeft = GetTopleftNonFixedCell();
+	if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
+		return cellID;
+
+    // calculate column index
+	// LUC
+    int fixedColWidth = GetFixedColumnWidth(TRUE);
+	int nFixedCols = m_nFixedCols + m_nFreezedCols;
+
+    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;
+        int col = 0;
+        while (col < nFixedCols)
+        {
+            xpos += GetColumnWidth(col);
+            if (xpos > point.x)
+                break;
+			col++;
+        }
+
+        cellID.col = col;
+    }
+    else    // in non-fixed col
+    {
+        int xpos = fixedColWidth;
+		int col = idTopLeft.col; //m_nFixedCols;
+        while ( col < GetColumnCount())
+        {
+            xpos += GetColumnWidth(col);
+            if (xpos > point.x)
+                break;
+			col++;
+        }
+
+        if (col >= GetColumnCount())
+            cellID.col = -1;
+        else
+            cellID.col = col;
+    }
+
+    // calculate row index
+	// LUC
+    int fixedRowHeight = GetFixedRowHeight(TRUE);
+    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;
+        int row = 0;
+		int nFixedRows = m_nFixedRows + m_nFreezedRows;
+        while (row < nFixedRows) 
+        {
+            ypos += GetRowHeight(row);
+            if (ypos > point.y)
+                break;
+			row++;
+        }
+        cellID.row = row;
+    }
+    else
+    {
+        int ypos = fixedRowHeight;
+		int row = idTopLeft.row; //m_nFixedRows;
+        while ( row < GetRowCount() )
+        {
+            ypos += GetRowHeight(row);
+            if (ypos > point.y)
+                break;
+			row++;
+        }
+
+        if (row >= GetRowCount())
+            cellID.row = -1;
+        else
+            cellID.row = row;
+    }
+
+	// LUC
+	if(cellOriginal != cellNull)
+	{
+		cellOriginal = cellID;
+	}
+	GetTopLeftMergedCell(cellID.row, cellID.col, rectNull);
+	
+    return cellID;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// CGridCtrl cellrange functions
+
+// Gets the first non-fixed cell ID
+CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
+{
+    // Used cached value if possible
+    if (m_idTopLeftCell.IsValid() && !bForceRecalculation)
+        return m_idTopLeftCell;
+
+    int nVertScroll = GetScrollPos(SB_VERT), 
+        nHorzScroll = GetScrollPos(SB_HORZ);
+
+	// LUC
+    m_idTopLeftCell.col = m_nFixedCols + m_nFreezedCols;
+    int nRight = 0;
+    while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount()-1))
+        nRight += GetColumnWidth(m_idTopLeftCell.col++);
+
+	// LUC
+    m_idTopLeftCell.row = m_nFixedRows + m_nFreezedRows;
+    int nTop = 0;
+    while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount()-1))
+        nTop += GetRowHeight(m_idTopLeftCell.row++);
+
+
+    //TRACE2("TopLeft cell is row %d, col %d\n",m_idTopLeftCell.row, m_idTopLeftCell.col);
+    return m_idTopLeftCell;
+}
+
+
+
+
+
+// This gets even partially visible cells
+CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/, 
+                                                  BOOL bForceRecalculation /*=FALSE*/)
+{
+    int i;
+    CRect rect;
+    GetClientRect(rect);
+
+    CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+    // calc bottom
+	// LUC
+    int bottom = GetFixedRowHeight();
+    //for (i = idTopLeft.row; i < GetRowCount(); i++)
+	for (i = m_nFixedRows; i < GetRowCount(); i++)
+    {
+		if(i == (m_nFixedRows+ m_nFreezedRows))
+		{
+			i = idTopLeft.row;
+		}
+        bottom += GetRowHeight(i);
+        if (bottom >= rect.bottom)
+        {
+            bottom = rect.bottom;
+            break;
+        }
+    }
+    int maxVisibleRow = min(i, GetRowCount() - 1);
+
+    // calc right
+	// LUC
+    int right = GetFixedColumnWidth();
+    //for (i = idTopLeft.col; i < GetColumnCount(); i++)
+	for (i = m_nFixedCols; i < GetColumnCount(); i++)
+    {
+		if(i == (m_nFixedCols + m_nFreezedCols))
+		{
+			i = idTopLeft.col;
+		}
+        right += GetColumnWidth(i);
+        if (right >= rect.right)
+        {
+            right = rect.right;
+            break;
+        }
+    }
+    int maxVisibleCol = min(i, GetColumnCount() - 1);
+    if (pRect)
+    {
+        pRect->left = pRect->top = 0;
+        pRect->right = right;
+        pRect->bottom = bottom;
+    }
+
+	// LUC
+	/*if(bIncludeFreezedCells)
+	{
+		if(m_nFreezedRows > 0)
+		{
+			idTopLeft.row = m_nFixedRows;
+		}
+		if(m_nFreezedCols > 0)
+		{
+			idTopLeft.col = m_nFixedCols;
+		}
+	}*/
+
+	if(!m_bExcludeFreezedRowsFromSelection)
+	{
+		if(m_nFreezedRows > 0)
+		{
+			idTopLeft.row = m_nFixedRows;
+		}
+		
+	}
+	if(!m_bExcludeFreezedColsFromSelection)
+	{
+		if(m_nFreezedCols > 0)
+		{
+			idTopLeft.col = m_nFixedCols;
+		}
+	}
+
+    return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
+}
+
+
+CCellRange CGridCtrl::GetVisibleFixedCellRange(LPRECT pRect /*=NULL*/, 
+                                                  BOOL bForceRecalculation /*=FALSE*/)
+{
+    int i;
+    CRect rect;
+    GetClientRect(rect);
+
+    CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+    // calc bottom
+	// LUC
+    int bottom = GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection);
+    for (i = idTopLeft.row; i < GetRowCount(); i++)
+    {
+        bottom += GetRowHeight(i);
+        if (bottom >= rect.bottom)
+        {
+            bottom = rect.bottom;
+            break;
+        }
+    }
+    int maxVisibleRow = min(i, GetRowCount() - 1);
+
+    // calc right
+    int right = 0;
+    for (i = 0; i < GetFixedColumnCount(m_bExcludeFreezedColsFromSelection); i++)
+    {
+        right += GetColumnWidth(i);
+        if (right >= rect.right)
+        {
+            right = rect.right;
+            break;
+        }
+    }
+    int maxVisibleCol = min(i, GetColumnCount() - 1);
+    if (pRect)
+    {
+        pRect->left = pRect->top = 0;
+        pRect->right = right;
+        pRect->bottom = bottom;
+    }
+
+    return CCellRange(idTopLeft.row, 0, maxVisibleRow, maxVisibleCol);
+}
+
+
+
+
+// used by ResetScrollBars() - This gets only fully visible cells
+CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation /*=FALSE*/)
+{
+    CRect rect;
+    GetClientRect(rect);
+
+    CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
+
+    // calc bottom
+    int i;
+    int bottom = GetFixedRowHeight();
+    for (i = idTopLeft.row; i < GetRowCount(); i++)
+    {
+        bottom += GetRowHeight(i);
+        if (bottom >= rect.bottom)
+            break;
+    }
+    int maxVisibleRow = min(i, GetRowCount() - 1);
+    if (maxVisibleRow > 0 && bottom > rect.bottom)
+        maxVisibleRow--;
+
+    // calc right
+    int right = GetFixedColumnWidth();
+    for (i = idTopLeft.col; i < GetColumnCount(); i++)
+    {
+        right += GetColumnWidth(i);
+        if (right >= rect.right)
+            break;
+    }
+    int maxVisibleCol = min(i, GetColumnCount() - 1);
+    if (maxVisibleCol > 0 && right > rect.right)
+        maxVisibleCol--;
+
+
+    return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
+}
+
+// Returns the minimum bounding range of the current selection
+// If no selection, then the returned CCellRange will be invalid
+CCellRange CGridCtrl::GetSelectedCellRange() const
+{
+    CCellRange Selection(GetRowCount(), GetColumnCount(), -1,-1);
+
+    for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+    {
+        DWORD key;
+        CCellID cell;
+        m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+
+        Selection.SetMinRow( min(Selection.GetMinRow(), cell.row) );
+        Selection.SetMinCol( min(Selection.GetMinCol(), cell.col) );
+        Selection.SetMaxRow( __max(Selection.GetMaxRow(), cell.row) );
+        Selection.SetMaxCol( __max(Selection.GetMaxCol(), cell.col) );
+    }
+
+    return Selection;
+}
+
+// Returns ALL the cells in the grid
+CCellRange CGridCtrl::GetCellRange() const
+{
+    return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
+}
+
+// Resets the selected cell range to the empty set.
+void CGridCtrl::ResetSelectedRange()
+{
+    m_PrevSelectedCellMap.RemoveAll();
+    SetSelectedRange(-1,-1,-1,-1);
+    SetFocusCell(-1,-1);
+}
+
+// Get/Set scroll position using 32 bit functions
+int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
+{
+    SCROLLINFO si;
+    si.cbSize = sizeof(SCROLLINFO);
+
+    if (bGetTrackPos)
+    {
+        if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
+            return si.nTrackPos;
+    }
+    else
+    {
+        if (GetScrollInfo(nBar, &si, SIF_POS))
+            return si.nPos;
+    }
+
+    return 0;
+}
+
+BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
+{
+    m_idTopLeftCell.row = -1;
+
+    SCROLLINFO si;
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask  = SIF_POS;
+    si.nPos   = nPos;
+    return SetScrollInfo(nBar, &si, bRedraw);
+}
+
+void CGridCtrl::EnableScrollBars(int nBar, BOOL bEnable /*=TRUE*/)
+{
+    if (bEnable)
+    {
+        if (!IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
+        {
+            m_nBarState |= GVL_HORZ;
+            CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
+        }
+        
+        if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
+        {
+            m_nBarState |= GVL_VERT;
+            CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
+        }
+    }
+    else
+    {
+        if ( IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
+        {
+            m_nBarState &= ~GVL_HORZ; 
+            CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
+        }
+        
+        if ( IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
+        {
+            m_nBarState &= ~GVL_VERT;
+            CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
+        }
+    }
+}
+
+// If resizing or cell counts/sizes change, call this - it'll fix up the scroll bars
+void CGridCtrl::ResetScrollBars()
+{
+    // Force a refresh. 
+    m_idTopLeftCell.row = -1;
+
+    if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd())) 
+        return;
+    
+    CRect rect;
+    
+    // This would have caused OnSize event - Brian 
+    //EnableScrollBars(SB_BOTH, FALSE); 
+    
+    GetClientRect(rect);
+    
+    if (rect.left == rect.right || rect.top == rect.bottom)
+        return;
+    
+    if (IsVisibleVScroll())
+        rect.right += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER);
+    
+    if (IsVisibleHScroll())
+        rect.bottom += GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYBORDER);
+    
+    rect.left += GetFixedColumnWidth(TRUE);
+    rect.top += GetFixedRowHeight(TRUE);
+    
+    
+    if (rect.left >= rect.right || rect.top >= rect.bottom)
+    {
+        EnableScrollBarCtrl(SB_BOTH, FALSE);
+        return;
+    }
+    
+    CRect VisibleRect(GetFixedColumnWidth(TRUE), GetFixedRowHeight(TRUE), 
+		              rect.right, rect.bottom);
+    CRect VirtualRect(GetFixedColumnWidth(TRUE), GetFixedRowHeight(TRUE),
+		              GetVirtualWidth(), GetVirtualHeight());
+    
+    // Removed to fix single row scrollbar problem (Pontus Goffe)
+    // CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
+    // if (!IsValid(visibleCells)) return;
+        
+    //TRACE(_T("Visible: %d x %d, Virtual %d x %d.  H %d, V %d\n"), 
+    //      VisibleRect.Width(), VisibleRect.Height(),
+    //      VirtualRect.Width(), VirtualRect.Height(),
+    //      IsVisibleHScroll(), IsVisibleVScroll());
+
+    // If vertical scroll bar, horizontal space is reduced
+    if (VisibleRect.Height() < VirtualRect.Height())
+        VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
+    // If horz scroll bar, vert space is reduced
+    if (VisibleRect.Width() < VirtualRect.Width())
+        VisibleRect.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
+    
+    // Recheck vertical scroll bar
+    //if (VisibleRect.Height() < VirtualRect.Height())
+    // VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
+    
+    if (VisibleRect.Height() < VirtualRect.Height())
+    {
+        EnableScrollBars(SB_VERT, TRUE); 
+        m_nVScrollMax = VirtualRect.Height() - 1;
+    }
+    else
+    {
+        EnableScrollBars(SB_VERT, FALSE); 
+        m_nVScrollMax = 0;
+    }
+
+    if (VisibleRect.Width() < VirtualRect.Width())
+    {
+        EnableScrollBars(SB_HORZ, TRUE); 
+        m_nHScrollMax = VirtualRect.Width() - 1;
+    }
+    else
+    {
+        EnableScrollBars(SB_HORZ, FALSE); 
+        m_nHScrollMax = 0;
+    }
+
+//    ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine
+
+    /* Old code - CJM
+    SCROLLINFO si;
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask = SIF_PAGE;
+    si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
+    SetScrollInfo(SB_HORZ, &si, FALSE); 
+    si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
+    SetScrollInfo(SB_VERT, &si, FALSE);
+
+    SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
+    SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
+    */
+
+    // New code - Paul Runstedler 
+    SCROLLINFO si;
+    si.cbSize = sizeof(SCROLLINFO);
+    si.fMask = SIF_PAGE | SIF_RANGE;
+    si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
+    si.nMin = 0;
+    si.nMax = m_nHScrollMax;
+    SetScrollInfo(SB_HORZ, &si, TRUE);
+
+    si.fMask |= SIF_DISABLENOSCROLL;
+    si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
+    si.nMin = 0;
+    si.nMax = m_nVScrollMax;
+    SetScrollInfo(SB_VERT, &si, TRUE);
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column position functions
+
+// returns the top left point of the cell. Returns FALSE if cell not visible.
+BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p)
+{
+    int i;
+
+    if (!IsValid(nRow, nCol))
+        return FALSE;
+
+    CCellID idTopLeft;
+	int nFixedCols = m_nFixedCols + m_nFreezedCols;
+	int nFixedRows = m_nFixedRows + m_nFreezedRows;
+
+	// LUC
+    if (nCol >= nFixedCols || nRow >= nFixedRows)
+        idTopLeft = GetTopleftNonFixedCell();
+
+    if ((nRow >= nFixedRows && nRow < idTopLeft.row) ||
+        (nCol>= nFixedCols && nCol < idTopLeft.col))
+        return FALSE;
+
+    p->x = 0;
+    if (nCol < 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 < nFixedCols; i++)
+                p->x += GetColumnWidth(i);
+            for (i = idTopLeft.col; i < nCol; i++)
+                p->x += GetColumnWidth(i);
+        }
+        
+        p->y = 0;
+        if (nRow < 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 < nFixedRows; i++)
+                    p->y += GetRowHeight(i);
+                for (i = idTopLeft.row; i < nRow; i++)
+                    p->y += GetRowHeight(i);
+            }
+            
+            return TRUE;
+}
+
+BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p)
+{
+    return GetCellOrigin(cell.row, cell.col, p);
+}
+
+// Returns the bounding box of the cell
+BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect)
+{
+    return GetCellRect(cell.row, cell.col, pRect);
+}
+
+BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect)
+{
+    CPoint 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 CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
+{
+    return GetTextRect(cell.row, cell.col, pRect);
+}
+
+BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
+{
+    CGridCellBase* pCell = GetCell( nRow, nCol);
+    if( pCell == NULL)
+        return FALSE;
+    
+    if( !GetCellRect( nRow, nCol, pRect) )
+        return FALSE;
+
+    return pCell->GetTextRect( pRect);
+}
+
+BOOL CGridCtrl::SetCellMaskEditable( int nRow, int nCol, BOOL bEditable )
+{
+	if (nRow < 0 || nRow >= m_pCellEnable.size())
+	{
+		return FALSE;
+	}
+
+	if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+	{
+		return FALSE;
+	}
+
+	m_pCellEnable[nRow][nCol].SetEnable(bEditable);
+
+	return TRUE;
+}
+
+BOOL CGridCtrl::isCellMaskEditable( int nRow, int nCol )
+{
+	if (nRow < 0 || nRow >= m_pCellEnable.size())
+	{
+		return FALSE;
+	}
+
+	if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+	{
+		return FALSE;
+	}
+	
+	return m_pCellEnable[nRow][nCol].isEnable();
+}
+
+BOOL CGridCtrl::isCellMaskActivated( int nRow, int nCol )
+{
+	if (nRow < 0 || nRow >= m_pCellEnable.size())
+	{
+		return FALSE;
+	}
+
+	if (nCol < 0 || nCol >= m_pCellEnable[nRow].size())
+	{
+		return FALSE;
+	}
+
+	return m_pCellEnable[nRow][nCol].isActivated();
+}
+
+// Returns the bounding box of a range of cells
+BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect)
+{
+    CPoint 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;
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Grid attribute functions
+
+LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
+{
+    LRESULT result = Default();
+
+    // Get the logical font
+    LOGFONT lf;
+    if (!GetObject((HFONT) hFont, sizeof(LOGFONT), &lf))
+        return result;
+
+    m_cellDefault.SetFont(&lf);
+    m_cellFixedColDef.SetFont(&lf);
+    m_cellFixedRowDef.SetFont(&lf);
+    m_cellFixedRowColDef.SetFont(&lf);
+
+    Refresh();
+
+    return result;
+}
+
+LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
+{
+    //LOGFONT    lf;
+    //m_cellDefault.GetFontObject()->GetLogFont(&lf);
+
+    return (LRESULT) m_cellDefault.GetFontObject()->GetSafeHandle();
+}
+
+#ifndef _WIN32_WCE_NO_CURSOR
+BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+    if (nHitTest == HTCLIENT)
+    {
+        switch (m_MouseMode)
+        {
+        case MOUSE_OVER_COL_DIVIDE:
+            SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+            break;
+        case MOUSE_OVER_ROW_DIVIDE:
+            SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+            break;
+#ifndef GRIDCONTROL_NO_DRAGDROP
+        case MOUSE_DRAGGING:
+            break;
+#endif
+        default:
+            if (!GetVirtualMode())
+            {
+                CPoint pt(GetMessagePos());
+                ScreenToClient(&pt);
+                CCellID cell = GetCellFromPt(pt);
+                if (IsValid(cell))
+                {
+                    CGridCellBase* pCell = GetCell(cell.row, cell.col);
+                    if (pCell)
+                        return pCell->OnSetCursor();
+                }
+            }
+
+            SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+        }
+        return TRUE;
+    }
+
+    return CWnd::OnSetCursor(pWnd, nHitTest, message);
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column count functions
+
+BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
+{
+    if (m_nFixedRows == nFixedRows)
+        return TRUE;
+
+//    ASSERT(nFixedRows >= 0);
+
+    ResetSelectedRange();
+
+    // Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    if (nFixedRows > GetRowCount())
+        if (!SetRowCount(nFixedRows))
+            return FALSE;
+        
+        if (m_idCurrentCell.row < nFixedRows)
+            SetFocusCell(-1, - 1);
+        
+        if (!GetVirtualMode())
+        {
+            if (nFixedRows > m_nFixedRows)
+            {
+                for (int i = m_nFixedRows; i < nFixedRows; i++)
+                    for (int j = 0; j < GetColumnCount(); j++)
+                    {
+                        SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDROW);
+                        SetItemBkColour(i, j, CLR_DEFAULT );
+                        SetItemFgColour(i, j, CLR_DEFAULT );
+                    }
+            }
+            else
+            {
+                for (int i = nFixedRows; i < m_nFixedRows; i++)
+                {
+                    int j;
+                    for (j = 0; j < GetFixedColumnCount(); j++)
+                        SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDROW );
+
+                    for (j = GetFixedColumnCount(); j < GetColumnCount(); j++)
+                    {
+                        SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDROW) );
+                        SetItemBkColour(i, j, CLR_DEFAULT );
+                        SetItemFgColour(i, j, CLR_DEFAULT );
+                    }
+                }
+            }
+        }
+
+        m_nFixedRows = nFixedRows;
+        
+        Refresh();
+        
+        return TRUE;
+}
+
+BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
+{
+    if (m_nFixedCols == nFixedCols)
+        return TRUE;
+
+//    ASSERT(nFixedCols >= 0);
+
+    if (nFixedCols > GetColumnCount())
+        if (!SetColumnCount(nFixedCols))
+            return FALSE;
+
+    if (m_idCurrentCell.col < nFixedCols)
+        SetFocusCell(-1, - 1);
+
+    ResetSelectedRange();
+
+    // Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    if (!GetVirtualMode())
+    {
+        if (nFixedCols > m_nFixedCols)
+        {
+            for (int i = 0; i < GetRowCount(); i++)
+                for (int j = m_nFixedCols; j < nFixedCols; j++)
+                {
+                    SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDCOL);
+                    SetItemBkColour(i, j, CLR_DEFAULT );
+                    SetItemFgColour(i, j, CLR_DEFAULT );
+                }
+        }
+        else
+        {
+			{ // Scope limit i,j
+	            for (int i = 0; i < GetFixedRowCount(); i++)
+		            for (int j = nFixedCols; j < m_nFixedCols; j++)
+			            SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL );
+			}
+			{// Scope limit i,j
+	            for (int i = GetFixedRowCount(); i < GetRowCount(); i++)
+		            for (int j = nFixedCols; j < m_nFixedCols; j++)
+			        {
+				        SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDCOL) );
+					    SetItemBkColour(i, j, CLR_DEFAULT );
+						SetItemFgColour(i, j, CLR_DEFAULT );
+	                }
+			}
+        }
+    }
+        
+    m_nFixedCols = nFixedCols;
+        
+    Refresh();
+        
+    return TRUE;
+}
+
+BOOL CGridCtrl::SetRowCount(int nRows)
+{
+    BOOL bResult = TRUE;
+
+//    ASSERT(nRows >= 0);
+    if (nRows == GetRowCount())
+        return bResult;
+
+	// Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    if (nRows < m_nFixedRows)
+        m_nFixedRows = nRows;
+
+    if (m_idCurrentCell.row >= nRows)
+        SetFocusCell(-1, - 1);
+
+    int addedRows = nRows - GetRowCount();
+
+    // If we are about to lose rows, then we need to delete the GridCell objects
+    // in each column within each row
+    if (addedRows < 0)
+    {
+        if (!GetVirtualMode())
+        {
+            for (int row = nRows; row < m_nRows; row++)
+            {
+                // Delete cells
+                for (int col = 0; col < m_nCols; col++)
+                    DestroyCell(row, col);
+            
+                // Delete rows
+                GRID_ROW* pRow = m_RowData[row];
+                if (pRow)
+                    delete pRow;
+            }
+        }
+        m_nRows = nRows;
+    }
+    
+    TRY
+    {
+        m_arRowHeights.SetSize(nRows);
+
+        if (GetVirtualMode())
+        {
+            m_nRows = nRows;
+            if (addedRows > 0)
+            {
+                int startRow = nRows - addedRows;
+                for (int row = startRow; row < nRows; row++)
+                    m_arRowHeights[row] = m_cellDefault.GetHeight();
+            }
+			ResetVirtualOrder();
+        }
+        else
+        {
+            // Change the number of rows.
+            m_RowData.SetSize(nRows);
+
+            // If we have just added rows, we need to construct new elements for each cell
+            // and set the default row height
+            if (addedRows > 0)
+            {
+                // initialize row heights and data
+                int startRow = nRows - addedRows;
+                for (int row = startRow; row < nRows; row++)
+                {
+                    m_arRowHeights[row] = m_cellDefault.GetHeight();
+
+                    m_RowData[row] = new GRID_ROW;
+                    m_RowData[row]->SetSize(m_nCols);
+                    for (int col = 0; col < m_nCols; col++)
+                    {
+                        GRID_ROW* pRow = m_RowData[row];
+                        if (pRow && !GetVirtualMode())
+                            pRow->SetAt(col, CreateCell(row, col));
+                    }
+                    m_nRows++;
+                }
+            }
+        }
+    }
+    CATCH (CMemoryException, e)
+    {
+        e->ReportError();
+        bResult = FALSE;
+    }
+    END_CATCH
+
+    SetModified();
+    ResetScrollBars();
+    Refresh();
+
+    return bResult;
+}
+
+BOOL CGridCtrl::SetColumnCount(int nCols)
+{
+    BOOL bResult = TRUE;
+
+//    ASSERT(nCols >= 0);
+
+    if (nCols == GetColumnCount())
+        return bResult;
+
+    // Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    if (nCols < m_nFixedCols)
+        m_nFixedCols = nCols;
+
+    if (m_idCurrentCell.col >= nCols)
+        SetFocusCell(-1, - 1);
+
+    int addedCols = nCols - GetColumnCount();
+
+    // If we are about to lose columns, then we need to delete the GridCell objects
+    // within each column
+    if (addedCols < 0 && !GetVirtualMode())
+    {
+        for (int row = 0; row < m_nRows; row++)
+            for (int col = nCols; col < GetColumnCount(); col++)
+                DestroyCell(row, col);
+    }
+
+    TRY 
+    {
+        // Change the number of columns.
+        m_arColWidths.SetSize(nCols);
+    
+        // Change the number of columns in each row.
+        if (!GetVirtualMode())
+            for (int i = 0; i < m_nRows; i++)
+                if (m_RowData[i])
+                    m_RowData[i]->SetSize(nCols);
+        
+        // If we have just added columns, we need to construct new elements for each cell
+        // and set the default column width
+        if (addedCols > 0)
+        {
+            int row, col;
+
+            // initialized column widths
+            int startCol = nCols - addedCols;
+            for (col = startCol; col < nCols; col++)
+                m_arColWidths[col] = m_cellFixedColDef.GetWidth();
+        
+            // initialise column data
+            if (!GetVirtualMode())
+            {
+                for (row = 0; row < m_nRows; row++)
+                    for (col = startCol; col < nCols; col++)
+                    {
+                        GRID_ROW* pRow = m_RowData[row];
+                        if (pRow)
+                            pRow->SetAt(col, CreateCell(row, col));
+                    }
+            }
+        }
+        // else    // check for selected cell ranges
+        //    ResetSelectedRange();
+    }
+    CATCH (CMemoryException, e)
+    {
+        e->ReportError();
+        bResult = FALSE;
+    }
+    END_CATCH
+
+	m_arColOrder.resize(nCols);  // Reset Column Order
+    for (int i = 0; i < nCols; i++)
+	{
+		m_arColOrder[i] = i;	
+	}
+
+    m_nCols = nCols;
+
+    SetModified();
+    ResetScrollBars();
+    Refresh();
+
+    return bResult;
+}
+
+BOOL CGridCtrl::UpdateCellEditableMask()
+{
+	if (m_nRows != m_pCellEnable.size())
+	{
+		m_pCellEnable.resize(m_nRows);
+	}
+
+	for (int i = 0; i<m_nRows; i++)
+	{
+		if (m_nCols != m_pCellEnable[i].size())
+		{
+			m_pCellEnable[i].resize(m_nCols);
+		}
+	}
+
+	return TRUE;
+}
+
+// Insert a column at a given position, or add to end of columns (if nColumn = -1)
+int CGridCtrl::InsertColumn(LPCTSTR strHeading,
+                            UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
+                            int nColumn  /* = -1 */)
+{
+//	ASSERT(!m_AllowReorderColumn); // function not implemented in case of m_AllowReorderColumn option
+    if (nColumn >= 0 && nColumn < m_nFixedCols)
+    {
+
+        // TODO: Fix it so column insertion works for in the fixed column area
+//        ASSERT(FALSE);
+        return -1;
+    }
+
+    // If the insertion is for a specific column, check it's within range.
+    if (nColumn >= 0 && nColumn > GetColumnCount())
+        return -1;
+
+    // Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    ResetSelectedRange();
+
+    // Gotta be able to at least _see_ some of the column.
+    if (m_nRows < 1)
+        SetRowCount(1);
+
+    // Allow the user to insert after the last of the columns, but process it as a
+    // "-1" column, meaning it gets flaged as being the last column, and not a regular
+    // "insert" routine.
+    if (nColumn == GetColumnCount())
+        nColumn = -1;
+
+    TRY
+    {
+        if (nColumn < 0)
+        {
+            nColumn = m_nCols;
+            m_arColWidths.Add(0);
+            if (!GetVirtualMode())
+            {
+                for (int row = 0; row < m_nRows; row++)
+                {
+                    GRID_ROW* pRow = m_RowData[row];
+                    if (!pRow)
+                        return -1;
+                    pRow->Add(CreateCell(row, nColumn));
+                }
+            }
+        } 
+        else
+        {
+            m_arColWidths.InsertAt(nColumn, (UINT)0);
+            if (!GetVirtualMode())
+            {
+                for (int row = 0; row < m_nRows; row++) 
+                {
+                    GRID_ROW* pRow = m_RowData[row];
+                    if (!pRow)
+                        return -1;
+                    pRow->InsertAt(nColumn, CreateCell(row, nColumn));
+                }
+            }
+        }
+    }
+    CATCH (CMemoryException, e)
+    {
+        e->ReportError();
+        return -1;
+    }
+    END_CATCH
+
+    m_nCols++;
+    
+    // Initialise column data
+    SetItemText(0, nColumn, strHeading);
+    for (int row = 0; row < m_nRows; row++) 
+        SetItemFormat(row, nColumn, nFormat);
+    
+    // initialized column width
+    m_arColWidths[nColumn] = GetTextExtent(0, nColumn, strHeading).cx;
+    
+    if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
+        m_idCurrentCell.col++;
+    
+    ResetScrollBars();
+
+    SetModified();
+    
+    return nColumn;
+}
+
+// Insert a row at a given position, or add to end of rows (if nRow = -1)
+int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
+{
+    if (nRow >= 0 && nRow < m_nFixedRows)
+    {
+        // TODO: Fix it so column insertion works for in the fixed row area
+//        ASSERT(FALSE);
+        return -1;
+    }
+
+    // If the insertion is for a specific row, check it's within range.
+    if (nRow >= 0 && nRow >= GetRowCount())
+        return -1;
+
+    // Force recalculation
+    m_idTopLeftCell.col = -1;
+
+    ResetSelectedRange();
+
+    // Gotta be able to at least _see_ some of the row.
+    if (m_nCols < 1)
+        SetColumnCount(1);
+
+    TRY
+    {
+        // Adding a row to the bottom
+        if (nRow < 0)
+        {
+            nRow = m_nRows;
+            m_arRowHeights.Add(0);
+            if (!GetVirtualMode())
+                m_RowData.Add(new GRID_ROW);
+			else
+				m_arRowOrder.push_back(m_nRows);
+
+        }
+        else
+        {
+            m_arRowHeights.InsertAt(nRow, (UINT)0);
+            if (!GetVirtualMode())
+                m_RowData.InsertAt(nRow, new GRID_ROW);
+			else
+			{
+				ResetVirtualOrder();
+			}
+        }
+
+        if (!GetVirtualMode())
+            m_RowData[nRow]->SetSize(m_nCols);
+    }
+    CATCH (CMemoryException, e)
+    {
+        e->ReportError();
+        return -1;
+    }
+    END_CATCH
+
+    m_nRows++;
+
+    // Initialise cell data
+    if (!GetVirtualMode())
+    {
+        for (int col = 0; col < m_nCols; col++)
+        {
+            GRID_ROW* pRow = m_RowData[nRow];
+            if (!pRow)
+                return -1;
+            pRow->SetAt(col, CreateCell(nRow, col));
+        }
+    }
+
+    // Set row title
+    SetItemText(nRow, 0, strHeading);
+
+    // initialized row height
+    if (strHeading && strHeading[0])
+        m_arRowHeights[nRow] = GetTextExtent(nRow, 0, strHeading).cy;
+    else
+        m_arRowHeights[nRow] = m_cellFixedRowDef.GetHeight();
+
+    if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
+        m_idCurrentCell.row++;
+
+    ResetScrollBars();
+
+    SetModified();
+
+    return nRow;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Cell creation stuff
+
+BOOL CGridCtrl::SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+//    ASSERT(IsValid(nRow, nCol));
+    if (!IsValid(nRow, nCol))
+        return FALSE;
+
+    if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+    {
+//        ASSERT( FALSE);
+        return FALSE;
+    }
+
+    CGridCellBase* pNewCell = (CGridCellBase*) pRuntimeClass->CreateObject();
+
+    CGridCellBase* pCurrCell = GetCell(nRow, nCol);
+    if (pCurrCell)
+        *pNewCell = *pCurrCell;
+
+    SetCell(nRow, nCol, pNewCell);
+    delete pCurrCell;
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::SetDefaultCellType( CRuntimeClass* pRuntimeClass)
+{
+//    ASSERT( pRuntimeClass != NULL );
+    if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+    {
+//        ASSERT( FALSE);
+        return FALSE;
+    }
+    m_pRtcDefault = pRuntimeClass;
+    return TRUE;
+}
+
+// Creates a new grid cell and performs any necessary initialisation
+/*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
+{
+//    ASSERT(!GetVirtualMode());
+
+    if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
+    {
+//        ASSERT( FALSE);
+        return NULL;
+    }
+    CGridCellBase* pCell = (CGridCellBase*) m_pRtcDefault->CreateObject();
+    if (!pCell)
+        return NULL;
+
+    pCell->SetGrid(this);
+    pCell->SetCoords(nRow, nCol); 
+
+    if (nCol < m_nFixedCols)
+        pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);
+    if (nRow < m_nFixedRows)
+        pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);
+    
+    pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
+
+    return pCell;
+}
+
+// Performs any cell cleanup necessary to maintain grid integrity
+/*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
+{
+    // Should NEVER get here in virtual mode.
+//    ASSERT(!GetVirtualMode());
+
+    // Set the cells state to 0. If the cell is selected, this
+    // will remove the cell from the selected list.
+    SetItemState(nRow, nCol, 0);
+
+    delete GetCell(nRow, nCol);
+}
+
+BOOL CGridCtrl::DeleteColumn(int nColumn)
+{
+    if (nColumn < 0 || nColumn >= GetColumnCount())
+        return FALSE;
+
+    ResetSelectedRange();
+
+    if (!GetVirtualMode())
+    {
+        for (int row = 0; row < GetRowCount(); row++)
+        {
+            GRID_ROW* pRow = m_RowData[row];
+            if (!pRow)
+                return FALSE;
+
+            DestroyCell(row, nColumn);
+        
+            pRow->RemoveAt(nColumn);
+        }
+    }
+    m_arColWidths.RemoveAt(nColumn);
+    m_nCols--;
+    if (nColumn < m_nFixedCols)
+        m_nFixedCols--;
+    
+    if (nColumn == m_idCurrentCell.col)
+        m_idCurrentCell.row = m_idCurrentCell.col = -1;
+    else if (nColumn < m_idCurrentCell.col)
+        m_idCurrentCell.col--;
+    
+    ResetScrollBars();
+
+    SetModified();
+
+    return TRUE;
+}
+
+
+void CGridCtrl::AddSubVirtualRow(int Num, int Nb)
+{
+//	ASSERT(Nb == -1 || Nb ==1); // only these vlaues are implemented now
+	if(!GetVirtualMode()) return;
+	for(int ind = 0; ind<m_nRows ; ind++)
+		if(m_arRowOrder[ind]>Num) m_arRowOrder[ind]+=Nb;
+	if(Nb>0)
+		m_arRowOrder.insert(m_arRowOrder.begin()+Num,Num);
+	else
+		m_arRowOrder.erase(m_arRowOrder.begin()+Num);
+}
+
+
+BOOL CGridCtrl::DeleteRow(int nRow)
+{
+    if (nRow < 0 || nRow >= GetRowCount())
+        return FALSE;
+
+    ResetSelectedRange();
+
+    if (!GetVirtualMode())
+    {
+        GRID_ROW* pRow = m_RowData[nRow];
+        if (!pRow)
+            return FALSE;
+
+        for (int col = 0; col < GetColumnCount(); col++)
+            DestroyCell(nRow, col);
+
+        delete pRow;
+        m_RowData.RemoveAt(nRow);
+    }
+    else
+    	AddSubVirtualRow(nRow,-1);
+
+    m_arRowHeights.RemoveAt(nRow);
+
+    m_nRows--;
+    if (nRow < m_nFixedRows)
+        m_nFixedRows--;
+    
+    if (nRow == m_idCurrentCell.row)
+        m_idCurrentCell.row = m_idCurrentCell.col = -1;
+    else if (nRow < m_idCurrentCell.row)
+        m_idCurrentCell.row--;
+    
+    ResetScrollBars();
+
+    SetModified();
+    
+    return TRUE;
+}
+
+// Handy function that removes all non-fixed rows
+BOOL CGridCtrl::DeleteNonFixedRows()
+{
+    ResetSelectedRange();
+    int nFixed = GetFixedRowCount();
+    int nCount = GetRowCount();
+    if (GetVirtualMode())
+	{
+		if(nCount != nFixed)
+		{
+			SetRowCount(nFixed);
+			m_arRowOrder.resize(nFixed);
+			m_arRowHeights.SetSize(nFixed);
+			m_idCurrentCell.row = m_idCurrentCell.col = -1;
+			ResetScrollBars();
+			SetModified();
+		}
+	}
+	else
+	{
+    // Delete all data rows
+    for (int nRow = nCount; nRow >= nFixed; nRow--)
+        DeleteRow(nRow);
+	}
+    return TRUE;
+}
+
+// Removes all rows, columns and data from the grid.
+BOOL CGridCtrl::DeleteAllItems()
+{
+    ResetSelectedRange();
+
+    m_arColWidths.RemoveAll();
+    m_arRowHeights.RemoveAll();
+
+    // Delete all cells in the grid
+    if (!GetVirtualMode())
+    {
+        for (int row = 0; row < m_nRows; row++)
+        {
+            for (int col = 0; col < m_nCols; col++)
+                DestroyCell(row, col);
+
+            GRID_ROW* pRow = m_RowData[row];
+            delete pRow;
+        }
+
+        // Remove all rows
+        m_RowData.RemoveAll();
+    }
+	else
+		m_arRowOrder.clear();
+
+
+    m_idCurrentCell.row = m_idCurrentCell.col = -1;
+    m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
+
+    ResetScrollBars();
+
+    SetModified();
+
+    return TRUE;
+}
+
+void CGridCtrl::AutoFill()
+{
+    if (!::IsWindow(m_hWnd))
+        return;
+
+    CRect rect;
+    GetClientRect(rect);
+
+    SetColumnCount(rect.Width() / m_cellDefault.GetWidth() + 1);
+    SetRowCount(rect.Height() / m_cellDefault.GetHeight() + 1);
+    SetFixedRowCount(1);
+    SetFixedColumnCount(1);
+    ExpandToFit();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl data functions
+
+// Set CListCtrl::GetNextItem for details
+CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
+{
+    if ((nFlags & GVNI_ALL) == GVNI_ALL)
+    {    // GVNI_ALL Search whole Grid beginning from cell
+        //          First row (cell.row) -- ONLY Columns to the right of cell
+        //          following rows       -- ALL  Columns
+        int row = cell.row , col = cell.col + 1;
+        if (row <= 0)
+            row = GetFixedRowCount();
+        for (; row < GetRowCount(); row++)
+        {
+            if (col <= 0)
+                col = GetFixedColumnCount();
+            for (; col < GetColumnCount(); col++)
+            {
+                int nState = GetItemState(row, col);
+                if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                    (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                    (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                    (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                    (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                    (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                    return CCellID(row, col);
+            }
+            // go to First Column
+            col = GetFixedColumnCount();
+        }
+    }
+    else if ((nFlags & GVNI_BELOW) == GVNI_BELOW && 
+             (nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
+    {   // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
+        //           Only rows starting with  cell.row and below
+        //           All rows   -- ONLY Columns to the right of cell
+        int row = cell.row;
+        if (row <= 0)
+            row = GetFixedRowCount();
+        for (; row < GetRowCount(); row++)
+        {
+            int col = cell.col + 1;
+            if (col <= 0)
+                col = GetFixedColumnCount();
+            for (; col < GetColumnCount(); col++) 
+            {
+                int nState = GetItemState(row, col);
+                if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                    (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                    (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                    (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                    (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                    (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                    return CCellID(row, col);
+            }
+        }
+    }
+    else if ((nFlags & GVNI_ABOVE) == GVNI_ABOVE) 
+    {
+        for (int row = cell.row - 1; row >= GetFixedRowCount(); row--) 
+        {
+            int nState = GetItemState(row, cell.col);
+            if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                return CCellID(row, cell.col);
+        }
+    }
+    else if ((nFlags & GVNI_BELOW) == GVNI_BELOW)
+    {
+        for (int row = cell.row + 1; row < GetRowCount(); row++) 
+        {
+            int nState = GetItemState(row, cell.col);
+            if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                return CCellID(row, cell.col);
+        }
+    } 
+    else if ((nFlags & GVNI_TOLEFT) == GVNI_TOLEFT)
+    {
+        for (int col = cell.col - 1; col >= GetFixedColumnCount(); col--) 
+        {
+            int nState = GetItemState(cell.row, col);
+            if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                return CCellID(cell.row, col);
+        }
+    }
+    else if ((nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
+    {
+        for (int col = cell.col + 1; col < GetColumnCount(); col++) 
+        {
+            int nState = GetItemState(cell.row, col);
+            if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) || 
+                (nFlags & GVNI_FOCUSED     && nState & GVIS_FOCUSED)     ||
+                (nFlags & GVNI_SELECTED    && nState & GVIS_SELECTED)    ||
+                (nFlags & GVNI_READONLY    && nState & GVIS_READONLY)    ||
+                (nFlags & GVNI_FIXED       && nState & GVIS_FIXED)       ||
+                (nFlags & GVNI_MODIFIED    && nState & GVIS_MODIFIED))
+                return CCellID(cell.row, col);
+        }
+    }
+    
+    return CCellID(-1, -1);
+}
+
+// Sorts on a given column using the cell text
+BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
+{
+    return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
+}
+
+void CGridCtrl::SetCompareFunction(PFNLVCOMPARE pfnCompare)
+{
+	m_pfnCompare = pfnCompare;
+}
+
+// Sorts on a given column using the cell text and using the specified comparison
+// function
+BOOL CGridCtrl::SortItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
+{
+    SetSortColumn(nCol);
+    SetSortAscending(bAscending);
+    ResetSelectedRange();
+    SetFocusCell(-1, - 1);
+
+	if (m_pfnCompare == NULL)
+		return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
+	else
+	    return CGridCtrl::SortItems(m_pfnCompare, nCol, bAscending, data);
+}
+
+// Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
+BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
+                          LPARAM data /* = 0 */)
+{
+    SetSortColumn(nCol);
+    SetSortAscending(bAscending);
+    ResetSelectedRange();
+    SetFocusCell(-1, -1);
+    return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
+}
+
+int CALLBACK CGridCtrl::pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+	UNUSED_ALWAYS(lParamSort);
+
+	CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
+	CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
+	if (!pCell1 || !pCell2) return 0;
+
+	return _tcscmp(pCell1->GetText(), pCell2->GetText());
+}
+
+int CALLBACK CGridCtrl::pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+	UNUSED_ALWAYS(lParamSort);
+
+	CGridCellBase* pCell1 = (CGridCellBase*) lParam1;
+	CGridCellBase* pCell2 = (CGridCellBase*) lParam2;
+	if (!pCell1 || !pCell2) return 0;
+
+	int nValue1 = _ttol(pCell1->GetText());
+	int nValue2 = _ttol(pCell2->GetText());
+
+	if (nValue1 < nValue2)
+		return -1;
+	else if (nValue1 == nValue2)
+		return 0;
+	else
+		return 1;
+}
+
+
+CGridCtrl *  CGridCtrl::m_This;
+// private recursive sort implementation
+bool CGridCtrl::NotVirtualCompare(int c1, int c2)
+{
+	return ! CGridCtrl::m_This->m_pfnVirtualCompare(c1, c2);
+}
+BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
+                          int low, int high)
+{
+    if (nCol >= GetColumnCount())
+        return FALSE;
+
+    if (high == -1)
+        high = GetRowCount() - 1;
+
+    int lo = low;
+    int hi = high;
+    
+    if (hi <= lo)
+        return FALSE;
+
+    if (GetVirtualMode())
+	{
+//		ASSERT(m_pfnVirtualCompare);
+		m_CurCol = m_arColOrder[nCol];
+		m_This = this;
+		std::stable_sort(m_arRowOrder.begin() + m_nFixedRows, m_arRowOrder.end(), 
+                         bAscending ? m_pfnVirtualCompare : NotVirtualCompare);
+		return TRUE;
+	}
+   
+    
+    //LPARAM midItem = GetItemData((lo + hi)/2, nCol);
+	LPARAM pMidCell = (LPARAM) GetCell((lo + hi)/2, nCol);
+    
+    // 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( (LPARAM)GetCell(lo, nCol), (LPARAM) pMidCell, data) < 0)
+                ++lo;
+        else
+            while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), pMidCell, 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((LPARAM)GetCell(hi, nCol), pMidCell, data) > 0)
+				--hi;
+		else
+			while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, 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((LPARAM)GetCell(lo, nCol), (LPARAM)GetCell(hi, nCol), data) != 0)
+            {
+				for (int col = 0; col < GetColumnCount(); col++)
+                {
+					CGridCellBase *pCell = GetCell(lo, col);
+                    SetCell(lo, col, GetCell(hi, col));
+                    SetCell(hi, col, pCell);
+                }
+                UINT nRowHeight = m_arRowHeights[lo];
+                m_arRowHeights[lo] = m_arRowHeights[hi];
+                m_arRowHeights[hi] = 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;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl data functions
+
+BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
+{
+    if (!pItem || GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
+    if (!pCell)
+        return FALSE;
+
+    SetModified(TRUE, pItem->row, pItem->col);
+
+    if (pItem->mask & GVIF_TEXT)
+        pCell->SetText(pItem->strText);
+    if (pItem->mask & GVIF_PARAM)
+        pCell->SetData(pItem->lParam);
+    if (pItem->mask & GVIF_IMAGE)
+        pCell->SetImage(pItem->iImage);
+    if (pItem->mask & GVIF_STATE)
+        SetItemState(pItem->row, pItem->col, pItem->nState);
+    if (pItem->mask & GVIF_FORMAT)
+        pCell->SetFormat(pItem->nFormat);
+    if (pItem->mask & GVIF_BKCLR)
+        pCell->SetBackClr(pItem->crBkClr);
+    if (pItem->mask & GVIF_FGCLR)
+        pCell->SetTextClr(pItem->crFgClr);
+    if (pItem->mask & GVIF_FONT)
+        pCell->SetFont(&(pItem->lfFont));
+    if( pItem->mask & GVIF_MARGIN)
+        pCell->SetMargin( pItem->nMargin);
+    
+    return TRUE;
+}
+
+BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
+{
+    if (!pItem)
+        return FALSE;
+    CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
+    if (!pCell)
+        return FALSE;
+
+    if (pItem->mask & GVIF_TEXT)
+        pItem->strText = GetItemText(pItem->row, pItem->col);
+    if (pItem->mask & GVIF_PARAM)
+        pItem->lParam  = pCell->GetData();;
+    if (pItem->mask & GVIF_IMAGE)
+        pItem->iImage  = pCell->GetImage();
+    if (pItem->mask & GVIF_STATE)
+        pItem->nState  = pCell->GetState();
+    if (pItem->mask & GVIF_FORMAT)
+        pItem->nFormat = pCell->GetFormat();
+    if (pItem->mask & GVIF_BKCLR)
+        pItem->crBkClr = pCell->GetBackClr();
+    if (pItem->mask & GVIF_FGCLR)
+        pItem->crFgClr = pCell->GetTextClr();
+    if (pItem->mask & GVIF_FONT)
+        memcpy(&(pItem->lfFont), pCell->GetFont(), sizeof(LOGFONT));
+    if( pItem->mask & GVIF_MARGIN)
+        pItem->nMargin = pCell->GetMargin();
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return FALSE;
+
+    pCell->SetText(str);
+
+    SetModified(TRUE, nRow, nCol);
+    return TRUE;
+}
+
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
+// EFW - 06/13/99 - Added to support printf-style formatting codes
+BOOL CGridCtrl::SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CString strText;
+
+    va_list argptr;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return FALSE;
+
+    // Format the message text
+    va_start(argptr, szFmt);
+    strText.FormatV(szFmt, argptr);
+    va_end(argptr);
+
+    pCell->SetText(strText);
+
+    SetModified(TRUE, nRow, nCol);
+    return TRUE;
+}
+
+// EFW - 06/13/99 - Added to support string resource ID.  Supports
+// a variable argument list too.
+BOOL CGridCtrl::SetItemTextFmtID(int nRow, int nCol, UINT nID, ...)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CString strFmt, strText;
+    va_list argptr;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return FALSE;
+
+    // Format the message text
+    va_start(argptr, nID);
+    VERIFY(strFmt.LoadString(nID));
+    strText.FormatV(strFmt, argptr);
+    va_end(argptr);
+
+    pCell->SetText(strText);
+
+    SetModified(TRUE, nRow, nCol);
+    return TRUE;
+}
+#endif
+
+BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return FALSE;
+
+    pCell->SetData(lParam);
+    SetModified(TRUE, nRow, nCol);
+    return TRUE;
+}
+
+LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return (LPARAM) 0;
+
+    return pCell->GetData();
+}
+
+BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return FALSE;
+
+    pCell->SetImage(iImage);
+    SetModified(TRUE, nRow, nCol);
+    return TRUE;
+}
+
+int CGridCtrl::GetItemImage(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return -1;
+
+    return pCell->GetImage();
+}
+
+BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
+{
+    BOOL bSelected = IsCellSelected(nRow, nCol);
+
+    // If the cell is being unselected, remove it from the selected list
+    if (bSelected && !(state & GVIS_SELECTED))
+    {
+        CCellID cell;
+        DWORD key = MAKELONG(nRow, nCol);
+
+        if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
+            m_SelectedCellMap.RemoveKey(key);
+    }
+
+    // If cell is being selected, add it to the list of selected cells
+    else if (!bSelected && (state & GVIS_SELECTED))
+    {
+        CCellID cell(nRow, nCol);
+        m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
+    }
+
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+
+    // Set the cell's state
+    pCell->SetState(state);
+
+    return TRUE;
+}
+
+UINT CGridCtrl::GetItemState(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return 0;
+
+    return pCell->GetState();
+}
+
+BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+
+    pCell->SetFormat(nFormat);
+    return TRUE;
+}
+
+UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return 0;
+
+    return pCell->GetFormat();
+}
+
+BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+
+    pCell->SetBackClr(cr);
+    return TRUE;
+}
+
+COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return 0;
+
+    return pCell->GetBackClr();
+}
+
+BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+    
+    pCell->SetTextClr(cr);
+    return TRUE;
+}
+
+COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return 0;
+    
+    return pCell->GetTextClr();
+}
+
+BOOL CGridCtrl::SetItemFont(int nRow, int nCol, const LOGFONT* plf)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+    
+    pCell->SetFont(plf);
+    
+    return TRUE;
+}
+
+const LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell) 
+        return GetDefaultCell(nRow < GetFixedRowCount(), nCol < GetFixedColumnCount())->GetFont();
+    
+    return pCell->GetFont();
+}
+
+BOOL CGridCtrl::IsItemEditing(int nRow, int nCol)
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return FALSE;
+
+    return pCell->IsEditing();
+}
+
+////////////////////////////////////////////////////////////////////////////////////
+// Row/Column size functions
+
+long CGridCtrl::GetVirtualWidth() const
+{
+    long lVirtualWidth = 0;
+    int iColCount = GetColumnCount();
+    for (int i = 0; i < iColCount; i++)
+        lVirtualWidth += m_arColWidths[i];
+
+    return lVirtualWidth;
+}
+
+long CGridCtrl::GetVirtualHeight() const
+{
+    long lVirtualHeight = 0;
+    int iRowCount = GetRowCount();
+    for (int i = 0; i < iRowCount; i++)
+        lVirtualHeight += m_arRowHeights[i];
+
+    return lVirtualHeight;
+}
+
+int CGridCtrl::GetRowHeight(int nRow) const
+{
+//    ASSERT(nRow >= 0 && nRow < m_nRows);
+    if (nRow < 0 || nRow >= m_nRows)
+        return -1;
+
+    return m_arRowHeights[nRow];
+}
+
+int CGridCtrl::GetColumnWidth(int nCol) const
+{
+//    ASSERT(nCol >= 0 && nCol < m_nCols);
+    if (nCol < 0 || nCol >= m_nCols)
+        return -1;
+
+    return m_arColWidths[m_arColOrder[nCol]];
+}
+
+BOOL CGridCtrl::SetRowHeight(int nRow, int height)
+{
+//    ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
+    if (nRow < 0 || nRow >= m_nRows || height < 0)
+        return FALSE;
+
+    m_arRowHeights[nRow] = height;
+    ResetScrollBars();
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
+{
+//    ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
+    if (nCol < 0 || nCol >= m_nCols || width < 0)
+        return FALSE;
+
+    m_arColWidths[m_arColOrder[nCol]] = width;
+    ResetScrollBars();
+
+    return TRUE;
+}
+
+// LUC
+int CGridCtrl::GetFixedRowHeight(BOOL bIncludeFreezedRows /*=FALSE*/) const
+{
+    int nHeight = 0;
+	int i;
+    for (i = 0; i < m_nFixedRows; i++)
+        nHeight += GetRowHeight(i);
+
+	if(bIncludeFreezedRows)
+	{
+		for ( ; i < (m_nFixedRows + m_nFreezedRows); i++)
+        nHeight += GetRowHeight(i);
+	}
+
+    return nHeight;
+}
+
+// LUC
+int CGridCtrl::GetFixedColumnWidth(BOOL bIncludeFreezedCols /*=FALSE*/) const
+{
+    int nWidth = 0;
+	int i;
+    for (i = 0; i < m_nFixedCols; i++)
+		nWidth += GetColumnWidth(i);
+
+	if(bIncludeFreezedCols)
+	{
+		for ( ; i < (m_nFixedCols + m_nFreezedCols); i++)
+        nWidth += GetColumnWidth(i);
+	}
+
+    return nWidth;
+}
+
+BOOL CGridCtrl::AutoSizeColumn(int nCol, UINT nAutoSizeStyle /*=GVS_DEFAULT*/, 
+                               BOOL bResetScroll /*=TRUE*/)
+{
+//    ASSERT(nCol >= 0 && nCol < m_nCols);
+    if (nCol < 0 || nCol >= m_nCols)
+        return FALSE;
+
+    //  Skip hidden columns when autosizing
+    if( GetColumnWidth( nCol) <=0 )
+        return FALSE;
+
+    CSize size;
+    CDC* pDC = GetDC();
+    if (!pDC)
+        return FALSE;
+
+    int nWidth = 0;
+
+//    ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
+    if (nAutoSizeStyle == GVS_DEFAULT)
+        nAutoSizeStyle = GetAutoSizeStyle();
+
+    int nStartRow = (nAutoSizeStyle & GVS_HEADER)? 0 : GetFixedRowCount();
+    int nEndRow   = (nAutoSizeStyle & GVS_DATA)? GetRowCount()-1 : GetFixedRowCount()-1;
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(nStartRow, nCol, nEndRow, nCol));
+
+    for (int nRow = nStartRow; nRow <= nEndRow; nRow++)
+    {
+        CGridCellBase* pCell = GetCell(nRow, nCol);
+        if (pCell)
+            size = pCell->GetCellExtent(pDC);
+        if (size.cx > nWidth)
+            nWidth = size.cx;
+    }
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+    m_arColWidths[nCol] = nWidth;
+
+    ReleaseDC(pDC);
+    if (bResetScroll)
+        ResetScrollBars();
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::AutoSizeRow(int nRow, BOOL bResetScroll /*=TRUE*/)
+{
+//    ASSERT(nRow >= 0 && nRow < m_nRows);
+    if (nRow < 0 || nRow >= m_nRows)
+        return FALSE;
+
+    //  Skip hidden rows when autosizing
+    if( GetRowHeight( nRow) <=0 )
+        return FALSE;
+
+    CSize size;
+    CDC* pDC = GetDC();
+    if (!pDC)
+        return FALSE;
+
+    int nHeight = 0;
+    int nNumColumns = GetColumnCount();
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(nRow, 0, nRow, nNumColumns));
+
+    for (int nCol = 0; nCol < nNumColumns; nCol++)
+    {
+        CGridCellBase* pCell = GetCell(nRow, nCol);
+        if (pCell)
+            size = pCell->GetCellExtent(pDC);
+        if (size.cy > nHeight)
+            nHeight = size.cy;
+    }
+    m_arRowHeights[nRow] = nHeight;
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+    ReleaseDC(pDC);
+    if (bResetScroll)
+        ResetScrollBars();
+
+    return TRUE;
+}
+
+void CGridCtrl::AutoSizeColumns(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
+{
+    int nNumColumns = GetColumnCount();
+    for (int nCol = 0; nCol < nNumColumns; nCol++)
+    {
+        //  Skip hidden columns when autosizing
+        if( GetColumnWidth( nCol) > 0 )
+            AutoSizeColumn(nCol, nAutoSizeStyle, FALSE);
+    }
+    ResetScrollBars();
+}
+
+void CGridCtrl::AutoSizeRows()
+{
+    int nNumRows = GetRowCount();
+    for (int nRow = 0; nRow < nNumRows; nRow++)
+    {
+        //  Skip hidden rows when autosizing
+        if( GetRowHeight( nRow) > 0 )
+            AutoSizeRow(nRow, FALSE);
+    }
+    ResetScrollBars();
+}
+
+// sizes all rows and columns
+// faster than calling both AutoSizeColumns() and AutoSizeRows()
+void CGridCtrl::AutoSize(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
+{
+    CDC* pDC = GetDC();
+    if (!pDC)
+        return;
+
+    int nNumColumns = GetColumnCount();
+
+    int nCol, nRow;
+
+//    ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
+    if (nAutoSizeStyle == GVS_DEFAULT)
+        nAutoSizeStyle = GetAutoSizeStyle();
+
+    int nStartRow = (nAutoSizeStyle & GVS_HEADER)? 0 : GetFixedRowCount();
+    int nEndRow   = (nAutoSizeStyle & GVS_DATA)? GetRowCount()-1 : GetFixedRowCount()-1;
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(nStartRow, 0, nEndRow, nNumColumns));
+
+    // Row initialisation - only work on rows whose height is > 0
+    for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+    {
+        if( GetRowHeight( nRow) > 0 )
+            m_arRowHeights[nRow] = 1;
+    }
+
+    CSize size;
+    for (nCol = 0; nCol < nNumColumns; nCol++)
+    {
+        //  Don't size hidden columns or rows
+        if( GetColumnWidth( nCol) > 0 )
+        {
+            // Skip columns that are hidden, but now initialize
+            m_arColWidths[nCol] = 0;
+            for (nRow = nStartRow; nRow <= nEndRow; nRow++)
+            {
+                if( GetRowHeight( nRow) > 0 )
+                {
+                    CGridCellBase* pCell = GetCell(nRow, nCol);
+                    if (pCell)
+                        size = pCell->GetCellExtent(pDC);
+                    if (size.cx >(int) m_arColWidths[nCol])
+                        m_arColWidths[nCol] = size.cx;
+                    if (size.cy >(int) m_arRowHeights[nRow])
+                        m_arRowHeights[nRow] = size.cy;
+                }
+            }
+        }
+    }
+
+    if (GetVirtualMode())
+        SendCacheHintToParent(CCellRange(-1,-1,-1,-1));
+
+    ReleaseDC(pDC);
+
+    ResetScrollBars();
+    Refresh();
+}
+
+// Expands the columns to fit the screen space. If bExpandFixed is FALSE then fixed 
+// columns will not be affected
+void CGridCtrl::ExpandColumnsToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+    if (bExpandFixed)
+	{
+		if (GetColumnCount() <= 0) return;
+	} 
+	else
+	{
+		if (GetColumnCount() <= GetFixedColumnCount()) return;
+	}
+
+    EnableScrollBars(SB_HORZ, FALSE);
+
+    int col;
+    CRect rect;
+    GetClientRect(rect);
+
+    int nFirstColumn = (bExpandFixed)? 0 : GetFixedColumnCount();
+
+    int nNumColumnsAffected = 0;
+    for (col = nFirstColumn; col < GetColumnCount(); col++)
+    {
+        if (m_arColWidths[col] > 0)
+            nNumColumnsAffected++;
+    }
+
+    if (nNumColumnsAffected <= 0)
+        return;
+
+    long virtualWidth = GetVirtualWidth();
+    int nDifference = rect.Width() -(int) virtualWidth;
+    int nColumnAdjustment = nDifference / nNumColumnsAffected;
+
+    for (col = nFirstColumn; col < GetColumnCount(); col++)
+    {
+        if (m_arColWidths[col] > 0)
+            m_arColWidths[col] += nColumnAdjustment;    
+    }
+
+    if (nDifference > 0)
+    {
+        int leftOver = nDifference % nNumColumnsAffected;
+        for (int nCount = 0, col = nFirstColumn; 
+             (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
+        {
+            if (m_arColWidths[col] > 0)
+                m_arColWidths[col] += 1;
+        }
+    }
+    else 
+    {
+        int leftOver = (-nDifference) % nNumColumnsAffected;
+        for (int nCount = 0, col = nFirstColumn; 
+             (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
+        {
+            if (m_arColWidths[col] > 0)
+                m_arColWidths[col] -= 1;
+        }
+    }
+
+    Refresh();
+
+    ResetScrollBars();
+}
+
+void CGridCtrl::ExpandLastColumn()
+{
+    if (GetColumnCount() <= 0)
+        return;
+
+    // Search for last non-hidden column
+    int nLastColumn = GetColumnCount()-1;
+    while (m_arColWidths[nLastColumn] <= 0)
+        nLastColumn--;
+
+    if (nLastColumn <= 0)
+        return;
+
+    EnableScrollBars(SB_HORZ, FALSE);
+
+    CRect rect;
+    GetClientRect(rect);
+
+    long virtualWidth = GetVirtualWidth();
+    int nDifference = rect.Width() -(int) virtualWidth;
+
+    if (nDifference > 0)
+    {
+        //if (GetVirtualHeight() > rect.Height())
+        //    nDifference -= GetSystemMetrics(SM_CXVSCROLL);
+
+        m_arColWidths[ nLastColumn ] += nDifference;
+        Refresh();
+    }
+
+    ResetScrollBars();
+}
+
+// Expands the rows to fit the screen space. If bExpandFixed is FALSE then fixed 
+// rows will not be affected
+void CGridCtrl::ExpandRowsToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+    if (bExpandFixed)
+	{
+		if (GetRowCount() <= 0) return;
+	} 
+	else
+	{
+		if (GetRowCount() <= GetFixedRowCount()) return;
+	}
+
+    EnableScrollBars(SB_VERT, FALSE); 
+
+    int row;
+    CRect rect;
+    GetClientRect(rect);
+    
+    int nFirstRow = (bExpandFixed)? 0 : GetFixedRowCount();
+
+    int nNumRowsAffected = 0;
+    for (row = nFirstRow; row < GetRowCount(); row++)
+    {
+        if (m_arRowHeights[row] > 0)
+            nNumRowsAffected++;
+    }
+
+    if (nNumRowsAffected <= 0)
+        return;
+
+    long virtualHeight = GetVirtualHeight();
+    int nDifference = rect.Height() -(int) virtualHeight;
+    int nRowAdjustment = nDifference / nNumRowsAffected;
+    
+    for (row = nFirstRow; row < GetRowCount(); row++)
+    {
+        if (m_arRowHeights[row] > 0)
+            m_arRowHeights[row] += nRowAdjustment;    
+    }
+    
+    if (nDifference > 0)
+    {
+        int leftOver = nDifference % nNumRowsAffected;
+        for (int nCount = 0, row = nFirstRow; 
+             (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
+        {
+            if (m_arRowHeights[row] > 0)
+                m_arRowHeights[row] += 1;
+        }
+    } 
+    else 
+    {
+        int leftOver = (-nDifference) % nNumRowsAffected;
+        for (int nCount = 0, row = nFirstRow; 
+             (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
+        {
+            if (m_arRowHeights[row] > 0)
+                m_arRowHeights[row] -= 1;
+        }
+    }
+
+    Refresh();
+
+    ResetScrollBars();
+}
+
+// Expands the cells to fit the screen space. If bExpandFixed is FALSE then fixed 
+// cells  will not be affected
+void CGridCtrl::ExpandToFit(BOOL bExpandFixed /*=TRUE*/)
+{
+    ExpandColumnsToFit(bExpandFixed);   // This will remove any existing horz scrollbar
+    ExpandRowsToFit(bExpandFixed);      // This will remove any existing vert scrollbar
+    ExpandColumnsToFit(bExpandFixed);   // Just in case the first adjustment was with a vert
+                                        // scrollbar in place
+    Refresh();
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// Attributes
+
+void CGridCtrl::SetVirtualMode(BOOL bVirtual)
+{
+    DeleteAllItems();
+    m_bVirtualMode = bVirtual;
+
+    // Force some defaults here.
+    if (m_bVirtualMode)
+    {
+        SetEditable(FALSE);
+        SetAutoSizeStyle(GVS_HEADER);
+        SetFixedColumnSelection(FALSE);
+        SetFixedRowSelection(FALSE);
+		ResetVirtualOrder();
+    }
+}
+
+void CGridCtrl::SetGridLines(int nWhichLines /*=GVL_BOTH*/) 
+{
+    m_nGridLines = nWhichLines;
+    Refresh();
+}
+
+void CGridCtrl::SetListMode(BOOL bEnableListMode /*=TRUE*/)
+{
+    ResetSelectedRange();
+    SetSortColumn(-1);
+    m_bListMode = bEnableListMode;
+    SetFixedRowSelection(FALSE);
+    Refresh();
+}
+
+void CGridCtrl::SetSortColumn(int nCol)
+{
+    if (m_nSortColumn >= 0)
+        InvalidateCellRect(0, m_nSortColumn);
+    m_nSortColumn = nCol;
+    if (nCol >= 0)
+        InvalidateCellRect(0, nCol);
+}
+
+BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
+{
+    return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
+}
+
+void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
+{
+    // Cannot guarantee sorting anymore...
+    if (nCol < 0 || nCol == GetSortColumn())
+        SetSortColumn(-1);
+
+    if (nRow >= 0 && nCol >= 0)
+    {
+        if (bModified)
+        {
+            SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
+            m_bModified = TRUE;
+        }
+        else
+            SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
+    }
+    else
+        m_bModified = bModified;
+
+    if (!m_bModified)
+    {
+        for (int row = 0; row < GetRowCount(); row++)
+            for (int col = 0; col < GetColumnCount(); col++)
+                SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
+    }
+}
+
+BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
+{
+    if (nRow >= 0 && nCol >= 0)
+        return ( (GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED );
+    else
+        return m_bModified;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////
+// GridCtrl cell visibility tests and invalidation/redraw functions
+
+void CGridCtrl::Refresh()
+{
+    if (GetSafeHwnd() && m_bAllowDraw)
+        Invalidate();
+}
+
+// EnsureVisible supplied by Roelf Werkman
+void CGridCtrl::EnsureVisible(int nRow, int nCol)
+{
+    if (!m_bAllowDraw)
+        return;
+
+    CRect rectWindow;
+    /*
+    // set the scroll to the approximate position of row (Nigel Page-Jones)
+    int nPos = (int)((float)nRow / GetRowCount() * 1000);
+    float fPos = (float)nPos / 1000;
+    SCROLLINFO scrollInfo;
+    GetScrollInfo(SB_VERT, &scrollInfo);
+    scrollInfo.nPos = (int)(scrollInfo.nMax * fPos);
+    SetScrollInfo(SB_VERT, &scrollInfo, FALSE);
+    
+    GetClientRect(rectWindow);
+
+    // redraw cells    if necessary (Nigel Page-Jones)
+    CCellID idTopLeft = GetTopleftNonFixedCell(FALSE);
+    CCellID idNewTopLeft = GetTopleftNonFixedCell(TRUE);
+    if (idNewTopLeft != idTopLeft)
+    {
+        rectWindow.top = GetFixedRowHeight();
+        InvalidateRect(rectWindow);
+    }
+    */
+
+    // We are going to send some scroll messages, which will steal the focus 
+    // from it's rightful owner. Squirrel it away ourselves so we can give
+    // it back. (Damir)
+    CWnd* pFocusWnd = GetFocus();
+
+    CCellRange VisibleCells = GetVisibleNonFixedCellRange();
+
+    int right = nCol - VisibleCells.GetMaxCol();
+    int left  = VisibleCells.GetMinCol() - nCol;
+    int down  = nRow - VisibleCells.GetMaxRow();
+    int up    = VisibleCells.GetMinRow() - nRow;
+
+    int iColumnStart;
+    int iRowStart;
+
+    iColumnStart = VisibleCells.GetMaxCol() + 1;
+    while( right > 0 )
+    {
+        if( GetColumnWidth( iColumnStart ) > 0 )
+            SendMessage( WM_HSCROLL, SB_LINERIGHT, 0 );
+
+        right--;
+        iColumnStart++;
+    }
+
+    iColumnStart = VisibleCells.GetMinCol() - 1;
+    while( left > 0 )
+    {
+        if( GetColumnWidth( iColumnStart ) > 0 )
+            SendMessage( WM_HSCROLL, SB_LINELEFT, 0 );
+        left--;
+        iColumnStart--;
+    }
+
+    iRowStart = VisibleCells.GetMaxRow() + 1;
+    while( down > 0 )
+    {
+        if( GetRowHeight( iRowStart ) > 0 )
+            SendMessage( WM_VSCROLL, SB_LINEDOWN, 0 );
+        down--;
+        iRowStart++;
+    }
+
+    iRowStart = VisibleCells.GetMinRow() - 1;
+    while( up > 0 )
+    {
+        if( GetRowHeight( iRowStart ) > 0 )
+            SendMessage( WM_VSCROLL, SB_LINEUP, 0 );
+        up--;
+        iRowStart--;
+    }
+
+    // Move one more if we only see a snall bit of the cell
+    CRect rectCell;
+    if (!GetCellRect(nRow, nCol, rectCell))
+    {
+		if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
+			pFocusWnd->SetFocus(); 
+        return;
+    }
+
+    GetClientRect(rectWindow);
+
+	// LUC
+    // The previous fix was fixed properly by Martin Richter 
+    while (rectCell.right > rectWindow.right
+        && rectCell.left > GetFixedColumnWidth(m_bExcludeFreezedColsFromSelection)
+        && IsVisibleHScroll() // Junlin Xu: added to prevent infinite loop
+        )
+    {
+        SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
+        if (!GetCellRect(nRow, nCol, rectCell))
+        {
+            pFocusWnd->SetFocus(); 
+            return;
+        }
+    }
+
+	// LUC
+    while (rectCell.bottom > rectWindow.bottom
+        && rectCell.top > GetFixedRowHeight(m_bExcludeFreezedRowsFromSelection)
+        && IsVisibleVScroll() // Junlin Xu: added to prevent infinite loop
+        )
+    {
+        SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
+        if (!GetCellRect(nRow, nCol, rectCell))
+        {
+            pFocusWnd->SetFocus(); 
+            return;
+        }
+    }
+
+    // restore focus to whoever owned it
+    pFocusWnd->SetFocus(); 
+}
+
+BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
+{
+    return IsCellEditable(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
+{
+    return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
+}
+
+BOOL CGridCtrl::IsCellSelected(CCellID &cell) const
+{
+    return IsCellSelected(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellSelected(int nRow, int nCol) const
+{
+    if (GetVirtualMode())
+    {   
+        if (!IsSelectable())
+            return FALSE;
+
+        CCellID cell;
+        DWORD key = MAKELONG(nRow, nCol);
+
+        return (m_SelectedCellMap.Lookup(key, (CCellID&)cell));       
+    }
+    else
+        return IsSelectable() && ((GetItemState(nRow, nCol) & GVIS_SELECTED) == GVIS_SELECTED);
+}
+
+BOOL CGridCtrl::IsCellVisible(CCellID cell) 
+{
+    return IsCellVisible(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::IsCellVisible(int nRow, int nCol)
+{
+    if (!IsWindow(m_hWnd))
+        return FALSE;
+
+    int x, y;
+
+	// LUC
+    CCellID TopLeft;
+    if (nCol >= GetFixedColumnCount(TRUE) || nRow >= GetFixedRowCount(TRUE))
+    {
+        TopLeft = GetTopleftNonFixedCell();
+        if (nCol >= GetFixedColumnCount(TRUE) && nCol < TopLeft.col)
+            return FALSE;
+        if (nRow >= GetFixedRowCount(TRUE) && nRow < TopLeft.row)
+            return FALSE;
+    }
+    
+    CRect rect;
+    GetClientRect(rect);
+    if (nCol < GetFixedColumnCount(TRUE))
+    {
+        x = 0;
+        for (int i = 0; i <= nCol; i++) 
+        {
+            if (x >= rect.right)
+                return FALSE;
+            x += GetColumnWidth(i);    
+        }
+    } 
+    else 
+    {
+        x = GetFixedColumnWidth(TRUE);
+        for (int i = TopLeft.col; i <= nCol; i++) 
+        {
+			if (x >= rect.right)
+				return FALSE;
+            x += GetColumnWidth(i);    
+        }
+    }
+    
+    if (nRow < GetFixedRowCount(TRUE))
+    {
+        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(TRUE);
+        for (int i = TopLeft.row; i <= nRow; i++) 
+        {
+            if (y >= rect.bottom)
+                return FALSE;
+            y += GetRowHeight(i);    
+        }
+    }
+    
+    return TRUE;
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
+{
+    return InvalidateCellRect(cell.row, cell.col);
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const int row, const int col)
+{
+    if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
+        return FALSE;
+
+    if (!IsValid(row, col))
+        return FALSE;
+
+    if (!IsCellVisible(row, col))
+        return FALSE;
+
+    CRect rect;
+    if (!GetCellRect(row, col, rect))
+        return FALSE;
+
+	// LUC
+	int nRow = row;
+	int nCol = col;
+	GetTopLeftMergedCell(nRow, nCol, rect);
+
+    rect.right++;
+    rect.bottom++;
+    InvalidateRect(rect, TRUE);
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
+{
+//    ASSERT(IsValid(cellRange));
+    if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
+        return FALSE;
+
+    CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
+
+    CRect rect;
+    if (!GetCellRangeRect(visibleCellRange, rect))
+        return FALSE;
+
+    rect.right++;
+    rect.bottom++;
+    InvalidateRect(rect, TRUE);
+
+    return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl Mouse stuff
+
+// Handles mouse wheel notifications
+// Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
+{
+    // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
+    // wheel scrolls whole pages, not just lines.
+    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 CWnd::OnMouseWheel(nFlags, zDelta, pt);
+}
+#endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+
+void CGridCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point)
+{
+    CRect rect;
+    GetClientRect(rect);
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+    // If outside client area, return (unless we are drag n dropping)
+    if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
+        return;
+#endif
+
+    // Sometimes a MOUSEMOVE message can come after the left buttons
+    // has been let go, but before the BUTTONUP message hs been processed.
+    // We'll keep track of mouse buttons manually to avoid this.
+    // All bMouseButtonDown's have been replaced with the member m_bLMouseButtonDown
+    // BOOL bMouseButtonDown = ((nFlags & MK_LBUTTON) == MK_LBUTTON);
+
+    // If the left mouse button is up, then test to see if row/column sizing is imminent
+    if (!m_bLMouseButtonDown ||
+        (m_bLMouseButtonDown && m_MouseMode == MOUSE_NOTHING))
+    {
+        if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
+        {
+            if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
+            {
+#ifndef _WIN32_WCE_NO_CURSOR
+                SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+#endif
+                m_MouseMode = MOUSE_OVER_COL_DIVIDE;
+            }
+        }
+        else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
+        {
+            if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
+            {
+#ifndef _WIN32_WCE_NO_CURSOR
+                SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+#endif
+                m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
+            }
+        }
+        else if (m_MouseMode != MOUSE_NOTHING)
+        {
+#ifndef _WIN32_WCE_NO_CURSOR
+            SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+            m_MouseMode = MOUSE_NOTHING;
+        }
+
+        if (m_MouseMode == MOUSE_NOTHING)
+        {
+            CGridCellBase* pCell = NULL;
+            CCellID idCurrentCell;
+            if (!GetVirtualMode() || m_bTitleTips)
+            {
+                // Let the cell know that a big fat cursor is currently hovering
+                // over it.
+                idCurrentCell = GetCellFromPt(point);
+                pCell = GetCell(idCurrentCell.row, idCurrentCell.col);
+                if (pCell)
+                    pCell->OnMouseOver();
+            }
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+            // Titletips anyone? anyone?
+            if (m_bTitleTips)
+            {
+                CRect TextRect, CellRect;
+                if (pCell)
+                {
+                    LPCTSTR szTipText = pCell->GetTipText();
+                    if (!m_bRMouseButtonDown
+						&& szTipText && szTipText[0]
+                        && !pCell->IsEditing()
+                        && GetCellRect( idCurrentCell.row, idCurrentCell.col, &TextRect)
+                        && pCell->GetTipTextRect( &TextRect)
+                        && GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect) )
+                    {
+						// LUC
+						int row = idCurrentCell.row;
+						int col = idCurrentCell.col;
+						GetTopLeftMergedCell(row, col, CellRect);
+//						TRACE0("Showing TitleTip\n");
+						m_TitleTip.Show(TextRect, pCell->GetTipText(),  0, CellRect,
+                                        pCell->GetFont(),  GetTitleTipTextClr(), GetTitleTipBackClr());
+                    }
+                }
+            }
+#endif
+        }
+
+        m_LastMousePoint = point;
+        return;
+    }
+
+    if (!IsValid(m_LeftClickDownCell))
+    {
+        m_LastMousePoint = point;
+        return;
+    }
+
+    // If the left mouse button is down, then process appropriately
+    if (m_bLMouseButtonDown)
+    {
+        switch (m_MouseMode)
+        {
+        case MOUSE_SELECT_ALL:
+            break;
+
+        case MOUSE_SELECT_COL:
+        case MOUSE_SELECT_ROW:
+        case MOUSE_SELECT_CELLS:
+            {
+                CCellID idCurrentCell = GetCellFromPt(point);
+                if (!IsValid(idCurrentCell))
+                    return;
+
+                if (idCurrentCell != GetFocusCell())
+                {
+                    OnSelecting(idCurrentCell);
+
+                    // EFW - BUG FIX - Keep the appropriate cell row and/or
+                    // column focused.  A fix in SetFocusCell() will place
+                    // the cursor in a non-fixed cell as needed.
+					// LUC
+                    if((idCurrentCell.row >= GetFixedRowCount(m_bExcludeFreezedRowsFromSelection) &&
+                      idCurrentCell.col >= GetFixedColumnCount(m_bExcludeFreezedColsFromSelection)) ||
+                      m_MouseMode==MOUSE_SELECT_COL ||
+                      m_MouseMode==MOUSE_SELECT_ROW)
+                    {
+                        SetFocusCell(idCurrentCell);
+                    }
+                }
+                break;
+            }
+
+        case MOUSE_SIZING_COL:
+            {
+                CDC* pDC = GetDC();
+                if (!pDC)
+                    break;
+
+                CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
+                    m_LastMousePoint.x + 2, rect.bottom);
+                pDC->InvertRect(&oldInvertedRect);
+                CRect newInvertedRect(point.x, rect.top, 
+                    point.x + 2, rect.bottom);
+                pDC->InvertRect(&newInvertedRect);
+                ReleaseDC(pDC);
+            }
+            break;
+            
+        case MOUSE_SIZING_ROW:        
+            {
+                CDC* pDC = GetDC();
+                if (!pDC)
+                    break;
+                
+                CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
+                    rect.right, m_LastMousePoint.y + 2);
+                pDC->InvertRect(&oldInvertedRect);
+                CRect newInvertedRect(rect.left, point.y, 
+                    rect.right, point.y + 2);
+                pDC->InvertRect(&newInvertedRect);
+                ReleaseDC(pDC);
+            }
+            break;
+            
+#ifndef GRIDCONTROL_NO_DRAGDROP
+        case MOUSE_PREPARE_EDIT:
+        case MOUSE_PREPARE_DRAG:
+            m_MouseMode = MOUSE_PREPARE_DRAG;
+            OnBeginDrag();    
+            break;
+#endif
+        }    
+    }
+
+    m_LastMousePoint = point;
+}
+
+// Returns the point inside the cell that was clicked (coords relative to cell top left)
+CPoint CGridCtrl::GetPointClicked(int nRow, int nCol, const CPoint& point)
+{
+    CPoint PointCellOrigin;
+    if( !GetCellOrigin( nRow, nCol, &PointCellOrigin)  )
+        return CPoint( 0, 0);
+
+    CPoint PointClickedCellRelative( point);
+    PointClickedCellRelative -= PointCellOrigin;
+    return PointClickedCellRelative;
+}
+
+void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
+{
+    TRACE0("CGridCtrl::OnLButtonDblClk\n");
+
+	// LUC
+	CCellID cellOriginal;
+    CCellID cell = GetCellFromPt(point, TRUE, cellOriginal);
+    if( !IsValid( cell) )
+    {
+        //ASSERT(FALSE);
+        return;
+    }
+
+#ifdef _WIN32_WCE
+    if (MouseOverColumnResizeArea(point))
+#else
+    if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
+#endif
+    {
+        CPoint start;
+        if (!GetCellOrigin(0, cell.col, &start))
+            return;
+
+        if (point.x - start.x < m_nResizeCaptureRange)     // Clicked right of border
+            cell.col--;
+
+        //  ignore columns that are hidden and look left towards first visible column
+        BOOL bFoundVisible = FALSE;
+        while( cell.col >= 0)
+        {
+            if( GetColumnWidth( cell.col) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            cell.col--;
+        }
+        if( !bFoundVisible)
+            return;
+
+        AutoSizeColumn(cell.col, GetAutoSizeStyle());
+        Invalidate();
+    }
+#ifdef _WIN32_WCE
+    else if (MouseOverRowResizeArea(point))
+#else
+    else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
+#endif
+    {
+        CPoint start;
+        if (!GetCellOrigin(0, cell.col, &start))
+            return;
+
+        if (point.y - start.y < m_nResizeCaptureRange)     // Clicked below border
+            cell.row--;
+
+        //  ignore rows that are hidden and look up towards first visible row
+        BOOL bFoundVisible = FALSE;
+        while( cell.row >= 0)
+        {
+            if( GetRowHeight( cell.row) > 0)
+            {
+                bFoundVisible = TRUE;
+                break;
+            }
+            cell.row--;
+        }
+        if( !bFoundVisible)
+            return;
+
+        AutoSizeRow(cell.row);
+        Invalidate();
+    }
+    else if (m_MouseMode == MOUSE_NOTHING)
+    {
+        CPoint pointClickedRel;
+        pointClickedRel = GetPointClicked( cell.row, cell.col, point);
+
+        CGridCellBase* pCell = NULL;
+        if (IsValid(cell))
+            pCell = GetCell(cell.row, cell.col);
+
+        // Clicked in the text area? Only then will cell selection work
+        BOOL bInTextArea = FALSE;
+        if (pCell)
+        {
+			// LUC
+            CRect rectCell;
+            if (GetCellRect(cellOriginal.row, cellOriginal.col, rectCell) && pCell->GetTextRect(rectCell))
+                bInTextArea = rectCell.PtInRect(point);
+        }
+
+        if (cell.row >= m_nFixedRows && IsValid(m_LeftClickDownCell) && 
+            cell.col >= m_nFixedCols && bInTextArea)
+        {
+            OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
+        }
+        else if (m_bListMode)
+        {
+            if (!IsValid(cell))
+                return;
+            if (cell.row >= m_nFixedRows && cell.col >= m_nFixedCols && bInTextArea)
+                OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
+        }
+
+        if (IsValid(cell))
+        {
+            CGridCellBase* pCell = GetCell(cell.row, cell.col);
+            if (pCell)
+                pCell->OnDblClick(pointClickedRel);
+            SendMessageToParent(cell.row, cell.col, NM_DBLCLK);
+        }
+    }
+
+    CWnd::OnLButtonDblClk(nFlags, point);
+}
+
+void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
+{
+#ifdef GRIDCONTROL_USE_TITLETIPS
+    // EFW - Bug Fix
+    m_TitleTip.Hide();  // hide any titletips
+#endif
+
+    // TRACE0("CGridCtrl::OnLButtonDown\n");
+    // CWnd::OnLButtonDown(nFlags, point);
+
+    SetFocus();
+	m_CurCol = -1;
+    m_bLMouseButtonDown   = TRUE;
+    m_LeftClickDownPoint = point;
+	// LUC
+	CCellID cellOriginal;
+    m_LeftClickDownCell  = GetCellFromPt(point, TRUE, cellOriginal);
+    if (!IsValid(m_LeftClickDownCell))
+        return;
+	m_CurRow = m_LeftClickDownCell.row;
+
+    // If the SHIFT key is not down, then the start of the selection area should be the 
+    // cell just clicked. Otherwise, keep the previous selection-start-cell so the user
+    // can add to their previous cell selections in an intuitive way. If no selection-
+    // start-cell has been specified, then set it's value here and now.
+    if ((nFlags & MK_SHIFT) != MK_SHIFT)
+        m_SelectionStartCell = m_LeftClickDownCell;
+    else
+    {
+        if (!IsValid(m_SelectionStartCell))
+            m_SelectionStartCell = m_idCurrentCell;
+    }
+
+    EndEditing();
+
+    // tell the cell about it 
+    CGridCellBase* pCell = GetCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+    if (pCell)
+        pCell->OnClickDown(GetPointClicked( m_LeftClickDownCell.row, m_LeftClickDownCell.col, point));
+
+    // Clicked in the text area? Only then will cell selection work
+    BOOL bInTextArea = FALSE;
+    if (pCell)
+    {
+        CRect rectCell;
+		// LUC
+        //if (GetCellRect(m_LeftClickDownCell.row, m_LeftClickDownCell.col, rectCell) &&
+        //    pCell->GetTextRect(rectCell))
+		if (GetCellRect(cellOriginal.row, cellOriginal.col, rectCell) &&
+            pCell->GetTextRect(rectCell))        
+        {
+            bInTextArea = rectCell.PtInRect(point);
+        }
+    }
+
+    // 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 && 
+        !(nFlags & MK_CONTROL) && bInTextArea &&
+        IsCellEditable(m_LeftClickDownCell))
+    {
+        m_MouseMode = MOUSE_PREPARE_EDIT;
+        return;
+    }
+    // If the user clicks on a selected cell, then prepare to drag it.
+    // (If the user moves the mouse, then dragging occurs)
+    else if (IsCellSelected(m_LeftClickDownCell))
+    {
+        SetFocusCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+
+        // If control is pressed then unselect the cell or row (depending on the list mode)
+        if (nFlags & MK_CONTROL)
+        {
+            SetFocusCell(m_LeftClickDownCell);
+            if (GetListMode())
+                SelectRows(m_LeftClickDownCell, TRUE, FALSE);
+            else
+                SelectCells(m_LeftClickDownCell, TRUE, FALSE);
+            return;
+        }
+#ifndef GRIDCONTROL_NO_DRAGDROP
+        else if (m_bAllowDragAndDrop)
+            m_MouseMode = MOUSE_PREPARE_DRAG;
+#endif
+    }
+    else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
+             m_MouseMode != MOUSE_OVER_ROW_DIVIDE)        
+    {
+		if (m_LeftClickDownCell.row >= GetFixedRowCount() && 
+			m_LeftClickDownCell.col >= GetFixedColumnCount())
+		{
+            SetFocusCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
+		}
+		else
+			SetFocusCell(-1, -1);
+
+		//Don't set focus on any cell if the user clicked on a fixed cell - David Pritchard
+        //if (GetRowCount() > GetFixedRowCount() && 
+        //    GetColumnCount() > GetFixedColumnCount())
+        //    SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
+        //                 max(m_LeftClickDownCell.col, m_nFixedCols));
+    }
+    
+    SetCapture();
+    
+    if (m_MouseMode == MOUSE_NOTHING)
+    {
+        if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
+        {
+            if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
+            {
+#ifndef _WIN32_WCE_NO_CURSOR
+                SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
+#endif
+                m_MouseMode = MOUSE_OVER_COL_DIVIDE;
+            }
+        }
+        else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
+        {
+            if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
+            {
+#ifndef _WIN32_WCE_NO_CURSOR
+                SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
+#endif
+                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;
+
+        // Kludge for if we are over the last column...
+        if (GetColumnWidth(GetColumnCount()-1) < m_nResizeCaptureRange)
+        {
+            CRect VisRect;
+            GetVisibleNonFixedCellRange(VisRect);
+            if (abs(point.x - VisRect.right) < m_nResizeCaptureRange)
+                m_LeftClickDownCell.col = GetColumnCount()-1;
+        }
+
+        CPoint start;
+        if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start))
+            return;
+
+        if( !m_bHiddenColUnhide)
+        {
+            //  ignore columns that are hidden and look left towards first visible column
+            BOOL bLookForVisible = TRUE;
+            BOOL bIsCellRightBorder = point.x - start.x >= m_nResizeCaptureRange;
+
+            if( bIsCellRightBorder
+                && m_LeftClickDownCell.col + 1 >= GetColumnCount() )
+            {
+                // clicked on last column's right border
+
+                // if last column is visible, don't do anything
+                if( m_LeftClickDownCell.col >= 0)
+                    bLookForVisible = FALSE;
+            }
+
+            if( bLookForVisible)
+            {
+                // clicked on column divider other than last right border
+                BOOL bFoundVisible = FALSE;
+                int iOffset = 1;
+
+                if( bIsCellRightBorder)
+                    iOffset = 0;
+
+                while( m_LeftClickDownCell.col - iOffset >= 0)
+                {
+                    if( GetColumnWidth( m_LeftClickDownCell.col - iOffset) > 0)
+                    {
+                        bFoundVisible = TRUE;
+                        break;
+                    }
+                    m_LeftClickDownCell.col--;
+                }
+                if( !bFoundVisible)
+                    return;
+            }
+        }
+
+
+        CRect rect;
+        GetClientRect(rect);
+        CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
+
+        CDC* pDC = GetDC();
+        if (pDC)
+        {
+            pDC->InvertRect(&invertedRect);
+            ReleaseDC(pDC);
+        }
+
+        // If we clicked to the right of the colimn divide, then reset the click-down cell
+        // as the cell to the left of the column divide - UNLESS we clicked on the last column
+        // and the last column is teensy (kludge fix)
+        if (point.x - start.x < m_nResizeCaptureRange)
+        {
+            if (m_LeftClickDownCell.col < GetColumnCount()-1 || 
+                GetColumnWidth(GetColumnCount()-1) >= m_nResizeCaptureRange)
+            {
+                if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start))
+                    return;
+            }
+        }
+
+		// Allow a cell resize width no greater than that which can be viewed within
+		// the grid itself
+		int nMaxCellWidth = rect.Width()-GetFixedColumnWidth();
+        rect.left  = start.x + 1;
+		rect.right = rect.left + nMaxCellWidth;
+
+        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;
+
+        // Kludge for if we are over the last column...
+        if (GetRowHeight(GetRowCount()-1) < m_nResizeCaptureRange)
+        {
+            CRect VisRect;
+            GetVisibleNonFixedCellRange(VisRect);
+            if (abs(point.y - VisRect.bottom) < m_nResizeCaptureRange)
+                m_LeftClickDownCell.row = GetRowCount()-1;
+        }
+
+        CPoint start;
+        if (!GetCellOrigin(m_LeftClickDownCell, &start))
+            return;
+
+        if( !m_bHiddenRowUnhide)
+        {
+            //  ignore rows that are hidden and look up towards first visible row
+            BOOL bLookForVisible = TRUE;
+            BOOL bIsCellBottomBorder = point.y - start.y >= m_nResizeCaptureRange;
+
+            if( bIsCellBottomBorder
+                && m_LeftClickDownCell.row + 1 >= GetRowCount() )
+            {
+                // clicked on last row's bottom border
+
+                // if last row is visible, don't do anything
+                if( m_LeftClickDownCell.row >= 0)
+                    bLookForVisible = FALSE;
+            }
+
+            if( bLookForVisible)
+            {
+                // clicked on row divider other than last bottom border
+                BOOL bFoundVisible = FALSE;
+                int iOffset = 1;
+
+                if( bIsCellBottomBorder)
+                    iOffset = 0;
+
+                while( m_LeftClickDownCell.row - iOffset >= 0)
+                {
+                    if( GetRowHeight( m_LeftClickDownCell.row - iOffset) > 0)
+                    {
+                        bFoundVisible = TRUE;
+                        break;
+                    }
+                    m_LeftClickDownCell.row--;
+                }
+                if( !bFoundVisible)
+                    return;
+            }
+        }
+
+        CRect rect;
+        GetClientRect(rect);
+        CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
+
+        CDC* pDC = GetDC();
+        if (pDC)
+        {
+            pDC->InvertRect(&invertedRect);
+            ReleaseDC(pDC);
+        }
+
+        // If we clicked below the row divide, then reset the click-down cell
+        // as the cell above the row divide - UNLESS we clicked on the last row
+        // and the last row is teensy (kludge fix)
+        if (point.y - start.y < m_nResizeCaptureRange)            // clicked below border
+        {
+            if (m_LeftClickDownCell.row < GetRowCount()-1 || 
+                GetRowHeight(GetRowCount()-1) >= m_nResizeCaptureRange)
+            {
+                if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start))
+                    return;
+            }
+        }
+
+		int nMaxCellHeight = rect.Height()-GetFixedRowHeight();
+        rect.top = start.y + 1;
+		rect.bottom = rect.top + nMaxCellHeight;
+
+        ClientToScreen(rect);
+
+#ifndef _WIN32_WCE_NO_CURSOR
+        ClipCursor(rect);
+#endif
+    }
+    else
+#ifndef GRIDCONTROL_NO_DRAGDROP
+    if (m_MouseMode != MOUSE_PREPARE_DRAG) // not sizing or editing -- selecting
+#endif
+    {
+	    SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+
+        // 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();
+        if (nFlags & MK_CONTROL)
+        {
+            for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
+            {
+                DWORD key;
+                CCellID cell;
+                m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
+                m_PrevSelectedCellMap.SetAt(key, cell);
+            }
+        }
+        
+        if (m_LeftClickDownCell.row < GetFixedRowCount())
+		{
+            OnFixedRowClick(m_LeftClickDownCell);
+            if(m_AllowReorderColumn && m_LeftClickDownCell.col >=  GetFixedColumnCount())
+			{
+				ResetSelectedRange(); // TODO : This is not the better solution, as we do not see why clicking in column header should reset selection
+											//but the state of selection is instable after drag (at least until someone debugs it), so better clear it allways.
+				m_MouseMode = MOUSE_PREPARE_DRAG;
+				m_CurCol = m_LeftClickDownCell.col;
+			}
+		}
+        else if (m_LeftClickDownCell.col < GetFixedColumnCount())
+            OnFixedColumnClick(m_LeftClickDownCell);
+        else
+        {
+            m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
+            OnSelecting(m_LeftClickDownCell);
+
+            m_nTimerID = SetTimer(WM_LBUTTONDOWN, m_nTimerInterval, 0);
+        }
+    }   
+    m_LastMousePoint = point;
+}
+
+void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
+{
+    // TRACE0("CGridCtrl::OnLButtonUp\n");
+
+    CWnd::OnLButtonUp(nFlags, point);
+
+    m_bLMouseButtonDown = FALSE;
+
+#ifndef _WIN32_WCE_NO_CURSOR
+    ClipCursor(NULL);
+#endif
+
+    if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
+    {
+        ReleaseCapture();
+        KillTimer(m_nTimerID);
+        m_nTimerID = 0;
+
+		// LUC
+		m_bExcludeFreezedRowsFromSelection = FALSE;
+		m_bExcludeFreezedColsFromSelection = FALSE;
+    }
+
+    CPoint pointClickedRel;
+    pointClickedRel = GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point);
+
+    // 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, pointClickedRel, 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) 
+    {
+        CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
+        if (pCell)
+            pCell->OnClick( GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point) );
+        SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
+	    SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
+        ResetSelectedRange();
+	    SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+    }
+#endif
+    else if (m_MouseMode == MOUSE_SIZING_COL)
+    {
+        CRect rect;
+        GetClientRect(rect);
+        CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
+        
+        CDC* pDC = GetDC();
+        if (pDC)
+        {
+            pDC->InvertRect(&invertedRect);
+            ReleaseDC(pDC);
+        }
+        
+        if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
+        {   
+            CPoint start;
+            if (!GetCellOrigin(m_LeftClickDownCell, &start))
+                return;
+
+            int nColumnWidth = __max(point.x - start.x, m_bAllowColHide? 0 : 1);
+
+            SetColumnWidth(m_LeftClickDownCell.col, nColumnWidth);
+            ResetScrollBars();
+            Invalidate();
+        }
+    }
+    else if (m_MouseMode == MOUSE_SIZING_ROW)
+    {
+        CRect rect;
+        GetClientRect(rect);
+        CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
+
+        CDC* pDC = GetDC();
+        if (pDC)
+        {
+            pDC->InvertRect(&invertedRect);
+            ReleaseDC(pDC);
+        }
+        
+        if (m_LeftClickDownPoint != point  && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
+        {
+            CPoint start;
+            if (!GetCellOrigin(m_LeftClickDownCell, &start))
+                return;
+            
+            int nRowHeight = __max(point.y - start.y, m_bAllowRowHide? 0 : 1);
+
+            SetRowHeight(m_LeftClickDownCell.row, nRowHeight);
+            ResetScrollBars();
+            Invalidate();
+        }
+    }
+    else
+    {
+	    SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
+
+        CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
+        if (pCell)
+            pCell->OnClick( GetPointClicked( m_idCurrentCell.row, m_idCurrentCell.col, point) );
+        SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
+    }
+    
+    m_MouseMode = MOUSE_NOTHING;
+    
+#ifndef _WIN32_WCE_NO_CURSOR
+    SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
+#endif
+    
+    if (!IsValid(m_LeftClickDownCell))
+        return;
+    
+    CWnd *pOwner = GetOwner();
+    if (pOwner && IsWindow(pOwner->m_hWnd))
+        pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
+        (LPARAM) GetSafeHwnd());
+}
+
+#ifndef _WIN32_WCE
+void CGridCtrl::OnRButtonDown(UINT nFlags, CPoint point)
+{
+    CWnd::OnRButtonDown(nFlags, point);
+	m_bRMouseButtonDown = TRUE;
+
+#ifdef GRIDCONTROL_USE_TITLETIPS
+	TRACE0("Hiding TitleTip\n");
+    m_TitleTip.Hide();  // hide any titletips
+#endif
+}
+
+// EFW - Added to forward right click to parent so that a context
+// menu can be shown without deriving a new grid class.
+void CGridCtrl::OnRButtonUp(UINT nFlags, CPoint point)
+{
+    CWnd::OnRButtonUp(nFlags, point);
+
+	m_bRMouseButtonDown = FALSE;
+
+    CCellID FocusCell;
+    FocusCell = GetCellFromPt(point);
+
+    EndEditing();        // Auto-destroy any InPlaceEdit's
+
+    // If not a valid cell, pass -1 for row and column
+    if(!IsValid(FocusCell))
+        SendMessageToParent(-1, -1, NM_RCLICK);
+    else
+    {
+        SetFocusCell(-1,-1);
+        SetFocusCell(__max(FocusCell.row, m_nFixedRows),
+            __max(FocusCell.col, m_nFixedCols));
+
+        // tell the cell about it
+        CGridCellBase* pCell = GetCell(FocusCell.row, FocusCell.col);
+        if (pCell)
+            pCell->OnRClick( GetPointClicked( FocusCell.row, FocusCell.col, point) );
+
+        SendMessageToParent(FocusCell.row, FocusCell.col, NM_RCLICK);		
+    }
+}
+#endif
+
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl printing
+
+// EFW - New print margin support functions
+void CGridCtrl::SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
+    int nLeftMargin, int nRightMargin, int nTopMargin,
+    int nBottomMargin, int nGap)
+{
+    // If any parameter is -1, keep the existing setting
+    if(nHeaderHeight > -1)
+        m_nHeaderHeight = nHeaderHeight;
+    if(nFooterHeight > -1)
+        m_nFooterHeight = nFooterHeight;
+    if(nLeftMargin > -1)
+        m_nLeftMargin = nLeftMargin;
+    if(nRightMargin > -1)
+        m_nRightMargin = nRightMargin;
+    if(nTopMargin > -1)
+        m_nTopMargin = nTopMargin;
+    if(nBottomMargin > -1)
+        m_nBottomMargin = nBottomMargin;
+    if(nGap > -1)
+        m_nGap = nGap;
+}
+
+void CGridCtrl::GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
+    int &nLeftMargin, int &nRightMargin, int &nTopMargin,
+    int &nBottomMargin, int &nGap)
+{
+    nHeaderHeight = m_nHeaderHeight;
+    nFooterHeight = m_nFooterHeight;
+    nLeftMargin = m_nLeftMargin;
+    nRightMargin = m_nRightMargin;
+    nTopMargin = m_nTopMargin;
+    nBottomMargin = m_nBottomMargin;
+    nGap = m_nGap;
+}
+
+void CGridCtrl::Print(CPrintDialog* pPrntDialog /*=NULL*/)
+{
+    CDC dc;
+
+    if (pPrntDialog == NULL)
+    {
+        CPrintDialog printDlg(FALSE);
+        if (printDlg.DoModal() != IDOK)             // Get printer settings from user
+            return;
+
+        dc.Attach(printDlg.GetPrinterDC());         // attach a printer DC
+    }
+    else
+        dc.Attach(pPrntDialog->GetPrinterDC());     // attach a printer DC
+        
+    dc.m_bPrinting = TRUE;
+
+    CString strTitle;
+    strTitle.LoadString(AFX_IDS_APP_TITLE);
+
+    if( strTitle.IsEmpty() )
+    {
+        CWnd *pParentWnd = GetParent();
+        while (pParentWnd)
+        {
+            pParentWnd->GetWindowText(strTitle);
+            if (strTitle.GetLength())  // can happen if it is a CView, CChildFrm has the title
+                break;
+            pParentWnd = pParentWnd->GetParent();
+        }
+    }
+
+    DOCINFO di;                                 // Initialise print doc details
+    memset(&di, 0, sizeof (DOCINFO));
+    di.cbSize = sizeof (DOCINFO);
+    di.lpszDocName = strTitle;
+
+    BOOL bPrintingOK = dc.StartDoc(&di);        // Begin a new print job
+
+    CPrintInfo Info;
+    Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
+
+    OnBeginPrinting(&dc, &Info);                // Initialise printing
+    for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
+    {
+        dc.StartPage();                         // begin new page
+        Info.m_nCurPage = page;
+        OnPrint(&dc, &Info);                    // Print page
+        bPrintingOK = (dc.EndPage() > 0);       // end page
+    }
+    OnEndPrinting(&dc, &Info);                  // Clean up after printing
+
+    if (bPrintingOK)
+        dc.EndDoc();                            // end a print job
+    else
+        dc.AbortDoc();                          // abort job.
+
+    dc.Detach();                                // detach the printer DC
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl printing overridables - for Doc/View print/print preview framework
+
+// EFW - Various changes in the next few functions to support the
+// new print margins and a few other adjustments.
+void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
+{
+    // OnBeginPrinting() is called after the user has committed to
+    // printing by OK'ing the Print dialog, and after the framework
+    // has created a CDC object for the printer or the preview view.
+
+    // This is the right opportunity to set up the page range.
+    // Given the CDC object, we can determine how many rows will
+    // fit on a page, so we can in turn determine how many printed
+    // pages represent the entire document.
+
+//    ASSERT(pDC && pInfo);
+    if (!pDC || !pInfo) return;
+
+    // Get a DC for the current window (will be a screen DC for print previewing)
+    CDC *pCurrentDC = GetDC();        // will have dimensions of the client area
+    if (!pCurrentDC) return;
+
+    CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
+    CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
+
+    // Create the printer font
+    int nFontSize = -10;
+    CString strFontName = _T("Arial");
+    m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,
+                             OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
+                             DEFAULT_PITCH | FF_DONTCARE, strFontName);
+
+    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+    // Get the average character width (in GridCtrl units) and hence the margins
+    m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"),52);
+    m_CharSize.cx /= 52;
+    int nMargins = (m_nLeftMargin+m_nRightMargin)*m_CharSize.cx;
+
+    // Get the page sizes (physical and logical)
+    m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
+
+    if( m_bWysiwygPrinting)
+    {
+        m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
+        m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
+    }
+    else
+    {
+        m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
+
+        m_LogicalPageSize.cx = GetVirtualWidth()+nMargins;
+#ifdef _WIN32_WCE
+        m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
+#else
+        m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
+#endif
+    }
+
+    m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
+                       - (m_nHeaderHeight+m_nFooterHeight + 2*m_nGap)*m_CharSize.cy;
+
+    // Get the number of pages. Assumes no row is bigger than the page size.
+    int nTotalRowHeight = 0;
+    m_nNumPages = 1;
+    for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
+    {
+        nTotalRowHeight += GetRowHeight(row);
+        if (nTotalRowHeight > m_nPageHeight) {
+            m_nNumPages++;
+            nTotalRowHeight = GetRowHeight(row);
+        }
+    }
+
+    // now, figure out how many additional pages must print out if rows ARE bigger
+    //  than page size
+    int iColumnOffset = 0;
+    int i1;
+    for( i1=0; i1 < GetFixedColumnCount(); i1++)
+    {
+        iColumnOffset += GetColumnWidth( i1);
+    }
+    m_nPageWidth = m_LogicalPageSize.cx - iColumnOffset
+                    - nMargins;
+    m_nPageMultiplier = 1;
+
+    if( m_bWysiwygPrinting)
+    {
+        int iTotalRowWidth = 0;
+        for( i1 = GetFixedColumnCount(); i1 < GetColumnCount(); i1++)
+        {
+            iTotalRowWidth += GetColumnWidth( i1);
+            if( iTotalRowWidth > m_nPageWidth)
+            {
+                m_nPageMultiplier++;
+                iTotalRowWidth = GetColumnWidth( i1);
+            }
+        }
+        m_nNumPages *= m_nPageMultiplier;
+    }
+
+    // Set up the print info
+    pInfo->SetMaxPage(m_nNumPages);
+    pInfo->m_nCurPage = 1;                        // start printing at page# 1
+
+    ReleaseDC(pCurrentDC);
+    pDC->SelectObject(pOldFont);
+}
+
+void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
+{
+    if (!pDC || !pInfo)
+        return;
+
+    //CRect rcPage(pInfo->m_rectDraw);
+    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+    // Set the page map mode to use GridCtrl units, and setup margin
+    pDC->SetMapMode(MM_ANISOTROPIC);
+    pDC->SetWindowExt(m_LogicalPageSize);
+    pDC->SetViewportExt(m_PaperSize);
+    pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx, 0);
+
+    // Header
+    pInfo->m_rectDraw.top    = 0;
+    pInfo->m_rectDraw.left   = 0;
+    pInfo->m_rectDraw.right  = m_LogicalPageSize.cx - (m_nLeftMargin + m_nRightMargin) * m_CharSize.cx;
+    pInfo->m_rectDraw.bottom = m_nHeaderHeight * m_CharSize.cy;
+    PrintHeader(pDC, pInfo);
+    pDC->OffsetWindowOrg(0, -m_nHeaderHeight * m_CharSize.cy);
+
+    // Gap between header and column headings
+    pDC->OffsetWindowOrg(0, -m_nGap * m_CharSize.cy);
+
+    pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
+
+    // We need to find out which row to start printing for this page.
+    int nTotalRowHeight = 0;
+    UINT nNumPages = 1;
+    m_nCurrPrintRow = GetFixedRowCount();
+
+
+    // Not only the row, but we need to figure out column, too
+
+    // Can print 4 pages, where page 1 and 2 represent the same rows but
+    // with different WIDE columns.
+    //
+    // .......
+    // .1 .2 .  If representing page 3  -->    iPageIfIgnoredWideCols = 2
+    // .......                                 iWideColPageOffset = 0
+    // .3 .4 .  If representing page 2  -->    iPageIfIgnoredWideCols = 1
+    // .......                                 iWideColPageOffset = 1
+
+    int iPageIfIgnoredWideCols = pInfo->m_nCurPage / m_nPageMultiplier;
+    int iWideColPageOffset = pInfo->m_nCurPage - ( iPageIfIgnoredWideCols * m_nPageMultiplier);
+    if( iWideColPageOffset > 0)
+        iPageIfIgnoredWideCols++;
+
+    if( iWideColPageOffset == 0)
+        iWideColPageOffset = m_nPageMultiplier;
+    iWideColPageOffset--;
+
+    // calculate current print row based on iPageIfIgnoredWideCols
+    while(  m_nCurrPrintRow < GetRowCount()
+            && (int)nNumPages < iPageIfIgnoredWideCols)
+    {
+        nTotalRowHeight += GetRowHeight(m_nCurrPrintRow);
+        if (nTotalRowHeight > m_nPageHeight) {
+            nNumPages++;
+            if ((int)nNumPages == iPageIfIgnoredWideCols) break;
+            nTotalRowHeight = GetRowHeight(m_nCurrPrintRow);
+        }
+        m_nCurrPrintRow++;
+    }
+
+    m_nPrintColumn = GetFixedColumnCount();
+    int iTotalRowWidth = 0;
+    int i1, i2;
+
+    // now, calculate which print column to start displaying
+    for( i1 = 0; i1 < iWideColPageOffset; i1++)
+    {
+        for( i2 = m_nPrintColumn; i2 < GetColumnCount(); i2++)
+        {
+            iTotalRowWidth += GetColumnWidth( i2);
+            if( iTotalRowWidth > m_nPageWidth)
+            {
+                m_nPrintColumn = i2;
+                iTotalRowWidth = 0;
+                break;
+            }
+        }
+    }
+
+
+    PrintRowButtons( pDC, pInfo);   // print row buttons on each page
+    int iColumnOffset = 0;
+    for( i1=0; i1 < GetFixedColumnCount(); i1++)
+    {
+        iColumnOffset += GetColumnWidth( i1);
+    }
+
+    // Print the column headings
+    pInfo->m_rectDraw.bottom = GetFixedRowHeight();
+
+    if( m_nPrintColumn == GetFixedColumnCount())
+    {
+        // have the column headings fcn draw the upper left fixed cells
+        //  for the very first columns, only
+        pDC->OffsetWindowOrg( 0, +GetFixedRowHeight());
+
+        m_nPageWidth += iColumnOffset;
+        m_nPrintColumn = 0;
+        PrintColumnHeadings(pDC, pInfo);
+        m_nPageWidth -= iColumnOffset;
+        m_nPrintColumn = GetFixedColumnCount();
+
+        pDC->OffsetWindowOrg( -iColumnOffset, -GetFixedRowHeight());
+    }
+    else
+    {
+        // changed all of this here to match above almost exactly same
+        pDC->OffsetWindowOrg( 0, +GetFixedRowHeight());
+
+        m_nPageWidth += iColumnOffset;
+
+        // print from column 0 ... last column that fits on the current page
+        PrintColumnHeadings(pDC, pInfo);
+        
+        m_nPageWidth -= iColumnOffset;
+ 
+        pDC->OffsetWindowOrg( -iColumnOffset, -GetFixedRowHeight());
+    }
+
+
+    if (m_nCurrPrintRow >= GetRowCount()) return;
+
+    // Draw as many rows as will fit on the printed page.
+    // Clip the printed page so that there is no partially shown
+    // row at the bottom of the page (the same row which will be fully
+    // shown at the top of the next page).
+
+    BOOL bFirstPrintedRow = TRUE;
+    CRect rect;
+    rect.bottom = -1;
+    while (m_nCurrPrintRow < GetRowCount())
+    {
+        rect.top = rect.bottom+1;
+        rect.bottom = rect.top + GetRowHeight(m_nCurrPrintRow) - 1;
+
+        if (rect.bottom > m_nPageHeight) break;            // Gone past end of page
+
+        rect.right = -1;
+
+        // modified to allow printing of wide grids on multiple pages
+        for (int col = m_nPrintColumn; col < GetColumnCount(); col++)
+        {
+            rect.left = rect.right+1;
+            rect.right =    rect.left
+                            + GetColumnWidth( col)
+                            - 1;
+
+            if( rect.right > m_nPageWidth)
+                break;
+
+            CGridCellBase* pCell = GetCell(m_nCurrPrintRow, col);
+            if (pCell)
+                pCell->PrintCell(pDC, m_nCurrPrintRow, col, rect);
+
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+            {
+                int Overlap = (col == 0)? 0:1;
+                pDC->MoveTo(rect.left-Overlap, rect.bottom);
+                pDC->LineTo(rect.right, rect.bottom);
+                if (m_nCurrPrintRow == 0) {
+                    pDC->MoveTo(rect.left-Overlap, rect.top);
+                    pDC->LineTo(rect.right, rect.top);
+                }
+            }
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+            {
+                int Overlap = (bFirstPrintedRow)? 0:1;
+                pDC->MoveTo(rect.right, rect.top-Overlap);
+                pDC->LineTo(rect.right, rect.bottom);
+                if (col == 0) {
+                    pDC->MoveTo(rect.left, rect.top-Overlap);
+                    pDC->LineTo(rect.left, rect.bottom);
+                }
+            }
+
+        }
+        m_nCurrPrintRow++;
+        bFirstPrintedRow = FALSE;
+    }
+
+
+    // Footer
+    pInfo->m_rectDraw.bottom = m_nFooterHeight * m_CharSize.cy;
+    pDC->SetWindowOrg( -m_nLeftMargin * m_CharSize.cx,
+        -m_LogicalPageSize.cy + m_nFooterHeight * m_CharSize.cy);
+    PrintFooter(pDC, pInfo);
+
+    // SetWindowOrg back for next page
+    pDC->SetWindowOrg(0,0);
+
+    pDC->SelectObject(pOldFont);
+}
+
+
+// added by M.Fletcher 12/17/00
+void CGridCtrl::PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
+                                   CDC *pDC, BOOL& bFirst)
+{
+   // print all cells from nStartColumn to nStopColumn on row
+   for (int col =nStartColumn; col < nStopColumn; col++)
+   {
+      rect.left = rect.right+1;
+      rect.right =    rect.left + GetColumnWidth( col) - 1;
+
+      if( rect.right > m_nPageWidth)
+         break;
+      
+      CGridCellBase* pCell = GetCell(row, col);
+      if (pCell)
+         pCell->PrintCell(pDC, row, col, rect);
+      
+      if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+      {
+         int Overlap = (col == 0)? 0:1;
+         
+         pDC->MoveTo(rect.left-Overlap, rect.bottom);
+         pDC->LineTo(rect.right, rect.bottom);
+         
+         if (row == 0)
+         {
+            pDC->MoveTo(rect.left-Overlap, rect.top);
+            pDC->LineTo(rect.right, rect.top);
+          }
+      }
+
+      if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+      {
+         int Overlap = (row == 0)? 0:1;
+
+         pDC->MoveTo(rect.right, rect.top-Overlap);
+         pDC->LineTo(rect.right, rect.bottom);
+         
+         if( bFirst)
+         {
+            pDC->MoveTo(rect.left-1, rect.top-Overlap);
+            pDC->LineTo(rect.left-1, rect.bottom);
+            bFirst = FALSE;
+          }
+
+       }
+
+   } // end of column cells loop
+
+
+} // end of CGridCtrl::PrintFixedRowCells
+
+void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
+{
+    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+    CRect rect;
+    rect.bottom = -1;
+
+    BOOL bFirst = TRUE;
+    BOOL bOriginal;
+    
+
+    // modified to allow column hdr printing of multi-page wide grids
+    for (int row = 0; row < GetFixedRowCount(); row++)
+    {
+        rect.top = rect.bottom+1;
+        rect.bottom = rect.top + GetRowHeight(row) - 1;
+
+        rect.right = -1;
+ 
+        // if printColumn > fixedcolumncount we are on page 2 or more
+        // lets printout those fixed cell headings again the 1 or more that would be missed
+        // added by M.Fletcher 12/17/00
+        if(m_nPrintColumn>= GetFixedColumnCount())
+        {
+           bOriginal=bFirst;
+           // lets print the missing fixed cells on left first out to last fixed column
+           PrintFixedRowCells(0,GetFixedColumnCount(), row, rect, pDC, bFirst);
+           bFirst=bOriginal;
+        }
+
+        // now back to normal business print cells in heading after all fixed columns
+        PrintFixedRowCells(m_nPrintColumn, GetColumnCount(), row, rect, pDC, bFirst);
+        
+    } // end of Row Loop
+
+    pDC->SelectObject(pOldFont);
+} // end of CGridCtrl::PrintColumnHeadings
+
+
+
+/*****************************************************************************
+Prints line of row buttons on each page of the printout.  Assumes that
+the window origin is setup before calling
+
+*****************************************************************************/
+void CGridCtrl::PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/)
+{
+    CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
+
+    CRect rect;
+    rect.right = -1;
+
+    BOOL bFirst = TRUE;
+    for( int iCol = 0; iCol < GetFixedColumnCount(); iCol++)
+    {
+        rect.left = rect.right+1;
+        rect.right =    rect.left
+                        + GetColumnWidth( iCol)
+                        - 1;
+
+        rect.bottom = -1;
+        for( int iRow = m_nCurrPrintRow; iRow < GetRowCount(); iRow++)
+        {
+            rect.top = rect.bottom+1;
+            rect.bottom = rect.top + GetRowHeight( iRow) - 1;
+
+            if( rect.bottom > m_nPageHeight)
+                break;
+
+            CGridCellBase* pCell = GetCell(iRow, iCol);
+            if (pCell)
+                pCell->PrintCell(pDC, iRow, iCol, rect);
+
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
+            {
+                int Overlap = (iCol == 0)? 0:1;
+                pDC->MoveTo(rect.left-Overlap, rect.bottom);
+                pDC->LineTo(rect.right, rect.bottom);
+                if( bFirst) {
+                    pDC->MoveTo(rect.left-Overlap, rect.top-1);
+                    pDC->LineTo(rect.right, rect.top-1);
+                    bFirst = FALSE;
+                }
+            }
+            if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
+            {
+                int Overlap = (iRow == 0)? 0:1;
+                pDC->MoveTo(rect.right, rect.top-Overlap);
+                pDC->LineTo(rect.right, rect.bottom);
+                if (iCol == 0) {
+                    pDC->MoveTo(rect.left, rect.top-Overlap);
+                    pDC->LineTo(rect.left, rect.bottom);
+                }
+            }
+
+        }
+    }
+    pDC->SelectObject(pOldFont);
+}
+
+void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
+{
+    // print App title on top right margin
+    CString strRight;
+    strRight.LoadString(AFX_IDS_APP_TITLE);
+
+    // print parent window title in the centre (Gert Rijs)
+    CString strCenter;
+    CWnd *pParentWnd = GetParent();
+    while (pParentWnd)
+    {
+        pParentWnd->GetWindowText(strCenter);
+        if (strCenter.GetLength())  // can happen if it is a CView, CChildFrm has the title
+            break;
+        pParentWnd = pParentWnd->GetParent();
+    }
+
+    CFont   BoldFont;
+    LOGFONT lf;
+
+    //create bold font for header and footer
+    VERIFY(m_PrinterFont.GetLogFont(&lf));
+    lf.lfWeight = FW_BOLD;
+    VERIFY(BoldFont.CreateFontIndirect(&lf));
+
+    CFont *pNormalFont = pDC->SelectObject(&BoldFont);
+    int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
+
+    CRect   rc(pInfo->m_rectDraw);
+    if( !strCenter.IsEmpty() )
+        pDC->DrawText( strCenter, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+    if( !strRight.IsEmpty() )
+        pDC->DrawText( strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+
+    pDC->SetBkMode(nPrevBkMode);
+    pDC->SelectObject(pNormalFont);
+    BoldFont.DeleteObject();
+
+    // draw ruled-line across top
+    pDC->SelectStockObject(BLACK_PEN);
+    pDC->MoveTo(rc.left, rc.bottom);
+    pDC->LineTo(rc.right, rc.bottom);
+}
+
+//print footer with a line and date, and page number
+void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
+{
+    // page numbering on left
+    CString strLeft;
+    strLeft.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage() );
+
+    // date and time on the right
+    CString strRight;
+    COleDateTime t = COleDateTime::GetCurrentTime();
+    strRight = t.Format(_T("%c"));
+    
+    CRect rc(pInfo->m_rectDraw);
+
+    // draw ruled line on bottom
+    pDC->SelectStockObject(BLACK_PEN);
+    pDC->MoveTo(rc.left, rc.top);
+    pDC->LineTo(rc.right, rc.top);
+
+    CFont BoldFont;
+    LOGFONT lf;
+
+    //create bold font for header and footer
+    m_PrinterFont.GetLogFont(&lf);
+    lf.lfWeight = FW_BOLD;
+    BoldFont.CreateFontIndirect(&lf);
+
+    CFont *pNormalFont = pDC->SelectObject(&BoldFont);
+    int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
+
+    // EFW - Bug fix - Force text color to black.  It doesn't always
+    // get set to a printable color when it gets here.
+    pDC->SetTextColor(RGB(0, 0, 0));
+
+    if( !strLeft.IsEmpty() )
+        pDC->DrawText( strLeft, &rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+    if( !strRight.IsEmpty() )
+        pDC->DrawText( strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
+
+    pDC->SetBkMode(nPrevBkMode);
+    pDC->SelectObject(pNormalFont);
+    BoldFont.DeleteObject();
+}
+
+void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
+{
+    m_PrinterFont.DeleteObject();
+}
+
+#endif  // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+
+
+#ifndef _WIN32_WCE
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl persistance
+
+BOOL CGridCtrl::Save(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
+{
+    CStdioFile File;
+    CFileException ex;
+	CString strSeparator(chSeparator);
+
+    if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate| CFile::typeText, &ex))
+    {
+        ex.ReportError();
+        return FALSE;
+    }
+
+    TRY
+    {
+        int nNumColumns = GetColumnCount();
+        for (int i = 0; i < GetRowCount(); i++)
+        {
+            for (int j = 0; j < nNumColumns; j++)
+            {
+                File.WriteString(GetItemText(i,j));
+                File.WriteString((j==(nNumColumns-1))? _T("\n"): strSeparator);
+            }
+        }
+
+        File.Close();
+    }
+
+    CATCH (CFileException, e)
+    {
+        AfxMessageBox(_T("Unable to save grid list"));
+        return FALSE;
+    }
+    END_CATCH
+
+    return TRUE;
+}
+
+BOOL CGridCtrl::Load(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    TCHAR *token, *end;
+    TCHAR buffer[1024];
+    CStdioFile File;
+    CFileException ex;
+
+    if (!File.Open(filename, CFile::modeRead | CFile::typeText))
+    {
+        ex.ReportError();
+        return FALSE;
+    }
+
+    DeleteAllItems();
+
+    TRY
+    {
+        // Read Header off file
+        File.ReadString(buffer, 1024);
+
+        // Get first token
+        for (token=buffer, end=buffer;
+             *end && (*end != chSeparator) && (*end != _T('\n')); 
+             end++)
+            ;
+
+        if ((*end == _T('\0')) && (token == end))
+            token = NULL;
+
+        *end = _T('\0');
+
+        while (token)
+        {
+            InsertColumn(token);
+
+            // Get next token
+            for (token=++end; *end && (*end != chSeparator) && (*end != _T('\n'));
+               end++)
+                ;
+
+            if ((*end == _T('\0')) && (token == end))
+                token = NULL;
+
+            *end = _T('\0');
+        }
+
+        // Read in rest of data
+        int nItem = 1;
+        while (File.ReadString(buffer, 1024))
+        {
+            // Get first token
+            for (token=buffer, end=buffer;
+              *end && (*end != chSeparator) && (*end != _T('\n')); end++)
+                ;
+
+            if ((*end == _T('\0')) && (token == end))
+                token = NULL;
+
+            *end = _T('\0');
+
+            int nSubItem = 0;
+            while (token)
+            {
+                if (!nSubItem)
+                    InsertRow(token);
+                else
+                    SetItemText(nItem, nSubItem, token);
+
+                // Get next token
+                for (token=++end; *end && (*end != chSeparator) && (*end != _T('\n'));
+                  end++)
+                    ;
+
+                if ((*end == _T('\0')) && (token == end))
+                    token = NULL;
+
+                *end = _T('\0');
+
+                nSubItem++;
+            }
+            nItem++;
+        }
+
+        AutoSizeColumns(GetAutoSizeStyle());
+        File.Close();
+    }
+
+    CATCH (CFileException, e)
+    {
+        AfxMessageBox(_T("Unable to load grid data"));
+        return FALSE;
+    }
+    END_CATCH
+
+    return TRUE;
+}
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl overrideables
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+// This is no longer needed since I've changed to OLE drag and drop - but it's
+// still cool code. :)
+CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
+{
+    CDC* pDC = GetDC();
+    if (!pDC)
+        return NULL;
+
+    CRect rect;
+    CCellID cell = GetFocusCell();
+    if (!GetCellRect(cell.row, cell.col, rect))
+        return NULL;
+    
+    // Translate coordinate system
+    rect.BottomRight() = CPoint(rect.Width(), rect.Height());
+    rect.TopLeft()     = CPoint(0, 0);
+    *pHotSpot = rect.BottomRight(); 
+    
+    // Create a new imagelist (the caller of this function has responsibility
+    // for deleting this list)
+    CImageList* pList = new CImageList;
+    if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1, 1))
+    {    
+        if (pList)
+            delete pList;
+        return NULL;
+    }
+    
+    // Create mem DC and bitmap
+    CDC MemDC;
+    CBitmap bm;
+    MemDC.CreateCompatibleDC(pDC);
+    bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
+    CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
+    MemDC.SetWindowOrg(0, 0);
+    
+    // Draw cell onto bitmap in memDC
+    CGridCellBase* pCell = GetCell(cell.row, cell.col);
+    if (pCell)
+        pCell->Draw(&MemDC, cell.row, cell.col, rect, FALSE);
+    
+    // Clean up
+    MemDC.SelectObject(pOldBitmap);
+    ReleaseDC(pDC);
+    
+    // Add the bitmap we just drew to the image list.
+    pList->Add(&bm, GetDefaultCell(FALSE, FALSE)->GetBackClr());
+    bm.DeleteObject();
+
+    return pList;
+}
+#endif
+
+void CGridCtrl::OnFixedRowClick(CCellID& cell)
+{
+    if (!IsValid(cell))
+        return;
+
+    if (GetHeaderSort())
+    {
+        CWaitCursor waiter;
+        if (cell.col == GetSortColumn())
+            SortItems(cell.col, !GetSortAscending());
+        else
+            SortItems(cell.col, TRUE);
+        Invalidate();
+    }
+
+	// Did the user click on a fixed column cell (so the cell was within the overlap of
+	// fixed row and column cells) - (fix by David Pritchard)
+    if (GetFixedColumnSelection())
+    {
+        if (cell.col < GetFixedColumnCount())
+        {
+            m_MouseMode = MOUSE_SELECT_ALL;
+            OnSelecting(cell);
+        }
+        else 
+        {
+            m_MouseMode = MOUSE_SELECT_COL;
+            OnSelecting(cell);
+        }
+    }
+}
+
+void CGridCtrl::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;
+//    }
+
+	// Did the user click on a fixed row cell (so the cell was within the overlap of
+	// fixed row and column cells) - (fix by David Pritchard)
+    if (GetFixedRowSelection())
+    {
+        if (cell.row < GetFixedRowCount())
+        {
+            m_MouseMode = MOUSE_SELECT_ALL;
+            OnSelecting(cell);
+        }
+        else
+        {
+            m_MouseMode = MOUSE_SELECT_ROW;
+            OnSelecting(cell);
+        }
+    }
+}
+
+// Gets the extent of the text pointed to by str (no CDC needed)
+// By default this uses the selected font (which is a bigger font)
+CSize CGridCtrl::GetTextExtent(int nRow, int nCol, LPCTSTR str)
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (!pCell)
+        return CSize(0, 0);
+    else
+        return pCell->GetTextExtent(str);
+}
+
+// virtual
+void CGridCtrl::OnEditCell(int nRow, int nCol, CPoint point, UINT nChar)
+{
+#ifndef GRIDCONTROL_NO_TITLETIPS
+    m_TitleTip.Hide();  // hide any titletips
+#endif
+
+    // Can we do it?
+    CCellID cell(nRow, nCol);
+    if (!IsValid(cell) || !IsCellEditable(nRow, nCol))
+        return;
+
+    // Can we see what we are doing?
+    EnsureVisible(nRow, nCol);
+    if (!IsCellVisible(nRow, nCol))
+        return;
+
+    // Where, exactly, are we gonna do it??
+    CRect rect;
+    if (!GetCellRect(cell, rect))
+        return;
+
+    // Check we can edit...
+    if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
+    {
+		// LUC
+		GetTopLeftMergedCell(nRow, nCol, rect);
+
+        // Let's do it...
+        CGridCellBase* pCell = GetCell(nRow, nCol);
+        if (pCell)
+		{
+			pCell->Edit(nRow, nCol, rect, point, IDC_INPLACE_CONTROL, nChar);
+		}
+            
+    }
+}
+
+// virtual
+void CGridCtrl::EndEditing()
+{
+    CCellID cell = GetFocusCell();
+    if (!IsValid(cell)) return;
+    CGridCellBase *pCell = GetCell(cell.row, cell.col);
+    if (pCell)
+        pCell->EndEdit();
+}
+
+// virtual
+void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
+{
+    CString strCurrentText = GetItemText(nRow, nCol);
+    if (strCurrentText != str)
+    {
+        SetItemText(nRow, nCol, str);
+        if (ValidateEdit(nRow, nCol, str) && 
+            SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
+        {
+            SetModified(TRUE, nRow, nCol);
+            RedrawCell(nRow, nCol);
+        }
+        else
+        {
+            SetItemText(nRow, nCol, strCurrentText);
+        }
+    }
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+    if (pCell)
+        pCell->OnEndEdit();
+}
+
+// If this returns FALSE then the editing isn't allowed
+// virtual
+BOOL CGridCtrl::ValidateEdit(int nRow, int nCol, LPCTSTR str)
+{
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return TRUE;
+
+    return pCell->ValidateEdit(str);
+}
+
+// virtual
+CString CGridCtrl::GetItemText(int nRow, int nCol) const
+{
+    if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
+        return _T("");
+
+    CGridCellBase* pCell = GetCell(nRow, nCol);
+//    ASSERT(pCell);
+    if (!pCell)
+        return _T("");
+
+    return pCell->GetText();
+}
+
+void CGridCtrl::ResetVirtualOrder()
+{
+	m_arRowOrder.resize(m_nRows);  
+    for (int i = 0; i < m_nRows; i++)
+	{
+		m_arRowOrder[i] = i;	
+	}
+}
+
+
+void CGridCtrl::Reorder(int From, int To)
+{
+		// Set line From just after Line To
+//	ASSERT(From>= GetFixedRowCount() && To>=GetFixedRowCount()-1 && From<m_nRows && To<m_nRows);
+	int Value = m_arRowOrder[From];
+	m_arRowOrder.erase(m_arRowOrder.begin()+From);
+	int Offset = (From>=To ? 1:0);
+	m_arRowOrder.insert(m_arRowOrder.begin()+To+Offset, Value);
+
+}
+
+
+// LUC
+INT_PTR CGridCtrl::MergeCells(CCellRange& mergedCellRange)
+{
+	INT_PTR nMergeID = -1;
+	if(IsValid(mergedCellRange))
+	{
+		m_arMergedCells.Add(mergedCellRange);
+		nMergeID =  m_arMergedCells.GetSize() - 1;
+	}
+
+	return nMergeID;
+
+}
+
+void CGridCtrl::SplitCells(INT_PTR nMergeID)
+{
+	if(nMergeID > -1)
+	{
+		m_arMergedCells.RemoveAt(nMergeID);
+	}
+}
+
+BOOL CGridCtrl::IsMergedCell(int row, int col, CCellRange& mergedCellRange)
+{
+	if((mergedCellRange.GetMinRow() <= row) && (mergedCellRange.GetMinCol() <= col)
+		&& (mergedCellRange.GetMaxRow() >= row) && (mergedCellRange.GetMaxCol() >= col))
+	{
+		return TRUE;
+	}
+
+	return FALSE;	
+}
+
+
+BOOL CGridCtrl::GetMergedCellRect(CCellRange& mergedCell, CRect& rect)
+{ 	
+	CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+	if(m_nFreezedRows > 0)
+	{
+		idTopLeftMin.row = m_nFixedRows;
+	}
+	if(m_nFreezedCols > 0)
+	{
+		idTopLeftMin.col = m_nFixedCols;
+	}
+				
+	int nMinRow = mergedCell.GetMinRow();
+	if(nMinRow < idTopLeftMin.row)
+		nMinRow = idTopLeftMin.row;
+	
+	int nMinCol = mergedCell.GetMinCol();
+	if(nMinCol < idTopLeftMin.col)
+		nMinCol = idTopLeftMin.col;
+	
+	int nMaxRow = mergedCell.GetMaxRow();
+	int nMaxCol = mergedCell.GetMaxCol();		
+	
+	while(!IsCellVisible(nMinRow, nMaxCol))
+	{
+		nMaxCol--;
+		if(nMaxCol <= nMinCol)
+		{
+			break;
+		}
+	}
+
+	while(!IsCellVisible(nMaxRow, nMinCol))
+	{
+		nMaxRow--;
+		if(nMaxRow <= nMinRow)
+		{
+			break;
+		}
+	}
+	
+	CRect rcTopLeft;
+	GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+	CRect rcBottomRight;
+	GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+	rect.left = rcTopLeft.left;
+	rect.top = rcTopLeft.top;
+	rect.right = rcBottomRight.right;
+	rect.bottom = rcBottomRight.bottom;				
+
+	return TRUE;
+}
+
+BOOL CGridCtrl::GetTopLeftMergedCell(int& row, int& col, CRect& mergeRect)
+{
+	BOOL bRet = FALSE;
+
+	INT_PTR size = m_arMergedCells.GetSize();
+	if(size > 0)
+	{	
+		for(INT_PTR i = 0; i < size; i++)
+		{
+			CCellRange& mergedCell = m_arMergedCells[i];
+			if(IsMergedCell(row, col, mergedCell))
+			{
+				CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+				if(m_nFreezedRows > 0)
+				{
+					idTopLeftMin.row = m_nFixedRows;
+				}
+				if(m_nFreezedCols > 0)
+				{
+					idTopLeftMin.col = m_nFixedCols;
+				}
+				
+				int nMinRow = mergedCell.GetMinRow();
+				int nMinCol = mergedCell.GetMinCol();
+
+				row = nMinRow;
+				col = nMinCol;
+
+				if(nMinRow < idTopLeftMin.row)
+					nMinRow = idTopLeftMin.row;
+				
+				if(nMinCol < idTopLeftMin.col)
+					nMinCol = idTopLeftMin.col;
+				
+				int nMaxRow = mergedCell.GetMaxRow();
+				int nMaxCol = mergedCell.GetMaxCol();
+
+				while(!IsCellVisible(nMinRow, nMaxCol))
+				{
+					nMaxCol--;
+					if(nMaxCol <= nMinCol)
+					{
+						break;
+					}
+				}
+
+				while(!IsCellVisible(nMaxRow, nMinCol))
+				{
+					nMaxRow--;
+					if(nMaxRow <= nMinRow)
+					{
+						break;
+					}
+				}
+				
+				if(mergeRect != rectNull)
+				{
+					CRect rcTopLeft;
+					GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+					CRect rcBottomRight;
+					GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+					mergeRect.left = rcTopLeft.left;
+					mergeRect.top = rcTopLeft.top;
+					mergeRect.right = rcBottomRight.right;
+					mergeRect.bottom = rcBottomRight.bottom;				
+				}								
+
+				bRet =  TRUE;
+			}
+		}
+	}
+
+	return bRet;
+}
+
+BOOL CGridCtrl::GetBottomRightMergedCell(int& row, int& col, CRect& mergeRect)
+{
+	BOOL bRet = FALSE;
+
+	INT_PTR size = m_arMergedCells.GetSize();
+	if(size > 0)
+	{	
+		for(INT_PTR i = 0; i < size; i++)
+		{
+			CCellRange& mergedCell = m_arMergedCells[i];
+			if(IsMergedCell(row, col, mergedCell))
+			{
+				CCellID idTopLeftMin = GetTopleftNonFixedCell();
+
+				if(m_nFreezedRows > 0)
+				{
+					idTopLeftMin.row = m_nFixedRows;
+				}
+				if(m_nFreezedCols > 0)
+				{
+					idTopLeftMin.col = m_nFixedCols;
+				}
+				
+				int nMinRow = mergedCell.GetMinRow();
+				int nMinCol = mergedCell.GetMinCol();				
+
+				if(nMinRow < idTopLeftMin.row)
+					nMinRow = idTopLeftMin.row;
+				
+				if(nMinCol < idTopLeftMin.col)
+					nMinCol = idTopLeftMin.col;
+				
+				int nMaxRow = mergedCell.GetMaxRow();
+				int nMaxCol = mergedCell.GetMaxCol();
+
+				row = nMaxRow;
+				col = nMaxCol;
+
+				while(!IsCellVisible(nMinRow, nMaxCol))
+				{
+					nMaxCol--;
+					if(nMaxCol <= nMinCol)
+					{
+						break;
+					}
+				}
+
+				while(!IsCellVisible(nMaxRow, nMinCol))
+				{
+					nMaxRow--;
+					if(nMaxRow <= nMinRow)
+					{
+						break;
+					}
+				}
+
+				if(mergeRect != rectNull)
+				{
+					CRect rcTopLeft;
+					GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+					CRect rcBottomRight;
+					GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+					mergeRect.left = rcTopLeft.left;
+					mergeRect.top = rcTopLeft.top;
+					mergeRect.right = rcBottomRight.right;
+					mergeRect.bottom = rcBottomRight.bottom;				
+				}								
+
+				bRet =  TRUE;
+			}
+		}
+	}
+
+	return bRet;
+}
+
+
+BOOL CGridCtrl::GetMergedCellRect(int row, int col, CRect& rect)
+{ 
+	INT_PTR size = m_arMergedCells.GetSize();
+	if(size > 0)
+	{	
+		for(INT_PTR i = 0; i < size; i++)
+		{
+			if(IsMergedCell(row, col, m_arMergedCells[i]))
+			{
+				CCellID idTopLeftMin = GetTopleftNonFixedCell();
+				
+				int nMinRow = m_arMergedCells[i].GetMinRow();
+				if(nMinRow < idTopLeftMin.row)
+					nMinRow = idTopLeftMin.row;
+				int nMinCol = m_arMergedCells[i].GetMinCol();
+				if(nMinCol < idTopLeftMin.col)
+					nMinCol = idTopLeftMin.col;
+				int nMaxRow = m_arMergedCells[i].GetMaxRow();
+				int nMaxCol = m_arMergedCells[i].GetMaxCol();
+
+				CRect rcTopLeft;
+				GetCellRect(nMinRow, nMinCol, rcTopLeft);
+
+				CRect rcBottomRight;
+				GetCellRect(nMaxRow, nMaxCol, rcBottomRight);
+
+				rect.left = rcTopLeft.left;
+				rect.top = rcTopLeft.top;
+				rect.right = rcBottomRight.right;
+				rect.bottom = rcBottomRight.bottom;				
+
+				return TRUE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+// LUC
+BOOL CGridCtrl::IsFocused(CGridCellBase& cell, int nRow, int nCol)
+{
+	BOOL bRet = cell.IsFocused();
+	if(!bRet && m_bDrawingMergedCell)
+	{
+		CCellRange& mergedCell = m_arMergedCells[m_nCurrentMergeID];
+		for(int row = mergedCell.GetMinRow(); row <= mergedCell.GetMaxRow(); row++)
+		{
+			for(int col = mergedCell.GetMinCol(); col <= mergedCell.GetMaxCol(); col++)
+			{
+				CGridCellBase* pCell = GetCell(row, col);
+				if(pCell != NULL)
+				{
+					if(pCell->IsFocused())
+					{
+						bRet = TRUE;
+					}
+				}
+			}
+		}				
+	}
+	
+	return bRet;
+}
+
+BOOL CGridCtrl::IsSelected(CGridCellBase& cell, int nRow, int nCol)
+{
+	BOOL bRet = cell.IsSelected();
+	if(!bRet && m_bDrawingMergedCell)
+	{
+		CCellRange& mergedCell = m_arMergedCells[m_nCurrentMergeID];
+		for(int row = mergedCell.GetMinRow(); row <= mergedCell.GetMaxRow(); row++)
+		{
+			for(int col = mergedCell.GetMinCol(); col <= mergedCell.GetMaxCol(); col++)
+			{
+				CGridCellBase* pCell = GetCell(row, col);
+				if(pCell != NULL)
+				{
+					if(pCell->IsSelected())
+					{
+						bRet = TRUE;
+					}
+				}
+			}
+		}				
+	}
+	
+	return bRet;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridCtrl.h b/SourceCode/Bond/Servo/GridControl/GridCtrl.h
new file mode 100644
index 0000000..84dd980
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridCtrl.h
@@ -0,0 +1,1090 @@
+/////////////////////////////////////////////////////////////////////////////
+// GridCtrl.h : header file
+//
+// MFC Grid Control - main header
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.20+
+//
+//////////////////////////////////////////////////////////////////////
+
+// FEATURES BY Mukit, Ataul (2007-11-17):
+// 1. Merge Cell 
+// 2. Ability to do XL Style Freeze Pane
+// 3. The Horizontal Gray Area Removed 
+  
+// FINDINGS:
+// 1. A cell cannot be edited if a tooltip is shown..
+// 2. The InplaceEditCtrl is not multiline even if a cell can contain Multiline Text..
+// 3. If a cell is too small, the InplaceEditCtrl is almost invisible..
+
+#if !defined(AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#include "CellRange.h"
+#include "GridCell.h"
+#include <afxtempl.h>
+#include <vector>
+using namespace std;
+
+
+struct CELL_ENABLE
+{
+	CELL_ENABLE()
+	{
+		nEnable = -1;
+	}
+	void SetEnable(BOOL bValue)
+	{
+		nEnable = bValue;
+	}
+	BOOL isEnable()
+	{
+        if (nEnable > 0)
+        {
+            return TRUE;
+		}
+		else
+		{
+			return FALSE;
+		}
+	}
+	BOOL isActivated()
+	{
+		if (nEnable < 0)
+		{
+			return FALSE;
+		}
+        else
+        {
+            return TRUE;
+        }
+	}
+	int nEnable;
+};
+
+///////////////////////////////////////////////////////////////////////////////////
+// Defines - these determine the features (and the final size) of the final code
+///////////////////////////////////////////////////////////////////////////////////
+
+//#define GRIDCONTROL_NO_TITLETIPS   // Do not use titletips for cells with large data
+//#define GRIDCONTROL_NO_DRAGDROP    // Do not use OLE drag and drop
+//#define GRIDCONTROL_NO_CLIPBOARD   // Do not use clipboard routines
+
+#ifdef _WIN32_WCE
+#   define GRIDCONTROL_NO_TITLETIPS   // Do not use titletips for cells with large data
+#   define GRIDCONTROL_NO_DRAGDROP    // Do not use OLE drag and drop
+#   define GRIDCONTROL_NO_CLIPBOARD   // Do not use clipboard routines
+#   define GRIDCONTROL_NO_PRINTING    // Do not use printing routines
+#   ifdef WCE_NO_PRINTING			  // Older versions of CE had different #def's
+#       define _WIN32_WCE_NO_PRINTING
+#   endif
+#   ifdef WCE_NO_CURSOR
+#       define _WIN32_WCE_NO_CURSOR
+#   endif
+#endif  // _WIN32_WCE
+
+// Use this as the classname when inserting this control as a custom control
+// in the MSVC++ dialog editor
+#define GRIDCTRL_CLASSNAME    _T("MFCGridCtrl")  // Window class name
+#define IDC_INPLACE_CONTROL   8                  // ID of inplace edit controls
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Conditional includes
+///////////////////////////////////////////////////////////////////////////////////
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+#   include "TitleTip.h"
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+#   include "GridDropTarget.h"
+#   undef GRIDCONTROL_NO_CLIPBOARD     // Force clipboard functions on
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+#   include <afxole.h>
+#endif
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Helper functions
+///////////////////////////////////////////////////////////////////////////////////
+
+// Handy functions
+#define IsSHIFTpressed() ( (GetKeyState(VK_SHIFT) & (1 << (sizeof(SHORT)*8-1))) != 0   )
+#define IsCTRLpressed()  ( (GetKeyState(VK_CONTROL) & (1 << (sizeof(SHORT)*8-1))) != 0 )
+
+// Backwards compatibility for pre 2.20 grid versions
+#define DDX_GridControl(pDX, nIDC, rControl)  DDX_Control(pDX, nIDC, rControl)     
+
+
+///////////////////////////////////////////////////////////////////////////////////
+// Structures
+///////////////////////////////////////////////////////////////////////////////////
+
+// This structure sent to Grid's parent in a WM_NOTIFY message
+typedef struct tagNM_GRIDVIEW {
+    NMHDR hdr;
+    int   iRow;
+    int   iColumn;
+} NM_GRIDVIEW;
+
+// This is sent to the Grid from child in-place edit controls
+typedef struct tagGV_DISPINFO {
+    NMHDR   hdr;
+    GV_ITEM item;
+} GV_DISPINFO;
+
+// This is sent to the Grid from child in-place edit controls
+typedef struct tagGV_CACHEHINT {
+    NMHDR      hdr;
+    CCellRange range;
+} GV_CACHEHINT;
+
+// storage typedef for each row in the grid
+typedef CTypedPtrArray<CObArray, CGridCellBase*> GRID_ROW;
+
+// For virtual mode callback
+typedef BOOL (CALLBACK* GRIDCALLBACK)(GV_DISPINFO *, LPARAM);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Defines
+///////////////////////////////////////////////////////////////////////////////////
+
+// Grid line/scrollbar selection
+#define GVL_NONE                0L      // Neither
+#define GVL_HORZ                1L      // Horizontal line or scrollbar
+#define GVL_VERT                2L      // Vertical line or scrollbar
+#define GVL_BOTH                3L      // Both
+
+// Autosizing option
+#define GVS_DEFAULT             0
+#define GVS_HEADER              1       // Size using column fixed cells data only
+#define GVS_DATA                2       // Size using column non-fixed cells data only
+#define GVS_BOTH                3       // Size using column fixed and non-fixed
+
+// Cell Searching options
+#define GVNI_FOCUSED            0x0001
+#define GVNI_SELECTED           0x0002
+#define GVNI_DROPHILITED        0x0004
+#define GVNI_READONLY           0x0008
+#define GVNI_FIXED              0x0010
+#define GVNI_MODIFIED           0x0020
+// LUC
+#define GVNI_FREEZED			0x0040
+
+#define GVNI_ABOVE              LVNI_ABOVE
+#define GVNI_BELOW              LVNI_BELOW
+#define GVNI_TOLEFT             LVNI_TOLEFT
+#define GVNI_TORIGHT            LVNI_TORIGHT
+#define GVNI_ALL                (LVNI_BELOW|LVNI_TORIGHT|LVNI_TOLEFT)
+#define GVNI_AREA               (LVNI_BELOW|LVNI_TORIGHT)
+
+// Hit test values (not yet implemented)
+#define GVHT_DATA               0x0000
+#define GVHT_TOPLEFT            0x0001
+#define GVHT_COLHDR             0x0002
+#define GVHT_ROWHDR             0x0004
+#define GVHT_COLSIZER           0x0008
+#define GVHT_ROWSIZER           0x0010
+#define GVHT_LEFT               0x0020
+#define GVHT_RIGHT              0x0040
+#define GVHT_ABOVE              0x0080
+#define GVHT_BELOW              0x0100
+
+// Messages sent to the grid's parent (More will be added in future)
+#define GVN_BEGINDRAG           LVN_BEGINDRAG        // LVN_FIRST-9
+#define GVN_BEGINLABELEDIT      LVN_BEGINLABELEDIT   // LVN_FIRST-5
+#define GVN_BEGINRDRAG          LVN_BEGINRDRAG
+#define GVN_COLUMNCLICK         LVN_COLUMNCLICK
+#define GVN_DELETEITEM          LVN_DELETEITEM
+#define GVN_ENDLABELEDIT        LVN_ENDLABELEDIT     // LVN_FIRST-6
+#define GVN_SELCHANGING         LVN_ITEMCHANGING
+#define GVN_SELCHANGED          LVN_ITEMCHANGED
+#define GVN_GETDISPINFO         LVN_GETDISPINFO 
+#define GVN_ODCACHEHINT         LVN_ODCACHEHINT 
+#define GVN_COMBOSELCHANGE		LVN_FIRST-10
+
+class CGridCtrl;
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCtrl window
+
+typedef bool (*PVIRTUALCOMPARE)(int, int);
+
+class CGridCtrl : public CWnd
+{
+    DECLARE_DYNCREATE(CGridCtrl)
+    friend class CGridCell;
+    friend class CGridCellBase;
+
+// Construction
+public:
+    CGridCtrl(int nRows = 0, int nCols = 0, int nFixedRows = 0, int nFixedCols = 0);
+
+    BOOL Create(const RECT& rect, CWnd* parent, UINT nID,
+                DWORD dwStyle = WS_CHILD | WS_BORDER | WS_TABSTOP | WS_VISIBLE);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Attributes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+
+///// LUC ///////////////////////////////////////////////////////////////////////
+
+	//// LUC : MergeCell////////
+	
+	INT_PTR MergeCells(CCellRange& mergedCellRange);
+	void SplitCells(INT_PTR nMergeID);
+
+	BOOL IsMergedCell(int row, int col, CCellRange& mergedCellRange);
+	BOOL GetMergedCellRect(int row, int col, CRect& rect);
+	BOOL GetMergedCellRect(CCellRange& mergedCell, CRect& rect);
+	BOOL GetTopLeftMergedCell(int& row, int& col, CRect& mergeRect);
+	BOOL GetBottomRightMergedCell(int& row, int& col, CRect& mergeRect);
+	virtual BOOL IsFocused(CGridCellBase& cell, int nRow, int nCol);
+	virtual BOOL IsSelected(CGridCellBase& cell, int nRow, int nCol);
+
+	BOOL	m_bDrawingMergedCell;
+	INT_PTR	m_nCurrentMergeID;
+
+	static CRect rectNull;		
+	static CCellID cellNull;
+
+	// LUC : Freeze Rows	
+
+	BOOL SetFreezedRowCount(int nFreezedRows)
+	{
+		BOOL bRet = FALSE;
+		if( (nFreezedRows >= 0) && ((nFreezedRows + m_nFixedRows) <= m_nRows) )
+		{
+			m_nFreezedRows = nFreezedRows;
+			ResetScrollBars();
+			Refresh();
+			bRet = TRUE;
+		}
+	
+		return bRet;
+		
+	}
+	
+	BOOL SetFreezedColumnCount(int nFreezedCols)
+	{
+		BOOL bRet = FALSE;
+		if( (nFreezedCols >= 0) && ((nFreezedCols + m_nFixedCols) <= m_nCols) )
+		{
+			m_nFreezedCols = nFreezedCols;
+			ResetScrollBars();
+			Refresh();
+			bRet = TRUE;
+		}
+	
+		return bRet;
+	}
+
+	// To avoid calling ResetScrollBars twice you can use SetFreezedFrame
+	BOOL SetFreezedFrame(int nFreezedRows, int nFreezedCols)
+	{
+		BOOL bRet = FALSE;
+		if( (nFreezedRows >= 0) && ((nFreezedRows + m_nFixedRows) <= m_nRows) )
+		{
+			m_nFreezedRows = nFreezedRows;			
+			bRet = TRUE;
+		}
+		if( (nFreezedCols >= 0) && ((nFreezedCols + m_nFixedCols) <= m_nCols) )
+		{
+			m_nFreezedCols = nFreezedCols;
+			bRet = TRUE;
+		}
+		else
+		{
+			bRet = FALSE;
+		}
+
+		ResetScrollBars();
+			
+		return bRet;			
+	}	
+	
+	int  GetFreezedRowCount() const                    { return m_nFreezedRows; }
+    int  GetFreezedColumnCount() const                 { return m_nFreezedCols; }	
+
+	void ShowHorzNonGridArea(BOOL bShow)
+	{
+		m_bShowHorzNonGridArea = bShow;
+	}
+
+	BOOL IsShowingHorzNonGridArea()
+	{
+		return m_bShowHorzNonGridArea;
+	}
+
+///////////////////////////////////////////////////////////////////////////////////////    
+	
+    int  GetRowCount() const                    { return m_nRows; }
+    int  GetColumnCount() const                 { return m_nCols; }
+    int  GetFixedRowCount(BOOL bIncludeFreezedRows = FALSE) const
+	{ 
+		return (bIncludeFreezedRows) ? (m_nFixedRows + m_nFreezedRows) : m_nFixedRows;
+	}
+    int  GetFixedColumnCount(BOOL bIncludeFreezedCols = FALSE) const            
+	{
+		return (bIncludeFreezedCols) ? (m_nFixedCols + m_nFreezedCols) : m_nFixedCols; 
+	}	
+	
+	BOOL SetRowCount(int nRows = 10);
+    BOOL SetColumnCount(int nCols = 10);
+
+	BOOL UpdateCellEditableMask();
+    
+	BOOL SetFixedRowCount(int nFixedRows = 1);
+    BOOL SetFixedColumnCount(int nFixedCols = 1);	
+
+public:
+    int  GetRowHeight(int nRow) const;
+    BOOL SetRowHeight(int row, int height);
+    int  GetColumnWidth(int nCol) const;
+    BOOL SetColumnWidth(int col, int width);
+
+    BOOL GetCellOrigin(int nRow, int nCol, LPPOINT p);
+    BOOL GetCellOrigin(const CCellID& cell, LPPOINT p);
+    BOOL GetCellRect(int nRow, int nCol, LPRECT pRect);
+    BOOL GetCellRect(const CCellID& cell, LPRECT pRect);
+
+    BOOL GetTextRect(const CCellID& cell, LPRECT pRect);
+    BOOL GetTextRect(int nRow, int nCol, LPRECT pRect);
+
+	BOOL SetCellMaskEditable(int nRow, int nCol, BOOL bEditable);
+	BOOL isCellMaskEditable(int nRow, int nCol);
+	BOOL isCellMaskActivated(int nRow, int nCol);
+
+    // LUC
+	// Change for MergeCell
+	CCellID GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck = TRUE, CCellID& cellOriginal = cellNull);
+
+	// LUC
+    //int  GetFixedRowHeight() const;
+    //int  GetFixedColumnWidth() const;	    
+	int	GetFixedRowHeight(BOOL bIncludeFreezedRows = FALSE) const;
+	int GetFixedColumnWidth(BOOL bIncludeFreezedCols = FALSE) const;
+
+    long GetVirtualWidth() const;
+    long GetVirtualHeight() const;
+
+    CSize GetTextExtent(int nRow, int nCol, LPCTSTR str);
+    // EFW - Get extent of current text in cell
+    inline CSize GetCellTextExtent(int nRow, int nCol)  { return GetTextExtent(nRow, nCol, GetItemText(nRow,nCol)); }
+
+    void     SetGridBkColor(COLORREF clr)         { m_crGridBkColour = clr;           }
+    COLORREF GetGridBkColor() const               { return m_crGridBkColour;          }
+    void     SetGridLineColor(COLORREF clr)       { m_crGridLineColour = clr;         }
+    COLORREF GetGridLineColor() const             { return m_crGridLineColour;        }
+
+	void	 SetTitleTipBackClr(COLORREF clr = CLR_DEFAULT) { m_crTTipBackClr = clr;  }
+	COLORREF GetTitleTipBackClr()				            { return m_crTTipBackClr; }
+	void	 SetTitleTipTextClr(COLORREF clr = CLR_DEFAULT) { m_crTTipTextClr = clr;  }
+	COLORREF GetTitleTipTextClr()				            { return m_crTTipTextClr; }
+
+    // ***************************************************************************** //
+    // These have been deprecated. Use GetDefaultCell and then set the colors
+    void     SetTextColor(COLORREF clr)      { m_cellDefault.SetTextClr(clr);        }
+    COLORREF GetTextColor()                  { return m_cellDefault.GetTextClr();    }
+    void     SetTextBkColor(COLORREF clr)    { m_cellDefault.SetBackClr(clr);        }
+    COLORREF GetTextBkColor()                { return m_cellDefault.GetBackClr();    }
+    void     SetFixedTextColor(COLORREF clr) { m_cellFixedRowDef.SetTextClr(clr); 
+                                               m_cellFixedColDef.SetTextClr(clr); 
+                                               m_cellFixedRowColDef.SetTextClr(clr); }
+    COLORREF GetFixedTextColor() const       { return m_cellFixedRowDef.GetTextClr(); }
+    void     SetFixedBkColor(COLORREF clr)   { m_cellFixedRowDef.SetBackClr(clr); 
+                                               m_cellFixedColDef.SetBackClr(clr); 
+                                               m_cellFixedRowColDef.SetBackClr(clr); }
+    COLORREF GetFixedBkColor() const         { return m_cellFixedRowDef.GetBackClr(); }
+    void     SetGridColor(COLORREF clr)      { SetGridLineColor(clr);                }
+    COLORREF GetGridColor()                  { return GetGridLineColor();            }
+    void     SetBkColor(COLORREF clr)        { SetGridBkColor(clr);                  }
+    COLORREF GetBkColor()                    { return GetGridBkColor();              }
+
+    void     SetDefCellMargin( int nMargin)  { m_cellDefault.SetMargin(nMargin); 
+                                               m_cellFixedRowDef.SetMargin(nMargin); 
+                                               m_cellFixedColDef.SetMargin(nMargin); 
+                                               m_cellFixedRowColDef.SetMargin(nMargin); }
+    int      GetDefCellMargin() const        { return m_cellDefault.GetMargin();     }
+
+    int      GetDefCellHeight() const        { return m_cellDefault.GetHeight();     }
+    void     SetDefCellHeight(int nHeight)   { m_cellDefault.SetHeight(nHeight); 
+                                               m_cellFixedRowDef.SetHeight(nHeight); 
+                                               m_cellFixedColDef.SetHeight(nHeight); 
+                                               m_cellFixedRowColDef.SetHeight(nHeight); }
+    int      GetDefCellWidth() const         { return m_cellDefault.GetWidth();     }
+    void     SetDefCellWidth(int nWidth)     { m_cellDefault.SetWidth(nWidth); 
+                                               m_cellFixedRowDef.SetWidth(nWidth); 
+                                               m_cellFixedColDef.SetWidth(nWidth); 
+                                               m_cellFixedRowColDef.SetWidth(nWidth); }
+
+    // ***************************************************************************** //
+
+    int GetSelectedCount() const                  { return (int)m_SelectedCellMap.GetCount(); }
+
+    CCellID SetFocusCell(CCellID cell);
+    CCellID SetFocusCell(int nRow, int nCol);
+    CCellID GetFocusCell() const                  { return m_idCurrentCell;           }
+
+
+    void SetVirtualMode(BOOL bVirtual);
+    BOOL GetVirtualMode() const                   { return m_bVirtualMode;            }
+    void SetCallbackFunc(GRIDCALLBACK pCallback, 
+                         LPARAM lParam)           { m_pfnCallback = pCallback; m_lParam = lParam; }
+    GRIDCALLBACK GetCallbackFunc()                { return m_pfnCallback;             }
+
+
+    void SetImageList(CImageList* pList)          { m_pImageList = pList;             }
+    CImageList* GetImageList() const              { return m_pImageList;              }
+
+    void SetGridLines(int nWhichLines = GVL_BOTH);
+    int  GetGridLines() const                     { return m_nGridLines;              }
+    void SetEditable(BOOL bEditable = TRUE)       { m_bEditable = bEditable;          }
+    BOOL IsEditable() const                       { return m_bEditable;               }
+    void SetListMode(BOOL bEnableListMode = TRUE);
+    BOOL GetListMode() const                      { return m_bListMode;               }
+    void SetSingleRowSelection(BOOL bSing = TRUE) { m_bSingleRowSelection = bSing;    }
+    BOOL GetSingleRowSelection()                  { return m_bSingleRowSelection & m_bListMode; }
+    void SetSingleColSelection(BOOL bSing = TRUE) { m_bSingleColSelection = bSing;    }
+    BOOL GetSingleColSelection()                  { return m_bSingleColSelection;     }
+    void EnableSelection(BOOL bEnable = TRUE)     { ResetSelectedRange(); m_bEnableSelection = bEnable; ResetSelectedRange(); }
+    BOOL IsSelectable() const                     { return m_bEnableSelection;        }
+    void SetFixedColumnSelection(BOOL bSelect)    { m_bFixedColumnSelection = bSelect;}
+    BOOL GetFixedColumnSelection()                { return m_bFixedColumnSelection;   }
+    void SetFixedRowSelection(BOOL bSelect)       { m_bFixedRowSelection = bSelect;   }
+    BOOL GetFixedRowSelection()                   { return m_bFixedRowSelection;      }
+    void EnableDragAndDrop(BOOL bAllow = TRUE)    { m_bAllowDragAndDrop = bAllow;     }
+    BOOL GetDragAndDrop() const                   { return m_bAllowDragAndDrop;       }
+    void SetRowResize(BOOL bResize = TRUE)        { m_bAllowRowResize = bResize;      }
+    BOOL GetRowResize() const                     { return m_bAllowRowResize;         }
+    void SetColumnResize(BOOL bResize = TRUE)     { m_bAllowColumnResize = bResize;   }
+    BOOL GetColumnResize() const                  { return m_bAllowColumnResize;      }
+    void SetHeaderSort(BOOL bSortOnClick = TRUE)  { m_bSortOnClick = bSortOnClick;    }
+    BOOL GetHeaderSort() const                    { return m_bSortOnClick;            }
+    void SetHandleTabKey(BOOL bHandleTab = TRUE)  { m_bHandleTabKey = bHandleTab;     }
+    BOOL GetHandleTabKey() const                  { return m_bHandleTabKey;           }
+    void SetDoubleBuffering(BOOL bBuffer = TRUE)  { m_bDoubleBuffer = bBuffer;        }
+    BOOL GetDoubleBuffering() const               { return m_bDoubleBuffer;           }
+    void EnableTitleTips(BOOL bEnable = TRUE)     { m_bTitleTips = bEnable;           }
+    BOOL GetTitleTips()                           { return m_bTitleTips;              }
+    void SetSortColumn(int nCol);
+    int  GetSortColumn() const                    { return m_nSortColumn;             }
+    void SetSortAscending(BOOL bAscending)        { m_bAscending = bAscending;        }
+    BOOL GetSortAscending() const                 { return m_bAscending;              }
+    void SetTrackFocusCell(BOOL bTrack)           { m_bTrackFocusCell = bTrack;       }
+    BOOL GetTrackFocusCell()                      { return m_bTrackFocusCell;         }
+    void SetFrameFocusCell(BOOL bFrame)           { m_bFrameFocus = bFrame;           }
+    BOOL GetFrameFocusCell()                      { return m_bFrameFocus;             }
+    void SetAutoSizeStyle(int nStyle = GVS_BOTH)  { m_nAutoSizeColumnStyle = nStyle;  }
+    int  GetAutoSizeStyle()                       { return m_nAutoSizeColumnStyle; }
+
+    void EnableHiddenColUnhide(BOOL bEnable = TRUE){ m_bHiddenColUnhide = bEnable;    }
+    BOOL GetHiddenColUnhide()                     { return m_bHiddenColUnhide;        }
+    void EnableHiddenRowUnhide(BOOL bEnable = TRUE){ m_bHiddenRowUnhide = bEnable;    }
+    BOOL GetHiddenRowUnhide()                     { return m_bHiddenRowUnhide;        }
+
+    void EnableColumnHide(BOOL bEnable = TRUE)    { m_bAllowColHide = bEnable;        }
+    BOOL GetColumnHide()                          { return m_bAllowColHide;           }
+    void EnableRowHide(BOOL bEnable = TRUE)       { m_bAllowRowHide = bEnable;        }
+    BOOL GetRowHide()                             { return m_bAllowRowHide;           }
+
+///////////////////////////////////////////////////////////////////////////////////
+// default Grid cells. Use these for setting default values such as colors and fonts
+///////////////////////////////////////////////////////////////////////////////////
+public:
+    CGridCellBase* GetDefaultCell(BOOL bFixedRow, BOOL bFixedCol) const;
+
+///////////////////////////////////////////////////////////////////////////////////
+// Grid cell Attributes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+    CGridCellBase* GetCell(int nRow, int nCol) const;   // Get the actual cell!
+
+    void SetModified(BOOL bModified = TRUE, int nRow = -1, int nCol = -1);
+    BOOL GetModified(int nRow = -1, int nCol = -1);
+    BOOL IsCellFixed(int nRow, int nCol);
+
+    BOOL   SetItem(const GV_ITEM* pItem);
+    BOOL   GetItem(GV_ITEM* pItem);
+    BOOL   SetItemText(int nRow, int nCol, LPCTSTR str);
+    // The following was virtual. If you want to override, use 
+    //  CGridCellBase-derived class's GetText() to accomplish same thing
+    CString GetItemText(int nRow, int nCol) const;
+
+    // EFW - 06/13/99 - Added to support printf-style formatting codes.
+    // Also supports use with a string resource ID
+#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
+    BOOL   SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...);
+    BOOL   SetItemTextFmtID(int nRow, int nCol, UINT nID, ...);
+#endif
+
+    BOOL   SetItemData(int nRow, int nCol, LPARAM lParam);
+    LPARAM GetItemData(int nRow, int nCol) const;
+    BOOL   SetItemImage(int nRow, int nCol, int iImage);
+    int    GetItemImage(int nRow, int nCol) const;
+    BOOL   SetItemState(int nRow, int nCol, UINT state);
+    UINT   GetItemState(int nRow, int nCol) const;
+    BOOL   SetItemFormat(int nRow, int nCol, UINT nFormat);
+    UINT   GetItemFormat(int nRow, int nCol) const;
+    BOOL   SetItemBkColour(int nRow, int nCol, COLORREF cr = CLR_DEFAULT);
+    COLORREF GetItemBkColour(int nRow, int nCol) const;
+    BOOL   SetItemFgColour(int nRow, int nCol, COLORREF cr = CLR_DEFAULT);
+    COLORREF GetItemFgColour(int nRow, int nCol) const;
+    BOOL SetItemFont(int nRow, int nCol, const LOGFONT* lf);
+    const LOGFONT* GetItemFont(int nRow, int nCol);
+
+    BOOL IsItemEditing(int nRow, int nCol);
+
+    BOOL SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass);
+    BOOL SetDefaultCellType( CRuntimeClass* pRuntimeClass);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Operations
+///////////////////////////////////////////////////////////////////////////////////
+public:
+    int  InsertColumn(LPCTSTR strHeading, UINT nFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE,
+                      int nColumn = -1);
+    int  InsertRow(LPCTSTR strHeading, int nRow = -1);
+    BOOL DeleteColumn(int nColumn);
+    BOOL DeleteRow(int nRow);
+    BOOL DeleteNonFixedRows();
+    BOOL DeleteAllItems();
+
+	void ClearCells(CCellRange Selection);
+
+    BOOL AutoSizeRow(int nRow, BOOL bResetScroll = TRUE);
+    BOOL AutoSizeColumn(int nCol, UINT nAutoSizeStyle = GVS_DEFAULT, BOOL bResetScroll = TRUE);
+    void AutoSizeRows();
+    void AutoSizeColumns(UINT nAutoSizeStyle = GVS_DEFAULT);
+    void AutoSize(UINT nAutoSizeStyle = GVS_DEFAULT);
+    void ExpandColumnsToFit(BOOL bExpandFixed = TRUE);
+    void ExpandLastColumn();
+    void ExpandRowsToFit(BOOL bExpandFixed = TRUE);
+    void ExpandToFit(BOOL bExpandFixed = TRUE);
+
+    void Refresh();
+    void AutoFill();   // Fill grid with blank cells
+
+    void EnsureVisible(CCellID &cell)       { EnsureVisible(cell.row, cell.col); }
+    void EnsureVisible(int nRow, int nCol);
+    BOOL IsCellVisible(int nRow, int nCol);
+    BOOL IsCellVisible(CCellID cell);
+    BOOL IsCellEditable(int nRow, int nCol) const;
+    BOOL IsCellEditable(CCellID &cell) const;
+    BOOL IsCellSelected(int nRow, int nCol) const;
+    BOOL IsCellSelected(CCellID &cell) const;
+	
+
+    // SetRedraw stops/starts redraws on things like changing the # rows/columns
+    // and autosizing, but not for user-intervention such as resizes
+    void SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars = FALSE);
+    BOOL RedrawCell(int nRow, int nCol, CDC* pDC = NULL);
+    BOOL RedrawCell(const CCellID& cell, CDC* pDC = NULL);
+    BOOL RedrawRow(int row);
+    BOOL RedrawColumn(int col);
+
+#ifndef _WIN32_WCE
+    BOOL Save(LPCTSTR filename, TCHAR chSeparator = _T(','));
+    BOOL Load(LPCTSTR filename, TCHAR chSeparator = _T(','));
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+// Cell Ranges
+///////////////////////////////////////////////////////////////////////////////////
+ public:
+    CCellRange GetCellRange() const;
+    CCellRange GetSelectedCellRange() const;
+    void SetSelectedRange(const CCellRange& Range, BOOL bForceRepaint = FALSE, BOOL bSelectCells = TRUE);
+    void SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
+                          BOOL bForceRepaint = FALSE, BOOL bSelectCells = TRUE);
+    BOOL IsValid(int nRow, int nCol) const;
+    BOOL IsValid(const CCellID& cell) const;
+    BOOL IsValid(const CCellRange& range) const;
+
+///////////////////////////////////////////////////////////////////////////////////
+// Clipboard, drag and drop, and cut n' paste operations
+///////////////////////////////////////////////////////////////////////////////////
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+    virtual void CutSelectedText();
+    virtual COleDataSource* CopyTextFromGrid();
+    virtual BOOL PasteTextToGrid(CCellID cell, COleDataObject* pDataObject, BOOL bSelectPastedCells=TRUE);
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+ public:
+    virtual void OnBeginDrag();
+    virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+    virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+    virtual void OnDragLeave();
+    virtual BOOL OnDrop(COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
+#endif
+
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+    virtual void OnEditCut();
+    virtual void OnEditCopy();
+    virtual void OnEditPaste();
+#endif
+    virtual void OnEditSelectAll();
+
+///////////////////////////////////////////////////////////////////////////////////
+// Misc.
+///////////////////////////////////////////////////////////////////////////////////
+public:
+    CCellID GetNextItem(CCellID& cell, int nFlags) const;
+
+	BOOL SortItems(int nCol, BOOL bAscending, LPARAM data = 0);
+    BOOL SortTextItems(int nCol, BOOL bAscending, LPARAM data = 0);
+    BOOL SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data = 0);
+
+	void SetCompareFunction(PFNLVCOMPARE pfnCompare);
+
+	// in-built sort functions
+	static int CALLBACK pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+	static int CALLBACK pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Printing
+///////////////////////////////////////////////////////////////////////////////////
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+public:
+    void Print(CPrintDialog* pPrntDialog = NULL);
+
+    // EFW - New printing support functions
+    void EnableWysiwygPrinting(BOOL bEnable = TRUE) { m_bWysiwygPrinting = bEnable;     }
+    BOOL GetWysiwygPrinting()                       { return m_bWysiwygPrinting;        }
+
+    void SetShadedPrintOut(BOOL bEnable = TRUE)     {   m_bShadedPrintOut = bEnable;    }
+    BOOL GetShadedPrintOut(void)                    {   return m_bShadedPrintOut;       }
+
+    // Use -1 to have it keep the existing value
+    void SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
+        int nLeftMargin, int nRightMargin, int nTopMargin,
+        int nBottomMargin, int nGap);
+
+    void GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
+        int &nLeftMargin, int &nRightMargin, int &nTopMargin,
+        int &nBottomMargin, int &nGap);
+
+///////////////////////////////////////////////////////////////////////////////////
+// Printing overrides for derived classes
+///////////////////////////////////////////////////////////////////////////////////
+public:
+    virtual void OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo);
+    virtual void OnPrint(CDC *pDC, CPrintInfo *pInfo);
+    virtual void OnEndPrinting(CDC *pDC, CPrintInfo *pInfo);
+
+#endif // #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+
+// Implementation
+public:
+    virtual ~CGridCtrl();
+
+protected:
+    BOOL RegisterWindowClass();
+    BOOL Initialise();
+    void SetupDefaultCells();
+
+    LRESULT SendMessageToParent(int nRow, int nCol, int nMessage) const;
+    LRESULT SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const;
+    LRESULT SendCacheHintToParent(const CCellRange& range) const;
+
+    BOOL InvalidateCellRect(const int row, const int col);
+    BOOL InvalidateCellRect(const CCellID& cell);
+    BOOL InvalidateCellRect(const CCellRange& cellRange);
+    void EraseBkgnd(CDC* pDC);
+
+    BOOL GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect);
+
+    BOOL SetCell(int nRow, int nCol, CGridCellBase* pCell);
+
+    int  SetMouseMode(int nMode) { int nOldMode = m_MouseMode; m_MouseMode = nMode; return nOldMode; }
+    int  GetMouseMode() const    { return m_MouseMode; }
+
+    BOOL MouseOverRowResizeArea(CPoint& point);
+    BOOL MouseOverColumnResizeArea(CPoint& point);
+
+    CCellID GetTopleftNonFixedCell(BOOL bForceRecalculation = FALSE);
+    CCellRange GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation = FALSE);
+	// LUC
+    CCellRange GetVisibleNonFixedCellRange(LPRECT pRect = NULL, BOOL bForceRecalculation = FALSE);
+    CCellRange GetVisibleFixedCellRange(LPRECT pRect = NULL, BOOL bForceRecalculation = FALSE);
+
+    BOOL IsVisibleVScroll() { return ( (m_nBarState & GVL_VERT) > 0); } 
+    BOOL IsVisibleHScroll() { return ( (m_nBarState & GVL_HORZ) > 0); }
+    void ResetSelectedRange();
+    void ResetScrollBars();
+    void EnableScrollBars(int nBar, BOOL bEnable = TRUE);
+    int  GetScrollPos32(int nBar, BOOL bGetTrackPos = FALSE);
+    BOOL SetScrollPos32(int nBar, int nPos, BOOL bRedraw = TRUE);
+
+    BOOL SortTextItems(int nCol, BOOL bAscending, int low, int high);
+    BOOL SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
+                   int low, int high);
+
+    CPoint GetPointClicked(int nRow, int nCol, const CPoint& point);
+
+	void ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText);
+
+// Overrrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CGridCtrl)
+    protected:
+    virtual void PreSubclassWindow();
+    //}}AFX_VIRTUAL
+
+protected:
+#if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
+    // Printing
+	virtual void PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
+                                    CDC *pDC, BOOL& bFirst);
+    virtual void PrintColumnHeadings(CDC *pDC, CPrintInfo *pInfo);
+    virtual void PrintHeader(CDC *pDC, CPrintInfo *pInfo);
+    virtual void PrintFooter(CDC *pDC, CPrintInfo *pInfo);
+    virtual void PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/);
+#endif
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+    // Drag n' drop
+    virtual CImageList* CreateDragImage(CPoint *pHotSpot);    // no longer necessary
+#endif
+
+    // Mouse Clicks
+    virtual void  OnFixedColumnClick(CCellID& cell);
+    virtual void  OnFixedRowClick(CCellID& cell);
+
+    // Editing
+    virtual void  OnEditCell(int nRow, int nCol, CPoint point, UINT nChar);
+    virtual void  OnEndEditCell(int nRow, int nCol, CString str);
+	virtual BOOL  ValidateEdit(int nRow, int nCol, LPCTSTR str);
+    virtual void  EndEditing();
+
+    // Drawing
+    virtual void  OnDraw(CDC* pDC);
+
+    // CGridCellBase Creation and Cleanup
+    virtual CGridCellBase* CreateCell(int nRow, int nCol);
+    virtual void DestroyCell(int nRow, int nCol);
+
+// Attributes
+protected:
+    // General attributes
+    COLORREF    m_crFixedTextColour, m_crFixedBkColour;
+    COLORREF    m_crGridBkColour, m_crGridLineColour;
+    COLORREF    m_crWindowText, m_crWindowColour, m_cr3DFace,     // System colours
+                m_crShadow;
+    COLORREF    m_crTTipBackClr, m_crTTipTextClr;                 // Titletip colours - FNA
+    
+    BOOL        m_bVirtualMode;
+    LPARAM      m_lParam;                                           // lParam for callback
+    GRIDCALLBACK m_pfnCallback;                                     // The callback function
+
+    int         m_nGridLines;
+    BOOL        m_bEditable;
+    BOOL        m_bModified;
+    BOOL        m_bAllowDragAndDrop;
+    BOOL        m_bListMode;
+    BOOL        m_bSingleRowSelection;
+    BOOL        m_bSingleColSelection;
+    BOOL        m_bAllowDraw;
+    BOOL        m_bEnableSelection;
+    BOOL        m_bFixedRowSelection, m_bFixedColumnSelection;
+    BOOL        m_bSortOnClick;
+    BOOL        m_bHandleTabKey;
+    BOOL        m_bDoubleBuffer;
+    BOOL        m_bTitleTips;
+    int         m_nBarState;
+    BOOL        m_bWysiwygPrinting;
+    BOOL        m_bHiddenColUnhide, m_bHiddenRowUnhide;
+    BOOL        m_bAllowColHide, m_bAllowRowHide;
+    BOOL        m_bAutoSizeSkipColHdr;
+    BOOL        m_bTrackFocusCell;
+    BOOL        m_bFrameFocus;
+    UINT        m_nAutoSizeColumnStyle;
+
+	// Cell enable
+	vector<vector<CELL_ENABLE>>	m_pCellEnable;
+
+    // Cell size details
+    int         m_nRows, m_nFixedRows, m_nCols, m_nFixedCols;
+	// LUC
+	int			m_nFreezedRows, m_nFreezedCols;
+	BOOL m_bExcludeFreezedRowsFromSelection;
+	BOOL m_bExcludeFreezedColsFromSelection;
+	
+	// LUC
+	CArray<CCellRange, CCellRange&> m_arMergedCells;
+	// LUC
+	BOOL m_bShowHorzNonGridArea;
+	
+    CUIntArray  m_arRowHeights, m_arColWidths;
+    int         m_nVScrollMax, m_nHScrollMax;
+
+    // Fonts and images
+    CRuntimeClass*   m_pRtcDefault; // determines kind of Grid Cell created by default
+    CGridDefaultCell m_cellDefault;  // "default" cell. Contains default colours, font etc.
+    CGridDefaultCell m_cellFixedColDef, m_cellFixedRowDef, m_cellFixedRowColDef;
+    CFont       m_PrinterFont;  // for the printer
+    CImageList* m_pImageList;
+
+    // Cell data
+    CTypedPtrArray<CObArray, GRID_ROW*> m_RowData;
+
+    // Mouse operations such as cell selection
+    int         m_MouseMode;
+    BOOL        m_bLMouseButtonDown, m_bRMouseButtonDown;
+    CPoint      m_LeftClickDownPoint, m_LastMousePoint;
+    CCellID     m_LeftClickDownCell, m_SelectionStartCell;
+    CCellID     m_idCurrentCell, m_idTopLeftCell;
+    INT_PTR     m_nTimerID;
+    int         m_nTimerInterval;
+    int         m_nResizeCaptureRange;
+    BOOL        m_bAllowRowResize, m_bAllowColumnResize;
+    int         m_nRowsPerWheelNotch;
+    CMap<DWORD,DWORD, CCellID, CCellID&> m_SelectedCellMap, m_PrevSelectedCellMap;
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+    CTitleTip   m_TitleTip;             // Title tips for cells
+#endif
+
+    // Drag and drop
+    CCellID     m_LastDragOverCell;
+#ifndef GRIDCONTROL_NO_DRAGDROP
+    CGridDropTarget m_DropTarget;       // OLE Drop target for the grid
+#endif
+
+    // Printing information
+    CSize       m_CharSize;
+    int         m_nPageHeight;
+    CSize       m_LogicalPageSize,      // Page size in gridctrl units.
+                m_PaperSize;            // Page size in device units.
+    // additional properties to support Wysiwyg printing
+    int         m_nPageWidth;
+    int         m_nPrintColumn;
+    int         m_nCurrPrintRow;
+    int         m_nNumPages;
+    int         m_nPageMultiplier;
+
+    // sorting
+    int          m_bAscending;
+    int          m_nSortColumn;
+	PFNLVCOMPARE m_pfnCompare;
+
+    // EFW - Added to support shaded/unshaded printout.  If true, colored
+    // cells will print as-is.  If false, all text prints as black on white.
+    BOOL        m_bShadedPrintOut;
+
+    // EFW - Added support for user-definable margins.  Top and bottom are in 
+    // lines.  Left, right, and gap are in characters (avg width is used).
+    int         m_nHeaderHeight, m_nFooterHeight, m_nLeftMargin,
+                m_nRightMargin, m_nTopMargin, m_nBottomMargin, m_nGap;
+
+protected:
+    void SelectAllCells();
+    void SelectColumns(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+    void SelectRows(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+    void SelectCells(CCellID currentCell, BOOL bForceRedraw=FALSE, BOOL bSelectCells=TRUE);
+    void OnSelecting(const CCellID& currentCell);
+
+    // Generated message map functions
+    //{{AFX_MSG(CGridCtrl)
+    afx_msg void OnPaint();
+    afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+    afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);
+    afx_msg void OnSize(UINT nType, int cx, int cy);
+    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
+    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+    afx_msg void OnTimer(UINT_PTR nIDEvent);
+    afx_msg UINT OnGetDlgCode();
+    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
+    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
+    afx_msg void OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnUpdateEditSelectAll(CCmdUI* pCmdUI);
+    //}}AFX_MSG
+#ifndef _WIN32_WCE_NO_CURSOR
+    afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+#endif
+#ifndef _WIN32_WCE
+    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
+    afx_msg void OnRButtonUp(UINT nFlags, CPoint point);    // EFW - Added
+    afx_msg void OnSysColorChange();
+#endif
+#ifndef _WIN32_WCE_NO_CURSOR
+    afx_msg void OnCaptureChanged(CWnd *pWnd);
+#endif
+#ifndef GRIDCONTROL_NO_CLIPBOARD
+    afx_msg void OnUpdateEditCopy(CCmdUI* pCmdUI);
+    afx_msg void OnUpdateEditCut(CCmdUI* pCmdUI);
+    afx_msg void OnUpdateEditPaste(CCmdUI* pCmdUI);
+#endif
+#if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
+    afx_msg void OnSettingChange(UINT uFlags, LPCTSTR lpszSection);
+#endif
+#if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
+    afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
+#endif
+    afx_msg LRESULT OnSetFont(WPARAM hFont, LPARAM lParam);
+    afx_msg LRESULT OnGetFont(WPARAM hFont, LPARAM lParam);
+    afx_msg LRESULT OnImeChar(WPARAM wCharCode, LPARAM lParam);
+    afx_msg void OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult);
+	afx_msg void OnComboSelChange(NMHDR* pNMHDR, LRESULT* pResult);
+    DECLARE_MESSAGE_MAP()
+
+    enum eMouseModes { MOUSE_NOTHING, MOUSE_SELECT_ALL, MOUSE_SELECT_COL, MOUSE_SELECT_ROW,
+                       MOUSE_SELECT_CELLS, MOUSE_SCROLLING_CELLS,
+                       MOUSE_OVER_ROW_DIVIDE, MOUSE_SIZING_ROW,
+                       MOUSE_OVER_COL_DIVIDE, MOUSE_SIZING_COL,
+                       MOUSE_PREPARE_EDIT,
+#ifndef GRIDCONTROL_NO_DRAGDROP
+                       MOUSE_PREPARE_DRAG, MOUSE_DRAGGING
+#endif
+    };
+//      for sort in virtual mode, and column order, save and load layer
+public:
+	typedef std::vector<int> intlist;
+	void Reorder(int From, int To);
+	void SetVirtualCompare(PVIRTUALCOMPARE VirtualCompare) { m_pfnVirtualCompare = VirtualCompare;}
+	int m_CurCol;
+	void AllowReorderColumn(bool b=true) { m_AllowReorderColumn = b;}
+	void EnableDragRowMode(bool b=true) { m_bDragRowMode = b; if(b) EnableDragAndDrop(); } // to change row order
+	int GetLayer(int** pLayer); //  gives back the number of ints of the area (do not forget to delete *pLayer)
+	void SetLayer(int* pLayer); // coming from a previous GetLayer (ignored if not same number of column, or the same revision number)
+	void ForceQuitFocusOnTab(bool b=true) { m_QuitFocusOnTab = b;} // use only if GetParent() is a CDialog
+	void AllowSelectRowInFixedCol(bool b=true) { m_AllowSelectRowInFixedCol = b;} // 
+//    allow acces?
+	intlist m_arRowOrder, m_arColOrder;
+	static CGridCtrl* m_This;
+protected:
+	virtual void AddSubVirtualRow(int Num, int Nb);
+	bool m_bDragRowMode;
+	int m_CurRow;
+private:
+	void ResetVirtualOrder();
+	PVIRTUALCOMPARE m_pfnVirtualCompare;
+	static bool NotVirtualCompare(int c1, int c2);
+	bool m_InDestructor;
+	bool m_AllowReorderColumn;
+	bool m_QuitFocusOnTab;
+	bool m_AllowSelectRowInFixedCol;
+
+};
+
+// Returns the default cell implementation for the given grid region
+inline CGridCellBase* CGridCtrl::GetDefaultCell(BOOL bFixedRow, BOOL bFixedCol) const
+{ 
+    if (bFixedRow && bFixedCol) return (CGridCellBase*) &m_cellFixedRowColDef;
+    if (bFixedRow)              return (CGridCellBase*) &m_cellFixedRowDef;
+    if (bFixedCol)              return (CGridCellBase*) &m_cellFixedColDef;
+    return (CGridCellBase*) &m_cellDefault;
+}
+
+inline CGridCellBase* CGridCtrl::GetCell(int nRow, int nCol) const
+{
+	if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) 
+        return NULL;
+	
+    if (GetVirtualMode())
+    {
+        CGridCellBase* pCell = GetDefaultCell(nRow < m_nFixedRows, nCol < m_nFixedCols);
+        static GV_DISPINFO gvdi;
+        gvdi.item.row     = nRow;
+        gvdi.item.col     = nCol;
+        gvdi.item.mask    = 0xFFFFFFFF;
+        gvdi.item.nState  = 0;
+        gvdi.item.nFormat = pCell->GetFormat();
+        gvdi.item.iImage  = pCell->GetImage();
+        gvdi.item.crBkClr = pCell->GetBackClr();
+        gvdi.item.crFgClr = pCell->GetTextClr();
+        gvdi.item.lParam  = pCell->GetData();
+        memcpy(&gvdi.item.lfFont, pCell->GetFont(), sizeof(LOGFONT));
+        gvdi.item.nMargin = pCell->GetMargin();
+        gvdi.item.strText.Empty();
+
+        // Fix the state bits
+        if (IsCellSelected(nRow, nCol))   gvdi.item.nState |= GVIS_SELECTED;
+        if (nRow < GetFixedRowCount())    gvdi.item.nState |= (GVIS_FIXED | GVIS_FIXEDROW);
+        if (nCol < GetFixedColumnCount()) gvdi.item.nState |= (GVIS_FIXED | GVIS_FIXEDCOL);
+        if (GetFocusCell() == CCellID(nRow, nCol)) gvdi.item.nState |= GVIS_FOCUSED;
+		if(!m_InDestructor)
+		{
+			gvdi.item.row = m_arRowOrder[nRow];
+			gvdi.item.col = m_arColOrder[nCol];
+
+			if (m_pfnCallback)
+				m_pfnCallback(&gvdi, m_lParam);
+			else
+				SendDisplayRequestToParent(&gvdi);
+			gvdi.item.row = nRow;        
+			gvdi.item.col = nCol;
+		}
+        static CGridCell cell;
+        cell.SetState(gvdi.item.nState);
+        cell.SetFormat(gvdi.item.nFormat);
+        cell.SetImage(gvdi.item.iImage);
+        cell.SetBackClr(gvdi.item.crBkClr);
+        cell.SetTextClr(gvdi.item.crFgClr);
+        cell.SetData(gvdi.item.lParam);
+        cell.SetFont(&(gvdi.item.lfFont));
+        cell.SetMargin(gvdi.item.nMargin);
+        cell.SetText(gvdi.item.strText);
+        cell.SetGrid((CGridCtrl*)this);
+
+        return (CGridCellBase*) &cell;
+    }
+
+    GRID_ROW* pRow = m_RowData[nRow];
+    if (!pRow) return NULL;
+	if(pRow->GetData() == NULL)
+		return NULL;
+    return pRow->GetAt(m_arColOrder[nCol]);
+}
+
+inline BOOL CGridCtrl::SetCell(int nRow, int nCol, CGridCellBase* pCell)
+{
+    if (GetVirtualMode())
+        return FALSE;
+
+    if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) 
+        return FALSE;
+
+    GRID_ROW* pRow = m_RowData[nRow];
+    if (!pRow) return FALSE;
+
+    pCell->SetCoords( nRow, nCol); 
+    pRow->SetAt(nCol, pCell);
+
+    return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCTRL_H__519FA702_722C_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp b/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp
new file mode 100644
index 0000000..c921abf
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridDropTarget.cpp
@@ -0,0 +1,156 @@
+// GridDropTarget.cpp : implementation file
+//
+// MFC Grid Control - Drag/Drop target implementation
+//
+// CGridDropTarget is an OLE drop target for CGridCtrl. All it does
+// is handle the drag and drop windows messages and pass them
+// directly onto the grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10+
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+
+#ifndef GRIDCONTROL_NO_DRAGDROP
+#include "GridDropTarget.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget
+
+CGridDropTarget::CGridDropTarget()
+{
+    m_pGridCtrl = NULL;
+    m_bRegistered = FALSE;
+}
+
+CGridDropTarget::~CGridDropTarget()
+{
+}
+
+// Overloaded Register() function performs the normal COleDropTarget::Register
+// but also serves to connect this COleDropTarget with the parent grid control,
+// where all drop messages will ultimately be forwarded.
+BOOL CGridDropTarget::Register(CGridCtrl *pGridCtrl)
+{
+    if (m_bRegistered)
+        return FALSE;
+
+    // Stop re-entry problems
+    static BOOL bInProcedure = FALSE;
+    if (bInProcedure)
+        return FALSE;
+    bInProcedure = TRUE;
+
+//    ASSERT(pGridCtrl->IsKindOf(RUNTIME_CLASS(CGridCtrl)));
+//    ASSERT(pGridCtrl);
+
+    if (!pGridCtrl || !pGridCtrl->IsKindOf(RUNTIME_CLASS(CGridCtrl)))
+    {
+        bInProcedure = FALSE;
+        return FALSE;
+    }
+
+    m_pGridCtrl = pGridCtrl;
+
+    m_bRegistered = COleDropTarget::Register(pGridCtrl);
+
+    bInProcedure = FALSE;
+    return m_bRegistered;
+}
+
+void CGridDropTarget::Revoke()
+{
+    m_bRegistered = FALSE;
+    COleDropTarget::Revoke();
+}
+
+BEGIN_MESSAGE_MAP(CGridDropTarget, COleDropTarget)
+    //{{AFX_MSG_MAP(CGridDropTarget)
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget message handlers
+
+DROPEFFECT CGridDropTarget::OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint /*point*/)
+{
+//    TRACE("In CGridDropTarget::OnDragScroll\n");
+    if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+    {
+        if (dwKeyState & MK_CONTROL)
+            return DROPEFFECT_COPY;
+        else
+            return DROPEFFECT_MOVE;
+    } else
+        return DROPEFFECT_NONE;
+}
+
+DROPEFFECT CGridDropTarget::OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, 
+                                        DWORD dwKeyState, CPoint point)
+{
+//    TRACE(_T("In CGridDropTarget::OnDragEnter\n"));
+//    ASSERT(m_pGridCtrl);
+
+    if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+        return m_pGridCtrl->OnDragEnter(pDataObject, dwKeyState, point);
+    else
+        return DROPEFFECT_NONE;
+}
+
+void CGridDropTarget::OnDragLeave(CWnd* pWnd)
+{
+//    TRACE(_T("In CGridDropTarget::OnDragLeave\n"));
+//    ASSERT(m_pGridCtrl);
+
+    if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+        m_pGridCtrl->OnDragLeave();
+}
+
+DROPEFFECT CGridDropTarget::OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, 
+                                       DWORD dwKeyState, CPoint point)
+{
+///    TRACE("In CGridDropTarget::OnDragOver\n");
+//    ASSERT(m_pGridCtrl);
+
+    if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+        return m_pGridCtrl->OnDragOver(pDataObject, dwKeyState, point);
+    else
+        return DROPEFFECT_NONE;
+}
+
+BOOL CGridDropTarget::OnDrop(CWnd* pWnd, COleDataObject* pDataObject,
+                             DROPEFFECT dropEffect, CPoint point)
+{
+//    TRACE(_T("In CGridDropTarget::OnDrop\n"));
+//    ASSERT(m_pGridCtrl);
+
+    if (pWnd->GetSafeHwnd() == m_pGridCtrl->GetSafeHwnd())
+        return m_pGridCtrl->OnDrop(pDataObject, dropEffect, point);
+    else
+        return FALSE;
+}
+
+#endif // GRIDCONTROL_NO_DRAGDROP
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/GridDropTarget.h b/SourceCode/Bond/Servo/GridControl/GridDropTarget.h
new file mode 100644
index 0000000..37788cf
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridDropTarget.h
@@ -0,0 +1,82 @@
+//////////////////////////////////////////////////////////////////////
+// GridDropTarget.h : header file
+//
+// MFC Grid Control - Drag/Drop target implementation
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_)
+#define AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+
+#include <afxole.h>
+
+class CGridCtrl;
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridDropTarget command target
+
+class CGridDropTarget : public COleDropTarget
+{
+public:
+    CGridDropTarget();
+    virtual ~CGridDropTarget();
+
+// Attributes
+public:
+    CGridCtrl* m_pGridCtrl;
+    BOOL       m_bRegistered;
+
+// Operations
+public:
+    BOOL Register(CGridCtrl *pGridCtrl);
+    virtual void Revoke();
+
+    BOOL        OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);
+    DROPEFFECT  OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+    void        OnDragLeave(CWnd* pWnd);
+    DROPEFFECT  OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);
+    DROPEFFECT  OnDragScroll(CWnd* pWnd, DWORD dwKeyState, CPoint point);
+
+// Overrides
+    // ClassWizard generated virtual function overrides
+    //{{AFX_VIRTUAL(CGridDropTarget)
+    //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+    // Generated message map functions
+    //{{AFX_MSG(CGridDropTarget)
+    //}}AFX_MSG
+
+    DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDDROPTARGET_H__5C610981_BD36_11D1_97CD_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp
new file mode 100644
index 0000000..9be4d81
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.cpp
@@ -0,0 +1,262 @@
+// InPlaceEdit.cpp : implementation file
+//
+// Adapted by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// The code contained in this file is based on the original
+// CGridInPlaceEdit from http://www.codeguru.com/listview/edit_subitems.shtml
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10+
+//
+// History:
+//         10 May 1998  Uses GVN_ notifications instead of LVN_,
+//                      Sends notification messages to the parent, 
+//                      instead of the parent's parent.
+//         15 May 1998  There was a problem when editing with the in-place editor, 
+//                      there arises a general protection fault in user.exe, with a 
+//                      few qualifications:
+//                         (1) This only happens with owner-drawn buttons;
+//                         (2) This only happens in Win95
+//                         (3) This only happens if the handler for the button does not 
+//                             create a new window (even an AfxMessageBox will avoid the 
+//                             crash)
+//                         (4) This will not happen if Spy++ is running.
+//                      PreTranslateMessage was added to route messages correctly.
+//                      (Matt Weagle found and fixed this problem)
+//         26 Jul 1998  Removed the ES_MULTILINE style - that fixed a few probs!
+//          6 Aug 1998  Added nID to the constructor param list
+//          6 Sep 1998  Space no longer clears selection when starting edit (Franco Bez)
+//         10 Apr 1999  Enter, Tab and Esc key prob fixed (Koay Kah Hoe)
+//                      Workaround for bizzare "shrinking window" problem in CE
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "TCHAR.h"
+#include "GridCtrl.h"
+#include "GridInPlaceEdit.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit
+
+CGridInPlaceEdit::CGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+                           int nRow, int nColumn, CString sInitText, 
+                           UINT nFirstChar)
+{
+    m_sInitText     = sInitText;
+    m_nRow          = nRow;
+    m_nColumn       = nColumn;
+    m_nLastChar     = 0; 
+    m_bExitOnArrows = (nFirstChar != VK_LBUTTON);    // If mouse click brought us here,
+                                                     // then no exit on arrows
+
+    m_Rect = rect;  // For bizarre CE bug.
+    
+    DWORD dwEditStyle = WS_BORDER|WS_CHILD|WS_VISIBLE| ES_AUTOHSCROLL //|ES_MULTILINE
+        | dwStyle;
+    if (!Create(dwEditStyle, rect, pParent, nID)) return;
+    
+    SetFont(pParent->GetFont());
+    
+    SetWindowText(sInitText);
+    SetFocus();
+    
+    switch (nFirstChar){
+        case VK_LBUTTON: 
+        case VK_RETURN:   SetSel((int)_tcslen(m_sInitText), -1); return;
+        case VK_BACK:     SetSel((int)_tcslen(m_sInitText), -1); break;
+        case VK_TAB:
+        case VK_DOWN: 
+        case VK_UP:   
+        case VK_RIGHT:
+        case VK_LEFT:  
+        case VK_NEXT:  
+        case VK_PRIOR: 
+        case VK_HOME:
+        case VK_SPACE:
+        case VK_END:      SetSel(0,-1); return;
+        default:          SetSel(0,-1);
+    }
+
+    // Added by KiteFly. When entering DBCS chars into cells the first char was being lost
+    // SenMessage changed to PostMessage (John Lagerquist)
+    if( nFirstChar < 0x80)
+        PostMessage(WM_CHAR, nFirstChar);   
+    else
+        PostMessage(WM_IME_CHAR, nFirstChar);
+}
+
+CGridInPlaceEdit::~CGridInPlaceEdit()
+{
+}
+
+BEGIN_MESSAGE_MAP(CGridInPlaceEdit, CEdit)
+    //{{AFX_MSG_MAP(CGridInPlaceEdit)
+    ON_WM_KILLFOCUS()
+    ON_WM_CHAR()
+    ON_WM_KEYDOWN()
+    ON_WM_GETDLGCODE()
+    ON_WM_CREATE()
+    //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit message handlers
+
+// If an arrow key (or associated) is pressed, then exit if
+//  a) The Ctrl key was down, or
+//  b) m_bExitOnArrows == TRUE
+void CGridInPlaceEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+    if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+        nChar == VK_DOWN  || nChar == VK_UP   ||
+        nChar == VK_RIGHT || nChar == VK_LEFT) &&
+        (m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
+    {
+        m_nLastChar = nChar;
+        GetParent()->SetFocus();
+        return;
+    }
+    
+    CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// As soon as this edit loses focus, kill it.
+void CGridInPlaceEdit::OnKillFocus(CWnd* pNewWnd)
+{
+    CEdit::OnKillFocus(pNewWnd);
+    EndEdit();
+}
+
+void CGridInPlaceEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
+{
+    if (nChar == VK_TAB || nChar == VK_RETURN)
+    {
+        m_nLastChar = nChar;
+        GetParent()->SetFocus();    // This will destroy this window
+        return;
+    }
+    if (nChar == VK_ESCAPE) 
+    {
+        SetWindowText(m_sInitText);    // restore previous text
+        m_nLastChar = nChar;
+        GetParent()->SetFocus();
+        return;
+    }
+    
+    CEdit::OnChar(nChar, nRepCnt, nFlags);
+    
+    // Resize edit control if needed
+    
+    // Get text extent
+    CString str;
+    GetWindowText( str );
+
+    // add some extra buffer
+    str += _T("  ");
+    
+    CWindowDC dc(this);
+    CFont *pFontDC = dc.SelectObject(GetFont());
+    CSize size = dc.GetTextExtent( str );
+    dc.SelectObject( pFontDC );
+       
+    // Get client rect
+    CRect ParentRect;
+    GetParent()->GetClientRect( &ParentRect );
+    
+    // Check whether control needs to be resized
+    // and whether there is space to grow
+    if (size.cx > m_Rect.Width())
+    {
+        if( size.cx + m_Rect.left < ParentRect.right )
+            m_Rect.right = m_Rect.left + size.cx;
+        else
+            m_Rect.right = ParentRect.right;
+        MoveWindow( &m_Rect );
+    }
+}
+
+UINT CGridInPlaceEdit::OnGetDlgCode() 
+{
+    return DLGC_WANTALLKEYS;
+}
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit overrides
+
+// Stoopid win95 accelerator key problem workaround - Matt Weagle.
+BOOL CGridInPlaceEdit::PreTranslateMessage(MSG* pMsg) 
+{
+    // Catch the Alt key so we don't choke if focus is going to an owner drawn button
+    if (pMsg->message == WM_SYSCHAR)
+        return TRUE;
+    
+    return CWnd::PreTranslateMessage(pMsg);
+}
+
+// Auto delete
+void CGridInPlaceEdit::PostNcDestroy() 
+{
+    CEdit::PostNcDestroy();
+    
+    delete this;	
+}
+
+////////////////////////////////////////////////////////////////////////////
+// CGridInPlaceEdit implementation
+
+void CGridInPlaceEdit::EndEdit()
+{
+    CString str;
+
+    // EFW - BUG FIX - Clicking on a grid scroll bar in a derived class
+    // that validates input can cause this to get called multiple times
+    // causing assertions because the edit control goes away the first time.
+    static BOOL bAlreadyEnding = FALSE;
+
+    if(bAlreadyEnding)
+        return;
+
+    bAlreadyEnding = TRUE;
+    GetWindowText(str);
+
+    // Send Notification to parent
+    GV_DISPINFO dispinfo;
+
+    dispinfo.hdr.hwndFrom = GetSafeHwnd();
+    dispinfo.hdr.idFrom   = GetDlgCtrlID();
+    dispinfo.hdr.code     = GVN_ENDLABELEDIT;
+
+    dispinfo.item.mask    = LVIF_TEXT|LVIF_PARAM;
+    dispinfo.item.row     = m_nRow;
+    dispinfo.item.col     = m_nColumn;
+    dispinfo.item.strText  = str;
+    dispinfo.item.lParam  = (LPARAM) m_nLastChar;
+
+    CWnd* pOwner = GetOwner();
+    if (pOwner)
+        pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
+
+    // Close this window (PostNcDestroy will delete this)
+    if (IsWindow(GetSafeHwnd()))
+        SendMessage(WM_CLOSE, 0, 0);
+    bAlreadyEnding = FALSE;
+}
diff --git a/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h
new file mode 100644
index 0000000..b26b207
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridInPlaceEdit.h
@@ -0,0 +1,83 @@
+//////////////////////////////////////////////////////////////////////
+// InPlaceEdit.h : header file
+//
+// MFC Grid Control - inplace editing class
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+class CGridInPlaceEdit : public CEdit
+{
+// Construction
+public:
+    CGridInPlaceEdit(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+                 int nRow, int nColumn, CString sInitText, UINT nFirstChar);
+
+// Attributes
+public:
+ 
+// Operations
+public:
+     void EndEdit();
+ 
+// Overrides
+     // ClassWizard generated virtual function overrides
+     //{{AFX_VIRTUAL(CGridInPlaceEdit)
+	public:
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+ 
+// Implementation
+public:
+     virtual ~CGridInPlaceEdit();
+ 
+// Generated message map functions
+protected:
+    //{{AFX_MSG(CGridInPlaceEdit)
+    afx_msg void OnKillFocus(CWnd* pNewWnd);
+    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
+    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg UINT OnGetDlgCode();
+	//}}AFX_MSG
+    DECLARE_MESSAGE_MAP()
+
+private:
+    int     m_nRow;
+    int     m_nColumn;
+    CString m_sInitText;
+    UINT    m_nLastChar;
+    BOOL    m_bExitOnArrows;
+    CRect   m_Rect;
+};
+ 
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_INPLACEEDIT_H__ECD42821_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/GridMemDC.h b/SourceCode/Bond/Servo/GridControl/GridMemDC.h
new file mode 100644
index 0000000..f0f4894
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/GridMemDC.h
@@ -0,0 +1,106 @@
+#if !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
+#define AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+// MemDC.h : header file
+//
+
+//////////////////////////////////////////////////
+// CGridMemDC - memory DC
+//
+// Author: Keith Rule
+// Email:  keithr@europa.com
+// Copyright 1996-1997, Keith Rule
+//
+// You may freely use or modify this code provided this
+// Copyright is included in all derived versions.
+//
+// History - 10/3/97 Fixed scrolling bug.
+//                   Added print support.
+//           25 feb 98 - fixed minor assertion bug
+//
+// This class implements a memory Device Context
+
+class CGridMemDC : public CDC
+{
+public:
+
+    // constructor sets up the memory DC
+    CGridMemDC(CDC* pDC) : CDC()
+    {
+//        ASSERT(pDC != NULL);
+
+        m_pDC = pDC;
+        m_pOldBitmap = NULL;
+#ifndef _WIN32_WCE_NO_PRINTING
+        m_bMemDC = !pDC->IsPrinting();
+#else
+        m_bMemDC = FALSE;
+#endif
+
+        if (m_bMemDC)    // Create a Memory DC
+        {
+            pDC->GetClipBox(&m_rect);
+            CreateCompatibleDC(pDC);
+            m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
+            m_pOldBitmap = SelectObject(&m_bitmap);
+#ifndef _WIN32_WCE
+            SetWindowOrg(m_rect.left, m_rect.top);
+#endif
+            // EFW - Bug fix - Fill background in case the user has overridden
+            // WM_ERASEBKGND.  We end up with garbage otherwise.
+            // CJM - moved to fix a bug in the fix.
+            FillSolidRect(m_rect, pDC->GetBkColor());
+        }
+        else        // Make a copy of the relevent parts of the current DC for printing
+        {
+#if !defined(_WIN32_WCE) || ((_WIN32_WCE > 201) && !defined(_WIN32_WCE_NO_PRINTING))
+            m_bPrinting = pDC->m_bPrinting;
+#endif
+            m_hDC       = pDC->m_hDC;
+            m_hAttribDC = pDC->m_hAttribDC;
+        }
+
+    }
+
+    // Destructor copies the contents of the mem DC to the original DC
+    ~CGridMemDC()
+    {
+        if (m_bMemDC)
+        {
+            // Copy the offscreen bitmap onto the screen.
+            m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
+                          this, m_rect.left, m_rect.top, SRCCOPY);
+
+            //Swap back the original bitmap.
+            SelectObject(m_pOldBitmap);
+        } else {
+            // All we need to do is replace the DC with an illegal value,
+            // this keeps us from accidently deleting the handles associated with
+            // the CDC that was passed to the constructor.
+            m_hDC = m_hAttribDC = NULL;
+        }
+    }
+
+    // Allow usage as a pointer
+    CGridMemDC* operator->() {return this;}
+        
+    // Allow usage as a pointer
+    operator CGridMemDC*() {return this;}
+
+private:
+    CBitmap  m_bitmap;      // Offscreen bitmap
+    CBitmap* m_pOldBitmap;  // bitmap originally found in CGridMemDC
+    CDC*     m_pDC;         // Saves CDC passed in constructor
+    CRect    m_rect;        // Rectangle of drawing area.
+    BOOL     m_bMemDC;      // TRUE if CDC really is a Memory DC.
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_MEMDC_H__CA1D3541_7235_11D1_ABBA_00A0243D1382__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp
new file mode 100644
index 0000000..2db8970
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.cpp
@@ -0,0 +1,185 @@
+// GridCellCheck.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for a combobox cell type of the
+// grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// Parts of the code contained in this file are based on the original
+// CInPlaceList from http://www.codeguru.com/listview
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// 23 Jul 2001 - Complete rewrite
+// 13 Mar 2004 - GetCellExtent and GetCheckPlacement fixed by Yogurt
+//             - Read-only now honoured - Yogurt
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellCheck.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridCellCheck, CGridCell)
+
+CGridCellCheck::CGridCellCheck() : CGridCell()
+{
+    m_bChecked = FALSE;
+    //m_Rect.IsRectNull();
+}
+
+CSize CGridCellCheck::GetCellExtent(CDC* pDC)
+{
+    // Using SM_CXHSCROLL as a guide to the size of the checkbox
+    int nWidth = GetSystemMetrics(SM_CXHSCROLL) + 2*GetMargin();	
+    CSize	cellSize = CGridCell::GetCellExtent(pDC);	
+    cellSize.cx += nWidth;	
+    cellSize.cy = max (cellSize.cy, nWidth);	
+    return  cellSize;
+}
+
+// i/o:  i=dims of cell rect; o=dims of text rect
+BOOL CGridCellCheck::GetTextRect( LPRECT pRect)
+{
+    BOOL bResult = CGridCell::GetTextRect(pRect);
+    if (bResult)
+    {
+        int nWidth = GetSystemMetrics(SM_CXHSCROLL) + 2*GetMargin();
+        pRect->left += nWidth;
+        if (pRect->left > pRect->right)
+            pRect->left = pRect->right;
+    }
+    return bResult;
+}
+
+// Override draw so that when the cell is selected, a drop arrow is shown in the RHS.
+BOOL CGridCellCheck::Draw(CDC* pDC, int nRow, int nCol, CRect rect,  BOOL bEraseBkgnd /*=TRUE*/)
+{
+    BOOL bResult = CGridCell::Draw(pDC, nRow, nCol, rect,  bEraseBkgnd);
+
+#ifndef _WIN32_WCE
+    // Store the cell's dimensions for later
+    m_Rect = rect;
+
+    CRect CheckRect = GetCheckPlacement();
+    rect.left = CheckRect.right;
+
+    // enough room to draw?
+    // if (CheckRect.Width() < rect.Width() && CheckRect.Height() < rect.Height()) {
+
+    // Do the draw 
+    pDC->DrawFrameControl(GetCheckPlacement(), DFC_BUTTON, 
+	    (m_bChecked)? DFCS_BUTTONCHECK | DFCS_CHECKED : DFCS_BUTTONCHECK);
+
+    // }
+#endif
+    return bResult;
+}
+
+void CGridCellCheck::OnClick(CPoint PointCellRelative)
+{
+	// PointCellRelative is relative to the topleft of the cell. Convert to client coords
+	PointCellRelative += m_Rect.TopLeft();
+
+    // Bail if cell is read-only
+    CCellID cell = GetGrid()->GetCellFromPt(PointCellRelative);	
+	if (GetGrid()->isCellMaskActivated(cell.row, cell.col))
+	{
+		if (!GetGrid()->isCellMaskEditable(cell.row, cell.col))
+		{
+			return;
+		}
+	}
+	else
+	{
+		if (!GetGrid()->IsCellEditable(cell))		
+			return;
+	}
+    
+	// GetCheckPlacement returns the checkbox dimensions in client coords. Only check/
+	// uncheck if the user clicked in the box
+	if (GetCheckPlacement().PtInRect(PointCellRelative))
+	{
+		m_bChecked = !m_bChecked;
+		GetGrid()->InvalidateRect(m_Rect);
+	}
+}
+
+//////////////////////////////////////////////////////////////////////
+// Operations
+//////////////////////////////////////////////////////////////////////
+
+BOOL CGridCellCheck::SetCheck(BOOL bChecked /*=TRUE*/)
+{
+	BOOL bTemp = m_bChecked;
+	m_bChecked = bChecked;
+	if (!m_Rect.IsRectEmpty())
+		GetGrid()->InvalidateRect(m_Rect);
+
+	return bTemp;
+}
+
+BOOL CGridCellCheck::GetCheck()
+{
+	return m_bChecked;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Protected implementation
+//////////////////////////////////////////////////////////////////////
+
+// Returns the dimensions and placement of the checkbox in client coords.
+CRect CGridCellCheck::GetCheckPlacement()
+{
+	int nWidth = GetSystemMetrics(SM_CXHSCROLL);
+	CRect place = m_Rect + CSize(GetMargin(), GetMargin());
+    place.right = place.left + nWidth;
+    place.bottom = place.top + nWidth;
+
+	/* for centering
+	int nDiff = (place.Width() - nWidth)/2;
+	if (nDiff > 0)
+	{
+		place.left += nDiff;
+		place.right = place.left + nWidth;
+	}
+	nDiff = (place.Height() - nWidth)/2;
+	if (nDiff > 0)
+	{
+		place.top += nDiff;
+		place.bottom = place.top + nWidth;
+	}
+    */
+
+    if (m_Rect.Height() < nWidth + 2 * static_cast<int> (GetMargin())) 
+    {		
+        place.top = m_Rect.top + (m_Rect.Height() - nWidth) / 2;	    
+        place.bottom = place.top + nWidth;	
+    }
+
+	return place;
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h
new file mode 100644
index 0000000..2a0981f
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCheck.h
@@ -0,0 +1,68 @@
+#if !defined(AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellCheck.h : header file
+//
+// MFC Grid Control - Grid combo cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include "GridCell.h"
+
+
+class CGridCellCheck : public CGridCell
+{
+    friend class CGridCtrl;
+    DECLARE_DYNCREATE(CGridCellCheck)
+
+public:
+    CGridCellCheck();
+
+public:
+	BOOL SetCheck(BOOL bChecked = TRUE);
+	BOOL GetCheck();
+
+// Operations
+	virtual CSize GetCellExtent(CDC* pDC);
+    virtual void OnClick( CPoint PointCellRelative);
+    virtual BOOL GetTextRect( LPRECT pRect);
+
+protected:
+	CRect GetCheckPlacement();
+
+    virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+protected:
+    BOOL  m_bChecked;
+    CRect m_Rect;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLCHECK_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp
new file mode 100644
index 0000000..711b933
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.cpp
@@ -0,0 +1,510 @@
+// GridCellCombo.cpp : implementation file
+//
+// MFC Grid Control - Main grid cell class
+//
+// Provides the implementation for a combobox cell type of the
+// grid control.
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// Parts of the code contained in this file are based on the original
+// CInPlaceList from http://www.codeguru.com/listview
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.22+
+//
+// History:
+// 6 Aug 1998 - Added CComboEdit to subclass the edit control - code 
+//              provided by Roelf Werkman <rdw@inn.nl>. Added nID to 
+//              the constructor param list.
+// 29 Nov 1998 - bug fix in onkeydown (Markus Irtenkauf)
+// 13 Mar 2004 - GetCellExtent fixed by Yogurt
+//
+/////////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCell.h"
+#include "GridCtrl.h"
+#include "GridCellCombo.h"
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit
+
+CComboEdit::CComboEdit()
+{
+}
+
+CComboEdit::~CComboEdit()
+{
+}
+
+// Stoopid win95 accelerator key problem workaround - Matt Weagle.
+BOOL CComboEdit::PreTranslateMessage(MSG* pMsg) 
+{
+	// Make sure that the keystrokes continue to the appropriate handlers
+	if (pMsg->message == WM_KEYDOWN || pMsg->message == WM_KEYUP)
+	{
+		::TranslateMessage(pMsg);
+		::DispatchMessage(pMsg);
+		return TRUE;
+	}	
+
+	// Catch the Alt key so we don't choke if focus is going to an owner drawn button
+	if (pMsg->message == WM_SYSCHAR)
+		return TRUE;
+
+	return CEdit::PreTranslateMessage(pMsg);
+}
+
+BEGIN_MESSAGE_MAP(CComboEdit, CEdit)
+	//{{AFX_MSG_MAP(CComboEdit)
+	ON_WM_KILLFOCUS()
+	ON_WM_KEYDOWN()
+	ON_WM_KEYUP()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit message handlers
+
+void CComboEdit::OnKillFocus(CWnd* pNewWnd) 
+{
+	CEdit::OnKillFocus(pNewWnd);
+	
+    CInPlaceList* pOwner = (CInPlaceList*) GetOwner();  // This MUST be a CInPlaceList
+    if (pOwner)
+        pOwner->EndEdit();	
+}
+
+void CComboEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+		 nChar == VK_DOWN  || nChar == VK_UP   ||
+		 nChar == VK_RIGHT || nChar == VK_LEFT) &&
+		(GetKeyState(VK_CONTROL) < 0 && GetDlgCtrlID() == IDC_COMBOEDIT))
+    {
+        CWnd* pOwner = GetOwner();
+        if (pOwner)
+            pOwner->SendMessage(WM_KEYDOWN, nChar, nRepCnt+ (((DWORD)nFlags)<<16));
+        return;
+    }
+
+	CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+void CComboEdit::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if (nChar == VK_ESCAPE) 
+	{
+        CWnd* pOwner = GetOwner();
+        if (pOwner)
+            pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
+        return;
+    }
+
+	if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+    {
+        CWnd* pOwner = GetOwner();
+        if (pOwner)
+            pOwner->SendMessage(WM_KEYUP, nChar, nRepCnt + (((DWORD)nFlags)<<16));
+        return;
+    }
+
+	CEdit::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList
+
+CInPlaceList::CInPlaceList(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+                           int nRow, int nColumn, 
+                           COLORREF crFore, COLORREF crBack,
+						   CStringArray& Items, CString sInitText, 
+						   UINT nFirstChar)
+{
+    m_crForeClr = crFore;
+    m_crBackClr = crBack;
+
+	m_nNumLines = 4;
+	m_sInitText = sInitText;
+ 	m_nRow		= nRow;
+ 	m_nCol      = nColumn;
+ 	m_nLastChar = 0; 
+	m_bExitOnArrows = FALSE; //(nFirstChar != VK_LBUTTON);	// If mouse click brought us here,
+
+	// Create the combobox
+ 	DWORD dwComboStyle = WS_BORDER|WS_CHILD|WS_VISIBLE|WS_VSCROLL|
+ 					     CBS_AUTOHSCROLL | dwStyle;
+	int nHeight = rect.Height();
+	rect.bottom = rect.bottom + m_nNumLines*nHeight + ::GetSystemMetrics(SM_CYHSCROLL);
+	if (!Create(dwComboStyle, rect, pParent, nID)) return;
+
+	// Add the strings
+	for (int i = 0; i < Items.GetSize(); i++) 
+		AddString(Items[i]);
+
+	SetFont(pParent->GetFont());
+	SetItemHeight(-1, nHeight);
+
+    int nMaxLength = GetCorrectDropWidth();
+    /*
+    if (nMaxLength > rect.Width())
+	    rect.right = rect.left + nMaxLength;
+	// Resize the edit window and the drop down window
+	MoveWindow(rect);
+    */
+
+	SetDroppedWidth(nMaxLength);
+
+	SetHorizontalExtent(0); // no horz scrolling
+
+	// Set the initial text to m_sInitText
+    if (::IsWindow(m_hWnd) && SelectString(-1, m_sInitText) == CB_ERR) 
+		SetWindowText(m_sInitText);		// No text selected, so restore what was there before
+
+    ShowDropDown();
+
+    // Subclass the combobox edit control if style includes CBS_DROPDOWN
+    if ((dwStyle & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST)
+    {
+        m_edit.SubclassDlgItem(IDC_COMBOEDIT, this);
+ 	    SetFocus();
+        switch (nFirstChar)
+        {
+            case VK_LBUTTON: 
+            case VK_RETURN:   m_edit.SetSel((int)_tcslen(m_sInitText), -1); return;
+            case VK_BACK:     m_edit.SetSel((int)_tcslen(m_sInitText), -1); break;
+            case VK_DOWN: 
+            case VK_UP:   
+            case VK_RIGHT:
+            case VK_LEFT:  
+            case VK_NEXT:  
+            case VK_PRIOR: 
+            case VK_HOME:  
+            case VK_END:      m_edit.SetSel(0,-1); return;
+            default:          m_edit.SetSel(0,-1);
+        }
+        SendMessage(WM_CHAR, nFirstChar);
+    }
+    else
+ 	    SetFocus();
+}
+
+CInPlaceList::~CInPlaceList()
+{
+}
+
+void CInPlaceList::EndEdit()
+{
+    CString str;
+    if (::IsWindow(m_hWnd))
+        GetWindowText(str);
+ 
+    // Send Notification to parent
+    GV_DISPINFO dispinfo;
+
+    dispinfo.hdr.hwndFrom = GetSafeHwnd();
+    dispinfo.hdr.idFrom   = GetDlgCtrlID();
+    dispinfo.hdr.code     = GVN_ENDLABELEDIT;
+ 
+    dispinfo.item.mask    = LVIF_TEXT|LVIF_PARAM;
+    dispinfo.item.row     = m_nRow;
+    dispinfo.item.col     = m_nCol;
+    dispinfo.item.strText = str;
+    dispinfo.item.lParam  = (LPARAM) m_nLastChar; 
+ 
+    CWnd* pOwner = GetOwner();
+    if (IsWindow(pOwner->GetSafeHwnd()))
+        pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo );
+ 
+    // Close this window (PostNcDestroy will delete this)
+    if (::IsWindow(m_hWnd))
+        PostMessage(WM_CLOSE, 0, 0);
+}
+
+int CInPlaceList::GetCorrectDropWidth()
+{
+    const int nMaxWidth = 200;  // don't let the box be bigger than this
+
+    // Reset the dropped width
+    int nNumEntries = GetCount();
+    int nWidth = 0;
+    CString str;
+
+    CClientDC dc(this);
+    int nSave = dc.SaveDC();
+    dc.SelectObject(GetFont());
+
+    int nScrollWidth = ::GetSystemMetrics(SM_CXVSCROLL);
+    for (int i = 0; i < nNumEntries; i++)
+    {
+        GetLBText(i, str);
+        int nLength = dc.GetTextExtent(str).cx + nScrollWidth;
+        nWidth = max(nWidth, nLength);
+    }
+    
+    // Add margin space to the calculations
+    nWidth += dc.GetTextExtent(_T("0")).cx;
+
+    dc.RestoreDC(nSave);
+
+    nWidth = min(nWidth, nMaxWidth);
+
+    return nWidth;
+    //SetDroppedWidth(nWidth);
+}
+
+/*
+// Fix by Ray (raybie@Exabyte.COM)
+void CInPlaceList::OnSelendOK() 
+{
+    int iIndex = GetCurSel(); 
+    if( iIndex != CB_ERR) 
+    { 
+        CString strLbText; 
+        GetLBText( iIndex, strLbText); 
+ 
+        if (!((GetStyle() & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)) 
+           m_edit.SetWindowText( strLbText); 
+    } 
+ 
+    GetParent()->SetFocus(); 	
+}
+*/
+
+void CInPlaceList::PostNcDestroy() 
+{
+	CComboBox::PostNcDestroy();
+
+	delete this;
+}
+
+BEGIN_MESSAGE_MAP(CInPlaceList, CComboBox)
+	//{{AFX_MSG_MAP(CInPlaceList)
+	ON_WM_KILLFOCUS()
+	ON_WM_KEYDOWN()
+	ON_WM_KEYUP()
+	ON_CONTROL_REFLECT(CBN_DROPDOWN, OnDropdown)
+	ON_CONTROL_REFLECT(CBN_SELCHANGE, OnSelChange)
+	ON_WM_GETDLGCODE()
+	ON_WM_CTLCOLOR_REFLECT()
+	//}}AFX_MSG_MAP
+	//ON_CONTROL_REFLECT(CBN_SELENDOK, OnSelendOK)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList message handlers
+
+UINT CInPlaceList::OnGetDlgCode() 
+{
+    return DLGC_WANTALLKEYS;
+}
+
+void CInPlaceList::OnDropdown() 
+{
+    SetDroppedWidth(GetCorrectDropWidth());
+}
+
+void CInPlaceList::OnSelChange()
+{
+	CString str;
+	GetLBText(GetCurSel(), str);
+
+	// Send Notification to parent
+	GV_DISPINFO dispinfo;
+
+	dispinfo.hdr.hwndFrom = GetSafeHwnd();
+	dispinfo.hdr.idFrom   = GetDlgCtrlID();
+	dispinfo.hdr.code     = GVN_COMBOSELCHANGE;
+
+	dispinfo.item.mask    = LVIF_TEXT|LVIF_PARAM;
+	dispinfo.item.row     = m_nRow;
+	dispinfo.item.col     = m_nCol;
+	dispinfo.item.strText = str;
+	dispinfo.item.lParam  = (LPARAM) m_nLastChar; 
+
+	CWnd* pOwner = GetOwner();
+	if (IsWindow(pOwner->GetSafeHwnd()))
+		pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo);
+}
+
+void CInPlaceList::OnKillFocus(CWnd* pNewWnd) 
+{
+	CComboBox::OnKillFocus(pNewWnd);
+
+	if (GetSafeHwnd() == pNewWnd->GetSafeHwnd())
+        return;
+
+    // Only end editing on change of focus if we're using the CBS_DROPDOWNLIST style
+    if ((GetStyle() & CBS_DROPDOWNLIST) == CBS_DROPDOWNLIST)
+        EndEdit();
+}
+
+// If an arrow key (or associated) is pressed, then exit if
+//  a) The Ctrl key was down, or
+//  b) m_bExitOnArrows == TRUE
+void CInPlaceList::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if ((nChar == VK_PRIOR || nChar == VK_NEXT ||
+		 nChar == VK_DOWN  || nChar == VK_UP   ||
+		 nChar == VK_RIGHT || nChar == VK_LEFT) &&
+		(m_bExitOnArrows || GetKeyState(VK_CONTROL) < 0))
+	{
+		m_nLastChar = nChar;
+		GetParent()->SetFocus();
+		return;
+	}
+
+	CComboBox::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+// Need to keep a lookout for Tabs, Esc and Returns.
+void CInPlaceList::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if (nChar == VK_ESCAPE) 
+		SetWindowText(m_sInitText);	// restore previous text
+
+	if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+	{
+		m_nLastChar = nChar;
+		GetParent()->SetFocus();	// This will destroy this window
+		return;
+	}
+
+	CComboBox::OnKeyUp(nChar, nRepCnt, nFlags);
+}
+
+HBRUSH CInPlaceList::CtlColor(CDC* /*pDC*/, UINT /*nCtlColor*/) 
+{
+    /*
+    static CBrush brush(m_crBackClr);
+    pDC->SetTextColor(m_crForeClr);
+    pDC->SetBkMode(TRANSPARENT);
+    return (HBRUSH) brush.GetSafeHandle();
+    */
+	
+	// TODO: Return a non-NULL brush if the parent's handler should not be called
+	return NULL;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CGridCellCombo 
+/////////////////////////////////////////////////////////////////////////////
+
+
+IMPLEMENT_DYNCREATE(CGridCellCombo, CGridCell)
+
+CGridCellCombo::CGridCellCombo() : CGridCell()
+{
+    SetStyle(CBS_DROPDOWN);  // CBS_DROPDOWN, CBS_DROPDOWNLIST, CBS_SIMPLE, CBS_SORT
+}
+
+// Create a control to do the editing
+BOOL CGridCellCombo::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+    m_bEditing = TRUE;
+    
+    // CInPlaceList auto-deletes itself
+    m_pEditWnd = new CInPlaceList(GetGrid(), rect, GetStyle(), nID, nRow, nCol, 
+                                  GetTextClr(), GetBackClr(), m_Strings, GetText(), nChar);
+
+    return TRUE;
+}
+
+CWnd* CGridCellCombo::GetEditWnd() const
+{
+	if (m_pEditWnd && (m_pEditWnd->GetStyle() & CBS_DROPDOWNLIST) != CBS_DROPDOWNLIST )
+		return &(((CInPlaceList*)m_pEditWnd)->m_edit);
+
+	return NULL;
+}
+
+
+CSize CGridCellCombo::GetCellExtent(CDC* pDC)
+{    
+    CSize sizeScroll (GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));    
+    CSize sizeCell (CGridCell::GetCellExtent(pDC));    
+    sizeCell.cx += sizeScroll.cx;    
+    sizeCell.cy = max(sizeCell.cy,sizeScroll.cy);    
+    return sizeCell;
+}
+
+// Cancel the editing.
+void CGridCellCombo::EndEdit()
+{
+    if (m_pEditWnd)
+        ((CInPlaceList*)m_pEditWnd)->EndEdit();
+}
+
+// Override draw so that when the cell is selected, a drop arrow is shown in the RHS.
+BOOL CGridCellCombo::Draw(CDC* pDC, int nRow, int nCol, CRect rect,  BOOL bEraseBkgnd /*=TRUE*/)
+{
+#ifdef _WIN32_WCE
+    return CGridCell::Draw(pDC, nRow, nCol, rect,  bEraseBkgnd);
+#else
+    // Cell selected?
+    //if ( !IsFixed() && IsFocused())
+    if (GetGrid()->IsCellEditable(nRow, nCol) && !IsEditing())
+    {
+        // Get the size of the scroll box
+        CSize sizeScroll(GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));
+
+        // enough room to draw?
+        if (sizeScroll.cy < rect.Width() && sizeScroll.cy < rect.Height())
+        {
+            // Draw control at RHS of cell
+            CRect ScrollRect = rect;
+            ScrollRect.left   = rect.right - sizeScroll.cx;
+            ScrollRect.bottom = rect.top + sizeScroll.cy;
+
+            // Do the draw 
+            pDC->DrawFrameControl(ScrollRect, DFC_SCROLL, DFCS_SCROLLDOWN);
+
+            // Adjust the remaining space in the cell
+            rect.right = ScrollRect.left;
+        }
+    }
+
+    CString strTempText = GetText();
+    if (IsEditing())
+        SetText(_T(""));
+
+    // drop through and complete the cell drawing using the base class' method
+    BOOL bResult = CGridCell::Draw(pDC, nRow, nCol, rect,  bEraseBkgnd);
+
+    if (IsEditing())
+        SetText(strTempText);
+
+	return bResult;
+#endif
+}
+
+// For setting the strings that will be displayed in the drop list
+void CGridCellCombo::SetOptions(const CStringArray& ar)
+{ 
+    m_Strings.RemoveAll();
+    for (int i = 0; i < ar.GetSize(); i++)
+        m_Strings.Add(ar[i]);
+}
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h
new file mode 100644
index 0000000..68fc54e
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellCombo.h
@@ -0,0 +1,178 @@
+#if !defined(AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+/////////////////////////////////////////////////////////////////////////////
+// GridCellCombo.h : header file
+//
+// MFC Grid Control - Grid combo cell class header file
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10
+//
+//////////////////////////////////////////////////////////////////////
+
+
+#include "GridCell.h"
+
+
+class CGridCellCombo : public CGridCell
+{
+    friend class CGridCtrl;
+    DECLARE_DYNCREATE(CGridCellCombo)
+
+public:
+    CGridCellCombo();
+
+// editing cells
+public:
+    virtual BOOL  Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+    virtual CWnd* GetEditWnd() const;
+    virtual void  EndEdit();
+
+// Operations
+public:
+	virtual CSize GetCellExtent(CDC* pDC);
+
+// CGridCellCombo specific calls
+public:
+    void  SetOptions(const CStringArray& ar);
+    void  SetStyle(DWORD dwStyle)           { m_dwStyle = dwStyle; }
+    DWORD GetStyle()                        { return m_dwStyle;    }
+
+protected:
+    virtual BOOL Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+
+    CStringArray m_Strings;
+    DWORD        m_dwStyle;
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CComboEdit window
+
+#define IDC_COMBOEDIT 1001
+
+class CComboEdit : public CEdit
+{
+// Construction
+public:
+	CComboEdit();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CComboEdit)
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	virtual ~CComboEdit();
+
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CComboEdit)
+	afx_msg void OnKillFocus(CWnd* pNewWnd);
+	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+	//}}AFX_MSG
+
+	DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceList window
+
+class CInPlaceList : public CComboBox
+{
+    friend class CComboEdit;
+
+// Construction
+public:
+	CInPlaceList(CWnd* pParent,         // parent
+                 CRect& rect,           // dimensions & location
+                 DWORD dwStyle,         // window/combobox style
+                 UINT nID,              // control ID
+                 int nRow, int nColumn, // row and column
+                 COLORREF crFore, COLORREF crBack,  // Foreground, background colour
+				 CStringArray& Items,   // Items in list
+                 CString sInitText,     // initial selection
+				 UINT nFirstChar);      // first character to pass to control
+
+// Attributes
+public:
+   CComboEdit m_edit;  // subclassed edit control
+
+// Operations
+public:
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CInPlaceList)
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	virtual ~CInPlaceList();
+    void EndEdit();
+
+protected:
+    int GetCorrectDropWidth();
+
+// Generated message map functions
+protected:
+	//{{AFX_MSG(CInPlaceList)
+	afx_msg void OnKillFocus(CWnd* pNewWnd);
+	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg void OnDropdown();
+	afx_msg void OnSelChange();
+	afx_msg UINT OnGetDlgCode();
+	afx_msg HBRUSH CtlColor(CDC* pDC, UINT nCtlColor);
+	//}}AFX_MSG
+	//afx_msg void OnSelendOK();
+
+	DECLARE_MESSAGE_MAP()
+
+private:
+	int		 m_nNumLines;
+	CString  m_sInitText;
+	int		 m_nRow;
+	int		 m_nCol;
+ 	UINT     m_nLastChar; 
+	BOOL	 m_bExitOnArrows; 
+    COLORREF m_crForeClr, m_crBackClr;
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_GRIDCELLCOMBO_H__ECD42822_16DF_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp
new file mode 100644
index 0000000..f643042
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.cpp
@@ -0,0 +1,268 @@
+///////////////////////////////////////////////////////////////////////////
+//
+// GridCellDateTime.cpp: implementation of the CGridCellDateTime class.
+//
+// Provides the implementation for a datetime picker cell type of the
+// grid control.
+//
+// Written by Podsypalnikov Eugen 15 Mar 2001
+// Modified:
+//    31 May 2001  Fixed m_cTime bug (Chris Maunder)
+//
+// For use with CGridCtrl v2.22+
+//
+///////////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellDateTime.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static const char* THIS_FILE=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// CGridCellDateTime
+
+IMPLEMENT_DYNCREATE(CGridCellDateTime, CGridCell)
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CGridCellDateTime::CGridCellDateTime() : CGridCell()
+{
+	m_dwStyle = 0;
+	m_cTime   = CTime::GetCurrentTime();
+}
+
+CGridCellDateTime::CGridCellDateTime(DWORD dwStyle) : CGridCell()
+{
+	Init(dwStyle);
+}
+
+CGridCellDateTime::~CGridCellDateTime()
+{
+}
+
+CSize CGridCellDateTime::GetCellExtent(CDC* pDC)
+{    
+    CSize sizeScroll (GetSystemMetrics(SM_CXVSCROLL), GetSystemMetrics(SM_CYHSCROLL));	
+    CSize sizeCell (CGridCell::GetCellExtent(pDC));	
+    sizeCell.cx += sizeScroll.cx;	
+    sizeCell.cy = max(sizeCell.cy,sizeScroll.cy);	
+    return sizeCell;
+}
+
+BOOL CGridCellDateTime::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, 
+							 UINT nID, UINT nChar)
+{
+	m_bEditing = TRUE;
+
+	// CInPlaceDateTime auto-deletes itself
+	m_pEditWnd = new CInPlaceDateTime(GetGrid(), rect,
+		m_dwStyle|DTS_UPDOWN, nID, nRow, nCol, 
+		GetTextClr(), GetBackClr(), GetTime(), nChar);
+	return TRUE;
+}
+
+CWnd* CGridCellDateTime::GetEditWnd() const
+{
+	return m_pEditWnd;
+}
+
+void CGridCellDateTime::EndEdit()
+{
+	if (m_pEditWnd) ((CInPlaceDateTime*)m_pEditWnd)->EndEdit();
+}
+
+void CGridCellDateTime::Init(DWORD dwStyle)
+{
+	m_dwStyle = dwStyle;
+
+	SetTime(CTime::GetCurrentTime());
+
+	SetFormat(DT_CENTER|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX
+#ifndef _WIN32_WCE
+		|DT_END_ELLIPSIS
+#endif
+		);
+}
+
+// Should be changed to use locale settings
+void CGridCellDateTime::SetTime(CTime time)
+{
+	m_cTime = time;
+
+	if (DTS_TIMEFORMAT == m_dwStyle) 
+	{
+#ifdef _WIN32_WCE
+		CString strTemp;
+		strTemp.Format(_T("%02d:%02d:%02d"), 
+			           m_cTime.GetHour(), m_cTime.GetMinute(), m_cTime.GetSecond());
+		SetText(strTemp);
+#else
+
+//		SetText(m_cTime.Format(_T("%H:%M:%S")));
+    	SetText(m_cTime.Format(_T("%X")));
+#endif
+	}
+	else if (DTS_SHORTDATEFORMAT == m_dwStyle) 
+	{
+#ifdef _WIN32_WCE
+		CString strTemp;
+		strTemp.Format(_T("%02d/%02d/%02d"), 
+			           m_cTime.GetMonth(), m_cTime.GetDay(), m_cTime.GetYear());
+		SetText(strTemp);
+#else
+//		SetText(m_cTime.Format(("%d/%m/%Y")));
+		SetText(m_cTime.Format(("%x")));
+#endif
+	}
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceDateTime
+
+CInPlaceDateTime::CInPlaceDateTime(CWnd* pParent, CRect& rect, DWORD dwStyle, UINT nID,
+								   int nRow, int nColumn, 
+								   COLORREF crFore, COLORREF crBack,
+								   CTime* pcTime,
+								   UINT nFirstChar)
+{
+	m_crForeClr     = crFore;
+	m_crBackClr     = crBack;
+	m_nRow          = nRow;
+	m_nCol          = nColumn;
+	m_nLastChar     = 0; 
+	m_bExitOnArrows = FALSE;
+	m_pcTime        = pcTime;
+
+	DWORD dwStl = WS_BORDER|WS_VISIBLE|WS_CHILD|dwStyle;
+
+	if (!Create(dwStl, rect, pParent, nID)) {
+		return;
+	}
+
+	SetTime(m_pcTime);
+
+	SetFont(pParent->GetFont());
+	SetFocus();
+
+	switch (nFirstChar) 
+	{
+		case VK_LBUTTON: 
+		case VK_RETURN: return;
+		case VK_BACK:   break;
+		case VK_DOWN: 
+		case VK_UP:   
+		case VK_RIGHT:
+		case VK_LEFT:  
+		case VK_NEXT:  
+		case VK_PRIOR: 
+		case VK_HOME:  
+		case VK_END:    return;
+		default:        break;
+	}
+	SendMessage(WM_CHAR, nFirstChar);
+}
+
+CInPlaceDateTime::~CInPlaceDateTime()
+{
+}
+
+void CInPlaceDateTime::EndEdit()
+{
+	CString str;
+	if (::IsWindow(m_hWnd)) 
+	{
+		GetWindowText(str);
+		GetTime(*m_pcTime);
+	}
+
+	// Send Notification to parent
+	GV_DISPINFO dispinfo;
+
+	dispinfo.hdr.hwndFrom = GetSafeHwnd();
+	dispinfo.hdr.idFrom   = GetDlgCtrlID();
+	dispinfo.hdr.code     = GVN_ENDLABELEDIT;
+
+	dispinfo.item.mask    = LVIF_TEXT|LVIF_PARAM;
+	dispinfo.item.row     = m_nRow;
+	dispinfo.item.col     = m_nCol;
+	dispinfo.item.strText = str;
+	dispinfo.item.lParam  = (LPARAM) m_nLastChar; 
+
+	CWnd* pOwner = GetOwner();
+	if (IsWindow(pOwner->GetSafeHwnd())) {
+		pOwner->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&dispinfo);
+	}
+
+	// Close this window (PostNcDestroy will delete this)
+	if (::IsWindow(m_hWnd)) {
+		PostMessage(WM_CLOSE, 0, 0);
+	}
+}
+
+void CInPlaceDateTime::PostNcDestroy() 
+{
+	CDateTimeCtrl::PostNcDestroy();
+	delete this;
+}
+
+BEGIN_MESSAGE_MAP(CInPlaceDateTime, CDateTimeCtrl)
+	//{{AFX_MSG_MAP(CInPlaceDateTime)
+	ON_WM_KILLFOCUS()
+	ON_WM_KEYDOWN()
+	ON_WM_KEYUP()
+	ON_WM_GETDLGCODE()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CInPlaceDateTime message handlers
+
+void CInPlaceDateTime::OnKillFocus(CWnd* pNewWnd) 
+{
+	CDateTimeCtrl::OnKillFocus(pNewWnd);
+
+	if (GetSafeHwnd() == pNewWnd->GetSafeHwnd()) {
+		return;
+	}
+	EndEdit();
+}
+
+UINT CInPlaceDateTime::OnGetDlgCode() 
+{
+	return DLGC_WANTALLKEYS;
+}
+
+void CInPlaceDateTime::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if (( nChar == VK_PRIOR || nChar == VK_NEXT ||
+		nChar == VK_DOWN  || nChar == VK_UP   ||
+		nChar == VK_RIGHT || nChar == VK_LEFT) &&
+		(m_bExitOnArrows  || GetKeyState(VK_CONTROL) < 0))
+	{
+		m_nLastChar = nChar;
+		GetParent()->SetFocus();
+		return;
+	}
+
+	CDateTimeCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
+}
+
+void CInPlaceDateTime::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
+{
+	if (nChar == VK_TAB || nChar == VK_RETURN || nChar == VK_ESCAPE)
+	{
+		m_nLastChar = nChar;
+		GetParent()->SetFocus();    // This will destroy this window
+		return;
+	}
+
+	CDateTimeCtrl::OnKeyUp(nChar, nRepCnt, nFlags);
+}
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h
new file mode 100644
index 0000000..e7d9c1c
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellDateTime.h
@@ -0,0 +1,92 @@
+// GridCellDateTime.h: interface for the CGridCellDateTime class.
+//
+// Provides the implementation for a datetime picker cell type of the
+// grid control.
+//
+// For use with CGridCtrl v2.22+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_)
+#define AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+#include "afxdtctl.h"	// for CDateTimeCtrl
+
+class CGridCellDateTime : public CGridCell  
+{
+  friend class CGridCtrl;
+  DECLARE_DYNCREATE(CGridCellDateTime)
+
+  CTime m_cTime;
+  DWORD m_dwStyle;
+
+public:
+	CGridCellDateTime();
+	CGridCellDateTime(DWORD dwStyle);
+	virtual ~CGridCellDateTime();
+    virtual CSize GetCellExtent(CDC* pDC);
+
+  // editing cells
+public:
+	void Init(DWORD dwStyle);
+	virtual BOOL  Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+	virtual CWnd* GetEditWnd() const;
+	virtual void  EndEdit();
+
+
+	CTime* GetTime() {return &m_cTime;};
+	void   SetTime(CTime time);
+};
+
+class CInPlaceDateTime : public CDateTimeCtrl
+{
+// Construction
+public:
+	CInPlaceDateTime(CWnd* pParent,         // parent
+                   CRect& rect,           // dimensions & location
+                   DWORD dwStyle,         // window/combobox style
+                   UINT nID,              // control ID
+                   int nRow, int nColumn, // row and column
+                   COLORREF crFore, COLORREF crBack,  // Foreground, background colour
+                   CTime* pcTime,
+          		   UINT nFirstChar);      // first character to pass to control
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CInPlaceList)
+	protected:
+	virtual void PostNcDestroy();
+	//}}AFX_VIRTUAL
+
+// Implementation
+public:
+	virtual ~CInPlaceDateTime();
+    void EndEdit();
+
+// Generated message map functions
+protected:
+	//{{AFX_MSG(CInPlaceList)
+	afx_msg void OnKillFocus(CWnd* pNewWnd);
+	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
+	afx_msg UINT OnGetDlgCode();
+	//}}AFX_MSG
+	//afx_msg void OnSelendOK();
+
+	DECLARE_MESSAGE_MAP()
+
+private:
+    CTime*   m_pcTime;
+	int		 m_nRow;
+	int		 m_nCol;
+ 	UINT     m_nLastChar; 
+	BOOL	 m_bExitOnArrows; 
+    COLORREF m_crForeClr, m_crBackClr;
+};
+
+#endif // !defined(AFX_DATETIMECELL_H__A0B7DA0A_0AFE_4D28_A00E_846C96D7507A__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp
new file mode 100644
index 0000000..96cc411
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.cpp
@@ -0,0 +1,42 @@
+// GridCellNumeric.cpp: implementation of the CGridCellNumeric class.
+//
+// Written by Andrew Truckle [ajtruckle@wsatkins.co.uk]
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridCellNumeric.h"
+#include "Gridinplaceedit.h"
+
+IMPLEMENT_DYNCREATE(CGridCellNumeric, CGridCell)
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static const char* THIS_FILE=__FILE__;
+#define new DEBUG_NEW
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+// Create a control to do the editing
+BOOL CGridCellNumeric::Edit(int nRow, int nCol, CRect rect, CPoint /* point */, UINT nID, UINT nChar)
+{
+    m_bEditing = TRUE;
+    
+    // CGridInPlaceEdit auto-deletes itself
+    m_pEditWnd = new CGridInPlaceEdit(GetGrid(), rect, /*GetStyle() |*/ ES_NUMBER, nID, nRow, nCol,
+		GetText(), nChar);
+
+    return TRUE;
+}
+
+// Cancel the editing.
+void CGridCellNumeric::EndEdit()
+{
+    if (m_pEditWnd)
+        ((CGridInPlaceEdit*)m_pEditWnd)->EndEdit();
+}
+
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h
new file mode 100644
index 0000000..3f6086a
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridCellNumeric.h
@@ -0,0 +1,26 @@
+// GridCellNumeric.h: interface for the CGridCellNumeric class.
+//
+// Written by Andrew Truckle [ajtruckle@wsatkins.co.uk]
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_)
+#define AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+
+class CGridCellNumeric : public CGridCell  
+{
+    DECLARE_DYNCREATE(CGridCellNumeric)
+
+public:
+    virtual BOOL Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+    virtual void EndEdit();
+
+};
+
+#endif // !defined(AFX_GRIDINTEGERCELL_H__3479ED0D_B57D_4940_B83D_9E2296ED75B5__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp
new file mode 100644
index 0000000..891ead0
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.cpp
@@ -0,0 +1,212 @@
+// GridURLCell.cpp: implementation of the CGridURLCell class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#include "stdafx.h"
+#include "GridCtrl.h"
+#include "GridURLCell.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CGridURLCell, CGridCell)
+
+#ifndef _WIN32_WCE
+HCURSOR CGridURLCell::g_hLinkCursor = NULL;
+#endif
+
+// Possible prefixes that indicate a hyperlink
+URLStruct CGridURLCell::g_szURIprefixes[] = { 
+    { _T("www."),    _tcslen(_T("www."))    },
+    { _T("http:"),   _tcslen(_T("http:"))   },
+    { _T("mailto:"), _tcslen(_T("mailto:")) },
+    { _T("ftp:"),    _tcslen(_T("ftp:"))    },
+    { _T("https:"),  _tcslen(_T("https:"))  },
+    { _T("news:"),   _tcslen(_T("news:"))   },
+    { _T("gopher:"), _tcslen(_T("gopher:")) },
+    { _T("telnet:"), _tcslen(_T("telnet:")) },
+    { _T("url:"),    _tcslen(_T("url:"))    },
+    { _T("file:"),   _tcslen(_T("file:"))   },
+    { _T("ftp."),    _tcslen(_T("ftp."))    }
+};
+
+//////////////////////////////////////////////////////////////////////
+// Construction/Destruction
+//////////////////////////////////////////////////////////////////////
+
+CGridURLCell::CGridURLCell()
+{
+#ifndef _WIN32_WCE
+    g_hLinkCursor = GetHandCursor();
+#endif
+	m_bLaunchUrl = TRUE;
+	m_clrUrl = GetSysColor(COLOR_HIGHLIGHT);
+}
+
+CGridURLCell::~CGridURLCell()
+{
+}
+
+BOOL CGridURLCell::Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd)
+{
+	// If url is present then change text color
+	if (HasUrl(GetText()))
+		SetTextClr(m_clrUrl);
+
+    // Good a place as any to store the bounds of the rect
+    m_Rect = rect;
+
+    return CGridCell::Draw(pDC, nRow, nCol, rect, bEraseBkgnd);
+}
+
+#pragma warning(disable:4100)
+BOOL CGridURLCell::Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar)
+{
+    return FALSE;
+}
+#pragma warning(default:4100)
+
+void CGridURLCell::OnClick(CPoint PointCellRelative)
+{
+#ifndef _WIN32_WCE
+    CString strURL;
+    if (GetAutoLaunchUrl() && OverURL(PointCellRelative, strURL))
+		ShellExecute(NULL, _T("open"), strURL, NULL,NULL, SW_SHOW);
+#endif
+}
+
+// Return TRUE if you set the cursor
+BOOL CGridURLCell::OnSetCursor()
+{
+#ifndef _WIN32_WCE
+    CString strURL;
+    CPoint pt(GetMessagePos());
+    GetGrid()->ScreenToClient(&pt);
+    pt = pt - m_Rect.TopLeft();
+
+    if (OverURL(pt, strURL))
+    {
+        SetCursor(g_hLinkCursor);
+		return TRUE;
+	}
+	else
+#endif
+		return CGridCell::OnSetCursor();
+}
+
+#ifndef _WIN32_WCE
+HCURSOR CGridURLCell::GetHandCursor()
+{
+	if (g_hLinkCursor == NULL)		// No cursor handle - load our own
+	{
+        // Get the windows directory
+		CString strWndDir;
+		GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
+		strWndDir.ReleaseBuffer();
+
+		strWndDir += _T("\\winhlp32.exe");
+		// This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
+		HMODULE hModule = LoadLibrary(strWndDir);
+		if( hModule )
+		{
+			HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
+			if( hHandCursor )
+			{
+				g_hLinkCursor = CopyCursor(hHandCursor);
+			}
+		}
+		FreeLibrary(hModule);
+	}
+
+	return g_hLinkCursor;
+}
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////////////
+// Helper functions
+
+BOOL CGridURLCell::HasUrl(CString str)
+{
+    int nNumPrefixes = sizeof(g_szURIprefixes) / sizeof(g_szURIprefixes[0]);
+    for (int i = 0; i < nNumPrefixes; i++)
+        //if (str.Left(g_szURIprefixes[i].nLength) == g_szURIprefixes[i].szURLPrefix)
+        if (str.Find(g_szURIprefixes[i].szURLPrefix) >= 0)
+            return TRUE;
+
+    return FALSE;
+}
+
+// here we figure out if we are over a URL or not
+BOOL CGridURLCell::OverURL(CPoint& pt, CString& strURL)
+{
+    //TRACE2("Checking point %d,%d\n",pt.x,pt.y);
+
+	BOOL bOverURL = FALSE;
+	CSize size = GetTextExtent(GetText());
+
+	// Add left of cell so we know if we clicked on text or not
+	pt.x += m_Rect.left;
+	CPoint center = m_Rect.CenterPoint();
+
+	if ((m_nFormat & DT_RIGHT) && pt.x >= (m_Rect.right - size.cx))
+	{
+		bOverURL = TRUE;
+	}	
+	else if ((m_nFormat & DT_CENTER) && 
+             ((center.x - (size.cx/2)) <= pt.x) && (pt.x <= (center.x + (size.cx/2))) )
+	{
+		bOverURL = TRUE;
+	}
+	else if (pt.x <= (size.cx + m_Rect.left))
+	{
+		bOverURL = TRUE;
+	}
+
+    if (!bOverURL)
+        return FALSE;
+
+    // We are over text - but are we over a URL?
+	bOverURL = FALSE;
+	strURL = GetText();
+
+	// Use float, otherwise we get an incorrect letter from the point
+	float width = (float)size.cx/(float)strURL.GetLength();
+
+	// remove left of cell so we have original point again 
+	pt.x -= m_Rect.left;
+	if (m_nFormat & DT_RIGHT)
+	{
+		int wide = m_Rect.Width() - size.cx;
+		pt.x -= wide;
+		if (pt.x <= 0)
+			return FALSE;
+	}
+
+	if (m_nFormat & DT_CENTER)
+	{
+		int wide = m_Rect.Width() - size.cx;
+		pt.x -= (wide/2);
+		if (pt.x <= 0 || pt.x > (size.cx + (wide/2)))
+			return FALSE;
+	}
+
+	// Turn point into a letter
+	int ltrs = (int)((float)pt.x/width);
+#if  !defined(_WIN32_WCE) || (_WIN32_WCE > 210)
+	// Find spaces before and after letter, process text between
+	int endSpace = strURL.Find(_T(' '), ltrs);
+	if (endSpace != -1)
+		strURL.Delete(endSpace, strURL.GetLength()-endSpace);
+
+	int beginSpace = strURL.ReverseFind(_T(' '));
+	if (beginSpace != -1)
+		strURL.Delete(0, ++beginSpace);
+#endif
+
+	// Does text have url
+	return HasUrl(strURL);
+}
+
diff --git a/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h
new file mode 100644
index 0000000..1960250
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/NewCellTypes/GridURLCell.h
@@ -0,0 +1,55 @@
+// GridURLCell.h: interface for the CGridURLCell class.
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_)
+#define AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif // _MSC_VER > 1000
+
+#include "GridCell.h"
+
+typedef struct {
+    LPCTSTR szURLPrefix;
+    size_t  nLength;
+} URLStruct;
+
+
+
+class CGridURLCell : public CGridCell  
+{
+    DECLARE_DYNCREATE(CGridURLCell)
+
+public:
+	CGridURLCell();
+	virtual ~CGridURLCell();
+
+    virtual BOOL     Draw(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBkgnd = TRUE);
+    virtual BOOL     Edit(int nRow, int nCol, CRect rect, CPoint point, UINT nID, UINT nChar);
+    virtual LPCTSTR  GetTipText() { return NULL; }
+	void SetAutoLaunchUrl(BOOL bLaunch = TRUE) { m_bLaunchUrl = bLaunch;	}
+	BOOL GetAutoLaunchUrl() { return m_bLaunchUrl;	}
+
+protected:
+    virtual BOOL OnSetCursor();
+    virtual void OnClick(CPoint PointCellRelative);
+
+	BOOL HasUrl(CString str);
+    BOOL OverURL(CPoint& pt, CString& strURL);
+
+protected:
+#ifndef _WIN32_WCE
+    static HCURSOR g_hLinkCursor;		// Hyperlink mouse cursor
+	HCURSOR GetHandCursor();
+#endif
+    static URLStruct g_szURIprefixes[];
+
+protected:
+	COLORREF m_clrUrl;
+	BOOL     m_bLaunchUrl;
+    CRect    m_Rect;
+};
+
+#endif // !defined(AFX_GRIDURLCELL_H__9F4A50B4_D773_11D3_A439_F7E60631F563__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/GridControl/TitleTip.cpp b/SourceCode/Bond/Servo/GridControl/TitleTip.cpp
new file mode 100644
index 0000000..b821a82
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/TitleTip.cpp
@@ -0,0 +1,341 @@
+////////////////////////////////////////////////////////////////////////////
+// TitleTip.cpp : implementation file
+//
+// Based on code by Zafir Anjum
+//
+// Adapted by Chris Maunder <cmaunder@mail.com>
+// Copyright (c) 1998-2002. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.20+
+//
+// History
+//         10 Apr 1999  Now accepts a LOGFONT pointer and 
+//                      a tracking rect in Show(...)  (Chris Maunder)
+//         18 Apr 1999  Resource leak in Show fixed by Daniel Gehriger
+//          8 Mar 2000  Added double-click fix found on codeguru
+//                      web site but forgot / can't find who contributed it
+//         28 Mar 2000  Aqiruse (marked with //FNA)
+//                      Titletips now use cell color
+//         18 Jun 2000  Delayed window creation added
+//
+/////////////////////////////////////////////////////////////////////////////
+ 
+#include "stdafx.h"
+#include "gridctrl.h"
+
+#ifndef GRIDCONTROL_NO_TITLETIPS
+
+#include "TitleTip.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static const char* THIS_FILE = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip
+
+CTitleTip::CTitleTip()
+{
+	// Register the window class if it has not already been registered.
+	WNDCLASS wndcls;
+	HINSTANCE hInst = AfxGetInstanceHandle();
+	if(!(::GetClassInfo(hInst, TITLETIP_CLASSNAME, &wndcls)))
+	{
+		// otherwise we need to register a new class
+		wndcls.style			= CS_SAVEBITS;
+		wndcls.lpfnWndProc		= ::DefWindowProc;
+		wndcls.cbClsExtra		= wndcls.cbWndExtra = 0;
+		wndcls.hInstance		= hInst;
+		wndcls.hIcon			= NULL;
+		wndcls.hCursor			= LoadCursor( hInst, IDC_ARROW );
+		wndcls.hbrBackground	= (HBRUSH)(COLOR_INFOBK +1);
+		wndcls.lpszMenuName		= NULL;
+		wndcls.lpszClassName	= TITLETIP_CLASSNAME;
+
+		if (!AfxRegisterClass(&wndcls))
+			AfxThrowResourceException();
+	}
+
+    m_dwLastLButtonDown = ULONG_MAX;
+    m_dwDblClickMsecs   = GetDoubleClickTime();
+    m_bCreated          = FALSE;
+    m_pParentWnd        = NULL;
+}
+
+CTitleTip::~CTitleTip()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CTitleTip, CWnd)
+	//{{AFX_MSG_MAP(CTitleTip)
+	ON_WM_MOUSEMOVE()
+	//}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip message handlers
+
+BOOL CTitleTip::Create(CWnd * pParentWnd)
+{
+//	ASSERT_VALID(pParentWnd);
+
+    // Already created?
+    if (m_bCreated)
+        return TRUE;
+
+	DWORD dwStyle = WS_BORDER | WS_POPUP; 
+	DWORD dwExStyle = WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
+	m_pParentWnd = pParentWnd;
+
+	m_bCreated = CreateEx(dwExStyle, TITLETIP_CLASSNAME, NULL, dwStyle, 
+                          CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 
+		                  NULL, NULL, NULL );
+
+    return m_bCreated;
+}
+
+BOOL CTitleTip::DestroyWindow() 
+{
+    m_bCreated = FALSE;
+	
+	return CWnd::DestroyWindow();
+}
+
+// Show 		 - Show the titletip if needed
+// rectTitle	 - The rectangle within which the original 
+//				    title is constrained - in client coordinates
+// lpszTitleText - The text to be displayed
+// xoffset		 - Number of pixel that the text is offset from
+//				   left border of the cell
+void CTitleTip::Show(CRect rectTitle, LPCTSTR lpszTitleText, int xoffset /*=0*/,
+                     LPRECT lpHoverRect /*=NULL*/,
+                     const LOGFONT* lpLogFont /*=NULL*/,
+                     COLORREF crTextClr /* CLR_DEFAULT */,
+                     COLORREF crBackClr /* CLR_DEFAULT */)
+{
+    if (!IsWindow(m_hWnd))
+        Create(m_pParentWnd);
+
+//	ASSERT( ::IsWindow( GetSafeHwnd() ) );
+
+    if (rectTitle.IsRectEmpty())
+        return;
+
+	// If titletip is already displayed, don't do anything.
+	if( IsWindowVisible() ) 
+		return;
+
+    m_rectHover = (lpHoverRect != NULL)? lpHoverRect : rectTitle;
+    m_rectHover.right++; m_rectHover.bottom++;
+
+	m_pParentWnd->ClientToScreen( m_rectHover );
+    ScreenToClient( m_rectHover );
+
+	// Do not display the titletip is app does not have focus
+	if( GetFocus() == NULL )
+		return;
+
+	// Define the rectangle outside which the titletip will be hidden.
+	// We add a buffer of one pixel around the rectangle
+	m_rectTitle.top    = -1;
+	m_rectTitle.left   = -xoffset-1;
+	m_rectTitle.right  = rectTitle.Width()-xoffset;
+	m_rectTitle.bottom = rectTitle.Height()+1;
+
+	// Determine the width of the text
+	m_pParentWnd->ClientToScreen( rectTitle );
+
+	CClientDC dc(this);
+	CString strTitle = _T("");
+    strTitle += _T(" ");
+    strTitle += lpszTitleText; 
+    strTitle += _T(" ");
+
+	CFont font, *pOldFont = NULL;
+    if (lpLogFont)
+    {
+        font.CreateFontIndirect(lpLogFont);
+	    pOldFont = dc.SelectObject( &font );
+    }
+    else
+    {
+        // use same font as ctrl
+	    pOldFont = dc.SelectObject( m_pParentWnd->GetFont() );
+    }
+
+	CSize size = dc.GetTextExtent( strTitle );
+
+    TEXTMETRIC tm;
+    dc.GetTextMetrics(&tm);
+    size.cx += tm.tmOverhang;
+
+	CRect rectDisplay = rectTitle;
+	rectDisplay.left += xoffset;
+	rectDisplay.right = rectDisplay.left + size.cx + xoffset;
+    
+    // Do not display if the text fits within available space
+    if ( rectDisplay.right > rectTitle.right-xoffset )
+    {
+		// Show the titletip
+        SetWindowPos( &wndTop, rectDisplay.left, rectDisplay.top, 
+            rectDisplay.Width(), rectDisplay.Height(), 
+            SWP_SHOWWINDOW|SWP_NOACTIVATE );
+        
+        // FNA - handle colors correctly
+        if (crBackClr != CLR_DEFAULT)
+        {
+		    CBrush backBrush(crBackClr);
+		    CBrush* pOldBrush = dc.SelectObject(&backBrush);
+		    CRect rect;
+		    dc.GetClipBox(&rect);     // Erase the area needed 
+
+		    dc.PatBlt(rect.left, rect.top, rect.Width(), rect.Height(),  PATCOPY);
+		    dc.SelectObject(pOldBrush);
+	    }
+        // Set color
+        if (crTextClr != CLR_DEFAULT)//FNA
+            dc.SetTextColor(crTextClr);//FA
+
+        dc.SetBkMode( TRANSPARENT );
+        dc.TextOut( 0, 0, strTitle );
+        SetCapture();
+    }
+    
+    dc.SelectObject( pOldFont );
+}
+
+void CTitleTip::Hide()
+{
+  	if (!::IsWindow(GetSafeHwnd()))
+        return;
+
+    if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
+        ReleaseCapture();
+
+	ShowWindow( SW_HIDE );
+}
+
+void CTitleTip::OnMouseMove(UINT nFlags, CPoint point) 
+{
+    if (!m_rectHover.PtInRect(point)) 
+    {
+        Hide();
+        
+        // Forward the message
+        ClientToScreen( &point );
+        CWnd *pWnd = WindowFromPoint( point );
+        if ( pWnd == this ) 
+            pWnd = m_pParentWnd;
+        
+        int hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
+        
+        if (hittest == HTCLIENT) {
+            pWnd->ScreenToClient( &point );
+            pWnd->PostMessage( WM_MOUSEMOVE, nFlags, MAKELONG(point.x,point.y) );
+        } else {
+            pWnd->PostMessage( WM_NCMOUSEMOVE, hittest, MAKELONG(point.x,point.y) );
+        }
+    }
+}
+
+BOOL CTitleTip::PreTranslateMessage(MSG* pMsg) 
+{
+    // Used to qualify WM_LBUTTONDOWN messages as double-clicks
+    DWORD dwTick=0;
+    BOOL bDoubleClick=FALSE;
+
+    CWnd *pWnd;
+	int hittest;
+	switch (pMsg->message)
+	{
+	case WM_LBUTTONDOWN:
+       // Get tick count since last LButtonDown
+        dwTick = GetTickCount();
+        bDoubleClick = ((dwTick - m_dwLastLButtonDown) <= m_dwDblClickMsecs);
+        m_dwLastLButtonDown = dwTick;
+        // NOTE: DO NOT ADD break; STATEMENT HERE! Let code fall through
+
+	case WM_RBUTTONDOWN:
+	case WM_MBUTTONDOWN:
+		{
+		POINTS pts = MAKEPOINTS( pMsg->lParam );
+		POINT  point;
+		point.x = pts.x;
+		point.y = pts.y;
+
+		ClientToScreen( &point );
+        Hide();
+
+		pWnd = WindowFromPoint( point );
+		if (!pWnd)
+			return CWnd::PreTranslateMessage(pMsg);
+
+		if( pWnd->GetSafeHwnd() == GetSafeHwnd()) 
+			pWnd = m_pParentWnd;
+
+		hittest = (int)pWnd->SendMessage(WM_NCHITTEST,0,MAKELONG(point.x,point.y));
+
+		if (hittest == HTCLIENT) 
+		{
+			pWnd->ScreenToClient( &point );
+			pMsg->lParam = MAKELONG(point.x,point.y);
+		}
+		else 
+		{
+			switch (pMsg->message) {
+			case WM_LBUTTONDOWN: 
+				pMsg->message = WM_NCLBUTTONDOWN;
+				break;
+			case WM_RBUTTONDOWN: 
+				pMsg->message = WM_NCRBUTTONDOWN;
+				break;
+			case WM_MBUTTONDOWN: 
+				pMsg->message = WM_NCMBUTTONDOWN;
+				break;
+			}
+			pMsg->wParam = hittest;
+			pMsg->lParam = MAKELONG(point.x,point.y);
+		}
+
+
+        // If this is the 2nd WM_LBUTTONDOWN in x milliseconds,
+        // post a WM_LBUTTONDBLCLK message instead of a single click.
+        pWnd->PostMessage(  bDoubleClick ? WM_LBUTTONDBLCLK : pMsg->message,
+                            pMsg->wParam,
+                            pMsg->lParam);
+		return TRUE;
+		}
+		
+	case WM_KEYDOWN:
+	case WM_SYSKEYDOWN:
+        Hide();
+		m_pParentWnd->PostMessage( pMsg->message, pMsg->wParam, pMsg->lParam );
+		return TRUE;
+	}
+
+	if( GetFocus() == NULL )
+	{
+        Hide();
+		return TRUE;
+	}
+
+	return CWnd::PreTranslateMessage(pMsg);
+}
+
+#endif // GRIDCONTROL_NO_TITLETIPS
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/GridControl/TitleTip.h b/SourceCode/Bond/Servo/GridControl/TitleTip.h
new file mode 100644
index 0000000..63d6d47
--- /dev/null
+++ b/SourceCode/Bond/Servo/GridControl/TitleTip.h
@@ -0,0 +1,87 @@
+/////////////////////////////////////////////////////////////////////////////
+// Titletip.h : header file
+//
+// MFC Grid Control - cell titletips
+//
+// Written by Chris Maunder <chris@codeproject.com>
+// Copyright (c) 1998-2005. All Rights Reserved.
+//
+// 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. 
+//
+// An email letting me know how 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.
+//
+// For use with CGridCtrl v2.10+
+//
+//////////////////////////////////////////////////////////////////////
+
+#if !defined(AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_)
+#define AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_
+
+#if _MSC_VER >= 1000
+#pragma once
+#endif // _MSC_VER >= 1000
+
+#define TITLETIP_CLASSNAME _T("ZTitleTip")
+
+/////////////////////////////////////////////////////////////////////////////
+// CTitleTip window
+
+class CTitleTip : public CWnd
+{
+// Construction
+public:
+	CTitleTip();
+	virtual ~CTitleTip();
+	virtual BOOL Create( CWnd *pParentWnd);
+
+// Attributes
+public:
+    void SetParentWnd(CWnd* pParentWnd)  { m_pParentWnd = pParentWnd; }
+    CWnd* GetParentWnd()                 { return m_pParentWnd;       }
+
+// Operations
+public:
+	void Show(CRect rectTitle, LPCTSTR lpszTitleText, 
+              int xoffset = 0, LPRECT lpHoverRect = NULL, 
+              const LOGFONT* lpLogFont = NULL,
+              COLORREF crTextClr = CLR_DEFAULT, COLORREF crBackClr = CLR_DEFAULT);
+    void Hide();
+
+// Overrides
+	// ClassWizard generated virtual function overrides
+	//{{AFX_VIRTUAL(CTitleTip)
+	public:
+	virtual BOOL PreTranslateMessage(MSG* pMsg);
+	virtual BOOL DestroyWindow();
+	//}}AFX_VIRTUAL
+
+// Implementation
+protected:
+	CWnd  *m_pParentWnd;
+	CRect  m_rectTitle;
+    CRect  m_rectHover;
+    DWORD  m_dwLastLButtonDown;
+    DWORD  m_dwDblClickMsecs;
+    BOOL   m_bCreated;
+
+	// Generated message map functions
+protected:
+	//{{AFX_MSG(CTitleTip)
+	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+	//}}AFX_MSG
+	DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+//{{AFX_INSERT_LOCATION}}
+// Microsoft Developer Studio will insert additional declarations immediately before the previous line.
+
+#endif // !defined(AFX_TITLETIP_H__C7165DA1_187F_11D1_992F_895E185F9C72__INCLUDED_)
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.cpp b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
new file mode 100644
index 0000000..9c88a9f
--- /dev/null
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.cpp
@@ -0,0 +1,74 @@
+锘�// PortConfigurationDlg.cpp: 瀹炵幇鏂囦欢
+//
+
+#include "stdafx.h"
+#include "Servo.h"
+#include "afxdialogex.h"
+#include "PortConfigurationDlg.h"
+
+
+// CPortConfigurationDlg 瀵硅瘽妗�
+
+IMPLEMENT_DYNAMIC(CPortConfigurationDlg, CDialogEx)
+
+CPortConfigurationDlg::CPortConfigurationDlg(CWnd* pParent /*=nullptr*/)
+	: CDialogEx(IDD_DIALOG_PORT_CONFIGURATION, pParent)
+{
+
+}
+
+CPortConfigurationDlg::~CPortConfigurationDlg()
+{
+}
+
+void CPortConfigurationDlg::DoDataExchange(CDataExchange* pDX)
+{
+	CDialogEx::DoDataExchange(pDX);
+}
+
+
+BEGIN_MESSAGE_MAP(CPortConfigurationDlg, CDialogEx)
+END_MESSAGE_MAP()
+
+
+// CPortConfigurationDlg 娑堟伅澶勭悊绋嬪簭
+
+BOOL CPortConfigurationDlg::OnInitDialog()
+{
+	CDialogEx::OnInitDialog();
+
+	// TODO:  鍦ㄦ娣诲姞棰濆鐨勫垵濮嬪寲
+        // 缁戝畾鑷畾涔夋帶浠讹紙蹇呴』涓庤祫婧愪腑鐨� ID 涓�鑷达級
+    m_wndGrid.SubclassDlgItem(IDC_GRID_PANEL_RECIPE, this);
+
+    // 璁剧疆琛屽垪鏁�
+    m_wndGrid.SetRowCount(9);        // 鍖呮嫭琛ㄥご1琛� + 鏁版嵁8琛�
+    m_wndGrid.SetColumnCount(4);
+
+    // 璁剧疆鍥哄畾鐨勮〃澶磋
+    m_wndGrid.SetFixedRowCount(1);
+    m_wndGrid.SetFixedColumnCount(0);
+
+    // 璁剧疆鍒楁爣棰�
+    m_wndGrid.SetItemText(0, 0, _T("Slot ID"));
+    m_wndGrid.SetItemText(0, 1, _T("EQ Recipe"));
+    m_wndGrid.SetItemText(0, 2, _T("Panel ID"));
+    m_wndGrid.SetItemText(0, 3, _T("鉁�"));
+
+    // 璁剧疆鍒楀
+    m_wndGrid.SetColumnWidth(0, 60);
+    m_wndGrid.SetColumnWidth(1, 150);
+    m_wndGrid.SetColumnWidth(2, 150);
+    m_wndGrid.SetColumnWidth(3, 40);
+
+    // 濉厖鏁版嵁琛�
+    for (int i = 1; i <= 8; ++i)
+    {
+        CString str;
+        str.Format(_T("%d"), i);
+        m_wndGrid.SetItemText(i, 0, str);
+    }
+
+	return TRUE;  // return TRUE unless you set the focus to a control
+	// 寮傚父: OCX 灞炴�ч〉搴旇繑鍥� FALSE
+}
diff --git a/SourceCode/Bond/Servo/PortConfigurationDlg.h b/SourceCode/Bond/Servo/PortConfigurationDlg.h
new file mode 100644
index 0000000..a016273
--- /dev/null
+++ b/SourceCode/Bond/Servo/PortConfigurationDlg.h
@@ -0,0 +1,27 @@
+锘�#pragma once
+#include "afxdialogex.h"
+#include "GridCtrl.h"
+
+// CPortConfigurationDlg 瀵硅瘽妗�
+
+class CPortConfigurationDlg : public CDialogEx
+{
+	DECLARE_DYNAMIC(CPortConfigurationDlg)
+
+public:
+	CPortConfigurationDlg(CWnd* pParent = nullptr);   // 鏍囧噯鏋勯�犲嚱鏁�
+	virtual ~CPortConfigurationDlg();
+
+// 瀵硅瘽妗嗘暟鎹�
+#ifdef AFX_DESIGN_TIME
+	enum { IDD = IDD_DIALOG_PORT_CONFIGURATION };
+#endif
+
+protected:
+	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 鏀寔
+	virtual BOOL OnInitDialog();
+	DECLARE_MESSAGE_MAP()
+
+private:
+	CGridCtrl m_wndGrid;
+};
diff --git a/SourceCode/Bond/Servo/Servo.rc b/SourceCode/Bond/Servo/Servo.rc
index 7bdf825..35bed87 100644
--- a/SourceCode/Bond/Servo/Servo.rc
+++ b/SourceCode/Bond/Servo/Servo.rc
Binary files differ
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj b/SourceCode/Bond/Servo/Servo.vcxproj
index 8fac7f2..21de14d 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj
+++ b/SourceCode/Bond/Servo/Servo.vcxproj
@@ -115,7 +115,7 @@
       <Optimization>Disabled</Optimization>
       <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <SDLCheck>true</SDLCheck>
-      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+      <AdditionalIncludeDirectories>.;..;..\DatabaseSDK\include;..\MELSECSDK\include;.\CCLinkPerformance;.\GridControl;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ClCompile>
     <Link>
       <SubSystem>Windows</SubSystem>
@@ -204,6 +204,20 @@
     <ClInclude Include="CRobotCmdTestDlg.h" />
     <ClInclude Include="CPagePortStatus.h" />
     <ClInclude Include="CPortStatusReport.h" />
+    <ClInclude Include="GridControl\CellRange.h" />
+    <ClInclude Include="GridControl\GridCell.h" />
+    <ClInclude Include="GridControl\GridCellBase.h" />
+    <ClInclude Include="GridControl\GridCellButton.h" />
+    <ClInclude Include="GridControl\GridCtrl.h" />
+    <ClInclude Include="GridControl\GridDropTarget.h" />
+    <ClInclude Include="GridControl\GridInPlaceEdit.h" />
+    <ClInclude Include="GridControl\GridMemDC.h" />
+    <ClInclude Include="GridControl\NewCellTypes\GridCellCheck.h" />
+    <ClInclude Include="GridControl\NewCellTypes\GridCellCombo.h" />
+    <ClInclude Include="GridControl\NewCellTypes\GridCellDateTime.h" />
+    <ClInclude Include="GridControl\NewCellTypes\GridCellNumeric.h" />
+    <ClInclude Include="GridControl\NewCellTypes\GridURLCell.h" />
+    <ClInclude Include="GridControl\TitleTip.h" />
     <ClInclude Include="JobSlotGrid.h" />
     <ClInclude Include="MsgDlg.h" />
     <ClInclude Include="PageRecipe.h" />
@@ -290,6 +304,7 @@
     <ClInclude Include="MapPosWnd.h" />
     <ClInclude Include="Model.h" />
     <ClInclude Include="PageRobotCmd.h" />
+    <ClInclude Include="PortConfigurationDlg.h" />
     <ClInclude Include="ProductionLogManager.h" />
     <ClInclude Include="Resource.h" />
     <ClInclude Include="SECSRuntimeManager.h" />
@@ -311,6 +326,18 @@
     <ClCompile Include="CRobotCmdTestDlg.cpp" />
     <ClCompile Include="CPagePortStatus.cpp" />
     <ClCompile Include="CPortStatusReport.cpp" />
+    <ClCompile Include="GridControl\GridCell.cpp" />
+    <ClCompile Include="GridControl\GridCellBase.cpp" />
+    <ClCompile Include="GridControl\GridCellButton.cpp" />
+    <ClCompile Include="GridControl\GridCtrl.cpp" />
+    <ClCompile Include="GridControl\GridDropTarget.cpp" />
+    <ClCompile Include="GridControl\GridInPlaceEdit.cpp" />
+    <ClCompile Include="GridControl\NewCellTypes\GridCellCheck.cpp" />
+    <ClCompile Include="GridControl\NewCellTypes\GridCellCombo.cpp" />
+    <ClCompile Include="GridControl\NewCellTypes\GridCellDateTime.cpp" />
+    <ClCompile Include="GridControl\NewCellTypes\GridCellNumeric.cpp" />
+    <ClCompile Include="GridControl\NewCellTypes\GridURLCell.cpp" />
+    <ClCompile Include="GridControl\TitleTip.cpp" />
     <ClCompile Include="JobSlotGrid.cpp" />
     <ClCompile Include="MsgDlg.cpp" />
     <ClCompile Include="PageRecipe.cpp" />
@@ -396,6 +423,7 @@
     <ClCompile Include="MapPosWnd.cpp" />
     <ClCompile Include="Model.cpp" />
     <ClCompile Include="PageRobotCmd.cpp" />
+    <ClCompile Include="PortConfigurationDlg.cpp" />
     <ClCompile Include="ProductionLogManager.cpp" />
     <ClCompile Include="SECSRuntimeManager.cpp" />
     <ClCompile Include="SecsTestDlg.cpp" />
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.filters b/SourceCode/Bond/Servo/Servo.vcxproj.filters
index 68273f0..b2ae64c 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.filters
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.filters
@@ -112,6 +112,43 @@
     <ClCompile Include="MsgDlg.cpp" />
     <ClCompile Include="CPagePortStatus.cpp" />
     <ClCompile Include="JobSlotGrid.cpp" />
+    <ClCompile Include="GridControl\GridCell.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\GridCellBase.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\GridCellButton.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\GridCtrl.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\GridDropTarget.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\GridInPlaceEdit.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\TitleTip.cpp">
+      <Filter>GridControl</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\NewCellTypes\GridCellCheck.cpp">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\NewCellTypes\GridCellCombo.cpp">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\NewCellTypes\GridCellDateTime.cpp">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\NewCellTypes\GridCellNumeric.cpp">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="GridControl\NewCellTypes\GridURLCell.cpp">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClCompile>
+    <ClCompile Include="PortConfigurationDlg.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="AlarmManager.h" />
@@ -223,6 +260,49 @@
     <ClInclude Include="CPagePortStatus.h" />
     <ClInclude Include="ServoCommo.h" />
     <ClInclude Include="JobSlotGrid.h" />
+    <ClInclude Include="GridControl\CellRange.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridCell.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridCellBase.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridCellButton.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridCtrl.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridDropTarget.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridInPlaceEdit.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\GridMemDC.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\TitleTip.h">
+      <Filter>GridControl</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\NewCellTypes\GridCellCheck.h">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\NewCellTypes\GridCellCombo.h">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\NewCellTypes\GridCellDateTime.h">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\NewCellTypes\GridCellNumeric.h">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClInclude>
+    <ClInclude Include="GridControl\NewCellTypes\GridURLCell.h">
+      <Filter>GridControl\NewCellTypes</Filter>
+    </ClInclude>
+    <ClInclude Include="PortConfigurationDlg.h" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="Servo.rc" />
@@ -241,5 +321,11 @@
     <Filter Include="CCLinkPerformance">
       <UniqueIdentifier>{77338295-9841-4706-8816-a958b1b5c465}</UniqueIdentifier>
     </Filter>
+    <Filter Include="GridControl">
+      <UniqueIdentifier>{1206b229-6054-40f2-8d8a-5848582a3896}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="GridControl\NewCellTypes">
+      <UniqueIdentifier>{52ebd40d-fb71-4a53-93ab-5b93670c706d}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
 </Project>
\ No newline at end of file
diff --git a/SourceCode/Bond/Servo/Servo.vcxproj.user b/SourceCode/Bond/Servo/Servo.vcxproj.user
index 405156d..0c03257 100644
--- a/SourceCode/Bond/Servo/Servo.vcxproj.user
+++ b/SourceCode/Bond/Servo/Servo.vcxproj.user
@@ -4,8 +4,8 @@
     <RESOURCE_FILE>Servo.rc</RESOURCE_FILE>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
-    <RemoteDebuggerCommand>D:\Servo\Debug\Servo.exe</RemoteDebuggerCommand>
-    <RemoteDebuggerWorkingDirectory>D:\Servo\Debug\</RemoteDebuggerWorkingDirectory>
+    <RemoteDebuggerCommand>\\DESKTOP-IODBVIQ\Servo\Debug\Servo.exe</RemoteDebuggerCommand>
+    <RemoteDebuggerWorkingDirectory>\\DESKTOP-IODBVIQ\Servo\Debug\</RemoteDebuggerWorkingDirectory>
     <RemoteDebuggerServerName>DESKTOP-IODBVIQ</RemoteDebuggerServerName>
     <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
   </PropertyGroup>
diff --git a/SourceCode/Bond/Servo/resource.h b/SourceCode/Bond/Servo/resource.h
index 3b75c47..0987ed3 100644
--- a/SourceCode/Bond/Servo/resource.h
+++ b/SourceCode/Bond/Servo/resource.h
Binary files differ

--
Gitblit v1.9.3