Click here to Skip to main content
15,887,344 members
Articles / Desktop Programming / WTL

A fast and lightweight cell control

Rate me:
Please Sign up or sign in to vote.
4.42/5 (31 votes)
11 Mar 2008CPOL1 min read 90.9K   4.5K   81  
A fast and lightweight cell control for displaying tabular data. The cell is a custom control derived from ATL::CWindow.
// MyCell - version 1.0
// Written by Yanxueming <yanxm2003@hotmail.com>
// Copyright (C) 2006-2006
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
#include "stdafx.h"
#include <atltypes.h>
#include <atlgdi.h>
#include <algorithm>
#include "../include/renderer.h"
#include "../include/Worksheet.h"
#include "../include/RgnLight.h"
#include "../include/rect_xor.h"
#include "../include/GdiSelectObject.h"
#include "../include/msg.h"
#include "../include/DrawTextAlignJustify.h"
#include "../include/DefaultSymbols.h"
#include "../include/CellFontSetup.h"
#include "../include/Workbook.h"
namespace mycell{
	class HeaderSetupDC
	{
		HDC hDC_;
		int nBKMode_;
		HFONT hFont_;
		//HPEN hPen_;
	public:
		HeaderSetupDC(HDC hDC):hDC_(hDC)
		{
			CDCHandle dc(hDC);
			nBKMode_=::SetBkMode(hDC,TRANSPARENT);
			hFont_=(HFONT)SelectObject(hDC,::GetStockObject(DEFAULT_GUI_FONT));
			//hPen_=(HPEN)SelectObject(hDC,::CreatePen(PS_SOLID,0,RGB(0,0,0)));
		}
		~HeaderSetupDC()
		{
			if(nBKMode_)
				::SetBkMode(hDC_,nBKMode_);
			if(hFont_ && HGDI_ERROR!=hFont_)
				SelectObject(hDC_,::GetStockObject(DEFAULT_GUI_FONT));
			//DeleteObject(SelectObject(hDC_,hPen_));
		}
	};
	//void GridRenderer::init_theme()
	//{
	//	hTheme_=OpenThemeData(pSheet->m_hWnd,L"Button");
	//}
	//static FONTDESC _fontDesc=
	//{
	//	sizeof(FONTDESC),OLESTR("����"),
	//		FONTSIZE(9),FW_NORMAL,
	//		GB2312_CHARSET,FALSE,FALSE,FALSE
	//};
	//PenFactory PenFactory::Instance();
	//map<CellType,CComPtr<ICellSymbol> > GridRenderer::mapSymbol_;
	//CComPtr<ICellSymbol> GridRenderer::pFillSymbol_;
	//GridRenderer::CellStoreCache GridRenderer::cellStoreCache_;

	void GridRenderer::Init(HWND hWndGrid/*Worksheet* pSheet*/)//GridRenderer(/*Worksheet* p):pSheet(p*/)
	{
		using namespace mycell;
		using namespace symbol;
		//CComObject<TextSymbol>* pTextSymbol;
		//CComObject<TextSymbol>::CreateInstance(&pTextSymbol);
		//CComPtr<ICellSymbol> pSymbol;
		//pTextSymbol->QueryInterface(IID_IUnknown,(void**)&pSymbol);
		//RegisterSymbol(ECT_TEXT,pSymbol);
		////RegisterSymbol(cellStatic,pSymbol);
		//RegisterSymbol(ECT_NONE,pSymbol);
		//RegisterSymbol(ECT_INT,pSymbol);
		//RegisterSymbol(ECT_UINT,pSymbol);
		//RegisterSymbol(ECT_UDOUBLE,pSymbol);
		//RegisterSymbol(ECT_DOUBLE,pSymbol);
		//RegisterSymbol(ECT_DEGREE,pSymbol);

		//CComObject<ThemeCheckBoxSymbol>* pCheckboxSymbol;
		//CComObject<ThemeCheckBoxSymbol>::CreateInstance(&pCheckboxSymbol);
		//pCheckboxSymbol->OpenThemeData(hWndGrid);
		//pSymbol.Release();
		//pCheckboxSymbol->QueryInterface(IID_IUnknown,(void**)&pSymbol);
		//RegisterSymbol(ECT_CHECKBOX,pSymbol);
		///*
		//if(!bThemeSupport){
		//	CComObject<CheckBoxSymbol>* pCheckboxSymbol;
		//	CComObject<CheckBoxSymbol>::CreateInstance(&pCheckboxSymbol);
		//	pSymbol.Release();
		//	pCheckboxSymbol->QueryInterface(IID_IUnknown,(void**)&pSymbol);
		//	RegisterSymbol(ECT_CHECKBOX,pSymbol);
		//}
		//*/

		//CComObject<ColorSymbol>* pColorSymbol;
		//CComObject<ColorSymbol>::CreateInstance(&pColorSymbol);
		//pSymbol.Release();
		//pColorSymbol->QueryInterface(IID_IUnknown,(void**)&pSymbol);
		//RegisterSymbol(ECT_COLOR,pSymbol);

		//CComObject<SimpleFillSymbol>* pFillSymbol;
		//CComObject<SimpleFillSymbol>::CreateInstance(&pFillSymbol);
		//pFillSymbol_.Release();
		//pFillSymbol->QueryInterface(IID_IUnknown,(void**)&pFillSymbol_);

		//pCurSelections=p->get_Selections();
		//HRESULT hr=OleCreateFontIndirect(&_fontDesc,IID_IFont,(void**)&pTmpFont_);
		//_ASSERT(SUCCEEDED(hr));
		//init_theme();
	}
	//void GridRenderer::ApplyIFont(FontDesc const& fontDesc,IFont* pFont)
	//{
	//	_ASSERT(NULL!=pFont);
	//	pFont->put_Name(CComBSTR(fontDesc.name));
	//	pFont->put_Size(fontDesc.cySize);
	//	pFont->put_Italic(fontDesc.IsItalic());
	//	pFont->put_Underline(fontDesc.IsUnderline());
	//	pFont->put_Strikethrough(fontDesc.IsStrikethrough());
	//	pFont->put_Weight(fontDesc.sWeight);
	//	pFont->put_Charset(fontDesc.sCharset);
	//	pFont->put_Bold(fontDesc.IsBold());
	//}
	/*
	BOOL GridRenderer::draw_HeaderCell(CDCHandle& dc,LPCTSTR lpText,int nCount,LPCRECT lprc,COLORREF backColor)const
	{
		//CDCHandle dc(hDC);
		CRect rc=*lprc;
		if(!(lprc->right > lprc->left && lprc->bottom > lprc->top))
			return FALSE;
		{
			CBrush solidBrush;
			solidBrush.Attach(::CreateSolidBrush(backColor));
			dc.FillRect(&rc,solidBrush);
			//����
			dc.MoveTo(rc.left,rc.bottom-1);
			dc.LineTo(rc.right-1,rc.bottom-1);
			dc.LineTo(rc.right-1,rc.top-1);
		}
		if(lprc->right > lprc->left+2 && lprc->bottom > lprc->top+2)
		{
			if(lpText){
				rc.DeflateRect(1,1);
				long nFormat=DT_VCENTER|DT_SINGLELINE|DT_CENTER;
				dc.DrawText(lpText,nCount, rc, nFormat);
			}
		}
		return TRUE;
	}
	HeaderSelectionType SetupRowHeaderDE(Worksheet* pSheet,CCellRange const& cr,CCell activeCell,int row)
	{
		//bFullInselection=FALSE;
		if(pSheet->get_ShowSelection()){
			if(row>=cr.TopRow() && row<=cr.BottomRow()){
				//bFullInselection=HEADER_COL==cr.LeftCol();
				backColor=HEADER_COL==cr.LeftCol()?HeaderColors::CLR_ACTIVE:HeaderColors::CLR_SELECTION;//RGB(0,0,0xff):RGB(255,192,111);
			}else if(row==activeCell.row){
				backColor=HeaderColors::CLR_SELECTION;//RGB(255,192,111);
			}else
				backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
		}else{
			backColor=HeaderColors::CLR_BKGND;
		}
	}
	*/
	ESelectionState GridRenderer::SetupRowHeaderDE(const Worksheet* pSheet,const Selections* pCurSelections,int row,COLORREF& backColor)const
	{
		//bFullInselection=FALSE;
		//int const leftCol=activeSelection_.LeftCol();
		//int const minRow=activeSelection_.TopRow();
		//int const maxRow=activeSelection_.BottomRow();
		if(pSheet->get_ShowSelection()){
			//const Selections* pCurSelections=pSheet->get_Selections();
			BOOL const bFullInselection=pCurSelections->IsFullColSelectedAtRow(row) ;//>CellInSelections(row,HEADER_COL);
			const bool bInSelection=bFullInselection?true:pCurSelections->RowInSelections(row);
			if(bFullInselection){
				backColor=HeaderColors::CLR_ACTIVE;
				return EST_IN_SELECTION;
			}else if(bInSelection||row==pSheet->GetActiveRow()){
				backColor=HeaderColors::CLR_SELECTION;//RGB(0,0,0xff):RGB(255,192,111);
				return EST_IN_PROJECTION_OF_SELECTION;
			}else
				backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
		}else
			backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
		return EST_NOT_IN_SELECTION;
	}

	//[firstRow,lastRow]
	void GridRenderer::draw_RowHeader(CDCHandle& dc,LPCRECT lprc,int firstRow,int lastRow,CRgnLight const* pRgnClip)
	{
		const Selections* pSelections=pSheet_->get_Selections();
		const RowHeader& rh=pSheet_->get_RowHeader();
		//int const rh.get_rows()=rh.get_rows();
		if(0==rh.get_rows()) return;
		BOOL const bAutoAppendRow=pSheet_->get_AutoAppendRow();

		int const topRow=firstRow;//rh.get_TopVisScrollRow();
		//CCellRange const selection=pSheet_->get_Selection();

		CCell const activeCell=pSheet_->GetActiveCell();
		_ASSERT(topRow<rh.get_rows());
		HeaderSetupDC setupDC(dc);
		GdiSelectObject<> gso(dc.m_hDC,CreatePen(PS_SOLID,0,HeaderColors::CLR_GRID));
		RECT rcCell={lprc->left,lprc->top,lprc->right,lprc->top};


		TCHAR text[MAX_CELLTEXT];
		/*
		DrawHeaderCellStruct dhcs;
		DrawTextStruct1 dts;
		dts.lpszCellText=text;
		dts.uDrawTextFormat=DT_VCENTER|DT_SINGLELINE|DT_CENTER;

		dhcs.pDTS=&dts;
		dhcs.hDC=dc.m_hDC;
		//dhcs.bHeaderCorner=FALSE;
		//dhcs.bRowHeader=TRUE;
		dhcs.headerType=MHT_ROW_HEADER;
		dhcs.activeRow=activeCell.row;
		dhcs.activeCol=activeCell.col;
		*/
		const CComPtr<ICellSymbol> pSymbol=cellTypeFactory_.GetSymbol(ECT_ROWHEADER);
		DrawCellInfo dci;
		ZeroMemory(&dci,sizeof(dci));
		for(int i=topRow;i<=lastRow && rcCell.bottom<=lprc->bottom;++i,rcCell.top=rcCell.bottom)
		{
			int const hi=rh.get_RowHeight(i);
			rcCell.bottom=rcCell.top+hi;

			if(pRgnClip->RectInRgn(rcCell)){
				int nCount=rh.get_text(i,text);
				if(bAutoAppendRow && i==rh.get_rows()-1){
					lstrcpy(text,_T("*"));
					nCount=1;
				}
				CComVariant val(text);
				dci.rcCell=rcCell;
				dci.pdata=&val;
				dci.nSelState=SetupRowHeaderDE(pSheet_,pSelections,i,dci.clrBkgnd);
				pSymbol->Draw(dc,i,HEADER_COL,&dci);
				////dhcs.bkclr=backColor;
				//dhcs.fillRect=rcCell;
				//dts.nTextLen=nCount;
				//pSheet_->SendNotifyMessageToListener(i,-1,OCN_DRAWHEADCELL,(LPARAM)&dhcs);
				//if(!dhcs.bHandled){
				//	//backColor=dhcs.bkclr;
				//	draw_HeaderCell(dc,text,nCount,&rcCell,dhcs.bkclr);
				//}
				//AtlTrace(_T("\nRowHeader::draw row=%d"),i+1);
			}
		}
		//draw remain part
		//if(i==rh.get_rows()){
		//	rcCell.bottom=lprc->bottom;
		//	//if(rect_intersect(*pRgnClip,&rcCell))
		//	FillRect(dc.m_hDC,&rcCell,(HBRUSH) GetStockObject(GRAY_BRUSH));
		//}
	}
	/*
	void SetupColHeaderDE(Worksheet* pSheet,CCellRange const& selection,CCell activeCell,int col,BOOL& bFullInselection)
	{
		bFullInselection=FALSE;
		if(pSheet->get_ShowSelection()){
			if(col>=selection.LeftCol() && col<=selection.RightCol()){
				bFullInselection=HEADER_ROW==selection.TopRow();
				backColor=HEADER_ROW==selection.TopRow()?HeaderColors::CLR_ACTIVE:HeaderColors::CLR_SELECTION;
			}else if(col==activeCell.col){
				backColor=HeaderColors::CLR_SELECTION;
			}else
				backColor=HeaderColors::CLR_BKGND;
		}else{
			backColor=HeaderColors::CLR_BKGND;
		}
	}
	*/
	ESelectionState GridRenderer::SetupColHeaderDE(const Worksheet* pSheet,const Selections* pCurSelections,int col,COLORREF& backColor)const
	{
		if(pSheet->get_ShowSelection()){
			//const Selections* pCurSelections=pSheet->get_Selections();
			BOOL const bFullInselection=pCurSelections->IsFullRowSelectedAtCol(col);//CellInSelections(HEADER_ROW,col);
			const bool bInSelection=bFullInselection?true:pCurSelections->ColInSelections(col);
			if(bFullInselection){
				backColor=HeaderColors::CLR_ACTIVE;
				return EST_IN_SELECTION;
			}else if(bInSelection||col==pSheet->GetActiveCol()){
				backColor=HeaderColors::CLR_SELECTION;//RGB(0,0,0xff):RGB(255,192,111);
				return EST_IN_PROJECTION_OF_SELECTION;
			}else
				backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
		}else
				backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
		return EST_NOT_IN_SELECTION;
	}

