自己写的GRID控件源码(源文件)

本文档提供了一个自定义GRID控件的源码,包含消息定义、结构体和内部函数实现,用于理解控件的工作原理和进行二次开发。源码中详细定义了各种常量、结构体成员以及数据处理函数,例如列宽调整、颜色设置、数据获取与设置等。

#include "stdafx.h"
#include "common.h"
#include "RRGrid.h"

 

 

//内部消息定义
#define GM_LOAD_GRID      WM_GRID_USER_INNER + 1
#define GM_SAVE_GRID     WM_GRID_USER_INNER+2
#define GM_SET_EDIT_TEXT    WM_GRID_USER_INNER+3
#define GM_GET_EDIT_TEXT    WM_GRID_USER_INNER+4
#define GM_GET_TITLE_TEXT    WM_GRID_USER_INNER+5

#define ROWS_MAX 32000//不包括第0行
#define COLS_MAX 256 //不包括第0列

#define CELL_TEXT_MAX    512
#define DATA_SYMBOL_LEN   12

#define LINE_BORDER_SIZE 6

#define CURSOR_ARROW  1
#define CURSOR_DRAG  2//改变列宽时光标状态
#define CURSOR_EDITING  3

//RR_GridCtrl_GetLogicColOnScreen 参数/返回值描述
#define RR_PARAM_MASk       0x0F
#define RR_PARAM_START_COLNO       0x00
#define RR_PARAM_END_COLNO     0x01
#define RR_RESULT_MASK       0xF0
#define RR_RESULT_HALF       0x00
#define RR_RESULT_INTACT      0x10

#define RR_GRID_FILE_HEAD      "RRGrid"
#define RR_STRUCT_SIZE_MAX      1300

 

typedef struct _tagGrid
{
 HWND hWnd;
 HWND hChildEdit;
 
 StringLink_T  *ptTextLink;

 UINT nGridId;
 
 HFONT hbodyfont;//第0列和数据单元采用一样的字体
 HFONT hheadfont;//标题字体
 HFONT htitlefont;//第0行字体

 HBRUSH hEditBackBrush;

 //栅格线颜色
 COLORREF crGridLine;
 
 //标题/第0行/0列文本颜色
 COLORREF crTextTitle;

 //画刷颜色(未选择高亮时,选择行画刷颜色跟其他行一样)
 COLORREF crBrushReadOnly;//只读时的颜色
 COLORREF crBrushCommon;//一般状态颜色
 //高亮:Grid有焦点时选择行画刷颜色
 COLORREF crBrushLight;
 //高亮: Grid无焦点时选择行画刷颜色
 COLORREF crBrushGray;

 //每个画刷颜色有一个文本颜色与之相配
 COLORREF crTextReadOnly;
 COLORREF crTextCommon;
 COLORREF crTextLight;
 COLORREF crTextGray;
 
 char *pszTitle;

 int titleheight;//标题高度
 int headerrowheight;//第0行高度(没有第0行,该值为0)
 int rowheight; //行高等高
 int columnwidths[COLS_MAX+1];//列宽不等宽
 int gridHeight;//客户区域高
 int gridWidth;//客户区域宽

 GridCell_T tEditCell;//当前正在编辑的逻辑单元
 int rows;//行数(包括第0行)
 int cols;//列数(包括第0列)
 int homerow;
 int homecol;//逻辑列号,指示横向滚动条当前位置所对应的左边第一列(不包括第0列,最小值为1)
 int leftvisiblecol; //逻辑列号,指示当前显示的左边第一列(为0(最小值)时表示当前没有显示的数据单元)
 int rightvisiblecol;
 int topvisiblerow;//逻辑行号
 int bottomvisiblerow;
 int sel_row;

 DWORD dwStyle;

 BOOL bCellModified;//单元内容被修改标志
 BOOL bRowModified;//行内容被修改标志
 BOOL bGridTextModified;//Grid内容被修改标志
 BOOL bGridFrameModified;
 
 //内部使用的一些状态变量
 int adjust_height;//bShowIntegralRow为TRUE时累计调整的高度
 BOOL bColumnSizing;//列宽正在改变中
 int resizeColumn;//改变列宽时使用
 int columnInitSize;//改变列宽时使用
 int columnInitx;//改变列宽时使用
 int cursortype;
 BOOL bGridHasFocus;//当前Grid获得焦点
 BOOL bSizing; //正在响应WM_SIZE
 BOOL bShowHScroll;//是否显示横向滚动条
 BOOL bShowVScroll; //是否显示纵向滚动条
 BOOL bEditing;//正在编辑中


 //默认值
 int init_rows;//行数(包括第0行)
 int init_cols;//列数(包括第0列)
 DWORD dwInitStyle;
} Grid_T;

typedef struct _tagGridSaveStruct
{
 COLORREF crGridLine;
 COLORREF crTextTitle;//Roger: 暂未提供接口修改
 COLORREF crBrushReadOnly;//只读时的颜色
 COLORREF crBrushCommon;//一般状态颜色
 COLORREF crBrushLight;
 COLORREF crBrushGray;
 COLORREF crTextReadOnly;
 COLORREF crTextCommon;
 COLORREF crTextLight;
 COLORREF crTextGray;
 int titleheight;//标题高度//Roger: 标题高度由标题文本确定
 int headerrowheight;//第0行高度(没有第0行,该值为0)
 int rowheight; //行高等高
 int columnwidths[COLS_MAX+1];//列宽不等宽
 int rows;//行数(包括第0行)
 int cols;//列数(包括第0列)
 int homerow; //单单homerow/homecol改变,不置Grid修改标志
 int homecol;//逻辑列号,指示横向滚动条当前位置所对应的左边第一列(不包括第0列,最小值为1)
 int sel_row;

 DWORD dwStyle;

}GridSaveStruct_T;

static BOOL RR_GridCtrl_Exit_Edit(HWND hWnd);
static BOOL RR_GridCtrl_Enter_Edit(HWND hWnd,GridCell_T*ptCell,int iSetSel);
static int RR_GridCtrl_GetNextNthColWithWidth(Grid_T * pGridData, int startcol, int direction);
static LRESULT RR_GridCtrlOnVScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
static int RR_GridCtrl_ChgSelRow(HWND hWnd,int new_row);
static void RR_GridCtrl_CalcVisibleCellBoundaries(Grid_T * pGridData);
static BOOL RR_GridCtrl_Discard_Edit(HWND hWnd);
static BOOL RR_GridCtrl_Force_Exit_Edit(HWND hWnd);


typedef   long  (__stdcall   *CELLEDIT_PROC_T)(HWND,UINT,WPARAM,LPARAM);  
static CELLEDIT_PROC_T OriginalEditProc;

 


////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
//
static BOOL RR_GridCtrl_CopyStruct(GridSaveStruct_T *pSaveStruct,Grid_T* pGridData,BOOL bFirstIsDest)
{
 
 if(pGridData==NULL || pSaveStruct == NULL )
 {
  return FALSE;
 }

 if(bFirstIsDest)
 {
  memcpy(pSaveStruct->columnwidths,pGridData->columnwidths,sizeof(pGridData->columnwidths));

  pSaveStruct->crGridLine = pGridData->crGridLine;
  pSaveStruct->crTextTitle = pGridData->crTextTitle;
  pSaveStruct->crBrushReadOnly = pGridData->crBrushReadOnly;
  pSaveStruct->crBrushCommon = pGridData->crBrushCommon;
  pSaveStruct->crBrushLight = pGridData->crBrushLight;
  pSaveStruct->crBrushGray = pGridData->crBrushGray;
  pSaveStruct->crTextReadOnly = pGridData->crTextReadOnly;
  pSaveStruct->crTextCommon = pGridData->crTextCommon;
  pSaveStruct->crTextLight = pGridData->crTextLight;
  pSaveStruct->crTextGray = pGridData->crTextGray;

  pSaveStruct->titleheight =  pGridData->titleheight;
  pSaveStruct->headerrowheight= pGridData->headerrowheight;
  pSaveStruct->rowheight = pGridData->rowheight;
  pSaveStruct->rows = pGridData->rows;
  pSaveStruct->cols = pGridData->cols;
  pSaveStruct->homerow=pGridData->homerow;
  pSaveStruct->homecol = pGridData->homecol;
  pSaveStruct->sel_row = pGridData->sel_row;

  pSaveStruct->dwStyle = pGridData->dwStyle;

 }
 else
 {
  memcpy(pGridData->columnwidths,pSaveStruct->columnwidths,sizeof(pSaveStruct->columnwidths));

  pGridData->crGridLine = pSaveStruct->crGridLine;
  pGridData->crTextTitle = pSaveStruct->crTextTitle;
  pGridData->crBrushReadOnly = pSaveStruct->crBrushReadOnly;
  pGridData->crBrushCommon = pSaveStruct->crBrushCommon;
  pGridData->crBrushLight = pSaveStruct->crBrushLight;
  pGridData->crBrushGray = pSaveStruct->crBrushGray;
  pGridData->crTextReadOnly = pSaveStruct->crTextReadOnly;
  pGridData->crTextCommon = pSaveStruct->crTextCommon;
  pGridData->crTextLight = pSaveStruct->crTextLight;
  pGridData->crTextGray = pSaveStruct->crTextGray;
  pGridData->titleheight =  pSaveStruct->titleheight;
  pGridData->headerrowheight= pSaveStruct->headerrowheight;
  pGridData->rowheight = pSaveStruct->rowheight;
  pGridData->rows = pSaveStruct->rows;
  pGridData->cols = pSaveStruct->cols;
  pGridData->homerow=pSaveStruct->homerow;
  pGridData->homecol = pSaveStruct->homecol;
  pGridData->sel_row = pSaveStruct->sel_row;

  pGridData->dwStyle = pSaveStruct->dwStyle;
 }

 return TRUE;
}

static BOOL RR_GetReadOnlyStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(pGridData->dwStyle & GS_READONLY)
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

static void RR_SetReadOnlyStyle(HWND hWnd ,BOOL bReadOnly)
{
 Grid_T * pGridData;
 DWORD dwSysStyle ;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 dwSysStyle = GetWindowLong(hWnd,GWL_STYLE);

 if (bReadOnly)
 {
  //只读时不接受焦点
  if(dwSysStyle & WS_TABSTOP)
  {
   dwSysStyle= dwSysStyle & (~WS_TABSTOP);
   SetWindowLong(hWnd,GWL_STYLE ,dwSysStyle);
  }
  pGridData->dwStyle = pGridData->dwStyle | GS_READONLY;
 }
 else
 {
  if(!(dwSysStyle & WS_TABSTOP))
  {
   dwSysStyle= dwSysStyle | WS_TABSTOP;
   SetWindowLong(hWnd,GWL_STYLE ,dwSysStyle);
  }
  pGridData->dwStyle = pGridData->dwStyle & ~GS_READONLY;
 }
}
 

static BOOL RR_GetExtendLastColumnStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_LASTCOL_NOEXTEND)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}


static BOOL RR_GetColumnAllowResizeStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_COLUMN_NORESIZE)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}

static void RR_SetColumnAllowResizeStyle(HWND hWnd ,BOOL bAllow)
{

 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if (bAllow)
 {
  pGridData->dwStyle = pGridData->dwStyle & ~GS_COLUMN_NORESIZE;
 }
 else
 {
  pGridData->dwStyle = pGridData->dwStyle | GS_COLUMN_NORESIZE;
 }
}

static BOOL RR_GetColHeadIsNumberStyle(HWND hWnd)
{
 //第0行是否设成ABCDE之类的字母
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_COLHEAD_CUSTOM)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}

 

static BOOL RR_GetRowHeadIsNumberStyle(HWND hWnd)
{
 //第0列是否设成12345之类的数字
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_ROWHEAD_CUSTOM)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}


static BOOL RR_GetShowIntegralRowStyle(HWND hWnd)
{
 //是否调整Grid高度,以显示完整的行高
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_GRIDHIGH_NOADJUST)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}


static BOOL RR_GetHighLightStyle(HWND hWnd)
{
 //选择行是否高亮显示
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_SELROW_INVISIBLE)
 {
  return FALSE;
 }
 else
 {
  return TRUE;
 }
}

static void RR_SetHighLightStyle(HWND hWnd ,BOOL bHighLight)
{
 //选择行是否高亮显示

 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if (bHighLight)
 {
  pGridData->dwStyle = pGridData->dwStyle & ~GS_SELROW_INVISIBLE;
 }
 else
 {
  pGridData->dwStyle = pGridData->dwStyle | GS_SELROW_INVISIBLE;
 }
}

static BOOL RR_GetInsertKeyStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_CANCEL_INSKEY)
 {
  return FALSE;//不响应Insert键进行插入
 }
 else
 {
  return TRUE;
 }
}

static BOOL RR_GetDeleteKeyStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_CANCEL_DELKEY)
 {
  return FALSE;//不响应Delete键进行行删除
 }
 else
 {
  return TRUE;
 }
}

static BOOL RR_GetEnterKeyStyle(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 if(pGridData->dwStyle & GS_CANCEL_ENTER_INSERT)
 {
  return FALSE;//回车键在最后行没有添加行功能
 }
 else
 {
  return TRUE;
 }
}

 
 
 

//返回值:TRUE ,不再交给默认过程处理
static LRESULT RR_CellEditOnKeyDown(HWND  hCellEdit, UINT message, WPARAM wParam, LPARAM lParam)
{
 LRESULT lRet = 0;
 HWND hGrid=GetParent(hCellEdit);
 Grid_T * pGridData = NULL;
 GridCell_T  tMoveToCell;

 pGridData = (Grid_T *)GetWindowLong(hGrid,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(!pGridData->bEditing)
 {
  return lRet;
 }

 switch(wParam)
 {
  case VK_ESCAPE:
   RR_GridCtrl_Discard_Edit(hGrid);
    lRet = TRUE;
   break;
  case VK_RETURN:
   if(pGridData->tEditCell.row == pGridData->rows-1 &&
    pGridData->tEditCell.col ==pGridData->cols-1 &&
    RR_GetEnterKeyStyle(hGrid))
   {
    //插入新行,进入新行编辑
    int row = pGridData->rows;
    
    if(SendMessage(hGrid,GM_GRID_INSERT_ROW,row,0)==0)
    {
     tMoveToCell.row = row ;
     tMoveToCell.col = pGridData->leftvisiblecol;
     RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,0);
    }
    lRet = TRUE;
    break;
   }
   
   
   if(pGridData->tEditCell.col<pGridData->rightvisiblecol)
   {
    tMoveToCell.row = pGridData->tEditCell.row ;
    tMoveToCell.col = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->tEditCell.col,1);
   }
   else if(pGridData->tEditCell.row < pGridData->bottomvisiblerow)
   {
    tMoveToCell.row = pGridData->tEditCell.row +1;
    tMoveToCell.col = pGridData->leftvisiblecol;
   }
   else
   {
    tMoveToCell.row = pGridData->topvisiblerow;
    tMoveToCell.col = pGridData->leftvisiblecol;
   }
   RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,0);
   lRet = TRUE;
   break;
  case VK_TAB:
   if(GetKeyState(VK_SHIFT) < 0)
   {
    //支持shift+TAB反方向移动
     if(pGridData->tEditCell.col>pGridData->leftvisiblecol)
    {
     tMoveToCell.row = pGridData->tEditCell.row ;
     tMoveToCell.col = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->tEditCell.col,-1);
    }
    else if(pGridData->tEditCell.row > pGridData->topvisiblerow)
    {
     tMoveToCell.row = pGridData->tEditCell.row -1;
     tMoveToCell.col = pGridData->rightvisiblecol;
    }
    else
    {
     tMoveToCell.row = pGridData->bottomvisiblerow;
     tMoveToCell.col = pGridData->rightvisiblecol;
    }
    
   }
   else
   {
    if(pGridData->tEditCell.col<pGridData->rightvisiblecol)
    {
     tMoveToCell.row = pGridData->tEditCell.row ;
     tMoveToCell.col = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->tEditCell.col,1);
    }
    else if(pGridData->tEditCell.row < pGridData->bottomvisiblerow)
    {
     tMoveToCell.row = pGridData->tEditCell.row +1;
     tMoveToCell.col = pGridData->leftvisiblecol;
    }
    else
    {
     tMoveToCell.row = pGridData->topvisiblerow;
     tMoveToCell.col = pGridData->leftvisiblecol;
    }
   }
   
   RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,0);
   lRet = TRUE;
   break;
  case VK_LEFT:
  {
   int start=0;
   int end=0;

   SendMessage(hCellEdit,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
   if(GetKeyState(VK_CONTROL) < 0 && (start >0 || end >0))
   {
     //VK_CONTROL键被按下(组合键)
     SendMessage(hCellEdit,EM_SETSEL,0,0);
    lRet = TRUE;
    break;
   }
   
   if(start==0 && end ==0)//左移一单元编辑
   {
    tMoveToCell.col = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->tEditCell.col,-1);
    tMoveToCell.row = pGridData->tEditCell.row;    
    RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,1);
    lRet = TRUE;
   }
   
  }
   break;
  case VK_RIGHT:
  {
   int start=0;
   int end=0;
   int len=0;

   len = SendMessage(hCellEdit,EM_LINELENGTH,0,0);
   SendMessage(hCellEdit,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
   if(GetKeyState(VK_CONTROL) < 0 && (end<len ||start<len))
   {
     //VK_CONTROL键被按下(组合键)
     SendMessage(hCellEdit,EM_SETSEL,len+1,len+1);
    lRet = TRUE;
    break;
   }
   
   if(start == len && end == len)
   {
    tMoveToCell.col = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->tEditCell.col,1);
    tMoveToCell.row = pGridData->tEditCell.row;    
    RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,1);
    lRet = TRUE;
   }
   
  }
   break;
  case VK_UP:
   tMoveToCell.col = pGridData->tEditCell.col;
   tMoveToCell.row = pGridData->tEditCell.row-1;    
   RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,1);
   lRet = TRUE;
   break;   
  case VK_DOWN:
   tMoveToCell.col = pGridData->tEditCell.col;
   tMoveToCell.row = pGridData->tEditCell.row+1;    
   RR_GridCtrl_Enter_Edit(hGrid,&tMoveToCell,1);
   lRet = TRUE; 
   break;
  default:
   break;
 }

 return lRet;
}