	//[leftCol,rightCol]
	void GridRenderer::draw_ColHeader(CDCHandle& dc,LPCRECT lprc,int leftCol,int rightCol,CRgnLight const* pRgnClip)
	{
		const CComPtr<ICellSymbol> pSymbol=cellTypeFactory_.GetSymbol(ECT_COLHEADER);
		if(!pSymbol){
			return;
		}
		//SelectionsHandler& selection=pSheet->get_Selection();
		const Selections* pSelections=pSheet_->get_Selections();

		GdiSelectObject<> gso(dc.m_hDC,CreatePen(PS_SOLID,0,HeaderColors::CLR_GRID));

		//CCellRange const selection=pSheet_->get_Selection();
		CCell const activeCell=pSheet_->GetActiveCell();
		const ColHeader& ch=pSheet_->get_ColHeader();
		//int const leftCol=ch.get_LeftVisScrollCol();
		int const cols=ch.get_cols();

		HeaderSetupDC setupDC(dc.m_hDC);
		RECT rcCell={lprc->left,lprc->top,lprc->left,lprc->bottom};
		TCHAR text[MAX_CELLTEXT];

		/*
		DrawHeaderCellStruct dhcs;
		DrawTextStruct1 dts;
		dts.lpszCellText=text;
		dts.uDrawTextFormat=DT_VCENTER|DT_SINGLELINE|DT_CENTER;
		dhcs.pDTS=&dts;
		dhcs.hDC=dc.m_hDC;
		//dhcs.bHeaderCorner=FALSE;
		//dhcs.bRowHeader=FALSE;
		dhcs.headerType=MHT_COL_HEADER;
		dhcs.activeRow=activeCell.row;
		dhcs.activeCol=activeCell.col;
		*/
		DrawCellInfo dci;
		ZeroMemory(&dci,sizeof(dci));
		for(int i=leftCol;i<=rightCol && rcCell.right<=lprc->right;++i,rcCell.left=rcCell.right)
		{
			int const wi=ch.get_ColWidth(i);
			rcCell.right=rcCell.left+wi;
			//if(rect_intersect(*pRgnClip,&rcCell)){
			if(pRgnClip->RectInRgn(rcCell)){
				int const nCount=ch.get_text(i,text);
				//selection.SetupColHeaderDE(i);
				//dhcs.bHandled=FALSE;

				CComVariant val(text);
				dci.rcCell=rcCell;
				dci.pdata=nCount>0?&val:NULL;
				dci.nSelState=SetupColHeaderDE(pSheet_,pSelections,i,dci.clrBkgnd);
				pSymbol->Draw(dc,HEADER_ROW,i,&dci);

				//if(bFullInSelection){
				//	dhcs.selType=MHST_IN_SELECTION;
				//}else if(selection.ColInside(i)){
				//	dhcs.selType=MHST_IN_PROJECTION_OF_SELECTION;
				//}else
				//	dhcs.selType=MHST_NOT_IN_SELECTION;
				//dhcs.bInSelection=selection.ColInside(i);
				//dhcs.bFullInSelection=HEADER_ROW==selection.TopRow();
				//dhcs.bkclr=backColor;
				/*
				dhcs.fillRect=rcCell;
				dts.nTextLen=nCount;
				pSheet_->SendNotifyMessageToListener(-1,i,OCN_DRAWHEADCELL,(LPARAM)&dhcs);
				if(!dhcs.bHandled){
					//backColor=dhcs.bkclr;
					draw_HeaderCell(dc,text,nCount,&rcCell,dhcs.bkclr);
				}
				*/
				//AtlTrace(_T("\nColHeader::draw col=%s rcCell(%d,%d,%d,%d)"),text,rcCell.left,rcCell.top,rcCell.right,rcCell.bottom);
			}
		}
		//if(i==cols){//draw remain part
		//	rcCell.right=lprc->right;
		//	FillRect(dc.m_hDC,&rcCell,(HBRUSH) GetStockObject(GRAY_BRUSH));
		//}
	}
	/*
	void RgnLight_intersect(CRgnLight const& src,LPCRECT lprc,CRgnLight& rgn)
	{
	for(LPCRECT lprect=src.GetFirst();lprect;lprect=CRgnLight::GetNext(lprect))
	{
	if(intersect(lprect,lprc))
	rgn.AddRect(*lprect);
	}
	}
	void GridRenderer::draw_content1(HDC hDC,LPCRECT lprc,CRgnLight const* pRgnClip)
	{
	CDCHandle dc(hDC);
	HeaderSetupDC setupDC(hDC);
	SelectionsHandler& selection=pSheet->get_Selection();
	RowHeader& rh=pSheet->get_RowHeader();
	ColHeader& ch=pSheet->get_ColHeader();
	int const bottomRow=rh.get_BottomVisScrollRow();
	int const leftCol=ch.get_LeftVisScrollCol();
	int const rightCol=ch.get_RightVisScrollCol();

	CRgnLight rgn;
	RgnLight_intersect(*pRgnClip,lprc,rgn);
	RECT rcClip;
	if(!rgn.GetBox(rcClip)) return;
	if(rcClip.top<lprc->top)
	rcClip.top=lprc->top;
	if(rcClip.left<lprc->left)
	rcClip.left=lprc->left;
	RECT rcCell=*lprc;
	int row=rh.get_TopVisScrollRow(),col=leftCol;
	for(;row<=bottomRow;++row){
	if(rcCell.top==rcClip.top){
	break;
	}else if(rcCell.top>rcClip.top){
	rcCell.top-=rh.get_RowHeight(--row);
	break;
	}
	rcCell.top+=rh.get_RowHeight(row);
	}
	for(;col<=rightCol;++col){
	if(rcCell.left==rcClip.left){
	break;
	}else if(rcCell.left>rcClip.left){
	rcCell.left-=ch.get_ColWidth(--col);
	break;
	}
	rcCell.left+=ch.get_ColWidth(col);
	}
	AtlTrace(_T("\nGrid::draw_content1 LeftTop=(%d,%d)"),row,col);
	int const left=rcCell.left;
	TCHAR text[500];
	for(;row<=bottomRow && rcCell.top<rcClip.bottom;++row,rcCell.top=rcCell.bottom){
	rcCell.bottom=rcCell.top+rh.get_RowHeight(row);
	rcCell.left=left;
	for(int j=col;j<=rightCol && rcCell.left<rcClip.right;++j,rcCell.left=rcCell.right)
	{
	rcCell.right=rcCell.left+ch.get_ColWidth(j);
	if(rect_intersect(rgn,&rcCell)){
	pSheet->GetCellText(row,j,text);
	selection.SetupCellDE(row,j);
	draw_cell(hDC,text,&rcCell);
	AtlTrace(_T("\n(draw)Grid::draw_content1 row=%d,j=%d rcCell(%d,%d,%d,%d)"),row+1,j+1,rcCell.left,rcCell.top,rcCell.right,rcCell.bottom);
	}
	#ifdef _DEBUG
	else
	AtlTrace(_T("\n(not draw)Grid::draw_content1 row=%d,j=%d rcCell(%d,%d,%d,%d)"),row+1,j+1,rcCell.left,rcCell.top,rcCell.right,rcCell.bottom);
	#endif
	}
	}
	}
	*/
	/*
	void SetupCellDE(CCellRange const& activeSelection,CCell activeCell,int row,int col)
	{
	CCell const tl=activeSelection.first;
	CCell const rb=activeSelection.second;
	if(row>=tl.row && row<=rb.row && col>=tl.col && col<=rb.col)
	backColor=Colors::CLR_SELECTION;//RGB(182,202,234);
	else
	backColor=Colors::CLR_BKGND;//RGB(0xff,0xff,0xff);
	if(row==activeCell.row && col==activeCell.col)
	backColor=Colors::CLR_ACTIVE;//RGB(166,160,240);
	}
	*/
	//class ContentSetupDC
	//{
	//	HDC hDC_;
	//	int nBKMode_;
	//	HFONT hFont_;
	//	HPEN hPen_;
	//public:
	//	HeaderSetupDC(HDC hDC):hDC_(hDC)
	//	{
	//		CDCHandle dc(hDC);
	//		nBKMode_=::SetBkMode(hDC,TRANSPARENT);
	//		hFont_=(HFONT)SelectObject(hDC,::GetStockObject(DEFAULT_GUI_FONT));
	//		hPen_=(HPEN)SelectObject(hDC,::CreatePen(PS_SOLID,0,Colors::CLR_GRID));
	//	}
	//	~HeaderSetupDC()
	//	{
	//		if(nBKMode_)
	//			::SetBkMode(hDC_,nBKMode_);
	//		if(hFont_ && HGDI_ERROR!=hFont_)
	//			SelectObject(hDC_,::GetStockObject(DEFAULT_GUI_FONT));
	//		DeleteObject(SelectObject(hDC_,hPen_));
	//	}
	//};
	/*
	class SelectPen
	{
	CDCHandle dc_;
	HPEN hPen_;
	public:
	SelectPen(HDC hDC,HPEN hPen):dc_(hDC)
	{
	hPen_=dc_.SelectPen(hPen);
	}
	~SelectPen()
	{
	DeleteObject();
	//dc_.DeletePen(dc_.SelectPen(hPen_));
	}
	};
	void GridRenderer::calc_freezeAlthogonalSession(const RowHeader& rh,const ColHeader& ch,LPCRECT lprcContent)
	{
	}
	*/
	void GridRenderer::calc_cells_session(CRgnLight const* pRgnClip,int firstCol,int firstRow,int lastCol,int lastRow,LPCRECT lprcContent,VisibleCellsSession& session)const
	{
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		session.clear();
		int const topRow=firstRow;//rh.get_TopVisScrollRow();
		int const bottomRow=lastRow;//rh.get_BottomVisScrollRow();
		int const leftCol=firstCol;//ch.get_LeftVisScrollCol();
		int const rightCol=lastCol;//ch.get_RightVisScrollCol();
		_ASSERT(bottomRow>=topRow);
		_ASSERT(rightCol>=leftCol);
		session.Reset(bottomRow-topRow+1,rightCol-leftCol+1,topRow,leftCol);

		RECT rcCell=*lprcContent;
		//CMergeCell* merge=NULL;
		const VisibleMergeCellMgr& visMergeCells=pSheet_->GetVisibleMergeCellMgr();
		for(int row=topRow;row<=bottomRow;++row,rcCell.top=rcCell.bottom){
			rcCell.bottom=rcCell.top+rh.get_RowHeight(row);

			//if(rcCell.bottom==rcCell.top)
			//	continue;

			rcCell.left=lprcContent->left;
			for(int col=leftCol;col<=rightCol;++col,rcCell.left=rcCell.right)
			{
				const CCell cell(row,col);
				CellItem&	 item=session.item(cell);
				item.clear();
				rcCell.right=rcCell.left+ch.get_ColWidth(col);

				//item.pMerge=pMerge;
				item.rcCell=rcCell;
				if(pRgnClip->RectInRgn(rcCell)){
					const CMergeCell* pMerge=visMergeCells.GetMergeCells(cell);
					if(pMerge){
						int const minR=pMerge->TopRow();
						int const minC=pMerge->LeftCol();
						int const maxR=pMerge->BottomRow();
						int const maxC=pMerge->RightCol();
						RECT rcMerge=rcCell;//pSheet_->raw_GetCellRect(cell);
						if(minC!=col){
							rcMerge.left-=ch.get_DiffWidths(minC,col);
						}
						if(maxC!=col){
							rcMerge.right+=ch.get_DiffWidths(col+1,maxC+1);
						}
						if(minR!=row){
							rcMerge.top-=rh.get_DiffHeights(minR,row);
						}
						if(maxR!=row)
							rcMerge.bottom+=rh.get_DiffHeights(row+1,maxR+1);

						item.put_MergeRect(rcMerge);
					}else{
						item.put_MergeRect(rcCell);
					}
					item.SetInClip();
					item.SetCSPack(pSheet_->GetCellStore(cell,ECSM_STYLE_VALID|ECSM_CELLTYPE_VALID,pMerge));
				}
				//session.push_back(item);
			}
			//bNotCalcVisibleCols=false;
		}
		//session.put_cols(nVisibleCols);
		//session.Sort();
	}
	/*
	void GridRenderer::calc_scrollCellsSession(const RowHeader& rh,const ColHeader& ch,LPCRECT lprcContent)//,VisibleCellsSession& vcs)//vector<VisibleCellSession>& vec)
	{
		session_.clear();
		//const RowHeader& rh=pSheet->get_RowHeader();
		//const ColHeader& ch=pSheet->get_ColHeader();
		//int const rows=rh.get_rows();
		//int const cols=ch.get_cols();
		int const topRow=rh.get_TopVisScrollRow();
		int const bottomRow=rh.get_BottomVisScrollRow();
		int const leftCol=ch.get_LeftVisScrollCol();
		int const rightCol=ch.get_RightVisScrollCol();

		//session_.put_cols(rightCol-leftCol+1);
		int nVisibleCols=0;
		bool bNotCalcVisibleCols=true;
		//int const logPixelsX=GetDeviceCaps(hDC, LOGPIXELSX);
		RECT rcCell=*lprcContent;
		CMergeCell* merge=NULL;
		VisibleMergeCellMgr& visMergeCells=pSheet->GetVisibleMergeCellMgr();
		//VisibleCellsSession::record_t	vcs_rec;
		for(int i=topRow;i<=bottomRow;++i,rcCell.top=rcCell.bottom){
			rcCell.bottom=rcCell.top+rh.get_RowHeight(i);

			if(rcCell.bottom==rcCell.top)
				continue;

			rcCell.left=lprcContent->left;
			//vcs_rec.clear();
			for(int j=leftCol;j<=rightCol;++j,rcCell.left=rcCell.right)
			{
				CellItem		vcs_cell;
				vcs_cell.clear();//rc={0,0,0,0};
				vcs_cell.row=i;
				vcs_cell.col=j;
				rcCell.right=rcCell.left+ch.get_ColWidth(j);

				if(rcCell.right==rcCell.left)
					continue;
				if(bNotCalcVisibleCols){
					++nVisibleCols;
				}
				merge=visMergeCells.GetMergeCells(i,j);
				vcs_cell.pMergeCells=merge;
				vcs_cell.rcCell=rcCell;
				if(merge){
					int const _row=merge->TopRow();
					int const _col=merge->LeftCol();
					int const minR=_row;
					int const minC=_col;
					int const maxR=merge->BottomRow();
					int const maxC=merge->RightCol();
					RECT rc1=pSheet->raw_GetCellRect(minR,minC);
					RECT rc2=pSheet->raw_GetCellRect(maxR,maxC);
					SetRect(&vcs_cell.rcMerge,min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom));
					if(visMergeCells.MergeCellShouldDraw(i,j,merge)){
						merge->dirty=true;
					}else{
						vcs_cell.hide();
					}
					vcs_cell.rcRender=vcs_cell.rcMerge;
				}else{
					vcs_cell.rcMerge=rcCell;
					vcs_cell.rcRender=rcCell;
				}
				session_.push_back(vcs_cell);
			}
			bNotCalcVisibleCols=false;
		}
		session_.put_cols(nVisibleCols);
		//session_.Sort();
	}
*/
	/*
	void GridRenderer::draw_borders(HDC hDC,CRgnLight const* pRgnClip)
	{
		RowHeader& rh=pSheet->get_RowHeader();
		ColHeader& ch=pSheet->get_ColHeader();
		int const topRow=rh.get_TopVisScrollRow();
		int const leftCol=ch.get_LeftVisScrollCol();
		int const bottomRow=pSheet->get_RowHeader().get_BottomVisScrollRow();
		int const rightCol=pSheet->get_ColHeader().get_RightVisScrollCol();

		for(size_t i=0;i<session_.size();++i)
		{
			CellItem& cell=session_[i];
			RECT const largeCell={cell.rc.left-1,cell.rc.top-1,cell.rc.right+1,cell.rc.bottom+1};
			if(cell.Visible() && pRgnClip->RectInRgn(largeCell)){
				style::StyleDesc& style=cell.GetStyle(pSheet);
				CellBorder cellBorder=*style.GetBorders();
				Border right=cellBorder.right;
				Border bottom=cellBorder.bottom;
				if(cell.pMergeCells){
					CCell const cid1={cell.row,cell.pMergeCells->RightCol()};
					CellItem* pCell =session_.GetItem(cid1);
					if(pCell){
						right=pCell->GetStyle(pSheet).GetBorders()->right;
					}

					CCell const cid2={cell.pMergeCells->BottomRow(),cell.col};
					pCell =session_.GetItem(cid2);
					if(pCell){
						bottom=pCell->GetStyle(pSheet).GetBorders()->bottom;
					}
				}
				{//block
					LPCRECT lprc=&cell.rc;
					bool const bDrawBottom=bottom.get_Weight()>1;
					bool const bDrawRight=right.get_Weight()>1;
					if(bDrawBottom){
						MoveToEx(hDC,lprc->left-1,lprc->bottom-1,NULL);
						bottom.LineTo(hDC,lprc->right-1,lprc->bottom-1);
					}
					if(bDrawRight){
						if(!bDrawBottom){
							MoveToEx(hDC,lprc->right-1,lprc->bottom-1,NULL);
						}
						right.LineTo(hDC,lprc->right-1,lprc->top-1);
					}
					
					bool const bDrawTop=topRow==cell.row && cellBorder.top.get_Weight()>1;
					if(bDrawTop){
						if(!bDrawRight)
							MoveToEx(hDC,lprc->right-1,lprc->top-1,NULL);
						cellBorder.top.LineTo(hDC,lprc->left-1,lprc->top-1);
					}
					if(leftCol==cell.col && cellBorder.left.get_Weight()>1){
						if(!bDrawTop)
							MoveToEx(hDC,lprc->left,lprc->top-1,NULL);
						cellBorder.left.LineTo(hDC,lprc->left,lprc->bottom-1);
					}
				}
			}
		}
	}
	*/
	struct SessionSorter
	{
		Worksheet* pSheet;
		SessionSorter(Worksheet* pSheet):pSheet(pSheet)
		{
		}
		template<class T>
			bool operator()(T const& l,T const& r)const
		{
			style::StyleDesc const& s1=l.raw_style();
			style::StyleDesc const& s2=r.raw_style();
			return s1.GetBorders()->max_weight()<s2.GetBorders()->max_weight();
		}
	};
	/*
	//����������Լ����Ϊ0��cellȥ�����border��С��С��������
	//�����ŵ�vec��
	void GridRenderer::clearup_session(CRgnLight const* pRgnClip,vector<CellItem>& vec)
	{
	int const topRow=pSheet->get_RowHeader().get_TopVisScrollRow();
	int const leftCol=pSheet->get_ColHeader().get_LeftVisScrollCol();
	int const bottomRow=pSheet->get_RowHeader().get_BottomVisScrollRow();
	int const rightCol=pSheet->get_ColHeader().get_RightVisScrollCol();

	//HeaderSetupDC setupDC(hDC);
	//GdiSelectObject<> gso(hDC,CreatePen(PS_SOLID,0,Colors::CLR_GRID));
	//TCHAR text[MAX_CELLTEXT];
	for(size_t i=0;i<session_.size();++i)
	{
	CellItem& cell=session_[i];//.item(i,j);
	int const r=cell.row;
	int const c=cell.col;
	if(cell.Visible()){
	if(pRgnClip->RectInRgn(cell.rc)){
	style::StyleDesc& style=cell.GetStyle(pSheet);
	CellBorder& cellBorder=*style.GetBorders();
	//Border left=pbdrs->left,top=pbdrs->top,right=pbdrs->right,bottom=pbdrs->bottom;
	//CellBorder cellBorder;
	//cellBorder.left=pbdrs->left;
	//cellBorder.top=pbdrs->top;
	//cellBorder.right=pbdrs->right;
	//cellBorder.bottom=pbdrs->bottom;
	{//block init borders-------------------------------------
	if(cellBorder.left.IsNull() && cell.col>0){
	if(cell.col==leftCol){
	style::StyleDesc _style;
	pSheet->GetCellStyle(cell.row,cell.col-1,_style);
	cellBorder.left=_style.GetBorders()->right;
	}else{
	style::StyleDesc& _style=session_[i-1].GetStyle(pSheet);
	cellBorder.left=_style.GetBorders()->right;
	}
	}
	if(cellBorder.right.IsNull() && cell.col<rightCol){
	if(cell.col==rightCol){
	style::StyleDesc _style;
	pSheet->GetCellStyle(cell.row,cell.col+1,_style);
	cellBorder.right=_style.GetBorders()->left;
	}else{
	style::StyleDesc& _style=session_[i+1].GetStyle(pSheet);
	cellBorder.right=_style.GetBorders()->left;
	}
	}
	if(cellBorder.top.IsNull() && cell.row>0){
	if(cell.row==topRow){
	style::StyleDesc _style;
	pSheet->GetCellStyle(cell.row-1,cell.col,_style);
	cellBorder.top=_style.GetBorders()->bottom;
	}else{
	style::StyleDesc& _style=session_[i-(rightCol-leftCol+1)].GetStyle(pSheet);
	cellBorder.top=_style.GetBorders()->bottom;
	}
	}
	if(cellBorder.bottom.IsNull() && cell.row<bottomRow){
	if(cell.row==bottomRow){
	style::StyleDesc _style;
	pSheet->GetCellStyle(cell.row+1,cell.col,_style);
	cellBorder.bottom=_style.GetBorders()->top;
	}else{
	style::StyleDesc& _style=session_[i+(rightCol-leftCol+1)].GetStyle(pSheet);
	cellBorder.bottom=_style.GetBorders()->top;
	}
	}
	}//:~block init borders-------------------------------------
	//pSheet->GetCellStyle(r,c,cell.style);
	//CMergeCell* merge=cell.pMergeCells;
	//if(merge){
	//	int const nCount=pSheet->GetCellText(r,c,text);
	//	draw_merge_cell(hDC,r,c,merge,text,nCount,&cell.rc,style);
	//	draw_cell_border(hDC,r,c,cellBorder.left,cellBorder.top,cellBorder.right,cellBorder.bottom,topRow,leftCol,&cell.rc);
	//	CCell const cell={r,c};
	//	bordersSession_.AddCellBorder(pSheet,cell,cellBorder);
	//	bordersSession_[cell].clear();
	//}else{
	//	int const nCount=pSheet->GetCellText(r,c,text);
	//	draw_cell(hDC,r,c,text,nCount,&cell.rc,style);
	//	draw_cell_border(hDC,r,c,cellBorder.left,cellBorder.top,cellBorder.right,cellBorder.bottom,topRow,leftCol,&cell.rc);
	//CCell const cell={r,c};
	//bordersSession_.AddCellBorder(pSheet,cell,cellBorder);
	//	bordersSession_[cell].clear();
	//}
	}
	vec.push_back(cell);
	}
	}
	std::sort(vec.begin(),vec.end(),SessionSorter(pSheet));
	}
	*/
	/*
	bool VLineIntersect(int y1,int y2,int y3,int y4,int& outY1,int& outY2)
	{
		_ASSERT(y1<y2);
		_ASSERT(y3<y4);
		if(y2<=y3 || y1>=y4)
			return false;
		outY1=max(y1,y3);
		outY2=min(y2,y4);
		return outY1<outY2;
	}
	bool HLineIntersect(int x1,int x2,int x3,int x4,int& outX1,int& outX2)
	{
		_ASSERT(x1<x2);
		_ASSERT(x3<x4);
		if(x2<=x3 || x1>=x4)
			return false;
		outX1=max(x1,x3);
		outX2=min(x2,x4);
		return outX1<outX2;
	}
	*/
	//struct DelayDrawCellStruct
	//{
	//	int row;
	//	int col;
	//	style::StyleDesc style;
	//	DrawCellStruct dcs;
	//	CString text;
	//};

	UINT GetDrawTextFormat(EXlHAlign xa)
	{
		UINT nFormat=DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
		switch(xa)
		{
		case xlHAlignJustify:
		case xlHAlignCenter:
			nFormat|=DT_CENTER;
			break;
		case xlHAlignLeft:
			nFormat|=DT_LEFT;
			break;
		case xlHAlignRight:
			nFormat|=DT_RIGHT;
			break;
		//case xlHAlignJustify:////��ɢ����
		//	{	
		//		if(DrawTextAlignJustify(hDC,rc,lpText,nCount,nFormat)){
		//			return;
		//		}else{
		//			nFormat|=DT_CENTER;
		//		}
		//	}break;;
		}
		return nFormat;
	}
	//�������淽��draw_content
	//void GridRenderer::draw_session(const Worksheet* pSheet,const Selections* pCurSelections,CDCHandle& dc,VisibleCellsSession& session,const RowHeader& rh,const ColHeader& ch,LPCRECT /*lprcRange*/,CRgnLight const* pRgnClip,EGridPart ePart,const CCellRange& activeSelection/*,const CCellRange& clipRange*/)
	void GridRenderer::draw_session(CDCHandle& dc,VisibleCellsSession& session,EGridPart ePart,const CCellRange& activeSelection)
	{
		const Selections* pSelections=pSheet_->get_Selections();
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		HeaderSetupDC setupDC(dc);
		GdiSelectObjectPlain gso(dc,PenFactory::Instance().gridLinePen);

		const int nBottomRow=session.BottomRow();
		const int nLeftCol=session.LeftCol();
		const int nRightCol=session.RightCol();
		//const int nCols=session.get_cols();
		//const int nRows=session.get_rows();
		//int const rh.get_FreezeBottomRow()=pSheet_->get_RowHeader().get_FreezeBottomRow();
		//int const ch.get_FreezeRightCol()=pSheet_->get_ColHeader().get_FreezeRightCol();

		//for(size_t i=0;i<session.size();++i)
		//const CCell topLeft=session.TopLeft();
		for(int row=session.TopRow();row<=nBottomRow;++row)
		{
			//const int row=topLeft.row+r;//cell.row;
			//if(row<clipRange.TopRow())
			//	continue;
			//else if(row>clipRange.BottomRow())
			//	break;

			for(int col=nLeftCol;col<=nRightCol;++col)
			{
				//if(col<clipRange.LeftCol())
				//	continue;
				//else if(col>clipRange.RightCol())
				//	break;
				const CCell cell(row,col);
				CellItem& item=session.item(cell);
				if(item.IsInClip()){
					draw_cell(dc,cell,item,activeSelection,pSelections,session);
				}
			}
		}
	}