static LRESULT   ModifierCellEditProc(HWND   hCellEdit,UINT   message,WPARAM   wParam,LPARAM   lParam)
{
 LRESULT lRet;
 
  switch (message)
  {
   case WM_GETDLGCODE:
  {
   lRet = CallWindowProc(OriginalEditProc,hCellEdit,message,wParam,lParam);  
   // If lParam points to an MSG structure
         if (lParam)
         {
          LPMSG lpmsg = (LPMSG)lParam;
          if (lpmsg->message == WM_KEYDOWN)
          {
           switch(lpmsg->wParam)
           {
            case VK_ESCAPE:
      case VK_RETURN:
      case VK_TAB:
      case VK_LEFT:
      case VK_RIGHT:
      case VK_UP:
      case VK_DOWN:
             lRet |= DLGC_WANTMESSAGE;
       break;
      default:
       break;
           }
          }
        }

   }   
   return lRet;
  case WM_KEYDOWN:
   lRet = RR_CellEditOnKeyDown(hCellEdit,message,wParam,lParam);
   if(lRet)
   {
    return 0;//lRet 返回TRUE ,不再交给默认过程处理
   }
   
   break;
   case WM_KILLFOCUS: 
  {
   HWND hParent = GetParent(hCellEdit);
   
   RR_GridCtrl_Force_Exit_Edit(hParent);
   SendMessage(hParent,message,wParam,lParam);
   }
   break;
  case WM_SETCURSOR:
   SetCursor(LoadCursor(NULL,IDC_IBEAM));
   return 0;
  case WM_ERASEBKGND:
   return 0;//直接return 编辑框将不会画鼠标指针
  default:
   break;
  }
 
 return   CallWindowProc(OriginalEditProc,hCellEdit,message,wParam,lParam);  
 }

static int  RR_GridCtrl_Notify(HWND hWnd,UINT code,LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 GridNotify_T tNotify;
 WPARAM wParam;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 //memset(tNotify,0,sizeof(GridNotify_T));
 tNotify.hwndFrom = hWnd;
 tNotify.idFrom = pGridData->nGridId;
 tNotify.code = code;
 tNotify.param = lParam;
 tNotify.retVal =0;

 wParam=MAKEWPARAM(tNotify.idFrom,tNotify.code);

 SendMessage(GetParent(hWnd),GM_GRID_NOTIFY,wParam,(LPARAM)&tNotify);
 //SendMessage(GetParent(hWnd),WM_COMMAND,wParam,lParam);

 return tNotify.retVal;

}
 

BOOL RR_GridCtrl_OutOfRange(GridCell_T *cell)
{
 if(cell->row > ROWS_MAX || cell->row <0 ||
  cell->col > COLS_MAX || cell->col<0)
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

 

//返回与szSymbol匹配项的索引
static ListNode * RR_GridCtrl_SearchData(StringLink_T  *ptStrLink,char  szSymbol[])
{
 StringLinkNode_T* pStrNode;
 ListNode *p = NULL;
 int len =0;

 if(ptStrLink == NULL || szSymbol == NULL)
 {
  return NULL;
 }

 len = strlen(szSymbol);
 
 List_ForEach(p,&(ptStrLink->head))
 {
  pStrNode = List_Entry(p,StringLinkNode_T,node);
  if(strncmp(pStrNode->szString,szSymbol,len) ==0)
  {
   return p;
  }
 }

 return NULL;
}

//bInsert :TRUE -- 插入行,排在row/col后面的单元行号加1
//FALSE -- 删除行,排在row/col后面的单元行号减1

static BOOL RR_GridCtrl_UpdateData(StringLink_T  *ptStrLink,int row ,BOOL bInsert)
{
 char szSymbol[DATA_SYMBOL_LEN+1];
 char szRow[DATA_SYMBOL_LEN+1];
 ListNode *p,*q;
 StringLinkNode_T *pStrNode = NULL;
 int len =0;
 int line=0;


 if(ptStrLink == NULL || row <1)
 {
  return FALSE;
 }

 sprintf(szSymbol,"%05d-%03d",row,0); //9
 len = strlen(szSymbol);

 List_ForEachSafe(p,q,&(ptStrLink->head))
  {
   pStrNode = List_Entry(p,StringLinkNode_T,node);
  if(strncmp(pStrNode->szString,szSymbol,len) >=0)
  {
   line = atoi(pStrNode->szString);
   RR_ASSERT(line>=row);

   if(bInsert)
   {
    line++;
    sprintf(szRow,"%05d",line);
    strncpy(pStrNode->szString,szRow,5);
   }
   else
   {
    if(line == row)
    {
     //删除该行的数据单元
     List_Del(&pStrNode->node);
     ptStrLink->node_cnt --;
     RR_Safe_Free(pStrNode->szString);
     RR_Safe_Free(pStrNode);
    }
    else
    {
     line--;
     sprintf(szRow,"%05d",line);
     strncpy(pStrNode->szString,szRow,5);
    }
   }
  }
  }

 return TRUE;
 
}

static int RR_GridCtrl_ChgSelRow(HWND hWnd,int new_row)
{
 Grid_T * pGridData = NULL;
 int old_row;
 int ret;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 RR_ASSERT(new_row>0 && new_row <pGridData->rows);

 old_row = pGridData->sel_row;
 if(new_row == old_row)
 {
  return 0;
 }

 ret = RR_GridCtrl_Notify(hWnd,GN_ROW_CHANGED,MAKELPARAM(new_row,old_row));
 if(ret== 0)
 {
  //选择行被改变
  pGridData->sel_row = new_row;
  pGridData->bRowModified = FALSE;
 }

 return ret; 
}

static int RR_GridCtrl_GetLogicColOnScreen(Grid_T* pGridData,int reference_col,unsigned char description)
{
 int gridWidth;
 int i=0;
 int col;

 RR_ASSERT(pGridData!=NULL);

 if(reference_col<0 || reference_col>=pGridData->cols)
 {
  RR_ASSERT(0);
  return -1;
 }


 gridWidth =  pGridData->gridWidth;
 col = reference_col;
  
 if((description&RR_PARAM_MASk) == RR_PARAM_START_COLNO)
 {
  //reference_col是开始列号
  if(reference_col>0)
  {
   gridWidth-=pGridData->columnwidths[0];
  }

  for(i = reference_col;i<pGridData->cols;i++)
  {
   if(pGridData->columnwidths[i]>0)
   {
    if(gridWidth <= pGridData->columnwidths[i])
    {
     if((description & RR_RESULT_MASK) == RR_RESULT_HALF)
     {
      //可以部分显示
      col = i;
     }
     else if(gridWidth == pGridData->columnwidths[i])
     {
      //完整显示单元
      col =i;
     }
     
     break;
    }
    
    gridWidth-=pGridData->columnwidths[i];
    col = i;

   }
  }

 }
 else
 {
  //reference_col是结束列号
  //返回的一定是Grid能完全装下的列号
  if(reference_col ==0 )
  {
   return 0;
  }
  
  gridWidth -= pGridData->columnwidths[0];

  //返回值>0
  for(i =reference_col;i>=1;i--)
  {
   if(pGridData->columnwidths[i]>0)
   {
    if(gridWidth < pGridData->columnwidths[i])
    {
     break;
    }
    else if (gridWidth ==pGridData->columnwidths[i])
    {
     col = i;
     break;
    }
     
    gridWidth-=pGridData->columnwidths[i];
    col = i;
   }
  }

 }

 return col;
}

//统计从startcol开始(含该列)到endcol(含)之间有宽度的列数
//pTotalWidth返回startcol 到endcol之间有宽度列宽度之和
//返回值:
static int RR_GridCtrl_GetColumnsWithWidth(Grid_T * pGridData, int startcol,int endcol,int* pTotalWidth)
{
 int totalpixels=0;
 int j;
 int colswithwidth=0;
 
 RR_ASSERT(pGridData!=NULL);

 if(startcol<0 || startcol>=pGridData->cols ||
  endcol<0 || endcol>=pGridData->cols||
  startcol>endcol)
 {
  if(pTotalWidth!=NULL)
  {
   *pTotalWidth =0;
  }
  return 0;
 }

 
 //列宽不等宽
 for(j=startcol;j<=endcol;j++)
 {
  if(pGridData->columnwidths[j]>0)
  {
   totalpixels += pGridData->columnwidths[j];
   colswithwidth++;
  }
 }

 if(pTotalWidth!=NULL)
 {
  *pTotalWidth = totalpixels;
 }

 return colswithwidth;
}

//得到下|direction|个有宽度的列的列号
//direction>0 往右数,direction <0往左数
//返回值<0表示往左(右)没有第|direction|个有宽度的列
//该函数可以返回第0列(调用时注意)
static int RR_GridCtrl_GetNextNthColWithWidth(Grid_T * pGridData, int startcol, int direction)
{
 int n=0;
 int col=startcol;
 int abs_val=abs(direction);

 RR_ASSERT(pGridData!=NULL);

 if(startcol<0 || startcol>=pGridData->cols)
 {
  //输入参数不合法
  return -1;
 }

 if(direction==0)
 {
  //RR_ASSERT(0);
  return startcol;
 }
 else if(direction>0)
 {
  col++;
 }
 else
 {
  col--;
 }

 while(col>=0 && col<pGridData->cols)
 {
  if(pGridData->columnwidths[col]!= 0)
  {
   n++;
   if(n==abs_val)
   {
    break;
   }
  }
  
  if(direction>0)
  {
   col++;
  }
  else
  {
   col--;
  }
 }

 if(n==abs_val)
 {
  RR_ASSERT(col>=0 && col<pGridData->cols);
  return col;
 }
 else
 {
  return -2;
 }
}


//得到逻辑单元的矩形区域 (支持第0行第0列的单元)
static BOOL RR_GridCtrl_GetCellRect(HWND hWnd,int row, int col,RECT *pCellRect)
{
 Grid_T * pGridData;
 RECT rect;
 RECT rtGrid;
 int offset =0;
 int j=0;

 if(pCellRect==NULL)
 {
  RR_ASSERT(0);
  return FALSE;
 }

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(row<0 || row>=pGridData->rows ||
  col<0 || col>=pGridData->cols)
 {
  SetRect(pCellRect,0,0,0,0);
  return FALSE;
 }


 if(col !=0)
 {
  if(pGridData->leftvisiblecol<1 || pGridData->rightvisiblecol<1)
  {
   //(当前没有显示的数据单元)
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  if(col < pGridData->leftvisiblecol || col > pGridData->rightvisiblecol)
  {
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  offset=pGridData->columnwidths[0];

  //计算从leftvisiblecol开始到col列的宽度偏移
  for(j=pGridData->leftvisiblecol ;j<col;j++)
  {
   offset +=pGridData->columnwidths[j];
  }
  
 }

 rect.left = offset ;
 rect.right = offset  +pGridData->columnwidths[col];

 if(RR_GetExtendLastColumnStyle(hWnd) &&
  RR_GridCtrl_GetNextNthColWithWidth(pGridData,col,1)<0)
 {
  //最后一列有宽度的列扩展到Grid右边界
  rect.right = pGridData->gridWidth;
 }
  
 offset =pGridData->titleheight;//重置offset
 if(row==0)
 {
  rect.top = offset;
  rect.bottom = offset+pGridData->headerrowheight;
 }
 else
 {
  if(pGridData->topvisiblerow<1 || pGridData->bottomvisiblerow<1)
  {
   //(当前没有显示的数据单元)
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  if(row < pGridData->topvisiblerow || row > pGridData->bottomvisiblerow)
  {
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  offset += pGridData->headerrowheight;
  for(j=pGridData->topvisiblerow;j<row;j++)
  {
     offset += pGridData->rowheight;
  }

  rect.top = offset;
  rect.bottom = offset+pGridData->rowheight;
 }

 SetRect(&rtGrid,0,0,pGridData->gridWidth,pGridData->gridHeight);
 if(!IntersectRect(pCellRect,&rect,&rtGrid))
 {
  //两个矩形没有交集
  SetRect(pCellRect,0,0,0,0);
  return FALSE;
 }

 if(IsRectEmpty(pCellRect))
 {
  return FALSE;
 }
 return TRUE;
 
}

//得到逻辑行的矩形区域,支持第0行
static BOOL RR_GridCtrl_GetRowRect(HWND hWnd,int row, RECT *pCellRect, BOOL bAdd0Col)
{
 Grid_T * pGridData;
 int offset =0;
 int j=0;
 RECT rtRow;
 RECT rtGrid;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 RR_ASSERT(pCellRect!=NULL);

 if(row<0 || row >=pGridData->rows)
 {
  SetRect(pCellRect,0,0,0,0);
  return FALSE;
 }

 if(bAdd0Col)
 {
  rtRow.left = 0;
 }
 else
 {
  rtRow.left = pGridData->columnwidths[0];
 }
 rtRow.right = pGridData->gridWidth;

 offset = pGridData->titleheight;
 if(row == 0)
 {
  rtRow.top = offset;
  rtRow.bottom = pGridData->titleheight+ pGridData->headerrowheight;
 }
 else
 {
  if(pGridData->topvisiblerow<1 || pGridData->bottomvisiblerow<1)
  {
   //(当前没有显示的数据单元)
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  if(row < pGridData->topvisiblerow || row > pGridData->bottomvisiblerow)
  {
   SetRect(pCellRect,0,0,0,0);
   return FALSE;
  }

  offset += pGridData->headerrowheight;
  for(j=pGridData->topvisiblerow;j<row;j++)
  {
     offset += pGridData->rowheight;
  }

  rtRow.top = offset;
  rtRow.bottom = offset+pGridData->rowheight;
 }

 SetRect(&rtGrid,0,0,pGridData->gridWidth,pGridData->gridHeight);
 if(!IntersectRect(pCellRect,&rtRow,&rtGrid))
 {
  //两个矩形没有交集
  SetRect(pCellRect,0,0,0,0);
  return FALSE;
 }

 RR_ASSERT(!IsRectEmpty(pCellRect));
 
 return TRUE;
}

//得到鼠标事件光标所在的行(逻辑行号)
int RR_GridCtrl_GetRowOfMouse(Grid_T * pGridData,int y)
{
 int row;
 int top=0;

 RR_ASSERT(pGridData!=NULL);

 if(y<0 || y>pGridData->gridHeight)
 {
  return -1;
 }

 if(pGridData->titleheight>0 && y< pGridData->titleheight )
 {
  return -1;
 }

 top = pGridData->titleheight;
 if(pGridData->headerrowheight >0 &&  (y>=top) &&
  (y<(pGridData->headerrowheight + top)))
 {
  return 0;
 }

 if(pGridData->topvisiblerow<=0)
 {
  return -1;
 }
 
 top+=pGridData->headerrowheight ;

 y-=top;
 row = y/pGridData->rowheight;
 row+=pGridData->topvisiblerow;

 if(row>pGridData->bottomvisiblerow)
 {
  return -1;
 }
 return row;
}

//得到鼠标事件光标所在的列(逻辑列号)
//x 是相对于Grid 窗口的坐标
int RR_GridCtrl_GetColOfMouse(Grid_T * pGridData,int x)
{
 int col=0;
 int left=0;
 int right=0;
 
 RR_ASSERT(pGridData!=NULL);

 if(x<0 || x>pGridData->gridWidth)
 {
  //x坐标在Grid窗口之外
  return -1;
 }

 if(pGridData->columnwidths[0]>0)
 {
  //第0列有宽度
  int border;

  border = pGridData->columnwidths[0];
  if(RR_GetExtendLastColumnStyle(pGridData->hWnd) &&
   RR_GridCtrl_GetNextNthColWithWidth(pGridData,0,1)<0)
  {
   //第0列是最后一列且被扩展
   border = pGridData->gridWidth;
  }

  if(x<border)
  {
   return 0;
  }
 }
 
 if(pGridData->leftvisiblecol<=0)
 {
  return -1;
 }
 
 left = pGridData->columnwidths[0];
 col=pGridData->leftvisiblecol;

 while(col<pGridData->rightvisiblecol)
 {
  if(x>=left && x<left+pGridData->columnwidths[col])
  {
   return col;
  }

  left+=pGridData->columnwidths[col];
  col++;
 }

 RR_ASSERT(col == pGridData->rightvisiblecol);

 if(RR_GetExtendLastColumnStyle(pGridData->hWnd)&&
  RR_GridCtrl_GetNextNthColWithWidth(pGridData,col,1)<0 )
 {
  right = pGridData->gridWidth;
 }
 else
 {
  right = left+pGridData->columnwidths[col];
  if(right>pGridData->gridWidth)
  {
   right = pGridData->gridWidth;
  }
 }

 
 if(x>=left && x<right)
 {
  return col;
 }
 else
 {
  return -1;
 }
 
 
}

//调整homecol,以使reference_col能显示在屏幕上(如果有宽度)
static void RR_GridCtrl_AdjustHomeCol(HWND hWnd,int reference_col)
{
 Grid_T * pGridData;
 int home_col=1;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 RR_ASSERT(pGridData->homecol>=0 && pGridData->homecol<pGridData->cols);

 if(reference_col<=0 || reference_col>=pGridData->cols)
 {
  return ;
 } 

 if(reference_col<pGridData->leftvisiblecol)
 {
  //拖出左边界外的列
  home_col = reference_col;
 }
 else
 {
  home_col = pGridData->homecol;
 }
 
 if(pGridData->columnwidths[home_col]<=0)
 {
  int col;
  
  col =RR_GridCtrl_GetNextNthColWithWidth(pGridData,home_col,1);
  if(col>0)
  {
   home_col = col;
  }
  else
  {
   home_col =RR_GridCtrl_GetNextNthColWithWidth(pGridData,home_col,-1);
   if(home_col<1)
   {
    home_col =1;
   }

  }
  
 }

 if(home_col!=pGridData->homecol)
 {
  RR_ASSERT(home_col>0 && home_col<pGridData->cols);
  pGridData->homecol = home_col;
 }
}

//根据滚动条当前位置设置home_col
//而RR_GridCtrl_AdjustHomeCol是先设置home_col 再由home_col去 调整滚动条位置
static void RR_GridCtrl_SetHomeCol(HWND hWnd,int pos)
{
 int home_col =0;
 int col =0;
 Grid_T * pGridData;

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);


 col =RR_GridCtrl_GetNextNthColWithWidth(pGridData,0,pos);
 if(col>0)
 {
  home_col = col;
 }
 else
 {
  col = RR_GridCtrl_GetColumnsWithWidth(pGridData,1,pGridData->cols-1,NULL);
  if(col>1)
  {
   home_col =RR_GridCtrl_GetNextNthColWithWidth(pGridData,0,col);
   if(home_col<1)
   {
    RR_ASSERT(0);
    home_col =1;
   }
  }
  else
  {
   home_col =1;
  }
 }

 if(home_col!=pGridData->homecol)
 {
  RR_ASSERT(home_col>0 && home_col<pGridData->cols);
  pGridData->homecol = home_col;
 }
 
}

static void RR_GridCtrl_InitStruct(Grid_T * pGridData)
{
 int i =0;
 
 RR_ASSERT(pGridData!=NULL);

 //初始化字体
 pGridData->htitlefont = CreateFont(20,0,0, 0,FW_HEAVY,FALSE,FALSE,FALSE,
   ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
   PROOF_QUALITY,VARIABLE_PITCH|FF_MODERN ,NULL);

 pGridData->hheadfont  = CreateFont(18,0,0, 0,FW_HEAVY,FALSE,FALSE,FALSE,
   ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
   PROOF_QUALITY,VARIABLE_PITCH|FF_MODERN ,NULL);

 pGridData->hbodyfont = CreateFont(16,0,0, 0,100,FALSE,FALSE,FALSE,
   ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,
   PROOF_QUALITY,VARIABLE_PITCH|FF_MODERN ,NULL);

 //初始化颜色值
 //pGridData->crTextTitle = RGB(0,0,0);

 //栅格线颜色
 pGridData->crGridLine =RGB(220,220,220);

 //画刷颜色
 pGridData->crBrushReadOnly =RGB(252,252,248);//RGB(252,248,251); //RGB(247,253,253);
 pGridData->crBrushCommon = RGB(255,255,255);
 pGridData->crBrushLight =RGB(0,80,226);//RGB(0,80,226);RGB(49,106,197);
 pGridData->crBrushGray = RGB(124,153,226);

 pGridData->crTextReadOnly = RGB(166,166,166);
 //pGridData->crTextCommon= RGB(0,0,0);
 pGridData->crTextLight =RGB(255,255,255);
 pGridData->crTextGray = RGB(216,228,248);

 pGridData->hEditBackBrush = CreateSolidBrush(pGridData->crBrushCommon);
  
 
 pGridData->homerow = 1;
 pGridData->homecol = 1;
 pGridData->sel_row = 1;
 pGridData->tEditCell.row =-1;
 pGridData->tEditCell.col =-1;
 

 pGridData->cursortype = CURSOR_ARROW;

 pGridData->headerrowheight = 18+LINE_BORDER_SIZE;
 pGridData->rowheight = 16+LINE_BORDER_SIZE;
 
 pGridData->columnwidths[0] = 50;
 for(i=1;i<pGridData->cols;i++)
 {
  pGridData->columnwidths[i]=50;
 }

 pGridData->ptTextLink = (StringLink_T*)RR_MALLOC(sizeof(StringLink_T));
 RR_InitStringLink(pGridData->ptTextLink);
  
}

static void  RR_GridCtrl_ResumeDefaultStruct(Grid_T * pGridData)
{
 int i=0;
 
 if(pGridData == NULL)
 {
  RR_ASSERT(0);
 }
  
 pGridData->rows = pGridData->init_rows;
 pGridData->cols = pGridData->init_cols;
 pGridData->dwStyle = pGridData->dwStyle;

 
 pGridData->homerow =1;
 pGridData->homecol = 1;
 pGridData->sel_row =1;

 if(pGridData->dwStyle & GS_NO_COLHEAD)
 {
  pGridData->headerrowheight =0;
 }
 else
 {
  pGridData->headerrowheight = 18+LINE_BORDER_SIZE;
 }

 pGridData->rowheight = 16+LINE_BORDER_SIZE; 
 memset(pGridData->columnwidths,0,sizeof(pGridData->columnwidths));
 
 if(!(pGridData->dwStyle & GS_NO_ROWHEAD))
 {
  pGridData->columnwidths[0] = 50;
 }  
 for(i=1;i<pGridData->cols;i++)
 {
  pGridData->columnwidths[i]=50;
 }

 //栅格线颜色
 pGridData->crGridLine =RGB(220,220,220);

 //画刷颜色
 pGridData->crBrushReadOnly =RGB(252,252,248);//RGB(252,248,251); //RGB(247,253,253);
 pGridData->crBrushCommon = RGB(255,255,255);
 pGridData->crBrushLight =RGB(0,80,226);//RGB(0,80,226);RGB(49,106,197);
 pGridData->crBrushGray = RGB(124,153,226);

 pGridData->crTextReadOnly = RGB(166,166,166);
 //pGridData->crTextCommon= RGB(0,0,0);
 pGridData->crTextLight =RGB(255,255,255);
 pGridData->crTextGray = RGB(216,228,248);

 if(pGridData->hEditBackBrush!=NULL)
 {
  DeleteObject(pGridData->hEditBackBrush);
 }
 pGridData->hEditBackBrush = CreateSolidBrush(pGridData->crBrushCommon);
 
}


static void RR_GridCtrl_FreeStruct(Grid_T * pGridData)
{

 if(pGridData->htitlefont!=NULL)
 {
  DeleteObject(pGridData->htitlefont);
 }
 if(pGridData->hheadfont!=NULL)
 {
  DeleteObject(pGridData->hheadfont);
 }
 if(pGridData->hbodyfont!=NULL)
 {
  DeleteObject(pGridData->hbodyfont);
 }

 if(pGridData->hEditBackBrush!=NULL)
 {
  DeleteObject(pGridData->hEditBackBrush);
 }

 RRFreeStringLink(pGridData->ptTextLink);
 RR_Safe_Free(pGridData->ptTextLink);
 
 RR_Safe_Free(pGridData->pszTitle);
 RR_Safe_Free(pGridData);
}

//设置标题条的显示位置
static void RR_GridCtrl_SetTitleBarArea(HWND hWnd)
{
 HDC dc;
 HFONT hOldFont;
 SIZE size;
 Grid_T * pGridData;
  
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);


 if(pGridData->pszTitle == NULL ||pGridData->pszTitle[0] == 0)
 {
  pGridData->titleheight=0;
  return;
 }
 
 dc=GetDC(hWnd);
 //dc = CreateDC("DISPLAY", NULL, NULL, NULL );
 hOldFont=(HFONT)SelectObject(dc,pGridData->htitlefont);
 GetTextExtentPoint32(dc,pGridData->pszTitle,strlen(pGridData->pszTitle),&size);
 SelectObject(dc,hOldFont);

 pGridData->titleheight = (int)(size.cy * RR_Get_Sector_Count(pGridData->pszTitle,'/n')+LINE_BORDER_SIZE);
 
 ReleaseDC(hWnd,dc);
 //DeleteDC( dc );
    
}


static void RR_GridCtrl_ShowHscroll(HWND hWnd)
{
 Grid_T * pGridData;
 int totalpixels=0;
 int colswithwidth=0;//有宽度的列数(除第0列外)
 int max=0;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL && pGridData->cols>0);


 colswithwidth = RR_GridCtrl_GetColumnsWithWidth(pGridData,1,pGridData->cols-1,&totalpixels);
 if(pGridData->columnwidths[0]>0 )
 {
  totalpixels += pGridData->columnwidths[0];
 }
 
 
 
 if(totalpixels > pGridData->gridWidth)
 {
  if(!pGridData->bShowHScroll )
  {
   //show hscrollbar
   ShowScrollBar(hWnd,SB_HORZ,TRUE);
  }
  RR_ASSERT(colswithwidth<pGridData->cols);
  SetScrollRange(hWnd,SB_HORZ,1,colswithwidth,TRUE);
  max = colswithwidth;
  colswithwidth = RR_GridCtrl_GetColumnsWithWidth(pGridData,1,pGridData->homecol,NULL);
  if(colswithwidth<1)
  {
   colswithwidth =1;
  }
  else if (colswithwidth>max)
  {
   RR_GridCtrl_SetHomeCol(hWnd,colswithwidth);
   colswithwidth =max;
  }

  SetScrollPos(hWnd,SB_HORZ,colswithwidth,TRUE);
  pGridData->bShowHScroll = TRUE;
 }
 else
 {
  pGridData->homecol =RR_GridCtrl_GetNextNthColWithWidth(pGridData,0,1);
  if(pGridData->homecol<1)
  {
   pGridData->homecol =1;
  }
  
  if(pGridData->bShowHScroll)
  {
   //hide hscrollbar
   ShowScrollBar(hWnd,SB_HORZ,FALSE);
  }
  
  SetScrollRange(hWnd,SB_HORZ,0,0,TRUE);
  pGridData->bShowHScroll = FALSE;
 }
 
}

void RR_GridCtrl_ShowVscroll(HWND hWnd)
{
 Grid_T * pGridData;
 int totalpixels;
 int max=0;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);


 totalpixels = pGridData->titleheight+pGridData->headerrowheight+((pGridData->rowheight) * (pGridData->rows-1)); //-1 :除去第0行计数
 if(totalpixels> pGridData->gridHeight)
 {
  int rows_onscreen;//屏幕上能显示的行数(不包括第0行)
  int pos ;
  
  if(!pGridData->bShowVScroll)
  {
   //显示纵向滚动条
   ShowScrollBar(hWnd,SB_VERT,TRUE);

  }

  totalpixels = pGridData->gridHeight - (pGridData->headerrowheight+pGridData->titleheight);
  rows_onscreen = totalpixels / (pGridData->rowheight);
  
  max = (pGridData->rows-1-rows_onscreen)+1;
  SetScrollRange(hWnd,SB_VERT,1,max,TRUE);

  if(pGridData->homerow<1)
  {
   RR_ASSERT(0);
   pos =1;
  }
  else if (pGridData->homerow<=max)
  {
   pos = pGridData->homerow;
  }
  else
  {
   pGridData->homerow = max; //调整homerow
   pos = max;
  }

  SetScrollPos(hWnd,SB_VERT,pos,TRUE);
  pGridData->bShowVScroll = TRUE;
 }
 else
 {
  pGridData->homerow =1;
  
  if(pGridData->bShowVScroll)
  {
   //隐藏纵向滚动条
   ShowScrollBar(hWnd,SB_VERT,FALSE);
  }
  
  SetScrollRange(hWnd,SB_VERT,0,0,TRUE);
  pGridData->bShowVScroll = FALSE;
 }
 
}

void RR_GridCtrl_Refresh(HWND hWnd,BOOL bUpdate)
{
 RECT rect;
 Grid_T * pGridData;

 //窗口是隐藏状态,无需刷新
 if(!(GetWindowLong(hWnd,GWL_STYLE)& WS_VISIBLE))
 {
  if(bUpdate)
  {
   UpdateWindow(hWnd);
  }
  return;
 }
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL); 

 SetRect(&rect,0,0,pGridData->gridWidth,pGridData->gridHeight);
 
 InvalidateRect(hWnd,&rect,FALSE);
 if(bUpdate)
 {
  UpdateWindow(hWnd);
 }
}

static void RR_GridCtrl_Resize(HWND hWnd)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 SendMessage(hWnd,WM_SIZE,SIZE_MAXIMIZED,MAKELPARAM(pGridData->gridWidth,pGridData->gridHeight));
}

static void RR_GridCtrl_SetFocus(HWND hWnd, BOOL bUpdate)
{
 Grid_T * pGridData;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(RR_GetReadOnlyStyle(hWnd))
 {
  if(bUpdate)
  {
   RR_GridCtrl_Refresh(hWnd,FALSE);
  }
  return;
 }
 
 if(GetFocus()!=hWnd)
 {
  SetFocus(hWnd);
 }

 
 if(bUpdate)
 {
  RR_GridCtrl_Refresh(hWnd,FALSE);
 }
}

static void RR_GridCtrl_CalcVisibleCellBoundaries(Grid_T * pGridData)
{
 int j;
 int height=0;

 RR_ASSERT(pGridData!=NULL); 

 //calc columns visible
 if(pGridData->homecol<=0||pGridData->homecol >= pGridData->cols ||
  pGridData->columnwidths[0]>=pGridData->gridWidth)
 {
  pGridData->rightvisiblecol  = pGridData->leftvisiblecol = 0;
 }
 else
 {
  if(pGridData->columnwidths[pGridData->homecol] >0)
  {
   pGridData->leftvisiblecol = pGridData->homecol;
  }
  else
  {
   pGridData->leftvisiblecol = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->homecol,1);
   if(pGridData->leftvisiblecol <0)
   {
    pGridData->leftvisiblecol =0;
   }
  }
  
  pGridData->rightvisiblecol  = RR_GridCtrl_GetLogicColOnScreen(pGridData,pGridData->homecol,RR_PARAM_START_COLNO|RR_RESULT_HALF);
  if(pGridData->rightvisiblecol <0)
  {
   RR_ASSERT(0);
   pGridData->rightvisiblecol  = pGridData->leftvisiblecol ;
  }

  if(pGridData->columnwidths[pGridData->rightvisiblecol] <=0)
  {
   pGridData->rightvisiblecol = RR_GridCtrl_GetNextNthColWithWidth(pGridData,pGridData->rightvisiblecol,-1);
   if(pGridData->rightvisiblecol <0)
   {
    pGridData->rightvisiblecol =pGridData->leftvisiblecol;
   }
  }
  
 }

 //calc rows visible;
 height = pGridData->titleheight+pGridData->headerrowheight;
 if(pGridData->homerow<=0 ||pGridData->homerow>=pGridData->rows ||
  height>=pGridData->gridHeight )
 {
  pGridData->bottomvisiblerow=pGridData->topvisiblerow = 0;
 }
 else
 {
  j=pGridData->homerow;
  pGridData->topvisiblerow = pGridData->homerow;

  j+=(pGridData->gridHeight-height)/pGridData->rowheight -1;

  if(j>=pGridData->rows)
  {
   j=pGridData->rows-1;   
  }
  
  pGridData->bottomvisiblerow  = (j>pGridData->topvisiblerow)?j:pGridData->topvisiblerow;

 }
 
}


static void RR_GridCtrl_DisplayTitle(HWND hWnd,HDC hdc)
{
 Grid_T * pGridData = NULL;
 RECT rect;
 HFONT hOldFont;
 COLORREF crOldColor;

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(pGridData->pszTitle[0]==0)
 {
  return;
 }

 SetRect(&rect,0,0,pGridData->gridWidth+1,pGridData->gridHeight+1);
 rect.bottom = pGridData->titleheight;
 
 SetBkMode(hdc,TRANSPARENT);
 hOldFont=(HFONT)SelectObject(hdc,pGridData->htitlefont);
 crOldColor = SetTextColor(hdc,pGridData->crTextTitle);
 

 //画矩形边框(EDGE_ETCHED: 突起内缘,凹下的外缘)
 DrawEdge(hdc,&rect,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST);
 DrawTextEx(hdc,pGridData->pszTitle,-1,&rect,/*DT_WORD_ELLIPSIS|*/DT_END_ELLIPSIS|DT_CENTER|DT_WORDBREAK|DT_NOPREFIX,NULL);

 SelectObject(hdc,hOldFont);
 SetTextColor(hdc,crOldColor);
}

//画空白区域矩形
static void RR_GridCtrl_DrawBlank(HDC hdc,RECT *pRect)
{
 HBRUSH holdbrush;
 HPEN holdpen;

 RR_ASSERT(pRect!=NULL);


 holdbrush=(HBRUSH)SelectObject(hdc,GetStockObject(LTGRAY_BRUSH));
 holdpen=(HPEN)SelectObject(hdc,GetStockObject(NULL_PEN));
 
 Rectangle(hdc,pRect->left,pRect->top,pRect->right,pRect->bottom);

 SelectObject(hdc,holdbrush);
 SelectObject(hdc,holdpen);
 

}

//返回值标识当前
static void  RR_GridCtrl_DrawCell(HWND hWnd,HDC hdc,GridCell_T *pGridCell,const RECT *pCellRect)
{
 Grid_T*pGridData;
 COLORREF crBrushColor;
 COLORREF crText;
 HBRUSH hbrush=NULL;
   HPEN hpen;
   HPEN  holdpen;
   HBRUSH  holdbrush;
 RECT rtCell;
 char szText[CELL_TEXT_MAX+1]={0};

 

 RR_ASSERT(pGridCell!=NULL && pCellRect!=NULL);

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 CopyRect(&rtCell,pCellRect);

 if(RR_GetReadOnlyStyle(hWnd))
 {
  crBrushColor = pGridData->crBrushReadOnly;
  crText = pGridData->crTextReadOnly;
 }
 else
 {
  crBrushColor = pGridData->crBrushCommon;
  crText = pGridData->crTextCommon;
 }

 if(!pGridData->bEditing && pGridCell->row >0 &&
  pGridCell->row   == pGridData->sel_row)
 {
  //是选择行
  if(RR_GetHighLightStyle(hWnd))
  {
   if(pGridData->bGridHasFocus )
   {
    crBrushColor =pGridData->crBrushLight;
    crText = pGridData->crTextLight;
   }
   else
   {
    crBrushColor =pGridData->crBrushGray;
    crText = pGridData->crTextGray;
   }
  }
 }

 hbrush = CreateSolidBrush(crBrushColor);
 hpen=CreatePen(PS_SOLID,1,pGridData->crGridLine);
 holdbrush=(HBRUSH)SelectObject(hdc,hbrush);
 holdpen=(HPEN)SelectObject(hdc,hpen);
 Rectangle(hdc,rtCell.left,rtCell.top,rtCell.right,rtCell.bottom);

 SelectObject(hdc,holdbrush);
 SelectObject(hdc,holdpen);
 DeleteObject(hbrush);
 DeleteObject(hpen);

 SetTextColor(hdc,crText);
   
 rtCell.right -= 2;
  rtCell.left += 2;

 if(!pGridData->bEditing ||
  !RR_GridCtrl_CmpCell(&pGridData->tEditCell,pGridCell))
 {
  RR_GridCtrl_GetCellText(hWnd, pGridCell->row,pGridCell->col,szText, sizeof(szText));

 }


 //文本在单元格里显示不下用省略号
 DrawTextEx(hdc,szText,-1,&rtCell,DT_END_ELLIPSIS|DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX,NULL);
}