	Border GridRenderer::VisibleCellsSession::GetLeftBorder(const Worksheet* pSheet,CCell cell)
	{
		CellItem& it=item(cell);
		pair<CellBorder,UINT> pr=it.GetBorder();
		if(xlEdgeLeft&pr.second){
			return pr.first.left;
		}else{
			Border bdr;
			if(!it.IsCSPackValid()){
				_ASSERT(!it.IsInClip());
				it.SetCSPack(pSheet->GetCellStore(cell,ECSM_STYLE_VALID));
			}
			//const CCell _cell(cell.row,it.pMergeCells?it.pMergeCells->LeftCol()-1:cell.col-1);
			const CellStorePack& csp=it.GetCSPack();
			const CMergeCell* pMerge=csp.GetMerge();//it.pMerge;
			if(pMerge)
				cell.col=pMerge->LeftCol();
			const CCell _cell(cell.row,pSheet->GetPreCol(cell.col));
			if(_cell.col==cell.col){
				bdr=pSheet->Style_GetStyleByID(it.GetCSPack().GetStyleID()).GetBorders()->left;
			}else{
				CellItem& itl=item(CCell(_cell.row,max(_cell.col,LeftCol()-1)));
				if(!itl.IsCSPackValid()){
					_ASSERT(!itl.IsInClip());
					itl.SetCSPack(pSheet->GetCellStore(_cell,ECSM_STYLE_VALID));
				}
				StylePack sp=it.GetCSPack().GetStylePack();
				StylePack spLeft=itl.GetCSPack().GetStylePack();
				if(sp.eStorePos>spLeft.eStorePos){
					bdr=pSheet->Style_GetStyleByID(spLeft.nStyleID).GetBorders()->right;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->left;
				}else{
					bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->left;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(spLeft.nStyleID).GetBorders()->right;
				}
				itl.SetRightBorder(bdr);
			}
			it.SetLeftBorder(bdr);
			return bdr;
		}
	}
	Border GridRenderer::VisibleCellsSession::GetRightBorder(const Worksheet* pSheet,CCell cell)
	{
		CellItem& it=item(cell);
		pair<CellBorder,UINT> pr=it.GetBorder();
		if(xlEdgeRight&pr.second){
			return pr.first.right;
		}else{
			Border bdr;
			if(!it.IsCSPackValid()){
				_ASSERT(!it.IsInClip());
				it.SetCSPack(pSheet->GetCellStore(cell,ECSM_STYLE_VALID));
			}
			//const CCell _cell(cell.row,it.pMergeCells?it.pMergeCells->RightCol()+1:cell.col+1);
			const CellStorePack& csp=it.GetCSPack();
			const CMergeCell* pMerge=csp.GetMerge();//it.pMerge;
			if(pMerge)
				cell.col=pMerge->RightCol();
			const CCell _cell(cell.row,pSheet->GetNextCol(cell.col));
			if(_cell.col==cell.col/*pSheet->get_ColHeader().get_cols()*/){
				bdr=pSheet->Style_GetStyleByID(it.GetCSPack().GetStyleID()).GetBorders()->right;
			}else{
				CellItem& itr=item(CCell(_cell.row,min(_cell.col,RightCol()+1)));
				if(!itr.IsCSPackValid()){
					_ASSERT(!itr.IsInClip());
					itr.SetCSPack(pSheet->GetCellStore(_cell,ECSM_STYLE_VALID));
				}
				StylePack sp=it.GetCSPack().GetStylePack();
				StylePack spRight=itr.GetCSPack().GetStylePack();
				if(sp.eStorePos>spRight.eStorePos){
					bdr=pSheet->Style_GetStyleByID(spRight.nStyleID).GetBorders()->left;
					if(bdr.IsNull()){
						bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->right;
					}
				}else{
					bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->right;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(spRight.nStyleID).GetBorders()->left;
				}
				itr.SetLeftBorder(bdr);
			}
			it.SetRightBorder(bdr);
			return bdr;
		}
	}
	Border GridRenderer::VisibleCellsSession::GetTopBorder(const Worksheet* pSheet,CCell cell)
	{
		CellItem& it=item(cell);
		pair<CellBorder,UINT> pr=it.GetBorder();
		if(xlEdgeTop&pr.second){
			return pr.first.top;
		}else{
			Border bdr;
			if(!it.IsCSPackValid()){
				_ASSERT(!it.IsInClip());
				it.SetCSPack(pSheet->GetCellStore(cell,ECSM_STYLE_VALID));
			}
			//const CCell _cell(it.pMergeCells?it.pMergeCells->TopRow()-1:cell.row-1,cell.col);
			const CellStorePack& csp=it.GetCSPack();
			const CMergeCell* pMerge=csp.GetMerge();//it.pMerge;
			if(pMerge)
				cell.row=pMerge->TopRow();
			const CCell _cell(pSheet->GetPreRow(cell.row),cell.col);
			if(_cell.row==cell.row){
				bdr=pSheet->Style_GetStyleByID(it.GetCSPack().GetStyleID()).GetBorders()->top;
			}else{
				CellItem& itl=item(CCell(max(_cell.row,TopRow()-1),_cell.col));
				if(!itl.IsCSPackValid()){
					_ASSERT(!itl.IsInClip());
					itl.SetCSPack(pSheet->GetCellStore(_cell,ECSM_STYLE_VALID));
				}
				StylePack sp=it.GetCSPack().GetStylePack();
				StylePack spTop=itl.GetCSPack().GetStylePack();
				if(sp.eStorePos>spTop.eStorePos){
					bdr=pSheet->Style_GetStyleByID(spTop.nStyleID).GetBorders()->bottom;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->top;
				}else{
					bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->top;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(spTop.nStyleID).GetBorders()->bottom;
				}
				itl.SetBottomBorder(bdr);
			}
			it.SetTopBorder(bdr);
			return bdr;
		}
	}
	Border GridRenderer::VisibleCellsSession::GetBottomBorder(const Worksheet* pSheet,CCell cell)
	{
		CellItem& it=item(cell);
		pair<CellBorder,UINT> pr=it.GetBorder();
		if(xlEdgeBottom&pr.second){
			return pr.first.bottom;
		}else{
			Border bdr;
			if(!it.IsCSPackValid()){
				_ASSERT(!it.IsInClip());
				it.SetCSPack(pSheet->GetCellStore(cell,ECSM_STYLE_VALID));
			}
			const CellStorePack& csp=it.GetCSPack();
			const CMergeCell* pMerge=csp.GetMerge();//it.pMerge;
			if(pMerge)
				cell.row=pMerge->BottomRow();
			const CCell _cell(pSheet->GetNextRow(cell.row),cell.col);
			if(_cell.row==cell.row/*pSheet->get_RowHeader().get_rows()*/){
				bdr=pSheet->Style_GetStyleByID(it.GetCSPack().GetStyleID()).GetBorders()->bottom;
			}else{
				CellItem& itr=item(CCell(min(_cell.row,BottomRow()+1),_cell.col));
				if(!itr.IsCSPackValid()){
					_ASSERT(!itr.IsInClip());
					itr.SetCSPack(pSheet->GetCellStore(_cell,ECSM_STYLE_VALID));
				}
				StylePack sp=it.GetCSPack().GetStylePack();
				StylePack spBottom=itr.GetCSPack().GetStylePack();
				if(sp.eStorePos>spBottom.eStorePos){
					bdr=pSheet->Style_GetStyleByID(spBottom.nStyleID).GetBorders()->top;
					if(bdr.IsNull()){
						bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->bottom;
					}
				}else{
					bdr=pSheet->Style_GetStyleByID(sp.nStyleID).GetBorders()->bottom;
					if(bdr.IsNull())
						bdr=pSheet->Style_GetStyleByID(spBottom.nStyleID).GetBorders()->top;
				}
				itr.SetTopBorder(bdr);
			}
			it.SetBottomBorder(bdr);
			return bdr;
		}
	}