//显示第0列
static void RR_GridCtrl_Display0Column(HWND hWnd,HDC hdc)
{
 Grid_T*pGridData;
 COLORREF crOldColor;
 RECT rectGrid;
 RECT rtCell;
 RECT rtTmp;
     HFONT hOldFont;
 char szText[CELL_TEXT_MAX+1]={0};
 int row=0;


 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 SetRect(&rectGrid,0,0,pGridData->gridWidth,pGridData->gridHeight);

 if(pGridData->cols<=0||pGridData->columnwidths[0]<=0 ||
  pGridData->gridWidth<=0 || pGridData->gridHeight<=0)
 {
  return;
 }

 SetBkMode(hdc,TRANSPARENT);
 crOldColor = SetTextColor(hdc,pGridData->crTextTitle);

 //显示第0行(header row)
 hOldFont = (HFONT)SelectObject(hdc,pGridData->hheadfont);
 SetRect(&rtCell,0,pGridData->titleheight,pGridData->columnwidths[0],pGridData->titleheight+pGridData->headerrowheight);

 if(RR_GridCtrl_GetNextNthColWithWidth(pGridData,0,1)<0)
 {
  //是最右边一列
  if(RR_GetExtendLastColumnStyle(hWnd))
  {
   //extend this column
   if(rtCell.right<rectGrid.right)
   {
    rtCell.right = rectGrid.right;
   }
  }
  else
  {
   if(rtCell.right<rectGrid.right)
   {
    //repaint right side of grid
    SetRect(&rtTmp,rtCell.right,pGridData->titleheight,rectGrid.right+1,rectGrid.bottom+1);
    RR_GridCtrl_DrawBlank(hdc,&rtTmp);
   }
  }
 }

 if(rtCell.top<rtCell.bottom)
  {
   CopyRect(&rtTmp,&rtCell);
  DrawEdge(hdc,&rtTmp,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST);
  }

 row=pGridData->topvisiblerow;
 if(row>0 && row<pGridData->rows &&
  (pGridData->bottomvisiblerow < pGridData->rows))
 {
  SelectObject(hdc,pGridData->hbodyfont); 
  
  while(row<=pGridData->bottomvisiblerow)
  {
   rtCell.top = rtCell.bottom;
    rtCell.bottom = rtCell.top + pGridData->rowheight;

   CopyRect(&rtTmp,&rtCell);
   DrawEdge(hdc,&rtTmp,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST);
   
   if(RR_GetRowHeadIsNumberStyle(hWnd))
   {
    sprintf(szText,"%d",row);
    RR_ASSERT(strlen(szText)<sizeof(szText));
    DrawTextEx(hdc,szText,-1,&rtTmp,DT_END_ELLIPSIS|DT_RIGHT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX,NULL);
   }
   else
   {
    RR_GridCtrl_GetCellText(hWnd, row,0,szText, sizeof(szText));
    DrawTextEx(hdc,szText,-1,&rtTmp,DT_END_ELLIPSIS|DT_LEFT|DT_VCENTER|DT_SINGLELINE|DT_NOPREFIX,NULL);
   }
       row++;
   }
  
 }

 SetRect(&rtTmp,rtCell.left,rtCell.bottom,rtCell.right+1,rectGrid.bottom+1);
 RR_GridCtrl_DrawBlank(hdc,&rtTmp);

      SelectObject(hdc,hOldFont);
 SetTextColor(hdc,crOldColor);
}

//显示除第0列外的列
static void RR_GridCtrl_DisplayColumn(HWND hWnd,HDC hdc,int col,int offset)
{
 Grid_T*pGridData;
     HFONT hOldFont;
 RECT rtCell;
 RECT rtTmp;
 RECT rectGrid;
 int row=0;
 char szText[CELL_TEXT_MAX+1]={0};
 COLORREF crOldColor;
 GridCell_T GridCell;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 SetRect(&rectGrid,0,0,pGridData->gridWidth,pGridData->gridHeight);

 if(col<=0||col >=pGridData->cols || offset>=pGridData->gridWidth ||
  pGridData->columnwidths[col]<=0)
 {
  return;
 }

 SetBkMode(hdc,TRANSPARENT);
 crOldColor = SetTextColor(hdc,pGridData->crTextTitle);

 //显示第0行( header row)
 hOldFont = (HFONT)SelectObject(hdc,pGridData->hheadfont);
 SetRect(&rtCell,offset,pGridData->titleheight,offset+pGridData->columnwidths[col],pGridData->titleheight +pGridData->headerrowheight);

 if(RR_GridCtrl_GetNextNthColWithWidth(pGridData,col,1)<0)
 {
  //当前列是最右边一列
  if(RR_GetExtendLastColumnStyle(hWnd))
  {
   //extend this column
   if(rtCell.right<rectGrid.right)
   {
    rtCell.right = rectGrid.right;
   }
  }
  else
  {
   if(rtCell.right<rectGrid.right)
   {
    //repaint right side of grid
    SetRect(&rtTmp,rtCell.right,pGridData->titleheight,rectGrid.right+1,rectGrid.bottom+1);
    RR_GridCtrl_DrawBlank(hdc,&rtTmp);
   }
  }
 }

 szText[0] =0;
  if(RR_GetColHeadIsNumberStyle(hWnd))
  {
  int high,low;
    
  high = ((col-1)/26);
  low = col % 26;
  
  if(high == 0)
  {
   high = 32;
  }
  else
  {
   high+=64;
  }

  if(low==0)
  {
   low = 90;
  }
  else
  {
   low += 64;
  }
  
  if(((high>64 && high<91)||high ==32) && low>64 && low<91)
  {
   sprintf(szText,"%c%c",high,low);
   RR_ASSERT(strlen(szText)<sizeof(szText));
  }
  }
  else
  {
   RR_GridCtrl_GetCellText(hWnd, 0,col,szText, sizeof(szText));
  }

  if(rtCell.top<rtCell.bottom)
  {
  CopyRect(&rtTmp,&rtCell);
  DrawEdge(hdc,&rtTmp,EDGE_ETCHED,BF_MIDDLE|BF_RECT|BF_ADJUST);
  DrawTextEx(hdc,szText,-1,&rtTmp,DT_END_ELLIPSIS|DT_CENTER|DT_VCENTER|DT_WORDBREAK|DT_SINGLELINE|DT_NOPREFIX,NULL);
  }

 //显示第0行外的行
 row=pGridData->topvisiblerow;
 if(row>0 && row<pGridData->rows &&
  (pGridData->bottomvisiblerow < pGridData->rows))
 {
  SelectObject(hdc,pGridData->hbodyfont);

  while(row<=pGridData->bottomvisiblerow)
  {
   rtCell.top = rtCell.bottom;
    rtCell.bottom = rtCell.top + pGridData->rowheight;
   RR_GridCtrl_SetCell(&GridCell,row,col);

   RR_GridCtrl_DrawCell(hWnd,hdc,&GridCell,&rtCell);
   
        row++;
  }
 
 }

 SetRect(&rtTmp,rtCell.left,rtCell.bottom,rtCell.right+1,rectGrid.bottom+1);
 RR_GridCtrl_DrawBlank(hdc,&rtTmp);

      SelectObject(hdc,hOldFont);
 SetTextColor(hdc,crOldColor);
}

static void RR_GridCtrl_DisplayCellEditBox(HWND hWnd)
{
 Grid_T*pGridData;
 RECT rtCell;
 RECT rtEdit;
 char szText[CELL_TEXT_MAX+1];

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(!RR_GridCtrl_GetCellRect(hWnd,pGridData->tEditCell.row,pGridData->tEditCell.col,&rtCell))
 {
  SetRect(&rtCell,0,0,0,0);
 }
 
 InflateRect(&rtCell, -1, -1);
 if(IsRectEmpty(&rtCell))
 {
  ShowWindow(pGridData->hChildEdit,SW_HIDE);
  return ;
 }

 
 GetWindowRect(pGridData->hChildEdit,&rtEdit);
 RR_ScreenRectToClient(hWnd,&rtEdit);
 if(EqualRect(&rtCell,&rtEdit))
 {
  return;
 }
 
 //不相等,需要调整
 MoveWindow(pGridData->hChildEdit,rtCell.left,rtCell.top,
   RR_RECT_WIDTH(rtCell),RR_RECT_HEIGHT(rtCell),FALSE);
 
 GetWindowText(pGridData->hChildEdit,szText,sizeof(szText));
 if(szText[0]!=0)
 {
  int start=0;
  int end=0;
  
  //编辑框在列宽变化过程中文本自动适应
  SendMessage(pGridData->hChildEdit,EM_GETSEL,(WPARAM)&start,(LPARAM)&end);
  SetWindowText(pGridData->hChildEdit,szText);
  SendMessage(pGridData->hChildEdit,EM_SETSEL,start,end);

 }
 ShowWindow(pGridData->hChildEdit,SW_SHOW);
 
}

static BOOL RR_GridCtrl_Discard_Edit(HWND hWnd)
{
 Grid_T*pGridData;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(!pGridData->bEditing)
 {
  //当前不是编辑状态
  return TRUE;
 }

 pGridData->tEditCell.row = -1;
 pGridData->tEditCell.col =-1;
 pGridData->bEditing = FALSE;

 if((GetWindowLong(pGridData->hChildEdit,GWL_STYLE)& WS_VISIBLE))
 {
  ShowWindow(pGridData->hChildEdit,SW_HIDE);
  //隐藏会让编辑框失去焦点,在失去焦点会调用RR_GridCtrl_Exit_Edit
 }

 SetWindowText(pGridData->hChildEdit,"");
 SendMessage(pGridData->hChildEdit,EM_SETMODIFY,FALSE,0);

 return TRUE;
}

static BOOL RR_GridCtrl_Exit_Edit(HWND hWnd)
{
 Grid_T*pGridData;
 char szText[CELL_TEXT_MAX+1]={0};
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(!pGridData->bEditing)
 {
  //当前不是编辑状态
  return TRUE;
 }

 RR_ASSERT(pGridData->tEditCell.row >0 && pGridData->tEditCell.col>0);

 if(RR_GridCtrl_Notify(hWnd,GN_EXIT_CELL_EDITBOX, MAKELPARAM(pGridData->tEditCell.row,pGridData->tEditCell.col )))
 {
  //父窗口通知响应不让退出编辑
  return FALSE;
 }


 pGridData->bCellModified = SendMessage(pGridData->hChildEdit,EM_GETMODIFY,0,0);
 if(pGridData->bCellModified)
 {
  if(!pGridData->bRowModified)
  {
   pGridData->bRowModified = TRUE;
  }
  if (!pGridData->bGridTextModified)
  {
   pGridData->bGridTextModified = TRUE;
  }
 }

 pGridData->bEditing = FALSE;
 
 //RR_GridCtrl_SetCellText不能放在只读标识获取之前
 //RR_GridCtrl_SetCellText不能放在pGridData->bEditing置FALSE之前
 GetWindowText(pGridData->hChildEdit,szText,sizeof(szText));
 RR_GridCtrl_SetCellText(hWnd,pGridData->tEditCell.row,pGridData->tEditCell.col,szText);


 if((GetWindowLong(pGridData->hChildEdit,GWL_STYLE)& WS_VISIBLE))
 {
  ShowWindow(pGridData->hChildEdit,SW_HIDE);
  //隐藏会让编辑框失去焦点,在失去
  //焦点会再次调用RR_GridCtrl_Exit_Edit
 }

 SetWindowText(pGridData->hChildEdit,"");
 SendMessage(pGridData->hChildEdit,EM_SETMODIFY,FALSE,0);

 if(pGridData->tEditCell.row!=-1 && pGridData->tEditCell.col!=-1)
 {
  RR_GridCtrl_Notify(hWnd,GN_AFTER_EXIT_CELL_EDITBOX, MAKELPARAM(pGridData->tEditCell.row,pGridData->tEditCell.col ));
 }

 pGridData->tEditCell.row = -1;
 pGridData->tEditCell.col =-1;

 return TRUE;
}

//强制性退出编辑,如果父窗口响应不让退出编辑,
//则将本次编辑的数据丢失
static BOOL RR_GridCtrl_Force_Exit_Edit(HWND hWnd)
{
 BOOL bRet = TRUE;
 Grid_T*pGridData;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(!pGridData->bEditing)
 {
  //当前不是编辑状态
  return TRUE;
 }
 
 if(!RR_GridCtrl_Exit_Edit(hWnd))
 {
  
  RR_GridCtrl_Discard_Edit(hWnd);
  bRet = FALSE;
 }

 return bRet;
}


//iSetSel 进入编辑框时设置光标位置 0 -- 光标在文本末
// 1-- 选中所有文本
static BOOL RR_GridCtrl_Enter_Edit(HWND hWnd,GridCell_T*ptCell,int iSetSel)
{
 Grid_T*pGridData;
 RECT rectCell;
 char szText[CELL_TEXT_MAX+1];
 int len=0;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(ptCell==NULL || ptCell->row<1 ||ptCell->row > pGridData->rows-1||
  ptCell->col<1 || ptCell->col > pGridData->cols-1 ||RR_GetReadOnlyStyle(hWnd))
 {
  return FALSE;
 }

 if(!RR_GridCtrl_GetCellRect(hWnd,ptCell->row,ptCell->col,&rectCell))
 {
  return FALSE;
 }

 InflateRect(&rectCell, -1, -1);
 if(IsRectEmpty(&rectCell))
 {
  return FALSE;
 }

 
 if(pGridData->bEditing)
 {
  //正在编辑
  RR_ASSERT(pGridData->tEditCell.row >0 && pGridData->tEditCell.col >0);
   //确认原来确实有有效的编辑单元
  if(pGridData->tEditCell.row==ptCell->row &&
   pGridData->tEditCell.col ==ptCell->col)
  {
   //已在编辑
   return TRUE;
  }
  else
  {
   //退出原来的编辑单元
   if(!RR_GridCtrl_Exit_Edit(hWnd))
   {
    //父窗口退出编辑通知响应不让退出
    return FALSE;
   }
  }
   
 }

 if(RR_GridCtrl_ChgSelRow(hWnd,ptCell->row))
 {
  //选择行不让改变
  return FALSE;
 }
 

 RR_GridCtrl_GetCellText(hWnd,ptCell->row,ptCell->col,szText,sizeof(szText));
 SetWindowText(pGridData->hChildEdit,szText);
 SendMessage(pGridData->hChildEdit,EM_SETMODIFY,FALSE,0);
 pGridData->bCellModified = FALSE;

 pGridData->bEditing = TRUE;
 pGridData->tEditCell.row = ptCell->row;
 pGridData->tEditCell.col = ptCell->col;

 
 //SendMessage(pGridData->hChildEdit,  WM_SETFONT, (WPARAM) pGridData->hbodyfont,  FALSE); 
 MoveWindow(pGridData->hChildEdit,rectCell.left,rectCell.top,
     RR_RECT_WIDTH(rectCell),RR_RECT_HEIGHT(rectCell),FALSE);
 ShowWindow(pGridData->hChildEdit,SW_SHOW);
 SetFocus(pGridData->hChildEdit);

 len = strlen(szText);
 if(iSetSel == 0) //光标在文本末
 {
  SendMessage(pGridData->hChildEdit,EM_SETSEL,len+1,len+1);
 }
 else if (iSetSel == 1)//所有文本被选中
 {
  SendMessage(pGridData->hChildEdit,EM_SETSEL,0,len+1);
 }


 RR_GridCtrl_Notify(hWnd,GN_ENTRY_CELL_EDITBOX,MAKELPARAM(ptCell->row,ptCell->col));
 return TRUE;
 
}

 

////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////

static LRESULT RR_GridCtrlOnSetText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 char *pszTitle = (char*)lParam;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 RR_Safe_Free(pGridData->pszTitle);

 if(pszTitle!=NULL)
 {
  pGridData->pszTitle = (char*)RR_MALLOC(strlen(pszTitle)+1);
  strcpy(pGridData->pszTitle,pszTitle);
 }
 else
 {
  pGridData->pszTitle = (char*)RR_MALLOC(1);
 }

 RR_GridCtrl_SetTitleBarArea(hWnd);
 RR_GridCtrl_Resize(hWnd);
 return 0;
    
}


static LRESULT RR_GridCtrlOnCreate(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 LPCREATESTRUCT lpcs;

 lpcs = (LPCREATESTRUCT)lParam;
 RR_ASSERT(lpcs->lpCreateParams!=NULL);
 pGridData = (Grid_T * )lpcs->lpCreateParams; 
 pGridData->hWnd =hWnd;
 SetWindowLong(hWnd,GWL_USERDATA,(LONG)pGridData);

 pGridData->hChildEdit =CreateWindowEx(0/*WS_EX_TRANSPARENT*/,"EDIT","",
     WS_CHILD|ES_AUTOHSCROLL|ES_LEFT/*|WS_BORDER*/,0,0,0,0,hWnd,NULL,lpcs->hInstance,NULL);
 RR_ASSERT(pGridData->hChildEdit!=NULL);


 OriginalEditProc=(CELLEDIT_PROC_T)GetWindowLong(pGridData->hChildEdit ,GWL_WNDPROC);  
 SetWindowLong(pGridData->hChildEdit,GWL_WNDPROC,(long)ModifierCellEditProc); 

 SendMessage(pGridData->hChildEdit,EM_LIMITTEXT,CELL_TEXT_MAX,0);
 SendMessage(pGridData->hChildEdit,  WM_SETFONT, (WPARAM) pGridData->hbodyfont,  FALSE); 


 RR_GridCtrl_SetTitleBarArea(hWnd);
 
 
 return 0;
}

static LRESULT RR_GridCtrlOnSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int gridWidth = LOWORD(lParam);
 int gridHeight = HIWORD(lParam);


 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);


 if(gridWidth == 0 || gridHeight==0)
 {
  return 0;
 }

 pGridData->gridWidth = gridWidth;
 pGridData->gridHeight = gridHeight;

 if(pGridData->bSizing)
 {
  return 0;
 }

 pGridData->bSizing= TRUE;
 
 RR_GridCtrl_ShowHscroll(hWnd);
 RR_GridCtrl_ShowVscroll(hWnd);

 gridWidth = pGridData->gridWidth;
 gridHeight = pGridData->gridHeight;

 //微调Grid大小,让其刚刚好放下完整的行
 if(RR_GetShowIntegralRowStyle(hWnd) && (pGridData->bShowVScroll))
 {
  int height = gridHeight;
  //int width=gridWidth;
  //int nrows;
  int remainder=0;


  height-=pGridData->titleheight + pGridData->headerrowheight;
  if(height <= pGridData->rowheight)
  {
   return 0;
  }

  //nrows=(int)((height)/pGridData->rowheight);//可以放下多少行
  //remainder=(height)-(nrows * pGridData->rowheight);
  remainder = height%(pGridData->rowheight);
  //if(remainder>0)
  {
   int adjust_height=0;
   int rect_bottom =0;
   RECT rect;

   GetWindowRect(hWnd,&rect);
   RR_ScreenRectToClient(GetParent(hWnd), &rect);
   rect_bottom = rect.bottom; 
   
   
   height = remainder+pGridData->adjust_height;
   adjust_height = height %(pGridData->rowheight);
   if(height - adjust_height>0)
   {
    RR_ASSERT((height - adjust_height )> adjust_height &&
     (height - adjust_height )> remainder);
    rect.bottom+=(height - adjust_height)-remainder;
    pGridData->adjust_height= adjust_height;
   }
   else
   {
    RR_ASSERT(height - adjust_height ==0);
    rect.bottom-= remainder;
    pGridData->adjust_height+=remainder;
   }

   if(rect_bottom!=rect.bottom)
   {
    MoveWindow(hWnd,rect.left,rect.top,RR_RECT_WIDTH(rect),RR_RECT_HEIGHT(rect),TRUE);
    RR_GridCtrl_ShowVscroll(hWnd);
   }
   
  }
 }
 
 pGridData->bSizing= FALSE;
 RR_GridCtrl_Refresh(hWnd,FALSE);
 return 0;    
}

static LRESULT RR_GridCtrlOnPaint(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 HDC hdc;
 PAINTSTRUCT ps;
 Grid_T * pGridData = NULL;
 int col;
 int offset=0;

 //避免闪烁
 HBITMAP hBitmap;
 HDC hdcMem;
 HGDIOBJ hOldSel ;
 RECT rtGrid;

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 


#ifdef _DEBUG
{
 RECT rtGrid;
 GetClientRect(hWnd,&rtGrid);
 RR_ASSERT(rtGrid.right == pGridData->gridWidth &&
  rtGrid.bottom == pGridData->gridHeight);
 RR_ASSERT(pGridData->homecol>0 && pGridData->homerow>0);
}
#endif

 RR_GridCtrl_CalcVisibleCellBoundaries(pGridData);
 RR_ASSERT(pGridData->leftvisiblecol>=0 && pGridData->rightvisiblecol  >= pGridData->leftvisiblecol
  &&pGridData->rightvisiblecol <pGridData->cols);


 hdc = BeginPaint(hWnd, &ps);
 //hdc = GetDC(hWnd);

 //避免闪烁
 hBitmap = CreateCompatibleBitmap(hdc,pGridData->gridWidth,pGridData->gridHeight);
 hdcMem = CreateCompatibleDC(hdc);
 hOldSel = SelectObject(hdcMem,hBitmap);
 SetRect(&rtGrid,0,0,pGridData->gridWidth,pGridData->gridHeight);
 FillRect( hdcMem, &rtGrid, (HBRUSH)GetStockObject(GRAY_BRUSH));//用背景色刷一下

 //display title
     RR_GridCtrl_DisplayTitle(hWnd,hdcMem/*hdc*/);
 
 //display column 0;
 if(pGridData->columnwidths[0]>0)
 {
  RR_GridCtrl_Display0Column(hWnd,hdcMem/*hdc*/);
  offset = pGridData->columnwidths[0];
 }
 
 col=pGridData->leftvisiblecol;
 if(col>0)
 {
  for(;col<=pGridData->rightvisiblecol;col++)
  {
   if(pGridData->columnwidths[col]>0 && offset< pGridData->gridWidth)
   {
    RR_GridCtrl_DisplayColumn(hWnd,hdcMem/*hdc*/,col,offset);
    offset+=pGridData->columnwidths[col];
   }
  }

 }

 //避免闪烁
 BitBlt(hdc,0,0,pGridData->gridWidth,pGridData->gridHeight,hdcMem,0,0,SRCCOPY);
 SelectObject(hdcMem,hOldSel);
 DeleteObject(hBitmap);
 DeleteDC(hdcMem);
 
 EndPaint(hWnd, &ps);
 //ValidateRect(hWnd,&rtGrid);
 //ReleaseDC(hWnd,hdc);

 if(pGridData->bEditing)
 {
  RR_GridCtrl_DisplayCellEditBox(hWnd);
 }

 
 return 0;
}


static int RR_GridCtrl_GetResizeCol(Grid_T * pGridData,int x,int y,int *pRefCol)
{
 int row ;
 int cur_col=-1;
 int left_col=-1;
 int right_col=-1;
 int resize_col =-1;

 RR_ASSERT(pGridData!=NULL);

 if(pRefCol!=NULL)
 {
  *pRefCol = -1;

 }

 row = RR_GridCtrl_GetRowOfMouse(pGridData,y);
 if (row!=0)
 {
  return -1;
 }

 cur_col = RR_GridCtrl_GetColOfMouse(pGridData,x);
 if(cur_col<0)
 {
  return -1;
 }
 else
 {
  if(pRefCol!=NULL)
  {
   *pRefCol = cur_col;
  }
 }

 left_col = RR_GridCtrl_GetColOfMouse(pGridData,x-6);
 right_col = RR_GridCtrl_GetColOfMouse(pGridData,x+6);
 if(left_col!=cur_col)
 {
  //鼠标在列的左部分
  if(right_col!=cur_col)
  {
   //同时也在右部分
    if(RR_GridCtrl_GetNextNthColWithWidth(pGridData,cur_col,1)<0 )
    {
     //最后一列可见的列(拖下一个)

    if(cur_col<pGridData->cols-1 )
    {
     resize_col = cur_col+1;
    }
    else
    {
     resize_col = pGridData->cols-1;
    }

    return resize_col;
    }

  }

  //鼠标在左部分拖上一个
  if(left_col<0)
  {
   if(pGridData->columnwidths[0]>0)
   {
    left_col =0;
   }
   else
   {
    left_col =1;
   }
  }

  resize_col = cur_col-1;
  if(resize_col<left_col)
  {
   resize_col = left_col;
  }
  return resize_col;  
 }
 
 if(right_col!=cur_col)
 {
  //鼠标在右部分
   if(RR_GridCtrl_GetNextNthColWithWidth(pGridData,cur_col,1)<0 )
   {
    //最后一列可见的列(拖下一个)

   if(cur_col<pGridData->cols-1 )
   {
    resize_col = cur_col+1;
   }
   else
   {
    resize_col = pGridData->cols-1;
   }

   return resize_col;
   }
  
  //在右部分拖自己
  return cur_col;
 }

 return resize_col;
}

static LRESULT RR_GridCtrlOnLButtonDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int row;
 int x=LOWORD(lParam);
 int y = HIWORD(lParam);


 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 row = RR_GridCtrl_GetRowOfMouse(pGridData,y);
 if (row == 0 && RR_GetColumnAllowResizeStyle(hWnd)&&
  pGridData->cursortype == CURSOR_DRAG)
 {
  int resize_col;

  resize_col = RR_GridCtrl_GetResizeCol(pGridData,x,y,NULL);
  if(resize_col>=0)
  {
   SetCapture(hWnd);

   if(!pGridData->bColumnSizing)
   {
    pGridData->bColumnSizing = TRUE;
    pGridData->columnInitx=x;
   }
   pGridData->resizeColumn =resize_col;
   pGridData->columnInitSize = pGridData->columnwidths[resize_col];
  } 
 }
 else
 {
  GridCell_T tCell;

  tCell.row = row;   
  tCell.col =  RR_GridCtrl_GetColOfMouse(pGridData,x);

  if(!RR_GridCtrl_Notify(hWnd,GN_CLICK_CELL, MAKELPARAM(tCell.row,tCell.col )))
  {
   if(pGridData->bEditing)
   {
    if(tCell.row >0 && tCell.col  >0)
    {
     if(tCell.row != pGridData->tEditCell.row ||
      tCell.col  != pGridData->tEditCell.col)
     {
      //切换到另外的单元编辑
      RR_GridCtrl_Enter_Edit(hWnd,&tCell,0);
     }
     
    }
    else
    {
     RR_GridCtrl_Exit_Edit(hWnd);
    }
    }
   else
   {
    //不在编辑中
    if(row>0 && row< pGridData->rows )
    {
     RR_GridCtrl_ChgSelRow(hWnd,row);
    }
   }
   
  }
  
   }

 if(!pGridData->bEditing)
 {
  //不在编辑中
  RR_GridCtrl_SetFocus(hWnd,TRUE);
 }
  
 return 0;
}

static LRESULT RR_GridCtrlOnMouseMove(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int x=LOWORD(lParam);
 int y=HIWORD(lParam);
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
   
 if(pGridData->bColumnSizing)
 {
  int add_width; //增减宽度
  int new_width;
  RECT rect;
  
  if(x<0 || x>pGridData->gridWidth+1 ||
   y<0 || y>pGridData->gridHeight+1)
  {
   return 0;
  }
  
  add_width=x-pGridData->columnInitx;
  new_width=pGridData->columnInitSize + add_width;
  if(new_width<0)
  {
   new_width=0;
  }
  else if(new_width>=pGridData->gridWidth)
  {
   new_width = pGridData->gridWidth-1;
  }

  if(pGridData->columnwidths[pGridData->resizeColumn] ==new_width)
  {
   //宽度没有发生变化
   return 0;
  }

  pGridData->columnwidths[pGridData->resizeColumn] = new_width;
  if(pGridData->resizeColumn>0)
  {
   RR_GridCtrl_AdjustHomeCol(hWnd,pGridData->resizeColumn);
  }
  
  RR_GridCtrl_ShowHscroll(hWnd);
  SetRect(&rect,0,pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);

  InvalidateRect(hWnd,&rect,FALSE);
 }
 else
 {
  int resize_col;

  resize_col = RR_GridCtrl_GetResizeCol(pGridData,x,y,NULL);

  if( resize_col>=0 &&  RR_GetColumnAllowResizeStyle(hWnd))
  {
   pGridData->cursortype = CURSOR_DRAG;
   SetCursor(LoadCursor(NULL, IDC_SIZEWE));
  }
  else if(pGridData->bEditing)
  {
   pGridData->cursortype = CURSOR_ARROW;//CURSOR_EDITING;
   SetCursor(LoadCursor(NULL,IDC_ARROW ));
  }
  else
  {
   pGridData->cursortype = CURSOR_ARROW;
   SetCursor(LoadCursor(NULL,IDC_ARROW ));
  }
 }

 
 
 return 0;
}

static LRESULT RR_GridCtrlOnLButtonUp(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);


 if(pGridData->bColumnSizing)
 {
  pGridData->bColumnSizing = FALSE;
  SetCursor(LoadCursor(NULL, IDC_ARROW));
  pGridData->cursortype = CURSOR_ARROW;

  if(pGridData->columnwidths[pGridData->resizeColumn] !=pGridData->columnInitSize)
  {
   pGridData->bGridFrameModified= TRUE;
  }
 }
 
 ReleaseCapture();

 return 0;
}

//双击事件之前会有一次Down事件,一次up事件
static LRESULT RR_GridCtrlOnLButtonDblclk(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 GridCell_T tCell;
 int x=LOWORD(lParam);
 int y=HIWORD(lParam);
 

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 tCell.row= RR_GridCtrl_GetRowOfMouse(pGridData,y);
 tCell.col = RR_GridCtrl_GetColOfMouse(pGridData,x);
 
 if(!RR_GridCtrl_Notify(hWnd,GN_DCLICK_CELL,MAKELPARAM(tCell.row,tCell.col )))
 {
  if(tCell.row >0 && tCell.col >0 && !pGridData->bEditing)
  {
   RR_GridCtrl_Enter_Edit(hWnd,&tCell,0);
  }
  else if (pGridData->bEditing)
  {
   RR_GridCtrl_Exit_Edit(hWnd);
  }
 }
 return 0;
}

static LRESULT RR_GridCtrlOnSetCursor(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 //注:鼠标在滚动条上也会收到WM_SETCURSOR消息,
 //造成滚动条上会显示双向箭头鼠标光标
 /*Grid_T * pGridData = NULL;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 switch(pGridData->cursortype)
 {
  case CURSOR_DRAG:
   SetCursor(LoadCursor(NULL, IDC_SIZEWE));
   break;
  case CURSOR_ARROW:
   SetCursor(LoadCursor(NULL,IDC_ARROW ));
   break;
  case CURSOR_EDITING:
   SetCursor(LoadCursor(NULL,IDC_IBEAM));
   break; 
  default:
   break;
 }*/

 return 0;
}
 


static LRESULT RR_GridCtrlOnDestroy(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData;
  
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 RR_GridCtrl_FreeStruct(pGridData);
 return 0;
}

static LRESULT RR_GridCtrlOnHScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData;
 RECT rect;
 int old_pos=0;
 int cur_pos=0;
 int min=0;
 int max=0; 
 int interval=0;


  
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 RR_GridCtrl_SetFocus(hWnd,FALSE);

  
 switch(LOWORD(wParam))
 {
  case SB_PAGERIGHT:
  {

   interval = RR_GridCtrl_GetColumnsWithWidth(pGridData,pGridData->leftvisiblecol,pGridData->rightvisiblecol,NULL);
   if(interval<2)
   {
    interval =1;
   }
   else
   {
    interval --;
   }
   old_pos=GetScrollPos(hWnd,SB_HORZ);
   cur_pos = old_pos+interval;
   GetScrollRange(hWnd,SB_HORZ,&min,&max);
   if(cur_pos>max)
   {
    cur_pos = max;
   }

   if(cur_pos>old_pos)
   {
    SetScrollPos(hWnd,SB_HORZ,cur_pos,TRUE);

    RR_GridCtrl_SetHomeCol(hWnd,cur_pos);

    SetRect(&rect,pGridData->columnwidths[0],pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);
    InvalidateRect(hWnd,&rect,FALSE);
   }
  }
   break;
  case SB_PAGELEFT:
  {

   interval = RR_GridCtrl_GetColumnsWithWidth(pGridData,pGridData->leftvisiblecol,pGridData->rightvisiblecol,NULL);
   if(interval<2)
   {
    interval =1;
   }
   else
   {
    interval --;
   }
   
   old_pos=GetScrollPos(hWnd,SB_HORZ);
   cur_pos = old_pos-interval;
   GetScrollRange(hWnd,SB_HORZ,&min,&max);
   if(cur_pos<min)
   {
    cur_pos = min;
   }

   if(cur_pos<old_pos)
   {
    SetScrollPos(hWnd,SB_HORZ,cur_pos,TRUE);
    RR_GridCtrl_SetHomeCol(hWnd,cur_pos);

    SetRect(&rect,pGridData->columnwidths[0],pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);
    InvalidateRect(hWnd,&rect,FALSE);
   }
  }
   break;
  case SB_LINERIGHT:
  {
   
   old_pos=GetScrollPos(hWnd,SB_HORZ);
   cur_pos = old_pos+1;
   GetScrollRange(hWnd,SB_HORZ,&min,&max);
   if(cur_pos>max)
   {
    cur_pos = max;
   }

   if(cur_pos>old_pos)
   {
    SetScrollPos(hWnd,SB_HORZ,cur_pos,TRUE);
    RR_GridCtrl_SetHomeCol(hWnd,cur_pos);

    SetRect(&rect,pGridData->columnwidths[0],pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);
    InvalidateRect(hWnd,&rect,FALSE);
   }
  }
   break;
  case SB_LINELEFT:
  {
   
   old_pos=GetScrollPos(hWnd,SB_HORZ);
   cur_pos = old_pos-1;
   GetScrollRange(hWnd,SB_HORZ,&min,&max);
   if(cur_pos<min)
   {
    cur_pos = min;
   }

   if(cur_pos<old_pos)
   {
    SetScrollPos(hWnd,SB_HORZ,cur_pos,TRUE);
    RR_GridCtrl_SetHomeCol(hWnd,cur_pos);
    
    SetRect(&rect,pGridData->columnwidths[0],pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);
    InvalidateRect(hWnd,&rect,FALSE);
   }
   
  }
   break;
  case SB_THUMBTRACK:
  {
   
   cur_pos=HIWORD(wParam);
   
   SetScrollPos(hWnd,SB_HORZ,cur_pos,TRUE);
   RR_GridCtrl_SetHomeCol(hWnd,cur_pos);
   
   SetRect(&rect,pGridData->columnwidths[0],pGridData->titleheight,
     pGridData->gridWidth,pGridData->gridHeight);
   InvalidateRect(hWnd,&rect,FALSE);
  }
   break;
  default:
   break;
  
 }

 return 0;
}