	//void GridRenderer::draw_cell(CDCHandle dc,const Worksheet* pSheet,CCell cell,CellItem& item,const CCellRange& activeSelection,CRgnLight const* pRgnClip,const Selections* pCurSelections,VisibleCellsSession& session)
	void GridRenderer::draw_cell(CDCHandle dc,CCell cell,CellItem& item,const CCellRange& activeSelection,const Selections* pSelections,VisibleCellsSession& session)
	{
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		//const Selections* pSelections=pSheet_->get_Selections();
		const BOOL bOwnerData=pSheet_->pWorkbook_->IsOwnerData();
		//const CMergeCell* merge=item.GetCSPack().GetMerge();
		const CMergeCell* merge=item.GetCSPack().GetMerge();
		//const pair<const StyleDesc*,const CComVariant*> pr=cellStoreCache_.GetCellStore(pSheet_,merge?merge->TopLeft():CCell(row,col));
		//const pair<const StyleDesc*,const CComVariant*> pr=merge?mergeCellCache_.GetCellStore(pSheet_,merge):cellStoreCache_.GetCellStore(pSheet_,cell);
		const CellStorePack& pr=item.GetCSPack();//merge?mergeCellCache_.GetCellStore(pSheet_,merge):cellStoreCache_.GetCellStore(pSheet_,cell);
		const style::StyleDesc& style=pSheet_->Style_GetStyleByID(pr.GetStylePack().nStyleID);//item.GetStyle(pSheet_,row,col);
		const RECT rcCell= item.get_MergeRect();//item.rcRender;

		const ESelectionMode esm=pSheet_->GetWorkbook()->get_SelectionMode();
		//test

		//TCHAR text[MAX_CELLTEXT];
		BOOL const bShowGrid=pSheet_->get_ShowGrid();
		BOOL const bShowSelection=pSheet_->get_ShowSelection();
		
		/*DrawCellStruct*/
		CComVariant vData;
		DrawCellInfo dcs;
		ZeroMemory(&dcs,sizeof(dcs));
		//dcs.hDC=dc.m_hDC;
		//pSheet_->GetActiveCell(dcs.activeRow,dcs.activeCol);
		//dcs.textRect=rcCell;
		//dcs.fMergeCell=NULL!=merge;
		//dcs.nCellType=pr.GetCellTypePack().cellType;//style.CellType_GetType();
		dcs.pMerge=merge?merge->get():NULL;
		//dcs.cellType=pr.GetCellTypePack().cellType;
		dcs.rcCell=rcCell;
		const BOOL bActive=pSheet_->GetActiveCell()==cell;
		dcs.nSelState=bActive?(EST_ACTIVECELL):(pSelections->CellInSelections(cell)?EST_IN_SELECTION:EST_NOT_IN_SELECTION);
		//dcs.bSelected=pSelections->CellInSelections(cell);

		const COLORREF cellBKClr=style.BKGND_HasColor()?style.BKGND_GetColor():Colors::CLR_BKGND;
		if(merge&&(activeSelection.Inside(merge->TopLeft())&&activeSelection.Inside(cell))){
			dcs.clrBkgnd=GetBKColor(pSheet_,merge->TopRow(),merge->LeftCol(),merge,cellBKClr);
		}else
			dcs.clrBkgnd=GetBKColor(pSheet_,cell.row,cell.col,merge,cellBKClr);

		//dcs.rcCell=item.rcCell;
		if(dcs.rcCell.right > dcs.rcCell.left+1 && dcs.rcCell.bottom > dcs.rcCell.top+1){
		////draw text
		//if(dcs.textRect.bottom>dcs.textRect.top-1 && dcs.textRect.right>dcs.textRect.left-1){
			int const _row=merge?merge->TopRow():cell.row;
			int const _col=merge?merge->LeftCol():cell.col;
			//int nCount=0;
			if(bOwnerData){
				//nCount=pSheet_->GetCellText(merge?merge->TopLeft():cell,text,true);
				if(pSheet_->GetCellText(merge?merge->TopLeft():cell,&vData,EGCVD_RENDER))
					dcs.pdata=&vData;
			}else{
				dcs.pdata=pr.GetCellValPack().pVal;
				//text[0]=0;
				//CComVariant vText=*pr.GetCellValPack().pVal;
				//if(SUCCEEDED(vText.ChangeType(VT_BSTR))){
				//	CString str(vText.bstrVal);
				//	lstrcpy(text,str);
				//	nCount=str.GetLength();
				//}
			}
			//DrawTextStruct dts;
			//dts.lpszCellText=text;
			//dts.nTextLen=nCount;
			//dcs.pDTS=&dts;
			dcs.cellType=static_cast<ECellType>(pr.GetCellTypePack().cellType);//_pStyle->CellType_GetType();
			dcs.hAlign=style.Align_GetHorizontal();
			dcs.vAlign=style.Align_GetVertical();

			//if(merge)
			{
				CRgn rgn=CreateRectRgn(item.rcCell.left,item.rcCell.top,item.rcCell.right,item.rcCell.bottom);
				dc.SelectClipRgn(rgn);
			}
			draw_cell_inner(dc,merge,_row,_col,dcs,style);
			if(bShowSelection)
				draw_cell_shrink(pSheet_,cell.row,cell.col,pSelections,dc,activeSelection,item,dcs);
			//if(merge)
			{
				dc.SelectClipRgn(NULL);
			}
		}
		//CellBorder const& cellBorder=*style.GetBorders();
		const CellBorder cellBorder=session.GetCellBorder(pSheet_,cell);
		//cellBorder.top=session.
		//��������
		if(bShowGrid){
			RECT _rc=item.rcCell;
			if(cellBorder.bottom.IsNull()||xlLineStyleNone==cellBorder.bottom.get_LineStyle()){
				if(!merge || merge && cell.row==merge->BottomRow()){
					dc.MoveTo(_rc.left,_rc.bottom-1);
					dc.LineTo(_rc.right+1,_rc.bottom-1);
				}
			}
			if(cellBorder.right.IsNull()||xlLineStyleNone==cellBorder.right.get_LineStyle()){
				const bool bDrawRight=!merge || cell.col==merge->RightCol()
					||pSheet_->GetNextCol( cell.col)== cell.col;
				if(bDrawRight){
					dc.MoveTo(_rc.right-1,_rc.top);
					dc.LineTo(_rc.right-1,_rc.bottom+1);
				}
			}
		}
		draw_cell_border(dc,cell,session,&item.rcCell,cellBorder,merge);

		if(bShowSelection && !pSelections->IsMultiSelectionMode()){
			if(ESM_SINGLECELL==esm){
				if(activeSelection.TopRow()== cell.row && activeSelection.LeftCol()== cell.col){
					const RECT rc={item.rcCell.left,item.rcCell.top,item.rcCell.right-1,item.rcCell.bottom-1};
					dc.DrawFocusRect(&rc);
				}
			}else{
				if(!(activeSelection.LeftCol()>=ch.get_cols() || activeSelection.TopRow()>=rh.get_rows()
					|| activeSelection.RightCol()<0 || activeSelection.BottomRow()<0))
				{
					draw_cell_DragBounds(pSheet_,dc,activeSelection,merge,item.rcCell,cell.row,cell.col,rh.get_rows(),ch.get_cols(),cellBKClr);
				}
			}
		}
		//��������
		GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareBlackPen1);
		if(ch.get_FreezeRightCol()==cell.col){
			dc.MoveTo(item.rcCell.right-1,item.rcCell.top);
			dc.LineTo(item.rcCell.right-1,item.rcCell.bottom);
		}
		if(rh.get_FreezeBottomRow()==cell.row){
			dc.MoveTo(item.rcCell.left,item.rcCell.bottom-1);
			dc.LineTo(item.rcCell.right,item.rcCell.bottom-1);
		}
	}
	/*
	void GridRenderer::draw_content(HDC hDC,LPCRECT lprcContent,CRgnLight const* pRgnClip)
	{
		CDCHandle dc(hDC);
		const RowHeader& rh=pSheet->get_RowHeader();
		const ColHeader& ch=pSheet->get_ColHeader();
		const ESelectionMode esm=pSheet->get_SelectionMode();

		HeaderSetupDC setupDC(hDC);

		//test
		LOGBRUSH lbr;
		lbr.lbColor=RGB(0,0,200);
		lbr.lbStyle=BS_SOLID;
		lbr.lbHatch=0;
		
		//GdiSelectObject<> gso(hDC,		
		//	CreatePen(PS_SOLID,0,Colors::CLR_GRID));

		GdiSelectObjectPlain gso(dc,PenFactory::Instance().gridLinePen);

		TCHAR text[MAX_CELLTEXT];
		int const nCols=session_.get_cols();//rightCol-leftCol+1;
		int const nRows=session_.get_rows();//bottomRow-topRow+1;

		BOOL const bShowGrid=pSheet->get_ShowGrid();
		
		DrawCellStruct dcs;
		dcs.hDC=hDC;
		pSheet->GetActiveCell(dcs.activeRow,dcs.activeCol);

		//about draw active selection bound
		CCellRange cr=pSheet->get_Selections().GetActiveSelection();
		cr.Normalize();
		pSheet->AdjustSelection(cr);
		cr.RightCol()=min(cr.RightCol(),ch.get_cols()-1);
		cr.BottomRow()=min(cr.BottomRow(),rh.get_rows()-1);
		cr.TopRow()=max(0,cr.TopRow());
		cr.LeftCol()=max(0,cr.LeftCol());
		//:~about draw active selection bound

		//for(size_t i=0;i<session_.size();++i)
		for(int r=0;r<nRows;++r)
		{
			for(int c=0;c<nCols;++c)
			{
				//CellItem& cell=session_[i];//session_.item(r,c);
				CellItem& cell=session_.item(r,c);
				if(pRgnClip->RectInRgn(cell.rcRender)){
					style::StyleDesc const& style=cell.GetStyle(pSheet);
					RECT const rcCell=cell.rcRender;//{cell.rc.left,cell.rc.top,bShowGrid?cell.rc.right-1:cell.rc.right,bShowGrid?cell.rc.bottom-1:cell.rc.bottom};
					CMergeCell* merge=cell.pMergeCells;
					int row=cell.row;
					int col=cell.col;

					dcs.textRect=rcCell;
					dcs.fMergeCell=NULL!=merge;

					CellBorder const& cellBorder=*style.GetBorders();
					{
						const StyleDesc::CellType_t* pCellType=style.GetCellTypePtr();
						if(merge && (cr.TopRow()!=HEADER_ROW && cr.LeftCol()!=HEADER_COL ))
							dcs.bkclr=GetBKColor(merge->TopRow(),merge->LeftCol(),style);
						else
							dcs.bkclr=GetBKColor(row,col,style);
						dcs.fillRect=cell.rcCell;
						{
							{//draw text
								StyleDesc _style=style;
								if(merge)
									pSheet->GetCellStyle(merge->TopRow(),merge->LeftCol(),_style);

								int const nCount=pSheet->GetCellText(merge?merge->TopRow():row,merge?merge->LeftCol():col,text);
								//dcs.fDrawText=true;
								DrawTextStruct dts;
								dts.lpszCellText=text;
								dts.nTextLen=nCount;
								dcs.pDTS=&dts;
								dcs.nCellType=_style.CellType_GetType();
								dcs.hAlignment=_style.Align_GetHorizontal();
								dcs.vAlignment=_style.Align_GetVertical();

								if(dcs.textRect.bottom>dcs.textRect.top && dcs.textRect.right>dcs.textRect.left){
									CellFontSetup cfs(dc,_style); 
									if(_style.IsOwnerDraw()){
										dcs.pDTS->uDrawTextFormat=GetDrawTextFormat((EXlHAlign)dcs.hAlignment);
										pSheet->SendNotifyMessageToListener(merge?merge->TopRow():row,merge?merge->LeftCol():col,OCN_DRAWCELL,(LPARAM)&dcs);
									}else{
										draw_cell(merge?merge->TopRow():row,merge?merge->LeftCol():col,dcs);
									}
								}
							}

							//��������
							if(bShowGrid){
								//style::Borders const* pborders=style.GetBorders();
								RECT _rc=cell.rcCell;
								if(cellBorder.bottom.IsNull()){
									if(!merge || merge && cell.row==merge->BottomRow()){
										MoveToEx(hDC,_rc.left,_rc.bottom-1,NULL);
										LineTo(hDC,_rc.right,_rc.bottom-1);
									}
								}
								if(cellBorder.right.IsNull()){
									if(!merge || merge && cell.col==merge->RightCol()){
										MoveToEx(hDC,_rc.right-1,_rc.bottom-1,NULL);
										LineTo(hDC,_rc.right-1,_rc.top-1);
									}
								}
							}
						}

						{
							Border left=cellBorder.left;
							Border top=cellBorder.top;
							Border right=cellBorder.right;
							Border bottom=cellBorder.bottom;
							//RECT __rc=cell.rcCell;
							if(cell.pMergeCells){
								if(cell.col!=cell.pMergeCells->LeftCol()){
									left.SetNull();
								}
								if(cell.col!=cell.pMergeCells->RightCol())
									right.SetNull();
								if(cell.row!=cell.pMergeCells->TopRow())
									top.SetNull();
								if(cell.row!=cell.pMergeCells->BottomRow())
									bottom.SetNull();
							}
							draw_border(hDC,cell.row,cell.col,left,top,right,bottom,&cell.rcCell);
						}
					}
					if(pSheet->get_ShowSelection()){
						draw_cell_DragBounds(dc,cr,esm,cell.rcCell,row,col,rh.get_rows(),ch.get_cols());
					}
				}
			}
		}
	}
	*/
	ECellSelectionRelations GridRenderer::GetCellSelectionRelations(const Worksheet* pSheet,const CCellRange& cr,int row,int col)const
	{
		int ecsr=0;
		int left=pSheet->GetNextCol(cr.LeftCol()-1);
		if(!cr.ColInside(left))
			left=cr.LeftCol();
		int top=pSheet->GetNextRow(cr.TopRow()-1);
		if(!cr.RowInside(top))
			top=cr.TopRow();
		int right=pSheet->GetPreCol(cr.RightCol()+1);
		if(!cr.ColInside(right))
			right=cr.RightCol();
		int bottom=pSheet->GetPreRow(cr.BottomRow()+1);
		if(!cr.RowInside(bottom))
			bottom=cr.BottomRow();
		//const SelectionsHandler& ss=pSheet->get_Selections();
		int outerLeft=pSheet->GetPreCol(left);
		int outerRight=pSheet->GetNextCol(right);
		int outerTop=pSheet->GetPreRow(top);
		int outerBottom=pSheet->GetNextRow(bottom);
		if(left==outerLeft) --outerLeft;
		if(right==outerRight)++outerRight;
		if(top==outerTop)--outerTop;
		if(bottom==outerBottom)++outerBottom;
		if(outerTop==row&&outerLeft==col)
			return ECSR_OUTER_LEFTTOP;
		else if(outerTop==row&&outerRight==col)
			return ECSR_OUTER_RIGHTTOP;
		else if(outerBottom==row&&outerLeft==col)
			return ECSR_OUTER_LEFTBOTTOM;
		else if(outerBottom==row&&outerRight==col)
			return ECSR_OUTER_RIGHTBOTTOM;
		if(cr.RowInside(row)){
			if(left==col)
				ecsr|=ECSR_INNER_LEFT;
			if(outerLeft==col)
				ecsr|=ECSR_OUTER_LEFT;
			if(right==col)
				ecsr|=ECSR_INNER_RIGHT;
			if(outerRight==col)
				ecsr|=ECSR_OUTER_RIGHT;
		}
		if(cr.ColInside(col)){
			if(top==row)
				ecsr|=ECSR_INNER_TOP;
			if(outerTop==row)
				ecsr|=ECSR_OUTER_TOP;
			if(bottom==row)
				ecsr|=ECSR_INNER_BOTTOM;
			if(outerBottom==row)
				ecsr|=ECSR_OUTER_BOTTOM;
		}
		return (ECellSelectionRelations)ecsr;
	}
	void GridRenderer::draw_cell_DragBounds(const Worksheet* pSheet,CDCHandle& dc,const CCellRange activeSelection,const CMergeCell* merge,RECT rcCell,int row,int col,int /*rows*/,int /*cols*/,COLORREF bkclr)const
	{
		//_ASSERT(!(activeSelection.LeftCol()>=cols || activeSelection.TopRow()>=rows|| activeSelection.RightCol()<0 || activeSelection.BottomRow()<0));
		LPCRECT lprc=&rcCell;
		//GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareBlackPen1);
		const int ecsr=(int)GetCellSelectionRelations(pSheet,activeSelection,row,col);
		const GDISetROP2 rop2(dc.m_hDC,R2_XORPEN);

		//�������
		if(ECSR_OUTER_LEFTTOP==ecsr){
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareWhitePen2);
			dc.MoveTo(lprc->right-1,lprc->bottom-1);
			dc.LineTo(lprc->right,lprc->bottom-1);
			return;
			/*
			GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
			dc.MoveTo(lprc->right-2,lprc->bottom-2);
			dc.LineTo(lprc->right-1,lprc->bottom-2);
			sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
			dc.MoveTo(lprc->right-2,lprc->bottom-1);
			dc.LineTo(lprc->right-1,lprc->bottom-1);
			//sop.SelectObject(CreatePen(PS_SOLID,1,RGB(255,0,0)));
			dc.MoveTo(lprc->right-1,lprc->bottom-2);
			dc.LineTo(lprc->right-1,lprc->bottom);
			return;
			*/
		}
		//
		if(ECSR_OUTER_RIGHTTOP==ecsr){
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->left,lprc->bottom-2);
			dc.LineTo(lprc->left+1,lprc->bottom);
			/*
			GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
			dc.MoveTo(lprc->left,lprc->bottom-2);
			dc.LineTo(lprc->left+1,lprc->bottom-2);
			sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
			dc.MoveTo(lprc->left,lprc->bottom-1);
			dc.LineTo(lprc->left+1,lprc->bottom-1);
			*/
			return;
		}
		if(ECSR_OUTER_LEFTBOTTOM==ecsr){
			/*
			GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
			dc.MoveTo(lprc->right-2,lprc->top);
			dc.LineTo(lprc->right-1,lprc->top);
			sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
			dc.LineTo(lprc->right+1,lprc->top);
			*/
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->right-2,lprc->top);
			dc.LineTo(lprc->right,lprc->top);
			return;
		}
		if(ECSR_OUTER_RIGHTBOTTOM==ecsr){
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->left,lprc->top);
			dc.LineTo(lprc->left+2,lprc->top);
			dc.MoveTo(lprc->left,lprc->top+1);
			dc.LineTo(lprc->left+2,lprc->top+1);
			/*
			GdiSelectObjectAutoDel sop(dc,PenFactory::CreateSquarePen(PS_SOLID,2,bkclr^RGB(255,255,255)));//CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
			dc.MoveTo(lprc->left,lprc->top+1);
			dc.LineTo(lprc->left+1,lprc->top+1);
			//dc.MoveTo(lprc->left,lprc->top+2);
			//dc.LineTo(lprc->left+2,lprc->top+2);
			sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
			dc.MoveTo(lprc->left-1,lprc->top+1);
			dc.LineTo(lprc->left-1,lprc->top-1);
			dc.LineTo(lprc->left+2,lprc->top-1);
			*/
			return;
		}

		if(ECSR_INNER_LEFT&ecsr){
			/*
			if(merge && merge->LeftCol()!=col){
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left,lprc->bottom);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left,lprc->bottom-1);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->left+1,lprc->bottom-1);
			}
			*/
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			//dc.MoveTo(lprc->left,row==activeSelection.TopRow()?lprc->top+1:lprc->top);
			dc.MoveTo(lprc->left,(ECSR_INNER_TOP&ecsr)?lprc->top+1:lprc->top);
			dc.LineTo(lprc->left,lprc->bottom);
		}
		if(ECSR_OUTER_LEFT&ecsr){
				/*
			if(merge && merge->LeftCol()-1!=col&&merge->RightCol()!=col){
				GdiSelectObjectAutoDel sop(dc,PenFactory::CreateSquarePen(PS_SOLID,2,bkclr^RGB(255,255,255)));//CreatePen(PS_SOLID,2,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->right-1,lprc->top);
				dc.LineTo(lprc->right-1,lprc->bottom);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->right-2,lprc->top);
				dc.LineTo(lprc->right-2,lprc->bottom-1);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->right-1,lprc->top);
				dc.LineTo(lprc->right-1,lprc->bottom-1);
				dc.MoveTo(lprc->right-2,lprc->bottom-1);
				dc.LineTo(lprc->right,lprc->bottom-1);
			}
				*/
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareWhitePen2);
			dc.MoveTo(lprc->right-1,lprc->top+1);
			dc.LineTo(lprc->right-1,lprc->bottom-1);
		}
		if(ECSR_INNER_RIGHT&ecsr){
			/*
			if(merge && merge->RightCol()!=col){
				GdiSelectObjectAutoDel sop(dc,PenFactory::CreateSquarePen(PS_SOLID,2,bkclr^RGB(255,255,255)));//CreatePen(PS_SOLID,2,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->right-1,lprc->top);
				dc.LineTo(lprc->right-1,lprc->bottom);
			}else{
				const int bottom=(ECSR_INNER_BOTTOM&ecsr)?(lprc->bottom-5):lprc->bottom;
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->right-2,lprc->top);
				dc.LineTo(lprc->right-2,bottom);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->right-1,lprc->top);
				dc.LineTo(lprc->right-1,bottom);
				if(!(ECSR_INNER_BOTTOM&ecsr)){
					dc.MoveTo(lprc->right-2,bottom);
					dc.LineTo(lprc->right,bottom);
				}
			}
			*/
			const int bottom=((ECSR_INNER_BOTTOM&ecsr)&&!(merge && merge->RightCol()!=col))?(lprc->bottom-5):lprc->bottom;
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareWhitePen2);
			//dc.MoveTo(lprc->right-1,row==activeSelection.TopRow()?lprc->top+2:lprc->top+1);
			dc.MoveTo(lprc->right-1,(ECSR_INNER_TOP&ecsr)?lprc->top+2:lprc->top+1);
			dc.LineTo(lprc->right-1,bottom);
		}
		if(ECSR_OUTER_RIGHT&ecsr){
			/*
			if(merge && merge->RightCol()+1!=col&&merge->LeftCol()!=col){
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left,lprc->bottom);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				const int bottom=(activeSelection.BottomRow()==row)?(lprc->bottom-4):lprc->bottom-1;
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left,bottom);
				if(activeSelection.BottomRow()!=row){
					sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
					dc.MoveTo(lprc->left,bottom);
					dc.LineTo(lprc->left+1,bottom);
				}else{
					dc.MoveTo(lprc->left,bottom+1);
					dc.LineTo(lprc->left+2,bottom+1);
					dc.MoveTo(lprc->left,bottom+2);
					dc.LineTo(lprc->left+2,bottom+2);
					sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
					dc.MoveTo(lprc->left,bottom+3);
					dc.LineTo(lprc->left+2,bottom+3);
				}
			}
			*/
			const int bottom=(activeSelection.BottomRow()==row&&!(merge && merge->RightCol()+1!=col&&merge->LeftCol()!=col))?(lprc->bottom-4):lprc->bottom;
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->left,lprc->top);//row==activeSelection.TopRow()?lprc->top+1:lprc->top);
			dc.LineTo(lprc->left,bottom);
			if(activeSelection.BottomRow()==row){
				//sop.SelectObject(PenFactory::Instance().squareWhitePen2);
				dc.MoveTo(lprc->left+1,bottom+1);
				dc.LineTo(lprc->left+1,bottom+4);
				dc.MoveTo(lprc->left,bottom+1);
				dc.LineTo(lprc->left,bottom+4);
			}
		}
		if(ECSR_INNER_TOP&ecsr){
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->left,lprc->top);
			dc.LineTo(lprc->right,lprc->top);

			/*
			if(merge && merge->TopRow()!=row){
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->right-1,lprc->top);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->right-1,lprc->top);
				dc.LineTo(lprc->right-1,lprc->top+1);
			}
			*/
		}
		if(ECSR_OUTER_TOP&ecsr){
				/*
			if(merge && merge->TopRow()-1!=row&&merge->BottomRow()!=row){
				GdiSelectObjectAutoDel sop(dc,PenFactory::CreateSquarePen(PS_SOLID,2,bkclr^RGB(255,255,255)));//CreatePen(PS_SOLID,2,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->right,lprc->bottom-1);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->bottom-2);
				dc.LineTo(lprc->right-1,lprc->bottom-2);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->right,lprc->bottom-1);
				//sop.SelectObject(CreatePen(PS_SOLID,1,RGB(255,0,0)));
				dc.MoveTo(lprc->right-1,lprc->bottom-2);
				dc.LineTo(lprc->right-1,lprc->bottom+1);
			}
				*/
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareWhitePen2);
			dc.MoveTo(lprc->left+1,lprc->bottom-1);
			dc.LineTo(lprc->right-1,lprc->bottom-1);
		}
		if(ECSR_INNER_BOTTOM&ecsr){
			const int right=((ECSR_INNER_RIGHT&ecsr)&&!(merge && merge->BottomRow()!=row))?(lprc->right-5):lprc->right-1;
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareWhitePen2);
			//dc.MoveTo(lprc->left+(col==activeSelection.LeftCol()?2:1),lprc->bottom-1);
			dc.MoveTo(lprc->left+((ECSR_INNER_LEFT&ecsr)?2:1),lprc->bottom-1);
			dc.LineTo(right,lprc->bottom-1);
			if(ECSR_INNER_RIGHT&ecsr){
				dc.MoveTo(right+3,lprc->bottom-2);
				dc.LineTo(lprc->right,lprc->bottom-2);

				sop.SelectObject(PenFactory::Instance().whitePen1);
				dc.MoveTo(right+2,lprc->bottom-1);
				dc.LineTo(lprc->right,lprc->bottom-1);
			}
			/*
			if(merge && merge->BottomRow()!=row){
				GdiSelectObjectAutoDel sop(dc,PenFactory::CreateSquarePen(PS_SOLID,2,bkclr^RGB(255,255,255)));//CreatePen(PS_SOLID,2,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->right,lprc->bottom-1);
			}else{
				const int right=(ECSR_INNER_RIGHT&ecsr)?(lprc->right-4):lprc->right-1;
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->bottom-2);
				dc.LineTo(right,lprc->bottom-2);
				sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(right,lprc->bottom-1);
				if(!(ECSR_INNER_RIGHT&ecsr)){
					dc.MoveTo(right,lprc->bottom-2);
					dc.LineTo(right,lprc->bottom);
				}else{
					dc.MoveTo(right+1,lprc->bottom-1);
					dc.LineTo(lprc->right,lprc->bottom-1);
					dc.MoveTo(lprc->right-1,lprc->bottom-3);
					dc.LineTo(lprc->right-1,lprc->bottom+1);
					sop.SelectObject(PenFactory::CreateSquarePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
					dc.MoveTo(right+1,lprc->bottom-3);
					dc.LineTo(lprc->right-2,lprc->bottom-3);
					dc.MoveTo(right+1,lprc->bottom-2);
					dc.LineTo(lprc->right-2,lprc->bottom-2);
				}
			}
			*/
		}
		if(ECSR_OUTER_BOTTOM&ecsr){
			const int right=((activeSelection.RightCol()==col)&&!(merge && merge->BottomRow()+1!=row&&merge->TopRow()!=row))?(lprc->right-4):lprc->right;
			GdiSelectObjectPlain sop(dc,PenFactory::Instance().whitePen1);
			dc.MoveTo(lprc->left,lprc->top);
			dc.LineTo(right,lprc->top);
			if(activeSelection.RightCol()==col){
				dc.MoveTo(right+1,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
				dc.MoveTo(right+1,lprc->top+1);
				dc.LineTo(lprc->right,lprc->top+1);
			}
			/*
			if(merge && merge->BottomRow()+1!=row&&merge->TopRow()!=row){
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
			}else{
				GdiSelectObjectAutoDel sop(dc,CreatePen(PS_SOLID,1,bkclr^RGB(255,255,255)));
				const int right=(activeSelection.RightCol()==col)?(lprc->right-4):lprc->right-1;
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(right,lprc->top);
				if(activeSelection.RightCol()!=col){
					sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
					dc.MoveTo(right,lprc->top-1);
					dc.LineTo(right,lprc->top+1);
				}else{
					dc.MoveTo(right+1,lprc->top);
					dc.LineTo(right+3,lprc->top);
					dc.MoveTo(right+1,lprc->top+1);
					dc.LineTo(right+3,lprc->top+1);
					sop.SelectObject(CreatePen(PS_SOLID,1,bkclr^Colors::CLR_GRID));
					dc.MoveTo(lprc->right-1,lprc->top);
					dc.LineTo(lprc->right-1,lprc->top+2); 
				}
			}
			*/
		}

		/*
		{
		//if(row==activeSelection.TopRow() //���ϱ�
		//	|| row==activeSelection.BottomRow()+1//���±�
		//	)
		if((ECSR_INNER_TOP&ecsr)||(ECSR_OUTER_BOTTOM&ecsr))
		{
		bool const bRightBottom=col==activeSelection.RightCol() && row==activeSelection.BottomRow()+1;
		int const x2=lprc->right-(bRightBottom?5:1);//lprc->right-1;
		dc.MoveTo(lprc->left,lprc->top);
		dc.LineTo(x2,lprc->top);

		if(bRightBottom){
		dc.MoveTo(x2+3,lprc->top+1);
		dc.LineTo(lprc->right-1,lprc->top+1);
		}

		}
		//if(row==activeSelection.TopRow()-1 //���ϱ�
		//	|| row==activeSelection.BottomRow())//���±�
		if((ECSR_OUTER_TOP&ecsr)||(ECSR_INNER_BOTTOM&ecsr))
		{
		bool const bRightBottom=col==activeSelection.RightCol() && row==activeSelection.BottomRow();
		int const x2=lprc->right-(bRightBottom?5:1);
		dc.MoveTo(lprc->left-1,lprc->bottom-1);
		dc.LineTo(x2,lprc->bottom-1);

		if(bRightBottom){
		//GdiSelectObjectPlain _sop(dc,PenFactory::Instance().squareBlackPen3);
		dc.MoveTo(x2+3,lprc->bottom-2);
		dc.LineTo(lprc->right-1,lprc->bottom-2);
		dc.MoveTo(x2+3,lprc->bottom-1);
		dc.LineTo(lprc->right-1,lprc->bottom-1);
		}
		}
		}
		//if(activeSelection.RowInside(row))
		{
		//if(col==activeSelection.LeftCol() //���ڱ�
		//	|| col==activeSelection.RightCol()+1)//�����
		if((ECSR_INNER_LEFT&ecsr)||(ECSR_OUTER_RIGHT&ecsr))
		{
		bool const bRightBottom=row==activeSelection.BottomRow() && col==activeSelection.RightCol()+1;
		int const y2=lprc->bottom - (bRightBottom?5:1);
		//dc.MoveTo(lprc->left,lprc->top-1);
		dc.MoveTo(lprc->left,lprc->top);
		dc.LineTo(lprc->left,y2);

		if(bRightBottom){
		dc.MoveTo(lprc->left+1,y2+3);
		dc.LineTo(lprc->left+1,lprc->bottom-1);
		}
		}
		//if(col==activeSelection.LeftCol()-1 //�����
		//	|| col==activeSelection.RightCol())//���ڱ�
		if((ECSR_INNER_RIGHT&ecsr)||(ECSR_OUTER_LEFT&ecsr))
		{
		bool const bRightBottom=row==activeSelection.BottomRow() && col==activeSelection.RightCol();
		int const y2=lprc->bottom-(bRightBottom?5:1);
		dc.MoveTo(lprc->right-1,lprc->top-1);
		dc.LineTo(lprc->right-1,y2);
		if(bRightBottom){
		//dc.MoveTo(lprc->right-2,y2+3);
		//dc.LineTo(lprc->right-2,lprc->bottom);
		}
		}
		}
		//if(col==activeSelection.RightCol()+1)
		//�������
		//if(row==activeSelection.BottomRow()+1)
		if(ECSR_OUTER_RIGHTBOTTOM==ecsr){
			dc.MoveTo(lprc->left-1,lprc->top+1);
			dc.LineTo(lprc->left+1,lprc->top+1);
		}
		//}
		//�������
		//if(row==activeSelection.BottomRow()+1 && col==activeSelection.LeftCol()-1)
		if(ECSR_OUTER_LEFTBOTTOM==ecsr){
			dc.MoveTo(lprc->right-1,lprc->top);
			dc.LineTo(lprc->right,lprc->top);
		}
		*/
	}
	/*
	//-----------------------draw merge selection bound
	void GridRenderer::draw_merge_selection_bound(HDC hDC,CCellRange cr,int nRows,int nCols,CRgnLight const* pRgnClip)
	{
		CDCHandle dc(hDC);
		RowHeader& rh=pSheet->get_RowHeader();
		ColHeader& ch=pSheet->get_ColHeader();
		int const topRow=rh.get_TopVisScrollRow();
		int const leftCol=ch.get_LeftVisScrollCol();
		int const bottomRow=rh.get_BottomVisScrollRow();
		int const rightCol=ch.get_RightVisScrollCol();

		GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareBlackPen2);
		for(int r=0;r<nRows;++r){
			for(int c=0;c<nCols;++c)
			{
				CellItem& cell=session_.item(r,c);
				if(pRgnClip->RectInRgn(cell.rc)){
					RECT const rcCell=cell.rc;
					CMergeCell* merge=cell.pMergeCells;
					if(merge){
						if(cell.Visible()){
							if(merge->TopRow()==cr.BottomRow()+1 && merge->LeftCol()==cr.RightCol()+1){
								//���Ͻ�
								dc.MoveTo(rcCell.left-1,rcCell.top+1);
								dc.LineTo(rcCell.left+1,rcCell.top+1);
							}else if(merge->TopRow()==cr.BottomRow()+1 && merge->RightCol()==cr.LeftCol()-1){
								//���Ͻ�
								dc.MoveTo(rcCell.right-1,rcCell.top);
								dc.LineTo(rcCell.right,rcCell.top);
							}else if(merge->BottomRow()==cr.TopRow()-1 && merge->LeftCol()==cr.RightCol()+1){
								//���½�
								dc.MoveTo(rcCell.left-1,rcCell.bottom-1);
								dc.LineTo(rcCell.left,rcCell.bottom-1);
							}

							if(merge->LeftCol()-1==cr.RightCol()//�����
								||merge->LeftCol()==cr.LeftCol()//�����
								){
								RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.RightCol());
								RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.RightCol());
								RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),merge->LeftCol());
								RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),merge->LeftCol());
								int y1,y2;
								if(VLineIntersect(rc1.top,rc2.bottom,rc3.top,rc4.bottom,y1,y2)){
									bool const bOutLeft=merge->LeftCol()-1==cr.RightCol() && cr.BottomRow()<=merge->BottomRow();
									int const yEnd=bOutLeft?y2-5:y2;
									dc.MoveTo(rc3.left,y1-1);
									dc.LineTo(rc3.left,nRows-1==merge->BottomRow()?yEnd-1:yEnd);
									if(bOutLeft){
										dc.MoveTo(rc3.left+1,yEnd+3);
										dc.LineTo(rc3.left+1,nRows-1==cr.BottomRow()?yEnd+4:y2+1);
									}
								}
							} 
							if(merge->RightCol()+1==cr.LeftCol()//���ұ�
								|| merge->RightCol()==cr.RightCol()//���ұ�
								){
								RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.LeftCol());
								RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.LeftCol());
								RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),merge->RightCol());
								RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),merge->RightCol());
								int y1,y2;
								if(VLineIntersect(rc1.top,rc2.bottom,rc3.top,rc4.bottom,y1,y2)){
									bool const bRightBottom=merge->RightCol()==cr.RightCol() && cr.BottomRow()==merge->BottomRow();
									int const yEnd=y2-(bRightBottom?5:0);//y2;
									dc.MoveTo(rc3.right-1,y1-1);
									dc.LineTo(rc3.right-1,yEnd);
									if(bRightBottom){
										//GdiSelectObjectPlain _sop(dc,PenFactory::Instance().squareBlackPen3);
										dc.MoveTo(rc3.right-2,yEnd+3);
										dc.LineTo(rc3.right-2,y2);
										dc.MoveTo(rc3.right-1,yEnd+3);
										dc.LineTo(rc3.right-1,y2);
									}
								}
							} 
							if(merge->TopRow()-1==cr.BottomRow()//���ϱ�
								||merge->TopRow()==cr.TopRow()//���ϱ�
								){
								RECT rc1=pSheet->raw_GetCellRect(cr.BottomRow(),cr.LeftCol());
								RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.RightCol());
								RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),merge->LeftCol());
								RECT rc4=pSheet->raw_GetCellRect(merge->TopRow(),merge->RightCol());
								int x1,x2;
								if(HLineIntersect(rc1.left,rc2.right,rc3.left,rc4.right,x1,x2)){
									bool const bOutUp=merge->TopRow()-1==cr.BottomRow() && cr.RightCol()<=merge->RightCol();
									int const xEnd=bOutUp?x2-5:x2;
									dc.MoveTo(x1-1,rc3.top);
									dc.LineTo(xEnd,rc3.top);
									if(bOutUp){
										dc.MoveTo(xEnd+3,rc3.top+1);
										dc.LineTo(x2+1,rc3.top+1);
									}
								}
							}
							if(merge->BottomRow()+1==cr.TopRow()//���±�
								||merge->BottomRow()==cr.BottomRow()//���±�
								){
								RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.LeftCol());
								RECT rc2=pSheet->raw_GetCellRect(cr.TopRow(),cr.RightCol());
								RECT rc3=pSheet->raw_GetCellRect(merge->BottomRow(),merge->LeftCol());
								RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),merge->RightCol());
								int x1,x2;
								if(HLineIntersect(rc1.left,rc2.right,rc3.left,rc4.right,x1,x2)){
									bool const bRightBottom=merge->BottomRow()==cr.BottomRow() && cr.RightCol()==merge->RightCol();
									int const xEnd=x2-(bRightBottom?5:1);//x2;
									dc.MoveTo(x1-1,rc3.bottom-1);
									dc.LineTo(xEnd,rc3.bottom-1);
									if(bRightBottom){
										//GdiSelectObjectPlain _sop(dc,PenFactory::Instance().squareBlackPen3);
										//dc.MoveTo(xEnd+3,rc3.bottom-1);
										//dc.LineTo(x2,rc3.bottom-1);
									}
								}
							}
							{
								GdiSelectObjectPlain sop(dc,PenFactory::Instance().squareBlackPen3);
								if(cr.LeftCol()>merge->LeftCol() && cr.LeftCol()<=merge->RightCol()){
									RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.LeftCol());
									RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.LeftCol());
									RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),leftCol);//merge->LeftCol());
									RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),leftCol);//merge->LeftCol());
									int y1,y2;
									if(VLineIntersect(rc1.top,rc2.bottom,rc3.top,rc4.bottom,y1,y2)){
										int const x=rc1.left-1;//cr.LeftCol()==leftCol?rc1.left:rc1.left-nDif;
										dc.MoveTo(x,y1);
										dc.LineTo(x,y2);
									}
								}
								if(cr.RightCol()>=merge->LeftCol() && cr.RightCol()<merge->RightCol()){
									RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.RightCol());
									RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.RightCol());
									RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),merge->RightCol());
									RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),merge->RightCol());
									int y1,y2;
									if(VLineIntersect(rc1.top,rc2.bottom,rc3.top,rc4.bottom,y1,y2)){
										dc.MoveTo(rc1.right-1,y1);
										dc.LineTo(rc1.right-1,y2);
									}
								}
								if(cr.TopRow()>merge->TopRow() && cr.TopRow()<=merge->BottomRow()){
									RECT rc1=pSheet->raw_GetCellRect(cr.TopRow(),cr.LeftCol());
									RECT rc2=pSheet->raw_GetCellRect(cr.TopRow(),cr.RightCol());
									RECT rc3=pSheet->raw_GetCellRect(merge->TopRow(),merge->LeftCol());
									RECT rc4=pSheet->raw_GetCellRect(merge->TopRow(),merge->RightCol());
									int x1,x2;
									if(HLineIntersect(rc1.left,rc2.right,rc3.left,rc4.right,x1,x2)){
										int const y=rc1.top-1;//cr.TopRow()==topRow?rc1.top:rc1.top-nDif;
										dc.MoveTo(x1,y);
										dc.LineTo(x2,y);
									}
								}
								if(cr.BottomRow()>=merge->TopRow() && cr.BottomRow()<merge->BottomRow()){
									RECT rc1=pSheet->raw_GetCellRect(cr.BottomRow(),cr.LeftCol());
									RECT rc2=pSheet->raw_GetCellRect(cr.BottomRow(),cr.RightCol());
									RECT rc3=pSheet->raw_GetCellRect(merge->BottomRow(),merge->LeftCol());
									RECT rc4=pSheet->raw_GetCellRect(merge->BottomRow(),merge->RightCol());
									int x1,x2;
									if(HLineIntersect(rc1.left,rc2.right,rc3.left,rc4.right,x1,x2)){
										dc.MoveTo(x1,rc1.bottom-1);
										dc.LineTo(x2,rc1.bottom-1);
									}
								}
							}
						}
					}
				}
			}
		}
	}
	*/
	//void GridRenderer::draw_border(HDC hDC,CellBorder bdrs,/*Border left,Border top,Border right,Border bottom,*/LPCRECT lprc)
	//{
	//	if(!bdrs.bottom.IsNull()){
	//		MoveToEx(hDC,lprc->left-1,lprc->bottom-1,NULL);
	//		bdrs.bottom.LineTo(hDC,lprc->right-1,lprc->bottom-1);
	//	}
	//	if(!bdrs.right.IsNull()){
	//		if(bdrs.bottom.IsNull())
	//			MoveToEx(hDC,lprc->right-1,lprc->bottom-1,NULL);
	//		bdrs.right.LineTo(hDC,lprc->right-1,lprc->top-1);
	//	}
	//	if(!bdrs.top.IsNull()){
	//		if(bdrs.right.IsNull())
	//			MoveToEx(hDC,lprc->right-1,lprc->top-1,NULL);
	//		bdrs.top.LineTo(hDC,lprc->left,lprc->top-1);
	//	}
	//	if(!bdrs.left.IsNull())
	//	{
	//		if(bdrs.top.IsNull())
	//			MoveToEx(hDC,lprc->left,lprc->top-1,NULL);
	//		bdrs.left.LineTo(hDC,lprc->left,lprc->bottom-1);
	//	}
	//	//DrawLine(bdrs.bottom,hDC,lprc->left-1,lprc->bottom-1,lprc->right-1,lprc->bottom-1);
	//	//DrawLine(bdrs.right,hDC,lprc->right-1,lprc->top-1,lprc->right-1,bdrs.right.get_Weight()>1?lprc->bottom-1:lprc->bottom);
	//	//DrawLine(bdrs.top,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//	//DrawLine(bdrs.left,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//}
	void GridRenderer::draw_cell_border_right(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		//CCell tmpCell(cell.row,cell.col+1);
		Border bdr=cellBorder.right;
		//Border bdr=GetRightBorder(pSheet,cell);
		if(!bdr.IsNull()){
			const int wi=min(2,bdr.get_Weight());
			HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,wi));
			if(hPenOld){
				dc.MoveTo(lprc->right-1,lprc->top+wi-1);
				dc.LineTo(lprc->right-1,lprc->bottom);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
	}
	void GridRenderer::draw_cell_border_left(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		CCell tmpCell(cell.row,cell.col-1);
		Border bdr=cellBorder.left;
		if(!bdr.IsNull()){
			const int wi=bdr.get_Weight();
			if(wi>2){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
				if(hPenOld){
					dc.MoveTo(lprc->left,lprc->top);
					dc.LineTo(lprc->left,lprc->bottom);
					DeleteObject(dc.SelectPen(hPenOld));
				}
			}
		}
	}
	void GridRenderer::draw_cell_border_bottom(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		Border bdr=cellBorder.bottom;
		//Border	bdr=GetBottomBorder(pSheet,cell);
		if(!bdr.IsNull()){
			switch(bdr.get_LineStyle())
			{
			case xlDouble:
				{

				}break;
			case xlSlantDashDot:
				break;
			default:
				const int wi=min(2,bdr.get_Weight());
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,wi));
				if(hPenOld){
					dc.MoveTo(lprc->left+wi-1,lprc->bottom-1);
					dc.LineTo(lprc->right,lprc->bottom-1);
					DeleteObject(dc.SelectPen(hPenOld));
				}
			}
		}
	}
	void GridRenderer::draw_cell_border_top(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		Border bdr=cellBorder.top;
		//Border bdr=GetTopBorder(pSheet,cell);
		if(!bdr.IsNull()){
			const int wi=bdr.get_Weight();
			if(3==wi){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
				if(hPenOld){
					dc.MoveTo(lprc->left,lprc->top);
					dc.LineTo(lprc->right,lprc->top);
					DeleteObject(dc.SelectPen(hPenOld));
				}
			}
		}
	}
	void GridRenderer::draw_cell_border_rightbottom(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		/*
		if(cellBorder.bottom.get_Weight()>2 || cellBorder.right.get_Weight()>2)
			return;
		const int rows=pSheet->get_RowHeader().get_rows();
		const int cols=pSheet->get_ColHeader().get_cols();
		Border bdrB=GetBottomBorder(pSheet,cell,cellBorder);
		Border bdrB1=bdrB;
		if(cell.col<cols-1){
			bdrB1=GetBottomBorder(pSheet,CCell(cell.row,cell.col+1));
			if(bdrB1.get_Weight()>bdrB.get_Weight())
				bdrB=bdrB1;
		}
		Border bdrR=cellBorder.right;//GetRightBorder(pSheet,cell,cellBorder);
		Border bdrR1=bdrR;
		if(cell.row<rows-1){
			bdrR1=GetRightBorder(pSheet,CCell(cell.row+1,cell.col));
		}
		if(bdrR1.get_Weight()>bdrR.get_Weight())
			bdrR=bdrR1;
		if(bdrB.IsNull()&&bdrR.IsNull())
			return;
		if(bdrR.get_Weight()>bdrB.get_Weight()){
			const int left=3==bdrR.get_Weight()?lprc->right-2:lprc->right-1;
			HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrR,1));
			dc.MoveTo(left,lprc->bottom-1);
			dc.LineTo(lprc->right,lprc->bottom-1);
			if(bdrB.get_Weight()>=2){
				dc.MoveTo(left,lprc->bottom-2);
				dc.LineTo(lprc->right,lprc->bottom-2);
			}
			DeleteObject(dc.SelectPen(hPenOld));
		}else{// if(bdrR.get_Weight()>bdrB.get_Weight()
			const int top=bdrB.get_Weight()>=2?lprc->bottom-2:lprc->bottom-1;
			HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrB,1));
			dc.MoveTo(lprc->right-1,top);
			dc.LineTo(lprc->right-1,lprc->bottom);
			if(bdrR.get_Weight()>=2){
				dc.MoveTo(lprc->right-2,top);
				dc.LineTo(lprc->right-2,lprc->bottom);
			}
			DeleteObject(dc.SelectPen(hPenOld));
		}
		*/
		/*
		const int wi=bdrR.get_Weight();
		switch(wi)
		{
		case 2:
		case 3:
			{
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,3==wi?bdrR:bdrB,2));
				dc.MoveTo(lprc->right-1,lprc->bottom-1);
				dc.LineTo(lprc->right-1,lprc->bottom);
				DeleteObject(dc.SelectPen(hPenOld));
			}break;
		default:
			{
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,3==wi?bdrR:bdrB,1));
				dc.MoveTo(lprc->right-1,lprc->bottom-2);
				dc.LineTo(lprc->right-1,lprc->bottom);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
	}
	void GridRenderer::draw_cell_border_leftbottom(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		/*
		if(cellBorder.bottom.get_Weight()>2 || cellBorder.left.get_Weight()>2)
			return;
		Border bdrL=session.GetLeftBorder(pSheet,cell);
		//if(3!=bdrL.get_Weight() && cell.row<pSheet->get_RowHeader().get_rows()-1){
		//	bdrL=GetLeftBorder(pSheet,CCell(cell.row+1,cell.col));
		//}
		if(3!=bdrL.get_Weight())
			return ;
		Border bdrB=GetBottomBorder(pSheet,cell,cellBorder);
		if(3!=bdrB.get_Weight()&&cell.col>0){
			bdrB=GetBottomBorder(pSheet,CCell(cell.row,cell.col-1));
		}
		if(3==bdrB.get_Weight()){
			HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrL,1));
			dc.MoveTo(lprc->left,lprc->bottom-2);
			dc.LineTo(lprc->left,lprc->bottom);
			DeleteObject(dc.SelectPen(hPenOld));
		}
		*/
		/*
		if(MIN_COL==cell.col || cell.row==pSheet->get_RowHeader().get_rows()-1)
			return;
		const Border bdrL=GetLeftBorder(pSheet,CCell(cell.row+1,cell.col));
		if(3==bdrL.get_Weight()){
			const Border bdrB=GetBottomBorder(pSheet,CCell(cell.row,cell.col-1));
			if(3==bdrB.get_Weight()){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrL,1));
				dc.MoveTo(lprc->left,lprc->bottom-2);
				dc.LineTo(lprc->left,lprc->bottom);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
		/*
		const int rows=pSheet->get_RowHeader().get_rows();
		//const int cols=pSheet->get_ColHeader().get_cols();
		Border bdr=cellBorder.bottom.get_Weight()>cellBorder.left.get_Weight()?cellBorder.bottom:cellBorder.left;
		if(cell.row<rows-1){
			CCell tmpCell(cell.row+1,cell.col);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->top.get_Weight())
				bdr=pbdrs->top;
			if(bdr.get_Weight()<pbdrs->left.get_Weight())
				bdr=pbdrs->left;
		}
		if(cell.col>0){
			CCell tmpCell(cell.row,cell.col-1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->bottom.get_Weight())
				bdr=pbdrs->bottom;
			if(bdr.get_Weight()<pbdrs->right.get_Weight())
				bdr=pbdrs->right;
		}
		if(cell.row<rows-1 && cell.col>0){
			CCell tmpCell(cell.row+1,cell.col-1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->top.get_Weight())
				bdr=pbdrs->top;
			if(bdr.get_Weight()<pbdrs->right.get_Weight())
				bdr=pbdrs->right;
		}
		if(bdr.get_Weight()>cellBorder.bottom.get_Weight() && bdr.get_Weight()>cellBorder.left.get_Weight()){
			//const int wi=min(2,bdr.get_Weight());
			HPEN hPenOld=NULL;
			switch(bdr.get_Weight())
			{
			case 3:
				hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
				dc.MoveTo(lprc->left,lprc->bottom-2);
				dc.LineTo(lprc->left+1,lprc->bottom-2);
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->left+1,lprc->bottom-1);
				break;
			//case 2:
			//	hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
			//	dc.MoveTo(lprc->left,lprc->bottom-1);
			//	dc.LineTo(lprc->left+1,lprc->bottom-1);
			//	break;
			default:
				return;
			//	break;
			//default:
			//	dc.MoveTo(lprc->left-1,lprc->bottom-1);
			//	dc.LineTo(lprc->left+1,lprc->bottom-1);
			}
			DeleteObject(dc.SelectPen(hPenOld));
		}
		*/
	}
	void GridRenderer::draw_cell_border_righttop(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		/*
		if(cellBorder.top.get_Weight()>2 || cellBorder.right.get_Weight()>2)
			return;
		const int cols=pSheet->get_ColHeader().get_cols();
		Border bdrT=GetTopBorder(pSheet,cell,cellBorder);
		if(3!=bdrT.get_Weight() && cell.col<cols-1){
			bdrT=GetTopBorder(pSheet,CCell(cell.row,cell.col+1));
		}
		if(3!=bdrT.get_Weight())
			return;
		Border bdrR=GetRightBorder(pSheet,cell,cellBorder);
		Border bdrR1=bdrR;
		if(cell.row>0){
			bdrR1=GetRightBorder(pSheet,CCell(cell.row-1,cell.col));
		}
		if(bdrR1.get_Weight()>bdrR.get_Weight())
			bdrR=bdrR1;
		const int wi=bdrR.get_Weight();
		const HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,3==wi?bdrR:bdrT,1));
		switch(wi)
		{
		case 3:
		case 2:
			dc.MoveTo(lprc->right-2,lprc->top);
			dc.LineTo(lprc->right,lprc->top);
			break;
		default:
			dc.MoveTo(lprc->right-1,lprc->top);
			dc.LineTo(lprc->right,lprc->top);
		}
		DeleteObject(dc.SelectPen(hPenOld));
		*/
		/*
		if(MIN_ROW==cell.row)
			return;
		const Border bdrR=GetRightBorder(pSheet,CCell(cell.row-1,cell.col));
		if(3==bdrR.get_Weight()){
			Border bdrT=GetTopBorder(pSheet,CCell(cell.row,cell.col));
			if(3!=bdrT.get_Weight() && cell.col<cols-1)
				bdrT=GetTopBorder(pSheet,CCell(cell.row,cell.col+1));
			if(3==bdrT.get_Weight()){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrR,1));
				dc.MoveTo(lprc->right-2,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
		/*
		Border bdrR,bdrT;
		if(cell.col<cols-1){
			bdrR=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row,cell.col+1)).first->GetBorders()->top;
			if(cell.row>0 && bdrR.get_Weight()<3){
				const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row-1,cell.col+1)).first->GetBorders();
				if(bdrR.get_Weight()<pbdrs->bottom.get_Weight()){
					bdrR=pbdrs->bottom;
				}
			}
			if(3==bdrR.get_Weight()){
				if(cell.row>0){
					bdrT=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row-1,cell.col)).first->GetBorders()->right;
					if(bdrT.get_Weight()<3){
						const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row-1,cell.col+1)).first->GetBorders();
						if(bdrT.get_Weight()<pbdrs->left.get_Weight())
							bdrT=pbdrs->left;
					}
				}
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrR,1));
				const int wiT=bdrT.get_Weight();
				int n=wiT>=2?2:1;
				dc.MoveTo(lprc->right-n,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
		/*
		Border bdr=cellBorder.top.get_Weight()>cellBorder.right.get_Weight()?cellBorder.top:cellBorder.right;
		if(cell.row>0){
			CCell tmpCell(cell.row-1,cell.col);
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->bottom.get_Weight())
				bdr=pbdrs->bottom;
			if(bdr.get_Weight()<pbdrs->right.get_Weight())
				bdr=pbdrs->right;
		}
		if(cell.col<cols-1){
			CCell tmpCell(cell.row,cell.col+1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->top.get_Weight())
				bdr=pbdrs->top;
			if(bdr.get_Weight()<pbdrs->left.get_Weight())
				bdr=pbdrs->left;
		}
		if(cell.row>0 && cell.col<cols-1){
			CCell tmpCell(cell.row-1,cell.col+1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->bottom.get_Weight())
				bdr=pbdrs->bottom;
			if(bdr.get_Weight()<pbdrs->left.get_Weight())
				bdr=pbdrs->left;
		}
		if(bdr.get_Weight()>cellBorder.top.get_Weight() && bdr.get_Weight()>cellBorder.right.get_Weight()){
			if(bdr.get_Weight()>2){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
				dc.MoveTo(lprc->right-2,lprc->top);
				dc.LineTo(lprc->right,lprc->top);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
	}
	void GridRenderer::draw_cell_border_lefttop(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,const CellBorder& cellBorder)
	{
		/*
		if(cellBorder.top.get_Weight()>2 || cellBorder.left.get_Weight()>2)
			return;
		Border bdrT=GetTopBorder(pSheet,cell,cellBorder);
		if(3!=bdrT.get_Weight() && cell.col>0){
			bdrT=GetTopBorder(pSheet,CCell(cell.row,cell.col-1));
		}
		if(3!=bdrT.get_Weight())
			return;
		Border bdrL=session.GetLeftBorder(pSheet,cell);
		//if(3!=bdrL.get_Weight() && cell.row>0){
		//	bdrL=GetLeftBorder(pSheet,CCell(cell.row-1,cell.col));
		//}
		if(3==bdrL.get_Weight()){
			HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrL,1));
			dc.MoveTo(lprc->left,lprc->top);
			dc.LineTo(lprc->left+1,lprc->top);
			DeleteObject(dc.SelectPen(hPenOld));
		}
		*/
		/*
		if(MIN_COL==cell.col  || MIN_ROW==cell.row)
			return;
		const Border bdrL=GetTopBorder(pSheet,CCell(cell.row,cell.col-1));
		if(3==bdrL.get_Weight()){
			const Border bdrT=GetLeftBorder(pSheet,CCell(cell.row-1,cell.col));
			if(3==bdrT.get_Weight()){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdrL,1));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left+1,lprc->top);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
		/*
		Border bdrL;
		if(cell.col>0){
			bdrL=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row,cell.col-1)).first->GetBorders()->top;
			if(cell.row>0 && bdrL.get_Weight()<3){
				const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row-1,cell.col-1)).first->GetBorders();
				if(bdrL.get_Weight()<pbdrs->bottom.get_Weight()){
					bdrL=pbdrs->bottom;
				}
			}
			if(3==bdr.get_Weight()){
				Border bdrL;
				if(cell.col>0){
					bdrL=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row,cell.col-1)).first->GetBorders()->left;
					if(bdrL.get_Weight()<3){
						const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,CCell(cell.row-1,cell.col-1)).first->GetBorders();
						if(bdrL.get_Weight()<pbdrs->bottom.get_Weight())
							bdrL=pbdrs->bottom;
					}
				}
				//const int n=bdrL.get_Weight()>=2?1
				if(bdrL.get_Weight()>=2){
					HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
					dc.MoveTo(lprc->left,lprc->top);
					dc.LineTo(lprc->left+1,lprc->top);
					DeleteObject(dc.SelectPen(hPenOld));
				}
			}
		}
		*/
		/*
		Border bdr=cellBorder.top.get_Weight()>cellBorder.left.get_Weight()?cellBorder.top:cellBorder.left;
		if(cell.row>0){
			CCell tmpCell(cell.row-1,cell.col);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->bottom.get_Weight())
				bdr=pbdrs->bottom;
			if(bdr.get_Weight()<pbdrs->left.get_Weight())
				bdr=pbdrs->left;
		}
		if(cell.col>0){
			CCell tmpCell(cell.row,cell.col-1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->top.get_Weight())
				bdr=pbdrs->top;
			if(bdr.get_Weight()<pbdrs->right.get_Weight())
				bdr=pbdrs->right;
		}
		if(cell.row>0 && cell.col>0){
			CCell tmpCell(cell.row-1,cell.col-1);
			//const Borders* pbdrs=pSheet->Style_GetCellStyle(tmpCell).GetBorders();
			const Borders* pbdrs=cellStoreCache_.GetCellStore(pSheet,tmpCell).first->GetBorders();
			if(bdr.get_Weight()<pbdrs->bottom.get_Weight())
				bdr=pbdrs->bottom;
			if(bdr.get_Weight()<pbdrs->right.get_Weight())
				bdr=pbdrs->right;
		}
		if(bdr.get_Weight()>cellBorder.top.get_Weight() && bdr.get_Weight()>cellBorder.left.get_Weight()){
			if(bdr.get_Weight()>2){
				HPEN hPenOld=dc.SelectPen(MyCell_CreatePen(dc,bdr,1));
				dc.MoveTo(lprc->left,lprc->top);
				dc.LineTo(lprc->left+1,lprc->top);
				DeleteObject(dc.SelectPen(hPenOld));
			}
		}
		*/
	}

	void GridRenderer::draw_cell_border(CDCHandle& dc,CCell cell,VisibleCellsSession& session,LPCRECT lprc,CellBorder cellBorder,const CMergeCell* pmerge)
	{
		//const RowHeader& rh=pSheet_->get_RowHeader();
		//const ColHeader& ch=pSheet_->get_ColHeader();
		//if(cellBorder.left.IsNull())
		//	cellBorder.left=session.GetLeftBorder(pSheet_,cell/*,cellBorder*/);
		//if(cellBorder.top.IsNull())
		//	cellBorder.top=GetTopBorder(pSheet_,cell,cellBorder);
		//if(cellBorder.right.IsNull())
		//	cellBorder.right=GetRightBorder(pSheet_,cell,cellBorder);
		//if(cellBorder.bottom.IsNull())
		//	cellBorder.bottom=GetBottomBorder(pSheet_,cell,cellBorder);

		if(!pmerge || pmerge->LeftCol()==cell.col)
			draw_cell_border_left(dc,cell,session,lprc,cellBorder);
		if(!pmerge || pmerge->RightCol()==cell.col)
			draw_cell_border_right(dc,cell,session,lprc,cellBorder);
		if(!pmerge || pmerge->TopRow()==cell.row)
			draw_cell_border_top(dc,cell,session,lprc,cellBorder);
		if(!pmerge || pmerge->BottomRow()==cell.row)
			draw_cell_border_bottom(dc,cell,session,lprc,cellBorder);
		/*
		draw_cell_border_rightbottom(pSheet_,dc,cell,session,lprc,cellBorder);
		draw_cell_border_leftbottom(pSheet_,dc,cell,session,lprc,cellBorder);
		draw_cell_border_righttop(pSheet_,dc,cell,session,lprc,cellBorder);
		draw_cell_border_lefttop(pSheet_,dc,cell,session,lprc,cellBorder);
		*/
		//if(!bottom.IsNull()){
		//	//if(!merge || merge && cell.row==merge->BottomRow()){
		//	dc.MoveTo(lprc->left,lprc->bottom-1);
		//	bottom.LineTo(dc,lprc->right,lprc->bottom-1);
		//	//dc.LineTo(_rc.right+1,_rc.bottom-1);
		//	//}
		//}
		//if(!right.IsNull()){
		//	//const bool bDrawRight=!merge || cell.col==merge->RightCol()
		//	//	||pSheet_->GetNextCol(cell.col)==cell.col;
		//	//if(bDrawRight){
		//	dc.MoveTo(lprc->right-1,lprc->top);
		//	right.LineTo(dc,lprc->right-1,lprc->bottom);
		//	//dc.LineTo(_rc.right-1,_rc.bottom+1);
		//	//}
		//}
	}
	/*
	void GridRenderer::draw_border1(const Worksheet* pSheet,CDCHandle& dc,int row,int col,Border left,Border top,Border right,Border bottom,LPCRECT lprc)
	{
		const RowHeader& rh=pSheet->get_RowHeader();
		const ColHeader& ch=pSheet->get_ColHeader();
		//int const ch.get_cols()=ch.get_cols();
		//int const rh.get_rows()=rh.get_rows();

		if(!left.IsNull() && left.get_Weight()>1){
			if(3==left.get_Weight()){
				left.put_Weight(1);
				MoveToEx(dc.m_hDC,lprc->left,lprc->top-1,NULL);
				left.LineTo(dc.m_hDC,lprc->left,lprc->bottom);
				left.put_Weight(3);
			}
		}
		
		if(!top.IsNull()){
			if(top.get_Weight()>1){
				if(3==top.get_Weight()){
					top.put_Weight(1);
					MoveToEx(dc.m_hDC,lprc->left-1,lprc->top,NULL);
					top.LineTo(dc.m_hDC,lprc->right,lprc->top);
					top.put_Weight(3);
				}
			}
		}else{
			if(col>0 && row>0){
				//���Ͻ�
				const StyleDesc& style=pSheet->Style_GetCellStyle(CCell(row-1,col-1));
				const Borders* pbdrs=style.GetBorders();
				if(!pbdrs->bottom.IsNull() && !pbdrs->right.IsNull()){
					switch(pbdrs->bottom.get_Weight())
					{
					//case 2:
					//	MoveToEx(dc.m_hDC,lprc->right-1,lprc->bottom-1,NULL);
					//	pbdrs->top.LineTo(dc.m_hDC,lprc->right,lprc->bottom-1);
					//	break;
					case 3:
						{
							Border bdr=pbdrs->bottom;
							bdr.put_Weight(2);
							MoveToEx(dc.m_hDC,lprc->left-1,lprc->top,NULL);
							bdr.LineTo(dc.m_hDC,lprc->left,lprc->top);
						}break;
					}
				}

			}
		}

		if(!right.IsNull()){
			int const offset=1;//right.get_Weight()>1?(right.get_Weight()>>1):1;
			if(2==right.get_Weight()){
				MoveToEx(dc.m_hDC,lprc->right-1,lprc->top-1,NULL);
				right.LineTo(dc.m_hDC,lprc->right-1,lprc->bottom-1);//right.get_Weight()>1?lprc->bottom-1:lprc->bottom);
			}else{
				if(3==right.get_Weight())
					right.put_Weight(2);
				MoveToEx(dc.m_hDC,lprc->right-offset,lprc->top-1,NULL);
				right.LineTo(dc.m_hDC,lprc->right-offset,lprc->bottom);//right.get_Weight()>1?lprc->bottom-1:lprc->bottom);
				if(2==right.get_Weight()){
					right.put_Weight(3);
				}
			}
		}else{
			if(col<ch.get_cols()-1 && row>0){
				//���Ͻ�
				const StyleDesc& style=pSheet->Style_GetCellStyle(CCell(row-1,col+1));
				const Borders* pbdrs=style.GetBorders();
				if(!pbdrs->bottom.IsNull() && !pbdrs->left.IsNull()){
					switch(pbdrs->bottom.get_Weight())
					{
					//case 2:
					//	MoveToEx(dc.m_hDC,lprc->right-1,lprc->bottom-1,NULL);
					//	pbdrs->top.LineTo(dc.m_hDC,lprc->right,lprc->bottom-1);
					//	break;
					case 3:
						{
							Border bdr=pbdrs->bottom;
							bdr.put_Weight(2);
							MoveToEx(dc.m_hDC,lprc->right-1,lprc->top,NULL);
							bdr.LineTo(dc.m_hDC,lprc->right,lprc->top);
						}break;
					}
				}
			}
		}
		if(!bottom.IsNull()){
			int const offset=1;//bottom.get_Weight()>1?(bottom.get_Weight()>>1):1;
			if(2==bottom.get_Weight()){
				MoveToEx(dc.m_hDC,lprc->left-1,lprc->bottom-1,NULL);
				bottom.LineTo(dc.m_hDC,lprc->right-1,lprc->bottom-1);
			}else{
				if(3==bottom.get_Weight())
					bottom.put_Weight(2);
				MoveToEx(dc.m_hDC,lprc->left-1,lprc->bottom-offset,NULL);
				bottom.LineTo(dc.m_hDC,lprc->right-1,lprc->bottom-offset);
				if(2==bottom.get_Weight()){
					bottom.put_Weight(3);
				}
			}
		}else{
			if(col<ch.get_cols()-1 && row<rh.get_rows()-1){
				//���½�
				const StyleDesc& style=pSheet->Style_GetCellStyle(CCell(row+1,col+1));
				const Borders* pbdrs=style.GetBorders();
				if(!pbdrs->top.IsNull() && !pbdrs->left.IsNull()){
					switch(pbdrs->top.get_Weight())
					{
					case 2:
						MoveToEx(dc.m_hDC,lprc->right-1,lprc->bottom-1,NULL);
						pbdrs->top.LineTo(dc.m_hDC,lprc->right,lprc->bottom-1);
						break;
					case 3:
						{
							Border bdr=pbdrs->top;
							bdr.put_Weight(2);
							MoveToEx(dc.m_hDC,lprc->right-1,lprc->bottom-1,NULL);
							bdr.LineTo(dc.m_hDC,lprc->right,lprc->bottom-1);
						}break;
					}
				}
			}
			if(col>0 && row<rh.get_rows()-1){//���½�
				const StyleDesc& style=pSheet->Style_GetCellStyle(CCell(row+1,col-1));
				const Borders* pbdrs=style.GetBorders();
				if(!pbdrs->top.IsNull() && !pbdrs->right.IsNull()){
					switch(pbdrs->top.get_Weight())
					{
					//case 2:
					//	MoveToEx(dc.m_hDC,lprc->left,lprc->bottom-1,NULL);
					//	pbdrs->top.LineTo(dc.m_hDC,lprc->right,lprc->bottom-1);
					//	break;
					case 3:
						{
							Border bdr=pbdrs->top;
							bdr.put_Weight(2);
							MoveToEx(dc.m_hDC,lprc->left-1,lprc->bottom-1,NULL);
							bdr.LineTo(dc.m_hDC,lprc->left,lprc->bottom-1);
						}break;
					}
				}
			}
		}
	}
	*/
	/*
	void GridRenderer::draw_content_old(HDC hDC,LPCRECT lprc,CRgnLight const* pRgnClip)
	{
	CDCHandle dc(hDC);
	HeaderSetupDC setupDC(hDC);
	//HPEN const hPenOld=dc.SelectPen(CreatePen(PS_SOLID,0,Colors::CLR_GRID));
	//SelectPen selPen(dc,CreatePen(PS_SOLID,0,Colors::CLR_GRID));
	GdiSelectObject<> gso(hDC,CreatePen(PS_SOLID,0,Colors::CLR_GRID));

	//SelectionsHandler& selection=pSheet->get_Selection();
	CCellRange const selection=pSheet->get_Selection();
	CCell const activeCell=pSheet->GetActiveCell();
	RowHeader& rh=pSheet->get_RowHeader();
	ColHeader& ch=pSheet->get_ColHeader();
	int const topRow=rh.get_TopVisScrollRow();
	int const bottomRow=rh.get_BottomVisScrollRow();
	int const leftCol=ch.get_LeftVisScrollCol();
	int const rightCol=ch.get_RightVisScrollCol();

	RECT rcCell=*lprc;
	TCHAR text[MAX_CELLTEXT];
	CMergeCell* merge=NULL;
	VisibleMergeCellMgr& visMergeCells=pSheet->GetVisibleMergeCellMgr();
	for(int i=rh.get_TopVisScrollRow();i<=bottomRow;++i,rcCell.top=rcCell.bottom){
	rcCell.bottom=rcCell.top+rh.get_RowHeight(i);
	rcCell.left=lprc->left;
	for(int j=leftCol;j<=rightCol;++j,rcCell.left=rcCell.right)
	{
	rcCell.right=rcCell.left+ch.get_ColWidth(j);
	if(pRgnClip->RectInRgn(rcCell)){
	if(merge=visMergeCells.GetMergeCells(i,j)){
	if(!visMergeCells.MergeCellShouldDraw(i,j,merge))
	continue;
	merge->dirty=true;
	int const _row=merge->TopRow();
	int const _col=merge->LeftCol();
	int const nCount=pSheet->GetCellText(_row,_col,text);
	//selection.SetupCellDE(_row,_col);
	SetupCellDE(selection,activeCell,_row,_col);
	int const minR=_row;//max(topRow,_row);
	int const minC=_col;//max(leftCol,_col);
	int const maxR=merge->BottomRow();//min(bottomRow,merge->BottomRow());
	int const maxC=merge->RightCol();//min(rightCol,merge->RightCol());
	RECT rc1=pSheet->raw_GetCellRect(minR,minC);
	RECT rc2=pSheet->raw_GetCellRect(maxR,maxC);
	RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
	//RECT rc;
	//UnionRect(&rc,&rc1,&rc2);
	//ECellType const cellType=pSheet->GetCellType(_row,_col);
	draw_merge_cell(hDC,_row,_col,merge,text,nCount,&rc);
	AtlTrace(_T("\nGrid::draw_content draw mergecell row=%d,col=%d text=%s rect(%d,%d,%d,%d)"),_row,_col,text,rc.left,rc.top,rc.right,rc.bottom);
	}else{
	int const nCount=pSheet->GetCellText(i,j,text);
	//selection.SetupCellDE(i,j);
	SetupCellDE(selection,activeCell,i,j);
	//ECellType const cellType=pSheet->GetCellType(i,j);
	draw_cell(hDC,i,j,text,nCount,&rcCell);
	//draw_cell_border(hDC,i,j,&rcCell);
	}
	//AtlTrace(_T("\nGrid::draw_content row=%d,col=%d rcCell(%d,%d,%d,%d)"),i+1,j+1,rcCell.left,rcCell.top,rcCell.right,rcCell.bottom);
	}
	}
	}
	}
	*/
	//void GridRenderer::draw_HeaderCorner(CDCHandle& dc,LPCRECT lprc,COLORREF backColor)const
	//{
	//	GdiSelectObject<> gso(dc,CreatePen(PS_SOLID,0,HeaderColors::CLR_GRID));
	//	draw_HeaderCell(dc,NULL,0,lprc,backColor);
	//}

	/*
	//prcӦ����3����Ч�ռ䣬��һ��Ϊѡ��IJ��֣�ʣ��2��Ϊδ��ѡ��IJ���
	//pbkClrΪ���������Ӧ�ı�����ɫ
	void GridRenderer::get_merge_cell_fillrect_region(int row,int col,CCellRange* pMergeCells,LPCRECT lprc,StyleDesc const& styleDesc,DrawCellStruct const& dcs,LPRECT prc,COLORREF* pbkClr)
	{
		CCellRange cr=pSheet->get_Selection();
		int minR=cr.TopRow(),minC=cr.LeftCol(),maxR=cr.BottomRow(),maxC=cr.RightCol();

		int const activeRow=dcs.activeRow;
		int const activeCol=dcs.activeCol;
		//pSheet->GetActiveCell(activeRow,activeCol);

		CCellRange crSel;
		crSel.set(minR,minC,maxR,maxC);
		//CBrush bkBrush,selBrush;

		//COLORREF const backColor=GetBKColor(row,col,styleDesc);
		//bkBrush.CreateSolidBrush(Colors::CLR_BKGND);

		COLORREF const _bkColor=styleDesc.HasColor()?styleDesc.GetColor():Colors::CLR_BKGND;
		COLORREF const selColor=activeRow==pMergeCells->TopRow() && activeCol==pMergeCells->LeftCol()?
			_bkColor^Colors::CLR_ACTIVE:_bkColor^Colors::CLR_SELECTION;

		pbkClr[0]=selColor;
		pbkClr[1]=_bkColor;
		pbkClr[2]=_bkColor;

		//selBrush.CreateSolidBrush(//Colors::CLR_SELECTION);
		//	activeRow==pMergeCells->TopRow() && activeCol==pMergeCells->LeftCol()?
		//	_bkColor^Colors::CLR_ACTIVE:_bkColor^Colors::CLR_SELECTION);
		RECT const rcNull={0,0,0,0};

		if(pMergeCells->IsIntersect(crSel)){
			int _minR,_maxR,_minC,_maxC;
			RECT rc1,rc2;

			if(pMergeCells->TopRow()<minR || pMergeCells->BottomRow()>maxR){
				int i=1;
				if(pMergeCells->TopRow()<minR){
					_minR=pMergeCells->TopRow();
					_maxR=minR-1;
					RECT rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
					RECT rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[i++]=rc;
					//dc.FillRect(&rc,bkBrush);
				}
				//if(pMergeCells->TopRow()<minR || pMergeCells->BottomRow()>maxR)
				{ 
					_minR=max(minR,pMergeCells->TopRow());
					_maxR=min(maxR,pMergeCells->BottomRow());
					rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
					rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
					//UnionRect(&rc,&rc1,&rc2);
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[0]=rc;
					//dc.FillRect(&rc,selBrush);
				}
				if(pMergeCells->BottomRow()>maxR){
					_minR=maxR+1;
					_maxR=pMergeCells->BottomRow();
					rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
					rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[i]=rc;
					//UnionRect(&rc,&rc1,&rc2);
					//dc.FillRect(&rc,bkBrush);
				}
			}else if(pMergeCells->LeftCol()<minC || pMergeCells->RightCol()>maxC){
				int i=1;
				if(pMergeCells->LeftCol()<minC){
					_minC=pMergeCells->LeftCol();
					_maxC=minC-1;
					RECT rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
					RECT rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[i++]=rc;
					//UnionRect(&rc,&rc1,&rc2);
					//dc.FillRect(&rc,bkBrush);
				}
				//if(pMergeCells->LeftCol()<minC || pMergeCells->RightCol()>maxC)
				{
					_minC=max(minC,pMergeCells->LeftCol());
					_maxC=min(maxC,pMergeCells->RightCol());
					rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
					rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[0]=rc;
					//UnionRect(&rc,&rc1,&rc2);
					//dc.FillRect(&rc,selBrush);
				}
				if(pMergeCells->RightCol()>maxC){
					_minC=maxC+1;
					_maxC=pMergeCells->RightCol();
					rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
					rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
					RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
					prc[i]=rc;
					//UnionRect(&rc,&rc1,&rc2);
					//dc.FillRect(&rc,bkBrush);
				}
			}else{
				prc[0]=*lprc;
				prc[1]=rcNull;
				prc[2]=rcNull;
			}
		}else{
			prc[0]=rcNull;
			prc[1]=*lprc;
			prc[2]=rcNull;
			//dc.FillRect(lprc,bkBrush);
		}
	}
	*/
	/*
	void GridRenderer::fill_merge_cell(HDC hDC,int row,int col,CCellRange* pMergeCells,LPCRECT lprc,StyleDesc const& styleDesc)
	{
		CDCHandle dc(hDC);
		//fill rect
		CCellRange cr=pSheet->get_Selection();
		int minR=cr.TopRow(),minC=cr.LeftCol(),maxR=cr.BottomRow(),maxC=cr.RightCol();

		int activeRow,activeCol;
		pSheet->GetActiveCell(activeRow,activeCol);

		CCellRange crSel;
		crSel.set(minR,minC,maxR,maxC);
		AtlTrace(_T("\ndraw_merge_cell pMergeCells(%d,%d,%d,%d),selection(%d,%d,%d,%d)"),
			pMergeCells->LeftCol(),pMergeCells->TopRow(),pMergeCells->RightCol(),pMergeCells->BottomRow(),
			minC,minR,maxC,maxR);
		CBrush bkBrush,selBrush;

		COLORREF const backColor=GetBKColor(row,col,styleDesc);
		bkBrush.CreateSolidBrush(Colors::CLR_BKGND);

		COLORREF const _bkColor=styleDesc.HasColor()?styleDesc.GetColor():Colors::CLR_BKGND;
		selBrush.CreateSolidBrush(//Colors::CLR_SELECTION);
			activeRow==pMergeCells->TopRow() && activeCol==pMergeCells->LeftCol()?
			_bkColor^Colors::CLR_ACTIVE:_bkColor^Colors::CLR_SELECTION);
		//activeBrush.CreateSolidBrush(Colors::CLR_ACTIVE);
		if(pMergeCells->IsIntersect(crSel)){
			int _minR,_maxR,_minC,_maxC;
			RECT rc1,rc2;
			if(pMergeCells->TopRow()<minR){
				_minR=pMergeCells->TopRow();
				_maxR=minR-1;
				RECT rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				RECT rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				//RECT rc;
				//UnionRect(&rc,&rc1,&rc2);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				dc.FillRect(&rc,bkBrush);
			}
			//if(pMergeCells->TopRow()<minR || pMergeCells->BottomRow()>maxR)
			{ 
				_minR=max(minR,pMergeCells->TopRow());
				_maxR=min(maxR,pMergeCells->BottomRow());
				rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				//UnionRect(&rc,&rc1,&rc2);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				dc.FillRect(&rc,selBrush);
			}
			if(pMergeCells->BottomRow()>maxR){
				_minR=maxR+1;
				_maxR=pMergeCells->BottomRow();
				rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
			//
			if(pMergeCells->LeftCol()<minC){
				_minC=pMergeCells->LeftCol();
				_maxC=minC-1;
				RECT rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				RECT rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
			if(pMergeCells->LeftCol()<minC || pMergeCells->RightCol()>maxC){
				_minC=max(minC,pMergeCells->LeftCol());
				_maxC=min(maxC,pMergeCells->RightCol());
				rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,selBrush);
			}
			if(pMergeCells->RightCol()>maxC){
				_minC=maxC+1;
				_maxC=pMergeCells->RightCol();
				rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
		}else
			dc.FillRect(lprc,bkBrush);
		//:~fill rect
	}
	*/
	/*
	void GridRenderer::draw_merge_cell(HDC hDC,int row,int col,CCellRange* pMergeCells,LPCTSTR lpText,int nCount,LPCRECT lprc,StyleDesc const& styleDesc)
	{
		CDCHandle dc(hDC);
		//if(lprc->right > lprc->left && lprc->bottom > lprc->top){
		//fill rect
		CCellRange cr=pSheet->get_Selection();
		int minR=cr.TopRow(),minC=cr.LeftCol(),maxR=cr.BottomRow(),maxC=cr.RightCol();
		//pSheet->get_Selection(minC,minR,maxC,maxR);

		int activeRow,activeCol;
		pSheet->GetActiveCell(activeRow,activeCol);

		CCellRange crSel;
		crSel.set(minR,minC,maxR,maxC);
		AtlTrace(_T("\ndraw_merge_cell pMergeCells(%d,%d,%d,%d),selection(%d,%d,%d,%d)"),
			pMergeCells->LeftCol(),pMergeCells->TopRow(),pMergeCells->RightCol(),pMergeCells->BottomRow(),
			minC,minR,maxC,maxR);
		CBrush bkBrush,selBrush;//,activeBrush;

		COLORREF const backColor=GetBKColor(row,col,styleDesc);
		bkBrush.CreateSolidBrush(Colors::CLR_BKGND);

		COLORREF const _bkColor=styleDesc.HasColor()?styleDesc.GetColor():Colors::CLR_BKGND;
		selBrush.CreateSolidBrush(//Colors::CLR_SELECTION);
			activeRow==pMergeCells->TopRow() && activeCol==pMergeCells->LeftCol()?
			_bkColor^Colors::CLR_ACTIVE:_bkColor^Colors::CLR_SELECTION);
		//activeBrush.CreateSolidBrush(Colors::CLR_ACTIVE);
		if(pMergeCells->IsIntersect(crSel)){
			int _minR,_maxR,_minC,_maxC;
			RECT rc1,rc2;
			if(pMergeCells->TopRow()<minR){
				_minR=pMergeCells->TopRow();
				_maxR=minR-1;
				RECT rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				RECT rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				//RECT rc;
				//UnionRect(&rc,&rc1,&rc2);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				dc.FillRect(&rc,bkBrush);
			}
			//if(pMergeCells->TopRow()<minR || pMergeCells->BottomRow()>maxR)
			{ 
				_minR=max(minR,pMergeCells->TopRow());
				_maxR=min(maxR,pMergeCells->BottomRow());
				rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				//UnionRect(&rc,&rc1,&rc2);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				dc.FillRect(&rc,selBrush);
			}
			if(pMergeCells->BottomRow()>maxR){
				_minR=maxR+1;
				_maxR=pMergeCells->BottomRow();
				rc1=pSheet->raw_GetCellRect(_minR,pMergeCells->LeftCol());
				rc2=pSheet->raw_GetCellRect(_maxR,pMergeCells->RightCol());
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
			//
			if(pMergeCells->LeftCol()<minC){
				_minC=pMergeCells->LeftCol();
				_maxC=minC-1;
				RECT rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				RECT rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
			if(pMergeCells->LeftCol()<minC || pMergeCells->RightCol()>maxC){
				_minC=max(minC,pMergeCells->LeftCol());
				_maxC=min(maxC,pMergeCells->RightCol());
				rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,selBrush);
			}
			if(pMergeCells->RightCol()>maxC){
				_minC=maxC+1;
				_maxC=pMergeCells->RightCol();
				rc1=pSheet->raw_GetCellRect(pMergeCells->TopRow(),_minC);
				rc2=pSheet->raw_GetCellRect(pMergeCells->BottomRow(),_maxC);
				RECT const rc={min(rc1.left,rc2.left),min(rc1.top,rc2.top),max(rc1.right,rc2.right),max(rc1.bottom,rc2.bottom)};
				//UnionRect(&rc,&rc1,&rc2);
				dc.FillRect(&rc,bkBrush);
			}
		}else
			dc.FillRect(lprc,bkBrush);
		//:~fill rect

		//StyleDesc styleDesc;
		//pSheet->GetCellStyle(row,col,styleDesc);
		ECellType const cellType=styleDesc.CellType_GetType();
		CellFontSetup cfs(dc,GetFont(styleDesc),styleDesc.GetColor());
		//COLORREF const backColor=GetBKColor(row,col,styleDesc);

		if(lprc->right > lprc->left+1 && lprc->bottom > lprc->top+1){
			switch(cellType)
			{
			case ECT_CHECKBOX:
				{
					UINT uFlag=DFCS_BUTTONCHECK|DFCS_FLAT;
					if(nCount>0 && 0!=(_tcsncmp(lpText,_T("0"),nCount)))
						uFlag|=DFCS_CHECKED;
					//RECT rc={lprc->left+2,lprc->top+2,lprc->right-2,lprc->bottom-2};
					CRect rcCell=*lprc;
					CPoint _pt=rcCell.CenterPoint();
					//int cx=rcCell.Width(); 
					//if(rcCell.Height()<cx) 
					//	cx=rcCell.Height();
					//cx=(cx-2)>>1;
					int const cx=CHECKBOX_HALF_WIDTH;
					rcCell.SetRect(_pt.x-cx,_pt.y-cx,_pt.x+cx,_pt.y+cx);
					DrawFrameControl(dc,&rcCell,DFC_BUTTON,uFlag);
				}break;
			case ECT_COLOR:
				{
					if(nCount>0){
						CComVariant vt(lpText);
						if(S_OK==vt.ChangeType(VT_I4)){
							CBrush br;
							br.CreateSolidBrush((COLORREF)(vt.lVal));
							RECT rc={lprc->left+1,lprc->top+1,lprc->right-1,lprc->bottom-1};
							dc.FillRect(&rc,br);
						}
					}
				}break;
			case cellOwnerDraw:
				{
					DrawCellStruct dcs;
					dcs.hDC=hDC;
					dcs.lprcCell=lprc;
					dcs.clrCellBack=backColor;
					dcs.lpszCellText=lpText;
					pSheet->SendNotifyMessageToListener(row,col,OCN_DRAWCELL,(LPARAM)&dcs);
				}break;
			default:
				if(lpText && lprc->right - lprc->left>5){
					draw_text(hDC,styleDesc,lpText,nCount,lprc);
					//long nFormat=DT_VCENTER|DT_SINGLELINE|DT_CENTER|DT_END_ELLIPSIS;
					//CRect rc=*lprc;
					//rc.DeflateRect(1,1);
					//::DrawText(hDC,lpText, nCount, rc, nFormat);
				}
			}
		}
		if(0 && pSheet->get_ShowGrid()){//����
			style::Borders const* pborders=styleDesc.GetBorders();
			if(pborders->bottom.IsNull()){
				dc.MoveTo(lprc->left,lprc->bottom-1);
				dc.LineTo(lprc->right-1,lprc->bottom-1);
			}
			if(pborders->right.IsNull()){
				dc.MoveTo(lprc->right-1,lprc->bottom-1);
				dc.LineTo(lprc->right-1,lprc->top-1);
			}
		}
		//draw_cell_border(hDC,row,col,styleDesc,lprc);
		//}
	}
	*/
	//void calc_rect(HDC hDC,LPCTSTR lpsz,int nCount,RECT& rc)
	//{
	//	DrawText(hDC,lpsz,nCount,&rc,DT_CALCRECT);
	//}