static LRESULT RR_GridCtrlOnVScroll(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData;
 RECT rect;
 int min=0,max=0; 
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 RR_GridCtrl_SetFocus(hWnd,FALSE);

 switch(LOWORD(wParam))
 {
  case SB_THUMBTRACK://拖动滚动条
   pGridData->homerow = HIWORD(wParam);
   SetScrollPos(hWnd,SB_VERT,HIWORD(wParam),TRUE);
   SetRect(&rect,0,pGridData->titleheight+pGridData->headerrowheight,
    pGridData->gridWidth,pGridData->gridHeight);
   InvalidateRect(hWnd,&rect,FALSE);
   break;
  case SB_PAGEDOWN://Roger: home行需要重设
  {
   int rows_page;
   int pos;
   
   SetRect(&rect,0,pGridData->titleheight+pGridData->headerrowheight,
    pGridData->gridWidth,pGridData->gridHeight);
   GetScrollRange(hWnd,SB_VERT,&min,&max);

   pos = GetScrollPos(hWnd,SB_VERT);
   rows_page =  RR_RECT_HEIGHT(rect)/pGridData->rowheight;
   pos+=rows_page;
   if(pos>max)
   {
    pos = max;
   }
   pGridData->homerow = pos;
   SetScrollPos(hWnd,SB_VERT,pos,TRUE);
   InvalidateRect(hWnd,&rect,FALSE);
  }
   break;
  case SB_PAGEUP:
  {
   int rows_page;
   int pos; 
   
   SetRect(&rect,0,pGridData->titleheight+pGridData->headerrowheight,
    pGridData->gridWidth,pGridData->gridHeight);
   GetScrollRange(hWnd,SB_VERT,&min,&max);

   rows_page =  RR_RECT_HEIGHT(rect)/pGridData->rowheight;
   pos = GetScrollPos(hWnd,SB_VERT);
   pos-=rows_page;
   if(pos<min)
   {
    pos = min;
   }
   pGridData->homerow =pos;
   SetScrollPos(hWnd,SB_VERT,pos,TRUE);
   InvalidateRect(hWnd,&rect,FALSE);
  }
   break;
  case SB_LINEDOWN:
  {
   int pos; 
   
   SetRect(&rect,0,pGridData->titleheight+pGridData->headerrowheight,
    pGridData->gridWidth,pGridData->gridHeight);
   GetScrollRange(hWnd,SB_VERT,&min,&max);
   pos=GetScrollPos(hWnd,SB_VERT);
   pos++;
   if(pos > max)
   {
    pos=max;
   }
   pGridData->homerow = pos;
   SetScrollPos(hWnd,SB_VERT,pos,TRUE);
   InvalidateRect(hWnd,&rect,FALSE);
  }
   break;
  case SB_LINEUP:
  {
   int pos; 
   
   SetRect(&rect,0,pGridData->titleheight+pGridData->headerrowheight,
    pGridData->gridWidth,pGridData->gridHeight);
   GetScrollRange(hWnd,SB_VERT,&min,&max);
   
   pos=GetScrollPos(hWnd,SB_VERT);
   pos--;
   
   if(pos < min)
   {
    pos=min;
   }
   pGridData->homerow = pos;
   SetScrollPos(hWnd,SB_VERT,pos,TRUE);
   InvalidateRect(hWnd,&rect,FALSE);
  }
   break;
  default:
   break;
  
 }
 return 0;
}

static LRESULT RR_GridCtrlOnKeyDown(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int rows_page=0;
 int row_diff=0;
 int row=0;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 
 switch(wParam)
 {
  case VK_NEXT://PAGE DOWN key
  {
   if(pGridData->rows <2 || pGridData->sel_row >= pGridData->rows-1 ||
    !pGridData->bShowVScroll)
   {
    break;
   }
   row = pGridData->sel_row;
   row_diff = row - pGridData->homerow;
   rows_page = pGridData->bottomvisiblerow - pGridData->topvisiblerow+1;
   if(row_diff>=0 && row_diff<rows_page )
   {
    //当前选择行是可见的,
    //选择行滚动条一起翻页
    RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_PAGEDOWN,0);
    //注意:此时不能基于topvisiblerow加,topvisiblerow要到WM_PAINT响应时才更新
    row = pGridData->homerow+row_diff;
   }
   else
   {
    //不可见,改变选择行,使其可见,滚动条不动
    if(row_diff<0)
    {
     row= pGridData->topvisiblerow;
    }
   }
   if(row<1)
   {
    row=1;
   }
   else if(row > pGridData->rows-1)
   {
    row=pGridData->rows-1;
   }

   RR_GridCtrl_ChgSelRow(hWnd,row);
   RR_GridCtrl_Refresh(hWnd,FALSE);
  }
   break;
  case VK_PRIOR://PAGE UP key
  {
   if(pGridData->rows <2 || pGridData->sel_row <2||
    !pGridData->bShowVScroll)
   {
    break;
   }

   row = pGridData->sel_row;

   row_diff = row- pGridData->homerow;
   rows_page = pGridData->bottomvisiblerow - pGridData->topvisiblerow+1;
   if(row_diff>=0 && row_diff<rows_page )
   {
    //当前选择行是可见的,
    //选择行滚动条一起翻页
    RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_PAGEUP,0);
    //注意:此时不能基于topvisiblerow加,topvisiblerow要到WM_PAINT响应时才更新
    row = pGridData->homerow+row_diff;
   }
   else
   {
    //不可见,改变选择行,使其可见,滚动条不动
    if(row_diff>=rows_page)
    {
     row= pGridData->bottomvisiblerow;
    }
   }
   if(row<1)
   {
    row=1;
   }
   else if(row > pGridData->rows-1)
   {
    row =pGridData->rows-1;
   }
   
   RR_GridCtrl_ChgSelRow(hWnd,row );
   RR_GridCtrl_Refresh(hWnd,FALSE);

  }
   break;
  case VK_DOWN:
  {
   if(pGridData->rows <2 || pGridData->sel_row >= pGridData->rows-1 )
   {
    break;
   }

   row = pGridData->sel_row;
   row ++;
   
   if(row > pGridData->rows-1)
   {
    row =pGridData->rows-1;
   }
   
   if(row > pGridData->bottomvisiblerow && pGridData->bShowVScroll)
   {
    RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_LINEDOWN,0);
   }

   RR_GridCtrl_ChgSelRow(hWnd,row );
   RR_GridCtrl_Refresh(hWnd,FALSE);
  }
   break;
  case VK_UP:
  {
   if(pGridData->rows <2 || pGridData->sel_row <2)
   {
    break;
   }
   
   row = pGridData->sel_row;
   row --;
   
   if(row <1)
   {
    row =1;
   }

   if(row <pGridData->topvisiblerow && pGridData->bShowVScroll)
   {
    RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_LINEUP,0);
   }
   
   RR_GridCtrl_ChgSelRow(hWnd,row );
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  }
  case VK_LEFT:
  {
   if(pGridData->bShowHScroll)
   {
    RR_GridCtrlOnHScroll(hWnd,WM_HSCROLL,SB_PAGELEFT,0);
   }
   break;
  }
  case VK_RIGHT:
  {
   if(pGridData->bShowHScroll)
   {
    RR_GridCtrlOnHScroll(hWnd,WM_HSCROLL,SB_PAGERIGHT,0);
   }
   break;
  }
  case VK_HOME :
   if(pGridData->rows <2 || pGridData->sel_row <2)
   {
    break;
   }
   if(pGridData->bShowVScroll)
   {
    int min;
    int max;
    
    GetScrollRange(hWnd,SB_VERT,&min,&max);
    SetScrollPos(hWnd,SB_VERT,min,TRUE);
    pGridData->homerow = min;
   }
   RR_GridCtrl_ChgSelRow(hWnd,1);
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case VK_END:
   if(pGridData->rows <2 || pGridData->sel_row >= pGridData->rows-1 )
   {
    break;
   }
   if(pGridData->bShowVScroll)
   {
    int min;
    int max;
    
    GetScrollRange(hWnd,SB_VERT,&min,&max);
    SetScrollPos(hWnd,SB_VERT,max,TRUE);
    pGridData->homerow = max;
   }
   RR_GridCtrl_ChgSelRow(hWnd,pGridData->rows-1);
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case VK_ESCAPE:
  case VK_TAB:
   //把焦点移到下一TABSTOP控件
   SetFocus(GetNextDlgTabItem(GetParent(hWnd),hWnd,FALSE));
   break;
  case VK_INSERT :
   if(pGridData->sel_row >0 && RR_GetInsertKeyStyle(hWnd))
   {
    SendMessage(hWnd,GM_GRID_INSERT_ROW,pGridData->sel_row,0);
   }
   break;
  case VK_DELETE:
   if(pGridData->sel_row >0 && RR_GetDeleteKeyStyle(hWnd))
   {
    SendMessage(hWnd,GM_GRID_DELETE_ROW,pGridData->sel_row,0);
   }
   break;
  case VK_RETURN:
   //如果是在最后行,添加一新行
   if(pGridData->rows>=2 && pGridData->sel_row < pGridData->rows-1 )
   {
    //移动到下一行
    row = pGridData->sel_row;
    row ++;
    
    if(row > pGridData->rows-1)
    {
     row =pGridData->rows-1;
    }
    
    if(row > pGridData->bottomvisiblerow && pGridData->bShowVScroll)
    {
     RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_LINEDOWN,0);
    }

    RR_GridCtrl_ChgSelRow(hWnd,row );
    RR_GridCtrl_Refresh(hWnd,FALSE);
   }
   else if(RR_GetEnterKeyStyle(hWnd))
   {
    //增加一新行
    RR_ASSERT(pGridData->rows>0);
    SendMessage(hWnd,GM_GRID_INSERT_ROW,pGridData->rows,0);
   }
   break;
  default:
   break;
 }
 return 0;
}

static LRESULT RR_GridCtrlOnGetDlgCode(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 LRESULT ReturnValue = DLGC_DEFPUSHBUTTON;
 LPMSG lpmsg = (LPMSG)lParam;

 if (lpmsg!=NULL)
 {
  if (lpmsg->message == WM_KEYDOWN)
  {
   switch(lpmsg->wParam)
   {
    case VK_RETURN:
    case VK_LEFT:
    case VK_RIGHT:
    case VK_UP:
    case VK_DOWN:
    case VK_ESCAPE:
     ReturnValue = DLGC_WANTMESSAGE;
     break;
    default:
     break;
   }
  }
 }
 
 return ReturnValue;
}

static LRESULT RR_GridCtrlOnLoadGrid(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 GridSaveStruct_T *ptSaveStruct = (GridSaveStruct_T *)wParam;
 StringLink_T  *pLink = (StringLink_T  *)lParam;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(pGridData->bEditing)
 {
  RR_GridCtrl_Force_Exit_Edit(hWnd);
 }

 if(pLink!=NULL)
 {
  RRFreeStringLink(pGridData->ptTextLink);
  RR_Safe_Free(pGridData->ptTextLink);
  pGridData->ptTextLink = pLink;
 }

 if(ptSaveStruct != NULL)
 {
  RR_GridCtrl_CopyStruct(ptSaveStruct,pGridData,FALSE);
  if(pGridData->hEditBackBrush!=NULL)
  {
   DeleteObject(pGridData->hEditBackBrush);
  } 
  pGridData->hEditBackBrush = CreateSolidBrush(pGridData->crBrushCommon);

  //注:字体暂未实现保存/装载
 }
 else
 {
  RR_GridCtrl_ResumeDefaultStruct(pGridData);
 }

 pGridData->bCellModified = FALSE;
 pGridData->bRowModified = FALSE;
 pGridData->bGridTextModified = FALSE;
 pGridData->bGridFrameModified = FALSE;
 
 RR_GridCtrl_Resize(hWnd);
 return 0;
 
}

static LRESULT RR_GridCtrlOnSaveGrid(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 LRESULT ReturnValue = 0;
 Grid_T * pGridData = NULL;
 char *pszFile = (char *)wParam;
 char szTmpFile[MAX_PATH];
 char *pDot;
 HANDLE hFile;
 BYTE buf[RR_STRUCT_SIZE_MAX];

 GridSaveStruct_T tSaveStruct;
 DWORD size=0;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL && pszFile!=NULL);
 RR_ASSERT(sizeof(tSaveStruct)<RR_STRUCT_SIZE_MAX);

 if(pGridData->bEditing)
 {
  RR_GridCtrl_Force_Exit_Edit(hWnd);
 }


 //先保证到临时文件,保存成功后再覆盖原文件
 pDot = strrchr(pszFile,'.');
 if(pDot==NULL)
 {
  return -1;//参数错误
 }

 strncpy(szTmpFile,pszFile,pDot-pszFile);
 strcpy(szTmpFile+(pDot-pszFile),".tmp");

 memset(buf,0,sizeof(buf));
 memset(&tSaveStruct,0,sizeof(tSaveStruct));
 strcpy((char*)buf,RR_GRID_FILE_HEAD);
 
 RR_GridCtrl_CopyStruct(&tSaveStruct,pGridData,TRUE);
 memcpy(buf+strlen(RR_GRID_FILE_HEAD)+1,&tSaveStruct,sizeof(tSaveStruct));

 //如果不存在,创建文件,如果存在,重写文件
 hFile = CreateFile(szTmpFile,GENERIC_WRITE,
  FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL);
 if(INVALID_HANDLE_VALUE == hFile)
 {
  return -2;//创建临时文件失败
 }

 if(!WriteFile(hFile,buf,RR_STRUCT_SIZE_MAX,&size,NULL) ||
  size != RR_STRUCT_SIZE_MAX)
 {
  CloseHandle(hFile); 
  return -3;//写临时文件失败
 }

 CloseHandle(hFile);
 if(pGridData->ptTextLink->node_cnt==0)
 {
  if(!CopyFile(szTmpFile,pszFile,FALSE))
  {
   RR_OUTPUT_LAST_ERR(hWnd);
   ReturnValue =-4;//拷贝失败
  }
  else
  {
   pGridData->bCellModified = FALSE;
   pGridData->bRowModified = FALSE;
   pGridData->bGridTextModified = FALSE;
   pGridData->bGridFrameModified = FALSE;
  }
  
  return ReturnValue;
 }

 if(!RR_Save_StringLink_To_File(szTmpFile,-1,pGridData->ptTextLink))
 {
  return -3;//写临时文件失败
 }

 if(ReturnValue == 0)
 {
  if(!CopyFile(szTmpFile,pszFile,FALSE))
  {
   RR_OUTPUT_LAST_ERR(hWnd);
   ReturnValue =-4;//拷贝失败
  }
  else
  {
   pGridData->bCellModified = FALSE;
   pGridData->bRowModified = FALSE;
   pGridData->bGridTextModified = FALSE;
   pGridData->bGridFrameModified = FALSE;
  }
  
 }
 return ReturnValue;
}

static LRESULT RR_GridCtrlOnInsertRow(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int row= (int)wParam;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(row<=0|| row >pGridData->rows || row >ROWS_MAX)
 {
  return -1;
 }


 //插入新行前通知父窗口
 lParam = MAKELPARAM(row,pGridData->rows-1);//新行号和原来的行数(不包括第0行)
   
       if(RR_GridCtrl_Notify(hWnd,GN_INSERT_ROW,lParam))
       {
        //消息返回值为非0:中断插入
        return 1;
       }

 if(pGridData->bEditing && !RR_GridCtrl_Exit_Edit(hWnd))
 {
  //父窗口退出编辑通知响应不让退出
  return 2;
 } 

 pGridData->rows++;
 if(row!=pGridData->rows)
 {
  //如果不是在最后插入,存储数据的ListBox需要更新
  RR_GridCtrl_UpdateData(pGridData->ptTextLink,row,TRUE);
 }

 RR_GridCtrl_Resize(hWnd);

 if(pGridData->bShowVScroll)
 {
  if(row <pGridData->topvisiblerow && pGridData->bShowVScroll)
  {
   RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_LINEUP,0);
  }
  else if(row > pGridData->bottomvisiblerow)
  {
   RR_GridCtrlOnVScroll(hWnd,WM_VSCROLL,SB_LINEDOWN,0);
  }
 }

 pGridData->bGridTextModified = TRUE;
 pGridData->bGridFrameModified = TRUE;
 
 RR_GridCtrl_CalcVisibleCellBoundaries(pGridData);
 RR_GridCtrl_ChgSelRow(hWnd,row );
 //RR_GridCtrl_Refresh(hWnd,FALSE);
 return 0;
}

static LRESULT RR_GridCtrlOnDeleteRow(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 int row= (int)wParam;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(row<=0|| row >pGridData->rows-1 )
 {
  return -1;
 }


 //删除行之前通知父窗口
 lParam = MAKELPARAM(row,pGridData->rows-1);//删除行号和未删除前总行数(不包括第0行)
   
       if(RR_GridCtrl_Notify(hWnd,GN_DELETE_ROW,lParam))
       {
        //消息返回值为非0:中断插入
        return 1;
       }

 if(pGridData->bEditing)
 {
  if(row == pGridData->tEditCell.row)
  {
   RR_GridCtrl_Discard_Edit(hWnd);
  }
  else
  {
   if(!RR_GridCtrl_Exit_Edit(hWnd))
   {
    //父窗口退出编辑通知响应不让退出
    return 2;
   }
  }
 } 

 RR_GridCtrl_UpdateData(pGridData->ptTextLink,row,FALSE);
 if(pGridData->rows <=2 )
 {
  //始终保持Grid有2X2个单元(含0行/0列)
  RR_GridCtrl_Refresh(hWnd,FALSE);
  return 0;
 }
 
 pGridData->rows--;
 pGridData->bGridTextModified = TRUE;
 pGridData->bGridFrameModified = TRUE;
 if(pGridData->sel_row >=pGridData->rows)
 {
  RR_GridCtrl_ChgSelRow(hWnd,pGridData->rows-1);
 }
 
 RR_GridCtrl_Resize(hWnd);
 return 0;
}

 

static LRESULT RR_GridCtrlOnGetCellTextLen(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 GridCell_T* pCell  = (GridCell_T*)wParam;
 Grid_T * pGridData = NULL;
 char szSymbol[DATA_SYMBOL_LEN+1];
 int len=0;
 int editing_len = 0;
 ListNode * pNode=NULL;
 StringLinkNode_T *pStrNode = NULL;


 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 if(pGridData == NULL || pCell==NULL)
 {
  return -1;
 }

 if(RR_GridCtrl_OutOfRange(pCell))
 {
   return  -2;
 }


 sprintf(szSymbol,"%05d-%03d",pCell->row,pCell->col); //9
 pNode= RR_GridCtrl_SearchData(pGridData->ptTextLink,szSymbol);
 if(pNode!=NULL)
 {
  pStrNode = List_Entry(pNode,StringLinkNode_T,node);
  
  len = strlen(pStrNode->szString);
  len -=DATA_SYMBOL_LEN;
 }

 if(pGridData->bEditing && RR_GridCtrl_CmpCell(&(pGridData->tEditCell),pCell))
 {
  editing_len = SendMessage(pGridData->hChildEdit,EM_LINELENGTH,0,0);
 }

 len = editing_len>len?editing_len:len;
 len+=10; //健壮性

 return len;
}


static LRESULT RR_GridCtrlOnGetCellText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 GridCell_T* pCell  = (GridCell_T*)wParam;
 char *pszText = (char *)lParam;
 Grid_T * pGridData = NULL;
 char szSymbol[DATA_SYMBOL_LEN+1];
 ListNode * pNode=NULL;
 StringLinkNode_T *pStrNode = NULL;


 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 if(pGridData == NULL || pCell==NULL || pszText == NULL)
 {
  if(pszText!=NULL)
  {
   pszText[0] = 0;//调用者保证此处不越界
  }
  return -1;
 }

 if(RR_GridCtrl_OutOfRange(pCell))
 {
  pszText[0] = 0;//调用者保证此处不越界
   return  -2;
 }

 sprintf(szSymbol,"%05d-%03d",pCell->row,pCell->col); //9
 
 pNode= RR_GridCtrl_SearchData(pGridData->ptTextLink,szSymbol);
 if(pNode !=NULL)
 {
  int len;

  pStrNode = List_Entry(pNode,StringLinkNode_T,node);

  len = strlen(pStrNode->szString);
  len -=DATA_SYMBOL_LEN;
  
  strcpy(pszText,pStrNode->szString+DATA_SYMBOL_LEN);//调用者保证此处不越界
 }
 else
 {
  pszText[0] = 0;//调用者保证此处不越界
 }
 
 return 0;
 
}

static LRESULT RR_GridCtrlOnSetCellText(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 GridCell_T* pCell = (GridCell_T*)wParam;
 char *pszText=(char*)lParam;
 char *pszBuf = NULL;
 char szSymbol[DATA_SYMBOL_LEN+1];
 int i=0;
 ListNode * pNode=NULL;
 StringLinkNode_T *pStrNode = NULL;

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);
 if(pGridData == NULL ||pCell == NULL || pszText == NULL)
 {
  return -1;//参数错误
 }

 if(RR_GridCtrl_OutOfRange(pCell))
 {
   return  -2;
 }

 if(pGridData->bEditing&& RR_GridCtrl_CmpCell(&(pGridData->tEditCell),pCell))
 {
  RR_GridCtrl_Discard_Edit(hWnd);
 }


 sprintf(szSymbol,"%05d-%03d",pCell->row,pCell->col);//9
 pNode = RR_GridCtrl_SearchData(pGridData->ptTextLink,szSymbol);

 RR_ASSERT(DATA_SYMBOL_LEN>=9);
 for (i =9;i<DATA_SYMBOL_LEN;i++)
 {
  szSymbol[i] = ' ';//预留
 }

 if(strlen(pszText) >CELL_TEXT_MAX )
 {
  pszBuf = (char*)RR_MALLOC(DATA_SYMBOL_LEN+CELL_TEXT_MAX+1);
  strncpy(pszBuf,szSymbol,DATA_SYMBOL_LEN);
  strncpy(pszBuf+DATA_SYMBOL_LEN,pszText,CELL_TEXT_MAX);
 }
 else
 {
  if(pszText[0]!=0)
  {
   pszBuf = (char*)RR_MALLOC(DATA_SYMBOL_LEN+strlen(pszText)+1);
   strncpy(pszBuf,szSymbol,DATA_SYMBOL_LEN);
   strcpy(pszBuf+DATA_SYMBOL_LEN,pszText);

  }
 }
 
 if(pNode!=NULL)
 {
  pStrNode = List_Entry(pNode,StringLinkNode_T,node);

  if(pszBuf !=NULL)
  {
   RR_Safe_Free(pStrNode->szString);
   pStrNode->szString= pszBuf;
  }
  else
  {
   List_Del(&pStrNode->node);
   pGridData->ptTextLink->node_cnt --;
   RR_Safe_Free(pStrNode->szString);
   RR_Safe_Free(pStrNode);
  }
 }
 else
 {
  if(pszBuf!=NULL)
  {
   RR_SqrtInsertStringToLink(pGridData->ptTextLink,pszBuf);
  }

 }

 pGridData->bGridTextModified = TRUE;
 RR_GridCtrl_Refresh(hWnd,FALSE);
 
 return 0;
   
}

static LRESULT RR_GridCtrlOnSetStyle(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 DWORD dwSysStyle;
 

 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(pGridData->dwStyle == (DWORD)wParam)
 {
  return 0;
 }

 pGridData->dwStyle = (DWORD)wParam;
 dwSysStyle = GetWindowLong(hWnd,GWL_STYLE);
 
 if(pGridData->dwStyle & GS_READONLY)
 {
  //只读
  //只读时不接受焦点
  if(dwSysStyle & WS_TABSTOP)
  {
   dwSysStyle= dwSysStyle & (~WS_TABSTOP);
   SetWindowLong(hWnd,GWL_STYLE ,dwSysStyle);
  }
 }
 else
 {
  //可骗辑
  if(!(dwSysStyle & WS_TABSTOP))
  {
   dwSysStyle= dwSysStyle | WS_TABSTOP;
   SetWindowLong(hWnd,GWL_STYLE ,dwSysStyle);
  }
 }
 
 RR_GridCtrl_Resize(hWnd);

 return 0;
}

 

static LRESULT RR_GridCtrlOnSetGridCellCount(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 Grid_T * pGridData = NULL;
 
 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 RR_ASSERT(pGridData!=NULL);

 if(wParam< 0 || wParam> ROWS_MAX ||
  lParam <0 || lParam >COLS_MAX)
 {
  return -1;
 }

 if((int)wParam+1 == pGridData->rows &&
  (int)lParam+1 == pGridData->cols)
 {
  return 0;
 }

 if(pGridData->bEditing)
 {
  RR_GridCtrl_Discard_Edit(hWnd);
 }

 RRFreeStringLink(pGridData->ptTextLink);
 pGridData->bGridTextModified = TRUE;

 pGridData->rows = (int)wParam+1;
 if(pGridData->rows<2)
 {
  pGridData->rows =2;
 }

 pGridData->cols = (int)lParam+1;
 if(pGridData->cols<2)
 {
  pGridData->cols =2;
 }

 pGridData->sel_row =1;
 pGridData->bGridFrameModified = TRUE;
 RR_GridCtrl_Resize(hWnd);
 return 0;
}

  
LRESULT CALLBACK RR_GridCtrlProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 LRESULT  ReturnValue=0;
 Grid_T * pGridData = NULL;

 pGridData = (Grid_T *)GetWindowLong(hWnd,GWL_USERDATA);
 
 switch (message)
 {
  case WM_CREATE:
   ReturnValue=RR_GridCtrlOnCreate(hWnd,message,wParam,lParam);
   break;
  case WM_SETTEXT: //设置标题文本
   ReturnValue=RR_GridCtrlOnSetText(hWnd,message,wParam,lParam);
              break;
  case WM_SIZE:
   ReturnValue=RR_GridCtrlOnSize(hWnd,message,wParam,lParam);
   break;
  case WM_PAINT:
   ReturnValue=RR_GridCtrlOnPaint(hWnd,message,wParam,lParam);
   break;
  case WM_LBUTTONDOWN:
   ReturnValue=RR_GridCtrlOnLButtonDown(hWnd,message,wParam,lParam);
   break;
  case WM_MOUSEMOVE: 
   ReturnValue=RR_GridCtrlOnMouseMove(hWnd,message,wParam,lParam);
   break;
  case WM_LBUTTONUP:
   ReturnValue=RR_GridCtrlOnLButtonUp(hWnd,message,wParam,lParam);
              break;
  case WM_LBUTTONDBLCLK:
   ReturnValue=RR_GridCtrlOnLButtonDblclk(hWnd,message,wParam,lParam);
   break;
  /*case WM_SETCURSOR:
   ReturnValue=RR_GridCtrlOnSetCursor(hWnd,message,wParam,lParam);
   break;*/
  case WM_ERASEBKGND:
   break;//自画
  case WM_KEYDOWN:
   ReturnValue=RR_GridCtrlOnKeyDown(hWnd,message,wParam,lParam);
   break;
  case WM_SETFOCUS:
  {
   RR_ASSERT(pGridData!=NULL);

   pGridData->bGridHasFocus = TRUE;
  
   if((HWND)wParam != pGridData->hChildEdit)
   {
    //焦点不是由单元编辑框失去
    
    //给父窗口发一个通知
    RR_GridCtrl_Notify(hWnd,GN_GET_FOCUS,(LPARAM)wParam);
    RR_GridCtrl_Refresh(hWnd,FALSE);
   }
  }
   break;
  case WM_KILLFOCUS: 
   RR_ASSERT(pGridData!=NULL);
   
   if((HWND)wParam != pGridData->hChildEdit)
   {
    //焦点不是由单元编辑窗口获得
    pGridData->bGridHasFocus = FALSE;
    RR_GridCtrl_Notify(hWnd,GN_LOST_FOCUS,(LPARAM)wParam);
   }
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case WM_DESTROY:
   ReturnValue=RR_GridCtrlOnDestroy(hWnd,message,wParam,lParam);
   break;
  case WM_HSCROLL:
   ReturnValue=RR_GridCtrlOnHScroll(hWnd,message,wParam,lParam);
   break;
  case WM_VSCROLL:
   ReturnValue=RR_GridCtrlOnVScroll(hWnd,message,wParam,lParam);
   break;
  case WM_GETDLGCODE:
   ReturnValue=RR_GridCtrlOnGetDlgCode(hWnd,message,wParam,lParam);
   break;
  case WM_CTLCOLOREDIT:
   if(pGridData!=NULL)
   {
    SetTextColor((HDC)wParam,pGridData->crTextCommon);
    SetBkMode((HDC)wParam,TRANSPARENT);
    ReturnValue = (LRESULT)pGridData->hEditBackBrush;
   }
   else
   {
    ReturnValue = DefWindowProc(hWnd, message, wParam, lParam);
   }
   break;
  case WM_ENABLE:
   if(wParam)
   {
    //enable 窗口
    RR_SetReadOnlyStyle(hWnd,FALSE);
   }
   else
   {
    //disable 窗口
    if(pGridData->bEditing)
    {
     RR_GridCtrl_Discard_Edit(hWnd);
    }
    
    RR_SetReadOnlyStyle(hWnd,TRUE);
   }
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case GM_LOAD_GRID:
   ReturnValue=RR_GridCtrlOnLoadGrid(hWnd,message,wParam,lParam);
   break;
  case GM_SAVE_GRID:
   ReturnValue=RR_GridCtrlOnSaveGrid(hWnd,message,wParam,lParam);
   break;
  case GM_GRID_INSERT_ROW:
   ReturnValue=RR_GridCtrlOnInsertRow(hWnd,message,wParam,lParam);
   break;
  case GM_GRID_DELETE_ROW:
   ReturnValue=RR_GridCtrlOnDeleteRow(hWnd,message,wParam,lParam);
   break;
  case GM_GRID_SET_READONLY:
   RR_ASSERT(pGridData!=NULL);
   if(wParam)
   {
    if(pGridData->bEditing)
    {
     RR_GridCtrl_Discard_Edit(hWnd);
    }
    RR_SetReadOnlyStyle(hWnd,TRUE);
   }
   else     
   {               
    RR_SetReadOnlyStyle(hWnd,FALSE);
   }
   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case GM_GET_CELL_TEXT_LEN:
   ReturnValue = RR_GridCtrlOnGetCellTextLen(hWnd,message,wParam,lParam);
   break;
  case GM_GET_CELL_TEXT:
   ReturnValue = RR_GridCtrlOnGetCellText(hWnd,message,wParam,lParam);
   break;
  case GM_SET_CELL_TEXT:
   ReturnValue =RR_GridCtrlOnSetCellText(hWnd,message,wParam,lParam);
   break;
  case GM_SET_EDIT_TEXT://wParam -- GridCell_T* ;lParam-- text
   if(pGridData->bEditing && RR_GridCtrl_CmpCell(&(pGridData->tEditCell),(GridCell_T*)wParam)
    && lParam!=0)
   {
    SetWindowText(pGridData->hChildEdit,(char *)lParam);
   }
   else
   {
    ReturnValue = -1;
   }
   break;
  case GM_GET_EDIT_TEXT:
   if(pGridData->bEditing && RR_GridCtrl_CmpCell(&(pGridData->tEditCell),(GridCell_T*)wParam)
    && lParam!=0)
   {
    char szBuf[CELL_TEXT_MAX+1];
    
    GetWindowText(pGridData->hChildEdit,szBuf,CELL_TEXT_MAX);
    strcpy((char*)lParam,szBuf);//调用者保证此处不越界
   }
   else
   {
    ReturnValue = -1;
   }
   break;
  case GM_GRID_SET_CELL_COUNT:
   ReturnValue =RR_GridCtrlOnSetGridCellCount(hWnd,message,wParam,lParam);
   break;
  case GM_GRID_CLEAR_TEXT:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->bEditing)
   {
    RR_GridCtrl_Discard_Edit(hWnd);
   }

   RRFreeStringLink(pGridData->ptTextLink);
   RR_GridCtrl_Refresh(hWnd, FALSE);
              break; 
  case GM_GRID_GET_ROWS:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue = pGridData->rows-1;
             break;
  case GM_GRID_GET_COLS:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue =  pGridData->cols-1;
              break;
  case GM_GET_COL_WIDTH:
   RR_ASSERT(pGridData!=NULL);
   if((int)wParam>=0 && (int)wParam <pGridData->cols)
   {
    ReturnValue = pGridData->columnwidths[wParam];
   }
   else
   {
    ReturnValue = -1;
   }
              break;
         case GM_GET_ROW_HEIGHT:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue = pGridData->rowheight;
              break;
        case GM_GET_HEADERROW_HEIGHT:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue = pGridData->headerrowheight;
              break;
  case GM_GET_SELECT_ROW:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue = pGridData->sel_row;
              break;
   case GM_SET_HEADER_ROW_HEIGHT:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->headerrowheight == (int)wParam)
   {
    break;
   }
   
   if(wParam >= 0)            
   {
    pGridData->headerrowheight = (int)wParam;
   }
   else
   {
    pGridData->headerrowheight =0;
   }
   pGridData->bGridFrameModified = TRUE;
   RR_GridCtrl_Resize(hWnd);
   break;
   case GM_SET_ROW_HEIGHT:
   {
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->rowheight  == (int)wParam)
   {
    break;
   }
   
   if(wParam <1)
   {
    wParam=1;
   }
   
   pGridData->rowheight = wParam;
   pGridData->bGridFrameModified = TRUE;
   RR_GridCtrl_Resize(hWnd);
   }
              break;
  case GM_SET_COL_WIDTH:
   if((wParam >= 0) && (wParam <= COLS_MAX) && (lParam >= 0))
   {
    RR_ASSERT(pGridData!=NULL);
    if(pGridData->columnwidths[wParam]  != (int)lParam)
    {
     pGridData->columnwidths[wParam] = lParam;
     pGridData->bGridFrameModified = TRUE;
     RR_GridCtrl_Resize(hWnd);
    }
   }
   else
   {
    ReturnValue =-1;
   }
   break;
  case GM_SET_GRID_LINE_COLOR:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->crGridLine != (COLORREF)wParam)
   {
    pGridData->crGridLine = (COLORREF)wParam;
    pGridData->bGridFrameModified = TRUE;

    RR_GridCtrl_Refresh(hWnd,FALSE);
   }
              break; 
  case GM_SET_NOFOCUS_SELLINE_COLOR:
   RR_ASSERT(pGridData!=NULL);
   RR_SetHighLightStyle(hWnd,TRUE);
   if(pGridData->crTextGray != (COLORREF)wParam ||
    pGridData->crBrushGray != (COLORREF)lParam)
   {
    pGridData->crTextGray = (COLORREF)wParam;
    pGridData->crBrushGray = (COLORREF)lParam;
    pGridData->bGridFrameModified = TRUE;
    
    RR_GridCtrl_Refresh(hWnd,FALSE);
   }
   break;
         case GM_SET_FOCUS_SELLINE_COLOR:
   RR_ASSERT(pGridData!=NULL);
   RR_SetHighLightStyle(hWnd,TRUE);
   if(pGridData->crTextLight!= (COLORREF)wParam ||
    pGridData->crBrushLight != (COLORREF)lParam)
   {
    pGridData->crTextLight= (COLORREF)wParam;
    pGridData->crBrushLight = (COLORREF)lParam;
    pGridData->bGridFrameModified = TRUE;
    
    RR_GridCtrl_Refresh(hWnd,FALSE);
   }
              break;
  case GM_SET_READONLY_COLOR:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->crTextReadOnly!= (COLORREF)wParam ||
    pGridData->crBrushReadOnly != (COLORREF)lParam)
   {
    pGridData->crTextReadOnly= (COLORREF)wParam;
    pGridData->crBrushReadOnly = (COLORREF)lParam;
    pGridData->bGridFrameModified = TRUE;

    if(RR_GetReadOnlyStyle(hWnd))
    {
     RR_GridCtrl_Refresh(hWnd,FALSE);
    }
   }
   break;
  case GM_SET_GRID_COLOR:
   RR_ASSERT(pGridData!=NULL);

   if(pGridData->crTextCommon!= (COLORREF)wParam)
   {
    pGridData->crTextCommon= (COLORREF)wParam;
    pGridData->bGridFrameModified = TRUE;
   }
   
   if(pGridData->crBrushCommon!= (COLORREF)lParam)
   {
    pGridData->crBrushCommon= (COLORREF)lParam;
    pGridData->bGridFrameModified = TRUE;
    
    if(pGridData->hEditBackBrush!=NULL)
    {
     DeleteObject(pGridData->hEditBackBrush);
    }
    pGridData->hEditBackBrush = CreateSolidBrush(pGridData->crBrushCommon);

   }

   RR_GridCtrl_Refresh(hWnd,FALSE);
   break;
  case GM_SET_TITLE_FONT:
   RR_ASSERT(pGridData!=NULL);
   if(wParam!=0)
   {
    if(pGridData->htitlefont!=NULL)
    {
     DeleteObject(pGridData->htitlefont);
    }
    pGridData->htitlefont = CreateFontIndirect((LOGFONT *)wParam);
   }
              break;
         case GM_SET_HEADING_FONT:
   RR_ASSERT(pGridData!=NULL);
   if(wParam!=0)
   {
    if(pGridData->hheadfont!=NULL)
    {
     DeleteObject(pGridData->hheadfont);
    }
    pGridData->hheadfont = CreateFontIndirect((LOGFONT *)wParam);
   }
              break;
  case GM_SET_BODY_FONT:
   RR_ASSERT(pGridData!=NULL);
   if(wParam!=0)
   {
    if(pGridData->hbodyfont!=NULL)
    {
     DeleteObject(pGridData->hbodyfont);
    }
    pGridData->hbodyfont = CreateFontIndirect((LOGFONT *)wParam);
   }
   break;
  case GM_GRID_ALLOW_COL_RESIZE:
   RR_ASSERT(pGridData!=NULL);
   RR_SetColumnAllowResizeStyle(hWnd,(BOOL)wParam);
              break;
  case GM_GET_EDIT_STATUS:
  {
   GridCell_T * pCell = (GridCell_T *)lParam;
   
   RR_ASSERT(pGridData!=NULL);

   if(pGridData->bEditing)
   {
    ReturnValue =1;
    if(pCell!=NULL)
    {
     pCell->row = pGridData->tEditCell.row;
     pCell->col = pGridData->tEditCell.col;
    }
   }
  }
   break;
  case GM_GRID_GET_STYLE:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue = pGridData->dwStyle;
   break;
  case GM_GRID_SET_STYLE:
   RR_GridCtrlOnSetStyle(hWnd,message,wParam,lParam);
   break;
  case GM_GET_GRID_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   ReturnValue =pGridData->bGridTextModified || pGridData->bGridFrameModified;
   if(pGridData->bEditing)
   {
    ReturnValue = ReturnValue||pGridData->bCellModified ;
   }
   break;
  case GM_SET_GRID_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   pGridData->bGridTextModified = (BOOL) lParam;
   break;
  case GM_GET_ROW_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->sel_row == (int)wParam)
   {
    ReturnValue = pGridData->bRowModified;
    if(pGridData->bEditing && pGridData->tEditCell.row== (int)wParam)
    {
     ReturnValue = ReturnValue||pGridData->bCellModified;
    }
   }
   break;
  case GM_SET_ROW_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->sel_row ==(int)wParam )
   {
    pGridData->bRowModified = (BOOL) lParam;
   }
   else
   {
    ReturnValue =-1;
   }
   break;
  case GM_GET_CELL_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->bEditing && RR_GridCtrl_CmpCell(&pGridData->tEditCell,(GridCell_T*)wParam))
   {
    ReturnValue = pGridData->bCellModified;
   }
   break;
  case GM_SET_CELL_MODIFY:
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->bEditing && RR_GridCtrl_CmpCell(&pGridData->tEditCell,(GridCell_T*)wParam))
   {
    pGridData->bCellModified = (BOOL) lParam;
   }
   else
   {
    ReturnValue =-1;
   }
   
   break;
  case GM_GRID_ENTRY_EDITBOX:
  {
   GridCell_T * pCell = (GridCell_T *)wParam;
   
   RR_ASSERT(pGridData!=NULL);
   if(pGridData->bEditing )
   {
    if(!RR_GridCtrl_CmpCell(&pGridData->tEditCell,pCell))
    {
     RR_GridCtrl_Discard_Edit(hWnd);
    }
    else
    {
     break;
    }
   }
   
   if(!RR_GridCtrl_Enter_Edit(hWnd,pCell,(int)lParam))
   {
    ReturnValue= -1;
   }
  }
   break;
  case GM_GRID_EXIT_EDITBOX:
   if(!RR_GridCtrl_Exit_Edit(hWnd))
   {
    ReturnValue= -1;
   }
   break;
  case GM_GET_TITLE_TEXT:
  {
   char* pszTitle = (char*)wParam;
   int buf_size = (int)lParam;

   RR_ASSERT(pGridData!=NULL);

   if(pGridData->pszTitle == NULL)
   {
    pszTitle[0] =0;
   }
   else
   {
    int len =strlen(pGridData->pszTitle);

    if(len<buf_size)
    {
     strcpy(pszTitle,pGridData->pszTitle);
    }
    else
    {
     strncpy(pszTitle,pGridData->pszTitle,buf_size-1);
     pszTitle[buf_size-1] =0;
    }

   }
   
  }
   break;
  default:
   return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return ReturnValue;
}