/*
	void GridRenderer::draw_text(CDCHandle& dc,EXlHAlign xa,LPCTSTR lpText, int nCount,LPCRECT lprc)const
	{
		CRect rc=*lprc;
		rc.DeflateRect(1,1);

		long nFormat=DT_VCENTER|DT_SINGLELINE|DT_END_ELLIPSIS;
		if(1){
			//EXlHAlign const xa=styleDesc.Align_GetHorizontal();
			switch(xa)
			{
			case xlHAlignCenter:
				nFormat|=DT_CENTER;
				break;
			case xlHAlignLeft:
				nFormat|=DT_LEFT;
				break;
			case xlHAlignRight:
				nFormat|=DT_RIGHT;
				break;
			case xlHAlignJustify:////��ɢ����
				{	
					if(DrawTextAlignJustify(dc.m_hDC,rc,lpText,nCount,nFormat)){
						return;
					}else{
						nFormat|=DT_CENTER;
					}
				}break;;
			}
		}
		::DrawText(dc.m_hDC,lpText, nCount, rc, nFormat);
	}
	*/
	COLORREF GridRenderer::GetBKColor(const Worksheet* pSheet,int row,int col,const CCellRange* /*pmerge*/,COLORREF bkColor)const//StyleDesc const& style)const
	{
		const CCell cell(row,col);
		//COLORREF bkColor=style.HasColor()?style.GetColor():Colors::CLR_BKGND;//HasBkColor()?style.GetBkColor():Colors::CLR_BKGND;
		if(pSheet->get_ShowSelection()){
			CCell acell=pSheet->GetActiveCell();
			const CCellRange* pCR=pSheet->GetMergeCells(acell);
			if(pCR){
				acell=pCR->TopLeft();
			}
			//const bool bActive=acell==cell && !pmerge?(TRUE):
			//	(pSheet->get_Selections()->CellInSelections());

			if(acell==cell){
				bkColor^=Colors::CLR_ACTIVE;
			}else if(pSheet->InSelection(row,col)){
				bkColor^=Colors::CLR_SELECTION;
			}
		}
		return bkColor;
	}
	/*
	//
	int split_text(HDC hDC,LPCTSTR lpText,int nCount,vector<pair<CString,SIZE> >& vl)
	{
		int height=0;
		RECT _rc={0};
		CString line;
		int i=0;
		for(;i<nCount-1;++i){
			if(0x0d==lpText[i] && 0x0a==lpText[i+1]){
				if(!line.IsEmpty())
				{
					DrawText(hDC,(LPCSTR)line,line.GetLength(),&_rc,DT_CALCRECT);
					SIZE const si={_rc.right-_rc.left,_rc.bottom-_rc.top};
					vl.push_back(make_pair(line,si));
					height+=si.cy;
					line.Empty();
					++i;
				}
			}else{
				line+=lpText[i];
			}
		}
		line+=lpText[nCount-1];
		if(!(0x0d==lpText[i] && 0x0a==lpText[i+1])){
			DrawText(hDC,(LPCSTR)line,line.GetLength(),&_rc,DT_CALCRECT);
			SIZE const si={_rc.right-_rc.left,_rc.bottom-_rc.top};
			vl.push_back(make_pair(line,si));
			height+=si.cy;
		}
		return height;
	}
	*/
	//void GridRenderer::draw_cell(HDC hDC,int row,int col,LPCTSTR lpText,int nCount,LPCRECT lprc,StyleDesc styleDesc,COLORREF bkColor)
	//void GridRenderer::draw_cell_shrink(CDCHandle& dc,int row,int col,DrawCellStruct& dcs,ECellBGShrinkState* peShrink,CMergeCell* pmerge)
	//void GridRenderer::draw_cell_shrink(CDCHandle& dc,int row,int col,CellItem& cell,DrawCellStruct& dcs)
	void GridRenderer::draw_cell_shrink(const Worksheet* pSheet,int row,int col,const Selections* pCurSelections,CDCHandle& dc,const CCellRange& activeSelection,CellItem& item,DrawCellInfo& dcs)const//,CMergeCell* pmerge)const
	{
		LPCRECT lprc=&dcs.rcCell;
		//_ASSERT(lprc->right > lprc->left+1 && lprc->bottom > lprc->top+1);
		if(!(lprc->right > lprc->left+1 && lprc->bottom > lprc->top+1))
			return;
		//int const row=cell.row;
		//int const col=cell.col;
		const SelectionsHandler* pSelection=pSheet->get_Selections();
		bool const bMultiSelectionMode=pSelection->IsMultiSelectionMode();
		const CMergeCell* pmerge=item.GetCSPack().GetMerge();
		//ECellBGShrinkState* peShrink=&cell.eShrink;
		_ASSERT(pmerge?pmerge->IsNormalize():TRUE);
		BYTE const bActiveCell=dcs.nSelState&EST_ACTIVECELL;//pmerge?(pmerge->Inside(dcs.activeRow,dcs.activeCol)):(row== dcs.activeRow && col==dcs.activeCol);
		const int N_SHRINK=bMultiSelectionMode?1:(pSheet->IsSelectAll()?1:2);
		int ecs=item.eShrink;
		if(ECBSS_UNKNOWN==ecs){
			//if(!pmerge){
			//	ecs=pCurSelections->get_CellBGShrinkState(row,col);
			//}else
			if(pmerge&&activeSelection==*pmerge){
				ecs=0;
				if(col==pmerge->LeftCol() && (ECBSS_SHRINK_LEFT&pCurSelections->get_CellBGShrinkState(/*row*/pmerge->TopRow(),col)))
					ecs|=ECBSS_SHRINK_LEFT;
				if(row==pmerge->TopRow() && (ECBSS_SHRINK_TOP&pCurSelections->get_CellBGShrinkState(row,pmerge->LeftCol()/*col*/)))
					ecs|=ECBSS_SHRINK_TOP;
				if(col==pmerge->RightCol()&&(ECBSS_SHRINK_RIGHT&pCurSelections->get_CellBGShrinkState(pmerge->TopRow(),col)))
					ecs|=ECBSS_SHRINK_RIGHT;
				if(row==pmerge->BottomRow() && (ECBSS_SHRINK_BOTTOM&pCurSelections->get_CellBGShrinkState(row,pmerge->LeftCol())))
					ecs|=ECBSS_SHRINK_BOTTOM;
				if(row==pmerge->TopRow()&&col==pmerge->LeftCol()&&(ECBSS_SHRINK_LEFTTOP&pCurSelections->get_CellBGShrinkState(row,col)))
					ecs|=ECBSS_SHRINK_LEFTTOP;
				if(row==pmerge->TopRow()&&col==pmerge->RightCol()&&(ECBSS_SHRINK_RIGHTTOP&pCurSelections->get_CellBGShrinkState(row,col)))
					ecs|=ECBSS_SHRINK_RIGHTTOP;
				if(row==pmerge->BottomRow()&&col==pmerge->LeftCol()&&(ECBSS_SHRINK_LEFTBOTTOM&pCurSelections->get_CellBGShrinkState(row,col)))
					ecs|=ECBSS_SHRINK_LEFTBOTTOM;
				if(row==pmerge->BottomRow()&&col==pmerge->RightCol()&&(ECBSS_SHRINK_RIGHTBOTTOM&pCurSelections->get_CellBGShrinkState(row,col)))
					ecs|=ECBSS_SHRINK_RIGHTBOTTOM;
			}else{
				ecs=pCurSelections->get_CellBGShrinkState(row,col);
			}
			item.eShrink=(ECellBGShrinkState)ecs;
		}
		if(bActiveCell){
			if(bMultiSelectionMode){
				//HGDIOBJ oldPen=SelectObject(dc.m_hDC,PenFactory::Instance().squareBlackPen1);
				GdiSelectObjectPlain soPen(dc.m_hDC,PenFactory::Instance().squareBlackPen1);
				const int left=lprc->left+((ECBSS_SHRINK_LEFT&ecs)?N_SHRINK:(N_SHRINK-1));
				const int top=lprc->top+((ECBSS_SHRINK_TOP&ecs)?N_SHRINK:(N_SHRINK-1));
				const int right=lprc->right-((ECBSS_SHRINK_RIGHT&ecs)?(N_SHRINK+1):N_SHRINK);
				const int bottom=lprc->bottom-((ECBSS_SHRINK_BOTTOM&ecs)?(N_SHRINK+1):N_SHRINK);
				if(!pmerge){
					GdiSelectObjectPlain soPen(dc.m_hDC,PenFactory::Instance().squareBlackPen1);
					GdiSelectObjectPlain soBrush(dc.m_hDC,GetStockObject(NULL_BRUSH));
					dc.Rectangle(left,top,right,bottom);
				}else{
					//++right;
					//++bottom;
					if(col==pmerge->LeftCol())
					{
						dc.MoveTo(left,top);
						//dc.LineTo(left,bottom-(row==pmerge->BottomRow()?0:-1));
						dc.LineTo(left,row==pmerge->BottomRow()?bottom:(bottom+1));
					}
					if(row==pmerge->TopRow())
					{
						dc.MoveTo(left,top);
						//dc.LineTo(right-(col==pmerge->RightCol()?1:0),top);
						dc.LineTo(col==pmerge->RightCol()?right:right+1,top);
					}
					if(col==pmerge->RightCol())
					{
						dc.MoveTo(right-1,top);
						//dc.LineTo(right-1,bottom-(row==pmerge->BottomRow()?1:0));
						dc.LineTo(right-1,row==pmerge->BottomRow()?bottom:(bottom+1));
					}
					if(row==pmerge->BottomRow())
					{
						dc.MoveTo(left,bottom-1);
						//dc.LineTo(right-(col==pmerge->RightCol()?1:0),bottom-1);
						dc.LineTo(col==pmerge->RightCol()?right:right+1,bottom-1);
					}
				}
				//SelectObject(dc.m_hDC,oldPen);
			}
		}//else
		if(ECBSS_SHRINK_NONE!=ecs)
		{
			//const GDISetROP2 rop2(dc.m_hDC,R2_XORPEN);
			const COLORREF crShrink=RGB(255,255,255);//240,240);
			GdiSelectObjectPlain soPen(dc.m_hDC,PenFactory::Instance().squareBlackPen1);
			if((ECBSS_SHRINK_LEFT&ecs)){
				int nShrink=N_SHRINK;
				if(!bMultiSelectionMode){
					if(0==col && pSelection->CellInSelections(row,-1))
						--nShrink;
				}
				//dc.FillSolidRect(lprc->left,lprc->top,nShrink,lprc->bottom-lprc->top,RGB(255,255,255));
				dc.FillSolidRect(lprc->left,lprc->top,nShrink,lprc->bottom-lprc->top,crShrink);
			}
			if((ECBSS_SHRINK_TOP&ecs)){
				int nShrink=N_SHRINK;
				if(!bMultiSelectionMode){
					if(0==row && pSelection->CellInSelections(-1,col))
						--nShrink;
				}
				dc.FillSolidRect(lprc->left,lprc->top,lprc->right-lprc->left,nShrink,crShrink);
			}
			if((ECBSS_SHRINK_RIGHT&ecs)){
				dc.FillSolidRect(lprc->right-(1+N_SHRINK),lprc->top,N_SHRINK+1,lprc->bottom-lprc->top,crShrink);
			}
			if((ECBSS_SHRINK_BOTTOM&ecs)){
				dc.FillSolidRect(lprc->left,lprc->bottom-(1+N_SHRINK),lprc->right-lprc->left,N_SHRINK+1,crShrink);
			}
			if(ECBSS_SHRINK_LEFTTOP&ecs){
				dc.FillSolidRect(lprc->left,lprc->top,N_SHRINK,N_SHRINK,crShrink);
			}
			if(ECBSS_SHRINK_RIGHTTOP&ecs){
				dc.FillSolidRect(lprc->right-(1+N_SHRINK),lprc->top,N_SHRINK,N_SHRINK,crShrink);
			}
			if(ECBSS_SHRINK_LEFTBOTTOM&ecs){
				dc.FillSolidRect(lprc->left,lprc->bottom-(1+N_SHRINK),N_SHRINK,N_SHRINK,crShrink);
			}
			if(ECBSS_SHRINK_RIGHTBOTTOM&ecs){
				dc.FillSolidRect(lprc->right-(1+N_SHRINK),lprc->bottom-(1+N_SHRINK),N_SHRINK,N_SHRINK,crShrink);
			}
		}
	}
	void GridRenderer::draw_cell_inner(CDCHandle& dc,const CMergeCell* /*merge*/,int row,int col,/*CRgnLight const* pRgnClip,*/DrawCellInfo& dci,style::StyleDesc const& style)const
	{
		LPCRECT lprc=&dci.rcCell;
		_ASSERT(lprc->right > lprc->left+1 && lprc->bottom > lprc->top+1);
		
		/*
		if(style.IsOwnerDraw()){
			CellFontSetup cfs(dc,style.Font_GetLogFont(),style.Font_GetColor());
			dcs.pDTS->uDrawTextFormat=GetDrawTextFormat((EXlHAlign)dcs.hAlignment);
			pSheet->SendNotifyMessageToListener(row,col,OCN_DRAWCELL,(LPARAM)&dcs);
			return;
		}
		*/

		//DrawCellInfo dci;
		//dci.pMerge=merge?merge->get():NULL;
		//dci.hAlign=(EXlHAlign)dcs.hAlign;
		//dci.vAlign=(EXlVAlign)dcs.vAlignment;
		//dci.lprcCell=&dcs.fillRect;
		//dci.nDataLen=dcs.pDTS->nTextLen;
		//dci.pdata=(BYTE*)dcs.pDTS->lpszCellText;

		//const StyleDesc* psd=&style;
		//if(psd->Font_IsNull())
		//	psd=&pSheet_->Style_GetStyleByID(pSheet_->get_RowHeader().Style_GetRowStyleID(row));
		//if(psd->Font_IsNull())
		//	psd=&pSheet_->Style_GetStyleByID(pSheet_->get_ColHeader().Style_GetColStyleID(col));
		//if(psd->Font_IsNull())
		//	psd=&pSheet_->Style_GetTableStyle();
		if(!style.Font_IsNull()){
			dci.pLogFont=(void*)&style.Font_GetLogFont();
			dci.clrFont=style.Font_GetColor();
		}
		//dci.clrBkgnd=dcs.bkclr;
		dci.bWrapText=style.Align_IsWrapText();

		CComPtr<ICellSymbol> pFillSymbol=cellTypeFactory_.GetFillSymbol(dci.cellType);
		//fill rect
		if(pFillSymbol){
			//if(merge)
			//	pFillSymbol_->SetMergeInfo(merge->LeftCol(),merge->TopRow(),merge->RightCol(),merge->BottomRow());
			pFillSymbol->Draw(dc.m_hDC,row,col,&dci);
		}
		//CBrush br(CreateSolidBrush(bkclr));
		//::FillRect(dcs.hDC,&dcs.fillRect,br);
		//:~fill rect
		//lprc=&dcs.textRect;
		if(!(lprc->right - lprc->left<=5 || lprc->bottom-lprc->top<=5))
			//&& pRgnClip->RectInRgn(*lprc))
		{
			CComPtr<ICellSymbol> pSymbol=cellTypeFactory_.GetSymbol(dci.cellType);
			if(!pSymbol){
				_ASSERT(FALSE);
				return;
			}
			//if(merge)
			//	pSymbol->SetMergeInfo(merge->LeftCol(),merge->TopRow(),merge->RightCol(),merge->BottomRow());
			//dci.lprcCell=&dcs.textRect;
			pSymbol->Draw(dc,row,col,&dci);
		}
	}
	/*
	class UseBorderPen
	{
	HDC hDC_;
	HGDIOBJ hOldPen_;
	public:
	UseBorderPen(HDC hDC,Border bdr):hDC_(hDC)
	{
	BYTE weight=bdr.get_Weight();
	EXlLineStyle style=bdr.get_LineStyle();
	int fnPenStyle=PS_SOLID;
	switch(style)
	{
	case xlContinuous:
	if(!weight)
	fnPenStyle=PS_DASH;
	else
	fnPenStyle=PS_SOLID;
	break;
	case xlDash:
	fnPenStyle=PS_DASH;
	break;
	case xlDashDot:
	fnPenStyle=PS_DASHDOT;
	break;
	case xlDashDotDot:
	fnPenStyle=PS_DASHDOTDOT;
	break;
	case xlDot:
	fnPenStyle=PS_DOT;
	break;
	case xlDouble:
	_ASSERT(FALSE);
	break;
	case xlSlantDashDot:
	_ASSERT(FALSE);
	break;
	case xlLineStyleNone:
	fnPenStyle=PS_NULL;
	break;
	}

	//DWORD dwPenStyle[] = { 
	//                       PS_DASH, 
	//                       PS_DASHDOT, 
	//                       PS_DOT, 
	//                       PS_INSIDEFRAME, 
	//                       PS_NULL, 
	//                       PS_SOLID 
	//                    }; 

	//UINT uHatch[] = { 
	//                  HS_BDIAGONAL, 
	//                  HS_CROSS, 
	//                  HS_DIAGCROSS, 
	//                  HS_FDIAGONAL, 
	//                  HS_HORIZONTAL, 
	//                  HS_VERTICAL     
	//                 }; 

	LOGBRUSH lb;
	lb.lbColor=bdr.get_Color();
	lb.lbStyle=BS_SOLID;
	lb.lbHatch=0;//uHatch[5]; 
	//fnPenStyle=PS_COSMETIC |PS_SOLID ;
	HPEN hPen=ExtCreatePen(PS_GEOMETRIC |fnPenStyle|PS_ENDCAP_SQUARE, 
	weight,&lb,0,NULL);
	hOldPen_=SelectObject(hDC_,hPen);
	}
	~UseBorderPen()
	{
	DeleteObject(SelectObject(hDC_,hOldPen_));
	}
	};
	*/
	//void GridRenderer::draw_cell_border(HDC hDC,Border left,Border top,Border right,Border bottom,LPCRECT lprc)
	//{
	//	if(!bottom.IsNull())
	//		DrawLine(bottom,hDC,lprc->left-1,lprc->bottom-1,lprc->right-1,lprc->bottom-1);
	//	if(!right.IsNull())
	//		DrawLine(right,hDC,lprc->right-1,lprc->top-1,lprc->right-1,right.get_Weight()>1?lprc->bottom-1:lprc->bottom);
	//	DrawLine(top,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//	DrawLine(left,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//}
	//void GridRenderer::draw_cell_border(HDC hDC,int row,int col,CMergeCell const* pMerge,int topRow,int leftCol,LPCRECT lprc)
	//{
	//	//if(!vcs.styleDesc.IsEmptyStyle() && !vcs.styleDesc.borders.empty()){
	//		CDCHandle dc(hDC);
	//		//int const row=vcs.row;
	//		//int const col=vcs.col;
	//		//LPCRECT lprc=&vcs.rc;

	//		GridBorders& borders=*pSheet;
	//		////CCellRange const* pMerge=pSheet->GetMergeCells(row,col);
	//		//CMergeCell const* pMerge=vcs.pMergeCells;
	//		
	//		//if(pMerge){
	//		int const _rrow=pMerge?pMerge->BottomRow():row;
	//		int const _rcol=pMerge?pMerge->RightCol():col;
	//		BorderPair borderPair;
	//		if(!borders.GetBorder(_rrow,_rcol,borderPair))
	//			return;
	//		//borders.GetRightBottomBorder(_rrow,_rcol,borderPair);
	//		if(!borderPair.bottom.IsNull())
	//			DrawLine(borderPair.bottom,hDC,lprc->left-1,lprc->bottom-1,lprc->right-1,lprc->bottom-1);
	//		if(!borderPair.right.IsNull())
	//			DrawLine(borderPair.right,hDC,lprc->right-1,lprc->top-1,lprc->right-1,lprc->bottom-1);

	//		//	//pBorderPair=borders.GetBorder(row,col);
	//		//	//if(pBorderPair){
	//		//		//if(!pBorderPair->top.IsNull())
	//		//		//	DrawLine(pBorderPair->top,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//		//		//if(!pBorderPair->left.IsNull())
	//		//		//	DrawLine(pBorderPair->left,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//		//	//}
	//		//}else{
	//		//	//BorderPair const* pBorderPair=borders.GetBorder(row,col);
	//		//	BorderPair borderPair;
	//		//	borders.GetRightBottomBorder(row,col,borderPair);
	//		//	if(!borderPair.bottom.IsNull())
	//		//		DrawLine(borderPair.bottom,hDC,lprc->left-1,lprc->bottom-1,lprc->right-1,lprc->bottom-1);
	//		//	if(!borderPair.right.IsNull())
	//		//		DrawLine(borderPair.right,hDC,lprc->right-1,lprc->top-1,lprc->right-1,lprc->bottom-1);

	//		//	//if(!pBorderPair->top.IsNull())
	//		//	//	DrawLine(pBorderPair->top,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//		//	//if(!pBorderPair->left.IsNull())
	//		//	//	DrawLine(pBorderPair->left,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//		//}
	//		if(/*topRow==row && */!borderPair.top.IsNull()/*(row,col,bdr)*/){
	//			DrawLine(borderPair.top,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//		}
	//		if(/*leftCol==col && */!borderPair.left.IsNull()/*borders.GetLeftBorder(row,col,bdr)*/){
	//			DrawLine(borderPair.left,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//		}

	//		//Border bdr;
	//		//if(/*topRow==row && */borders.GetTopBorder(row,col,bdr)){
	//		//	DrawLine(bdr,hDC,lprc->left-1,lprc->top-1,lprc->right-1,lprc->top-1);
	//		//}
	//		//if(/*leftCol==col && */borders.GetLeftBorder(row,col,bdr)){
	//		//	DrawLine(bdr,hDC,lprc->left-1,lprc->top-1,lprc->left-1,lprc->bottom-1);
	//		//}
	//	//}
	//}
	COLORREF SetupHeaderCornerDE(const Worksheet* pSheet,BOOL isSelectAll)
	{
		//_ASSERT(FALSE);
		return pSheet->get_ShowSelection()?(isSelectAll?HeaderColors::CLR_ACTIVE:HeaderColors::CLR_BKGND):(HeaderColors::CLR_BKGND);
	}
	/*
	struct CInvalidateRectSession
	{
		HWND hWnd_;
		LPCRECT lprc_;
		CInvalidateRectSession(HWND hWnd,LPCRECT lprc):hWnd_(hWnd),lprc_(lprc)
		{
			InvalidateRect(hWnd_,lprc,FALSE);
		}
		~CInvalidateRectSession()
		{
			ValidateRect(hWnd_,lprc_);
		}
	};
	*/
	void GridRenderer::draw(const Worksheet* pSheet,const CellAxisInfo* pcai,HDC hDC,LPCRECT lprcClient,const CRgnLight* pRgnClip)
	{
		pSheet_=pSheet;
		CDCHandle dc(hDC);

		//const StyleDesc& style=pSheet->GetDefaultStyle();
		//CellFontSetup cfs(dc,style); 
		//cellStoreCache_.clear();
		//mergeCellCache_.clear();

		//const Selections* pSelections=pSheet->get_Selections();
		VisibleCellsSession session_;
		//SetMapMode(hDC,MM_TWIPS);
		//CInvalidateRectSession irs(pSheet->m_hWnd,lprcClient);
		const CellAxisInfo& cai=*pcai;//pSheet->get_CellAxisInfo(/*lprcClient*/);
		const RowHeader& rh=pSheet->get_RowHeader();
		const ColHeader& ch=pSheet->get_ColHeader();
		int const rows=rh.get_rows();
		int const cols=ch.get_cols();
		int const nFreezeBottomRow=rh.get_FreezeBottomRow();
		int const nFreezeTopRow=rh.get_FreezeTopRow();
		int const nFreezeRightCol=ch.get_FreezeRightCol();
		int const nFreezeLeftCol=ch.get_FreezeLeftCol();
		int const nTopVisScrollRow=rh.get_TopVisScrollRow();
		int const nBottomVisScrollRow=rh.get_BottomVisScrollRow();
		int const nLeftVisScrollCol=ch.get_LeftVisScrollCol();
		int const nRightVisScrollCol=ch.get_RightVisScrollCol();
		BOOL const bShowRowHeader=pSheet->get_ShowRowHeader();
		BOOL const bShowColHeader=pSheet->get_ShowColHeader();
		BOOL const IsFreezeRowVisible=rh.IsFreezeRowVisible();
		BOOL const IsFreezeColVisible=ch.IsFreezeColVisible();
		/*
		BOOL const bShowFreezeAlthogonal=rh.IsFreezeRowVisible()&&ch.IsFreezeColVisible();
		RECT const de.rRowHeader={lprcClient->left,get_ShowColHeader()?(lprcClient->top+ch.get_height()):lprcClient->top.rRowHeader.left+(get_ShowRowHeader()?rh.get_width():0),lprcClient->bottom};
		RECT const de.rColHeader={get_ShowRowHeader()?(lprcClient->left+rh.get_width()):lprcClient->left
			,lprcClient->top,lprcClient->right.rColHeader.top+(get_ShowColHeader()?ch.get_height():0)};
		RECT const de.rAlthogonal={lprcClient->left,lprcClient->top.rRowHeader.right.rColHeader.bottom};
		RECT const de.rFreezeAlthogonal={de.rRowHeader.right.rColHeader.bottom,
			de.rRowHeader.right+(ch.IsFreezeColVisible()?ch.get_DiffWidths(ch.get_FreezeLeftCol(),ch.get_FreezeRightCol()+1):0),
			de.rColHeader.bottom+(rh.IsFreezeRowVisible()?rh.get_DiffHeights(rh.get_FreezeTopRow(),rh.get_FreezeBottomRow()+1):0)};
		RECT const de.rFreezeRows={de.rFreezeAlthogonal.right.rFreezeAlthogonal.top,lprcClient->right.rFreezeAlthogonal.bottom};
		RECT const de.rFreezeCols={de.rFreezeAlthogonal.left.rFreezeAlthogonal.bottom.rFreezeAlthogonal.right,lprcClient->bottom};
		RECT const rContent={de.rFreezeRows.left.rFreezeCols.top,lprcClient->right,lprcClient->bottom};
		*/
		CFont hFont=pSheet->Style_GetTableStyle().Font_GetHFont(hDC);

		//HGDIOBJ hOldFont=SelectObject(hDC,hFont);
		GdiSelectObjectPlain selFont(hDC,hFont);

		//about draw active selection bound
		CCellRange activeSelection=pSheet->get_Selections()->GetActiveSelection();
		_ASSERT(activeSelection.IsNormalize());
		//activeSelection.Normalize();
		pSheet->AdjustSelection(activeSelection);
		/*
		activeSelection.SetRightCol(min(activeSelection.RightCol(),ch.get_cols()-1));
		activeSelection.SetBottomRow(min(activeSelection.BottomRow(),rh.get_rows()-1));
		activeSelection.SetTopRow(max(0,activeSelection.TopRow()));
		activeSelection.SetLeftCol(max(0,activeSelection.LeftCol()));
		*/
		//:~about draw active selection bound

		RECT rcTmp;


		//draw header parts
		if(bShowRowHeader && bShowColHeader &&pRgnClip->RectInRgn(cai.get_HeaderAlthonogalRect(rcTmp)))
		{
			const CComPtr<ICellSymbol> pSymbol=cellTypeFactory_.GetSymbol(ECT_HEADERCORNER);
			if(pSymbol){
				GdiSelectObject<> gso(dc,CreatePen(PS_SOLID,0,HeaderColors::CLR_GRID));
				DrawCellInfo dci;
				ZeroMemory(&dci,sizeof(dci));
				BOOL const bSelectAll=pSheet->IsSelectAll();
				dci.clrBkgnd=SetupHeaderCornerDE(pSheet,bSelectAll);
				dci.nSelState=bSelectAll?EST_IN_SELECTION:EST_NOT_IN_SELECTION;
				dci.rcCell=rcTmp;
				pSymbol->Draw(dc,HEADER_ROW,HEADER_COL,&dci);
			}
			/*
			TCHAR text[1]={0};
			DrawHeaderCellStruct dhcs;
			DrawTextStruct1 dts;
			dts.lpszCellText=text;
			dts.nTextLen=0;
			dhcs.pDTS=&dts;
			dhcs.hDC=hDC;
			dhcs.headerType=MHT_HEADER_CORNER;
			dhcs.bHandled=FALSE;
			dhcs.selType=bSelectAll?EST_IN_SELECTION:EST_NOT_IN_SELECTION;
			dhcs.fillRect=rcTmp;
			pSheet->SendNotifyMessageToListener(-1,-1,OCN_DRAWHEADCELL,(LPARAM)&dhcs);
			if(!dhcs.bHandled){
				draw_HeaderCorner(dc,&rcTmp,dhcs.bkclr);
			}
			*/
		}
		if(bShowColHeader && cols>0){
			if(IsFreezeColVisible && pRgnClip->RectInRgn(cai.get_HeaderHFreezeRect(rcTmp)))
				draw_ColHeader(dc,&rcTmp,nFreezeLeftCol,nFreezeRightCol,pRgnClip);
			if(pRgnClip->RectInRgn(cai.get_HeaderHScrollRect(rcTmp))){
				draw_ColHeader(dc,&rcTmp,nLeftVisScrollCol,cols-1,pRgnClip);
			}
		}
		if(bShowRowHeader && rows>0){
				if(IsFreezeRowVisible && pRgnClip->RectInRgn(cai.get_HeaderVFreezeRect(rcTmp)))
					draw_RowHeader(dc,&rcTmp,nFreezeTopRow,nFreezeBottomRow,pRgnClip);
				if(pRgnClip->RectInRgn(cai.get_HeaderVScrollRect(rcTmp)))
					draw_RowHeader(dc,&rcTmp,nTopVisScrollRow,rows-1/*nBottomVisScrollRow*/,pRgnClip);
		}
		//:~draw header parts

		//draw EGP_FREEZE_ALTHOGONAL ������������
		if(IsFreezeRowVisible 
			&& IsFreezeColVisible 
			&& pRgnClip->RectInRgn(cai.get_FreezeAlthonogalRect(rcTmp))
			)
		{
			calc_cells_session(pRgnClip,nFreezeLeftCol,nFreezeTopRow,nFreezeRightCol,nFreezeBottomRow,&rcTmp,session_);
			//const CCellRange clip(nFreezeTopRow,nFreezeLeftCol,nFreezeBottomRow,nFreezeRightCol);
			draw_session(dc,session_,EGP_SCROLLABLE,activeSelection);
		}
		if(IsFreezeRowVisible && pRgnClip->RectInRgn(cai.get_FreezeHScrollRect(rcTmp))){
			calc_cells_session(pRgnClip,nLeftVisScrollCol
				,nFreezeTopRow
				,nRightVisScrollCol
				,nFreezeBottomRow,&rcTmp,session_);
			//const CCellRange clip(nFreezeTopRow,nLeftVisScrollCol,nFreezeBottomRow,nRightVisScrollCol);
			draw_session(dc,session_,EGP_SCROLLABLE,activeSelection);
		}
		if(IsFreezeColVisible && pRgnClip->RectInRgn(cai.get_FreezeVScrollRect(rcTmp))){
			calc_cells_session(pRgnClip,nFreezeLeftCol
				,nTopVisScrollRow
				,nFreezeRightCol
				,nBottomVisScrollRow,&rcTmp,session_);
			//const CCellRange clip(nTopVisScrollRow,nFreezeLeftCol,nBottomVisScrollRow,nFreezeRightCol);
			draw_session(dc,session_,EGP_SCROLLABLE,activeSelection);
		}

		if(rows>0 && cols>0 && pRgnClip->RectInRgn(cai.get_ScrollRect(rcTmp))){
			//calc_scrollCellsSession(rh,ch,&de.rScroll);
			//draw_content(hDC,&de.rScroll,pRgnClip);
			calc_cells_session(pRgnClip,nLeftVisScrollCol
				,nTopVisScrollRow
				,nRightVisScrollCol
				,nBottomVisScrollRow,&rcTmp,session_);
			//const CCellRange clip(nTopVisScrollRow,nLeftVisScrollCol,nBottomVisScrollRow,nRightVisScrollCol);
			draw_session(dc,session_,EGP_SCROLLABLE,activeSelection);
		}

		//draw remain parts
		int const bottomRow=nBottomVisScrollRow;
		//if(0==rows || bottomRow==rows-1)
		{
			SetRect(&rcTmp,0,cai.HRemainAxis,cai.VClientAxis,cai.HClientAxis);
			if(pRgnClip->RectInRgn(rcTmp))
				FillRect(hDC,&rcTmp,(HBRUSH) GetStockObject(WHITE_BRUSH));
		}
		//if(0==cols || nRightVisScrollCol==cols-1)
		{
			SetRect(&rcTmp,cai.VRemainAxis,0,cai.VClientAxis,cai.HRemainAxis);
			if(pRgnClip->RectInRgn(rcTmp))
				FillRect(hDC,&rcTmp,(HBRUSH) GetStockObject(WHITE_BRUSH));
		}
		//:~draw border parts

//----------------draw header 
//
		//pSheet->GetSelectionBound().Draw(hDC,lprcClient);
		//SelectObject(hDC,hOldFont);
	}
	//void GridRenderer::OnThemeChanged(HWND hWnd)
	//{
	//	for(map<CellType,CComPtr<ICellSymbol> >::iterator it=mapSymbol_.begin();it!=mapSymbol_.end();++it){
	//		CComPtr<ICellSymbol>& pSymbol=it->second;
	//		if(pSymbol)
	//			pSymbol->OnThemeChanged(hWnd);
	//	}
	//}

}//namespace mycell2

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

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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
China China
My name is Yanxueming,i live in Chengdu China.Graduated from UESTC in 1999.

Comments and Discussions