BOOL APIENTRY DllMain( HANDLE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
      )
{
 switch(ul_reason_for_call)
 {
  case DLL_PROCESS_ATTACH:
  case DLL_THREAD_ATTACH:
   break;
  case DLL_PROCESS_DETACH:
  case DLL_THREAD_DETACH:
#ifdef _DEBUG
  _CrtDumpMemoryLeaks(); //内存泄露检测
#endif
  default:
   break;
 }
 
    return TRUE;
}

/////////////////////////////////--提供给外部的接口函数-------------

BOOL RR_GridCtrl_Register(HINSTANCE hInstance)
{
 static BOOL s_bRegister  = FALSE;
 WNDCLASS wclass;

 if(s_bRegister)
 {
  //已经注册
  return  FALSE;
 }
  
     wclass.style = CS_DBLCLKS;//CS_HREDRAW|CS_VREDRAW;
 wclass.lpfnWndProc = (WNDPROC)RR_GridCtrlProc;
 wclass.cbClsExtra = 0;
 wclass.cbWndExtra = 0;
 wclass.hInstance = hInstance;
 wclass.hIcon = NULL;
 wclass.hCursor = NULL;
 wclass.hbrBackground =NULL;//(HBRUSH)(GetStockObject(GRAY_BRUSH));
 wclass.lpszClassName = RR_GRIDCTRL_CLASS;
 wclass.lpszMenuName = NULL;

 if( (void *)RegisterClass (&wclass)!=NULL )
 {
  s_bRegister = TRUE;
 }
 else
 {
  RR_ASSERT(0);
  return FALSE;
 }
 
 return TRUE;
}

void RR_GridCtrl_SetCell(GridCell_T *cell,int row, int col)
{
 cell->row = row;
 cell->col = col;
}

BOOL RR_GridCtrl_CmpCell(const GridCell_T *pCell1,const GridCell_T *pCell2)
{
 if(pCell1 == NULL && pCell2 == NULL)
 {
  return TRUE;
 }
 else if (pCell1 == NULL || pCell2 == NULL)
 {
  return FALSE;
 }
 else if(pCell1->row == pCell2->row && pCell1->col == pCell2->col)
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}

BOOL RR_GridCtrl_GetCellText(HWND hGrid,int row ,int col ,char *pszBuf,int buf_size)
{
 int ReturnValue=0;
 GridCell_T tCell;
 char szText[CELL_TEXT_MAX+1];

 if(pszBuf==NULL ||buf_size<1 || hGrid == NULL)
 {
  return FALSE;
 }

 tCell.row = row;
 tCell.col = col;

 ReturnValue = SendMessage(hGrid,GM_GET_CELL_TEXT,(WPARAM)&tCell,(LPARAM)szText);
 if(ReturnValue<0)
 {
  pszBuf[0] =0;
  return FALSE;
 }
 else
 {
  int len = strlen(szText);

  if(len >= buf_size)
  {
   strncpy(pszBuf,szText,buf_size-1);
   pszBuf[buf_size-1]=0;
  }
  else
  {
   strcpy(pszBuf,szText);
  }
 }
 
 return TRUE;
}

BOOL RR_GridCtrl_SetCellText(HWND hGrid,int row ,int col ,char *pszText)
{
 int ReturnValue=0;
 GridCell_T tCell;

 if(hGrid == NULL)
 {
  return FALSE;
 }

 tCell.row = row;
 tCell.col = col; 

 ReturnValue = SendMessage(hGrid,GM_SET_CELL_TEXT,(WPARAM)&tCell,(LPARAM)pszText);
 if(ReturnValue<0)
 {
  return FALSE;
 }

 RR_GridCtrl_Refresh(hGrid,FALSE);
 
 return TRUE;
}

BOOL RR_GridCtrl_GetEditText(HWND hGrid,int row ,int col ,char *pszBuf,int buf_size)
{
 int ReturnValue=0;
 GridCell_T tCell;
 char szText[CELL_TEXT_MAX+1];

 if(pszBuf==NULL ||buf_size<1 || hGrid == NULL)
 {
  return FALSE;
 }

 tCell.row = row;
 tCell.col = col;

 ReturnValue = SendMessage(hGrid,GM_GET_EDIT_TEXT,(WPARAM)&tCell,(LPARAM)szText);
 if(ReturnValue<0)
 {
  pszBuf[0] =0;
  return FALSE;
 }
 else
 {
  int len = strlen(szText);

  if(len >= buf_size)
  {
   strncpy(pszBuf,szText,buf_size-1);
   pszBuf[buf_size-1]=0;
  }
  else
  {
   strcpy(pszBuf,szText);
  }
 }
 
 return TRUE;
}

BOOL RR_GridCtrl_SetEditText(HWND hGrid,int row ,int col ,char *pszText)
{
 int ReturnValue=0;
 GridCell_T tCell;

 if(hGrid == NULL)
 {
  return FALSE;
 }

 tCell.row = row;
 tCell.col = col; 

 ReturnValue = SendMessage(hGrid,GM_SET_EDIT_TEXT,(WPARAM)&tCell,(LPARAM)pszText);
 if(ReturnValue<0)
 {
  return FALSE;
 }
 return TRUE;
}

BOOL RR_GridCtrl_SetTitle(HWND hGrid,char szTitle[])
{
 int ReturnValue=0;

 if(hGrid == NULL)
 {
  return FALSE;
 }
 
 ReturnValue = SendMessage(hGrid,WM_SETTEXT,0,(LPARAM)szTitle);
 if(ReturnValue<0)
 {
  return FALSE;
 }
 return TRUE;
 
}

BOOL RR_GridCtrl_GetTitle(HWND hGrid,char szTitle[],int buf_size)
{
 int ReturnValue=0;

 if(szTitle==NULL || buf_size<1)
 {
  return FALSE;
 }

 if(hGrid == NULL )
 {
  szTitle[0] =0;
  return FALSE;
 }
 
 ReturnValue = SendMessage(hGrid,GM_GET_TITLE_TEXT,(WPARAM)szTitle,(LPARAM)buf_size);
 if(ReturnValue<0)
 {
  return FALSE;
 }
 return TRUE;
}

 

//pGridRect --相对于父窗口客户区域的矩形
//hWndParent -- 创建子窗口一定要指定父窗口
HWND RR_Create_GridCtrl(DWORD dwStyle,HWND hWndParent,RECT *pGridRect, int nId,char szGridTitle[],int rows,int cols)
{
 HWND hGrid=NULL;
 RECT rtDst;
 RECT rtParent;
 Grid_T * pGridData = NULL;
 BOOL bVisible = FALSE;

 
 if(hWndParent==NULL||pGridRect==NULL )
 {
  return NULL;
 } 

 if(IsRectEmpty(pGridRect))
 {
  return NULL;
 }

 GetClientRect(hWndParent,&rtParent);
 if(!IntersectRect(&rtDst,pGridRect,&rtParent))
 {
  //两个矩形没有交集
  return NULL;
 }


 pGridData = (Grid_T *)RR_MALLOC(sizeof(Grid_T));
 RR_ASSERT(pGridData!=NULL);

 
 if(szGridTitle!=NULL)
 {
  pGridData->pszTitle = (char*)RR_MALLOC(strlen(szGridTitle)+1);
  strcpy(pGridData->pszTitle,szGridTitle);
 }
 else
 {
  pGridData->pszTitle = (char*)RR_MALLOC(1);
 }

 //如果没有第0行,第0行高度为0
 //如果没有第0列,第0行宽度为0
 //但是rows/cols仍需加上第0行/第0列的计数 
 if(rows>0)
 {
  if(rows>ROWS_MAX)
  {
   pGridData->rows = ROWS_MAX+1;
  }
  else
  {
   pGridData->rows = rows+1;//加上第0行
  }
 }
 else
 {
  pGridData->rows =  2;
 }


 if(cols>0)
 {
  if(cols>COLS_MAX)
  {
   pGridData->cols =COLS_MAX+1;
  }
  else
  {
   pGridData->cols = cols+1;//加上第0列
  }
 }
 else
 {
  pGridData->cols = 2;
 }

 

 RR_GridCtrl_InitStruct(pGridData);
 pGridData->dwStyle  = pGridData->dwStyle | dwStyle;
 
 
 if(dwStyle&GS_VISIBLE)
 {
  bVisible = TRUE;
 }
 
 if(dwStyle & GS_NO_COLHEAD)
 {
  pGridData->headerrowheight =0;
 }
 if(dwStyle & GS_NO_ROWHEAD)
 {
  pGridData->columnwidths[0] = 0;
 } 

 pGridData->init_rows = pGridData->rows ;
 pGridData->init_cols = pGridData->cols ;
 pGridData->dwInitStyle = pGridData->dwStyle;


 pGridData->nGridId = (UINT)nId;
 //WS_EX_CLIENTEDGE: 有边框,边框是凹下去的
 //WS_CLIPCHILDREN 因为列宽变化造成编辑控件移动,使用该风格会带来显示上的问题
 hGrid=CreateWindowEx(WS_EX_CLIENTEDGE,RR_GRIDCTRL_CLASS,"",
                WS_CHILD/*|WS_CLIPCHILDREN/*|WS_HSCROLL |WS_VSCROLL*/,0,0,0,0,hWndParent,(HMENU)nId,(HINSTANCE)GetWindowLong(hWndParent,GWL_HINSTANCE),(LPVOID)pGridData);
 if(hGrid!=NULL)
 {
  if(!(pGridData->dwStyle & GS_READONLY))
  {
   //可编辑
   SetWindowLong(hGrid,GWL_STYLE ,GetWindowLong(hGrid,GWL_STYLE) | WS_TABSTOP);
  }

  
  MoveWindow(hGrid,rtDst.left,rtDst.top,rtDst.right-rtDst.left,rtDst.bottom - rtDst.top,FALSE);

  if(bVisible)
  {
   ShowWindow(hGrid,SW_SHOW);
  }
  
 }
 else
 {
  RR_GridCtrl_FreeStruct(pGridData);
 }
 
 return hGrid;
}

BOOL RR_Save_GridCtrl(char szFile[],HWND hGrid)
{

 if(szFile == NULL ||szFile[0]==0 || hGrid == NULL)
 {
  return FALSE;
 }

 //放入消息队列
 if(SendMessage(hGrid,GM_SAVE_GRID,(WPARAM)szFile,0)==0)
 {
  return TRUE;
 }
 
 return FALSE;
}

BOOL RR_Load_GridCtrl(char szFile[],HWND hGrid,BOOL* pbFileError)
{
  HANDLE hFile;
 BYTE buf[RR_STRUCT_SIZE_MAX];
 GridSaveStruct_T tSaveStruct;
 ULONG size =0; 
 int lRet;
 StringLink_T  *plink=NULL;
 BOOL bReadSucess = TRUE;

 if(pbFileError!=NULL)
 {
  *pbFileError = FALSE;
 }

 if(szFile==NULL|| szFile[0] == 0)
 {
  if(pbFileError!=NULL)
  {
   *pbFileError = TRUE;
  }
  return FALSE;
 }

 if(hGrid == NULL)
 {
  return FALSE;
 }

 //打开已存在的文件
 hFile = CreateFile(szFile,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
  FILE_ATTRIBUTE_READONLY,NULL);
 if(INVALID_HANDLE_VALUE == hFile) //文件不存在
 {
  bReadSucess = FALSE;
 }

 if(bReadSucess)
 {
  if(!ReadFile(hFile,buf,RR_STRUCT_SIZE_MAX,&size,NULL) ||
   size!=RR_STRUCT_SIZE_MAX)
  {
   
   bReadSucess = FALSE;
  }
  
  CloseHandle(hFile);  
 }

 if(bReadSucess)
 {
  if(strcmp((char*)buf,RR_GRID_FILE_HEAD)==0)
  {
   memcpy(&tSaveStruct,buf+strlen(RR_GRID_FILE_HEAD)+1,sizeof(tSaveStruct));
  }
  else
  {
   bReadSucess = FALSE;
  }
 }

 plink = (StringLink_T*)RR_MALLOC(sizeof(StringLink_T));
 RR_InitStringLink(plink);

 if(bReadSucess)
 {
  if(!RR_Load_File_To_StringLink(szFile,RR_STRUCT_SIZE_MAX,plink))
  {
   RRFreeStringLink(plink);
  }
 }

 if(bReadSucess)
 {
  //link链表数据将传给Grid,由Grid负责释放
  lRet = SendMessage(hGrid,GM_LOAD_GRID,(WPARAM)&tSaveStruct,(LPARAM)plink);
  
 }
 else
 {
  if(pbFileError!=NULL)
  {
   *pbFileError = TRUE;
  }
  
  lRet = SendMessage(hGrid,GM_LOAD_GRID,(WPARAM)NULL,(LPARAM)plink);
 }

 if(lRet==0)
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
 
}

HWND RR_GetDlgGridItem(HWND hDlg,int id)
{
 //char szClassName[101];
 //HWND hGrid= NULL;

 if(hDlg==NULL)
 {
  return NULL;
 }

 return GetDlgItem(hDlg,id) ;
 
 /*GetClassName(hDlg,szClassName,sizeof(szClassName));

 if(strcmp(szClassName,"#32770")==0)//父窗口是否对话框类
 {
  hGrid = GetDlgItem(hDlg,id);
  if(hGrid!= NULL)
  {
   GetClassName(hGrid,szClassName,sizeof(szClassName));
   if(strcmp(szClassName,RR_GRIDCTRL_CLASS) != 0)
   {
    hGrid = NULL;
   }
  }
  
  return hGrid;
 }
 else
 {
  return NULL;
 }*/

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值