Click here to Skip to main content
15,891,777 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 91K   4.5K   81  
A fast and lightweight cell control for displaying tabular data. The cell is a custom control derived from ATL::CWindow.
/* -------------------------------------------------------------------------
//MyCell Library - MyCell version 1.0
//
// This file is a part of the MyCell Library.
// The use and distribution terms for this software are covered by the
// Common Public License 1.0 (http://opensource.org/licenses/cpl.php)
// which can be found in the file CPL.txt at this distribution. By using
// this software in any fashion, you are agreeing to be bound by the terms
// of this license. You must not remove this notice, or any other, from
// this software.
//
// Creator: yanxueming
// Email: xueming.yan@gmail.com
// -----------------------------------------------------------------------*/
#include "stdafx.h"
#include <atltypes.h>
#include "../include/SelectionsHandler.h"
#include "../include/Worksheet.h"
#include "../include/Workbook.h"
#include "../include/rect_xor.h"
#include "../include/msg.h"
#include "../include/algorithm.h"
namespace mycell{
	////-----------------------------------------------------------------//
	////pt should be screen coords
	////-----------------------------------------------------------------//
	//CCell GetMouseCell(Worksheet* pSheet,POINT pt)
	//{
	//	/*
	//	pSheet->ScreenToClient(&pt);
	//	return pSheet->GetCellByPos(pt.x,pt.y);
	//	ECellHitTestConstants hit;
	//	CCell cell=pSheet->HitTest(pt.x,pt.y,hit);
	//	return cell;
	//	*/
	//	return pSheet->GetCellByScreenPos(pt.x,pt.y);
	//}

	SelectionsHandler::SelectionsHandler(Worksheet* p):baseClass(p)//,autoScrollType_(0)
	{
		//pCurSelections_=p->get_Selections();
		//pSheet_->SetActiveCell(0,0);
		//activeSelection_.SetTopLeft(0,0);
		//activeSelection_.SetRightBottom(0,0);
		//ZeroMemory(&activeCell_,sizeof(CCell));
		//ZeroMemory(&activeSelection_,sizeof(CCellRange));
	}

	//bool SelectionsHandler::InSelection(int row,int col)const
	//{
	//	CCellRange cr=activeSelection_;
	//	cr.Normalize();
	//	pSheet_->AdjustSelection(cr);
	//	CCell const tl=cr.TopLeft();
	//	CCell const rb=cr.RightBottom();
	//	if(row>=tl.row && row<=rb.row && col>=tl.col && col<=rb.col)
	//		return true;
	//	return false;
	//}

	//void SelectionsHandler::SetupRowHeaderDE(int row,DrawEnvironment& de,BOOL& bFullInselection)
	//{
	//	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();
	//		bFullInselection=baseClass::CellInSelections(row,HEADER_COL);
	//		const bool bInSelection=bFullInselection?true:baseClass::RowInSelections(row);
	//		if(bFullInselection){
	//			de.backColor=HeaderColors::CLR_ACTIVE;
	//		}else if(bInSelection||row==pSheet_->GetActiveRow()){
	//			de.backColor=HeaderColors::CLR_SELECTION;//RGB(0,0,0xff):RGB(255,192,111);
	//		}else
	//			de.backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
	//	}else
	//		de.backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
	//}
	//void SelectionsHandler::SetupHeaderCornerDE(DrawEnvironment& de)
	//{
	//	//int const minRow=min(activeSelection_.TopRow(),activeSelection_.BottomRow());
	//	//int const minCol=min(activeSelection_.LeftCol(),activeSelection_.RightCol());
	//	//if(HEADER_ROW==minRow && HEADER_COL==minCol)
	//	if(pSheet_->get_Selections()->IsSelectAll())
	//		de.backColor=HeaderColors::CLR_ACTIVE;
	//	else
	//		de.backColor=HeaderColors::CLR_BKGND;
	//}
	//void SelectionsHandler::SetupColHeaderDE(int col,DrawEnvironment& de,BOOL& bFullInselection)
	//{
	//	bFullInselection=FALSE;
	//	if(pSheet_->get_ShowSelection()){
	//		//const Selections* pCurSelections_=pSheet_->get_Selections();
	//		bFullInselection=baseClass::CellInSelections(HEADER_ROW,col);
	//		const bool bInSelection=bFullInselection?true:baseClass::ColInSelections(col);
	//		/*
	//		int minCol,maxCol;
	//		MinMax<int>(activeSelection_.LeftCol(),activeSelection_.RightCol(),minCol,maxCol);
	//		if(col>=minCol && col<=maxCol){
	//			int const topRow=min(activeSelection_.TopRow(),activeSelection_.BottomRow());
	//			bFullInselection=HEADER_ROW==topRow;
	//			de.backColor=HEADER_ROW==topRow?HeaderColors::CLR_ACTIVE:HeaderColors::CLR_SELECTION;
	//		}else if(col==pSheet_->GetActiveCol()){
	//			de.backColor=HeaderColors::CLR_SELECTION;
	//		}else
	//			de.backColor=HeaderColors::CLR_BKGND;
	//			*/
	//		if(bFullInselection){
	//			de.backColor=HeaderColors::CLR_ACTIVE;
	//		}else if(bInSelection||col==pSheet_->GetActiveCol()){
	//			de.backColor=HeaderColors::CLR_SELECTION;//RGB(0,0,0xff):RGB(255,192,111);
	//		}else
	//			de.backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
	//	}else
	//			de.backColor=HeaderColors::CLR_BKGND;//RGB(200,200,200);
	//}
	//void SelectionsHandler::SetupCellDE(int row,int col,DrawEnvironment& de)
	//{
	//	CCell const tl=activeSelection_.GetTopLeft();
	//	CCell const rb=activeSelection_.GetRightBottom();
	//	if(row>=tl.row && row<=rb.row && col>=tl.col && col<=rb.col)
	//		de.backColor=Colors::CLR_SELECTION;//RGB(182,202,234);
	//	else
	//		de.backColor=Colors::CLR_BKGND;//RGB(0xff,0xff,0xff);
	//	if(row==pSheet_->GetActiveRow() && col==pSheet_->GetActiveCol())
	//		de.backColor=Colors::CLR_ACTIVE;//RGB(166,160,240);
	//}
	/*
	BOOL SelectionsHandler::IsFullRowSelected(CCellRange const& cr)
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		return HEADER_ROW==cr.TopRow() && rh.get_rows()-1==cr.BottomRow();
	}
	BOOL SelectionsHandler::IsFullColSelected(CCellRange const& cr)
	{
		ColHeader& ch=pSheet_->get_ColHeader();
		return HEADER_COL==cr.LeftCol() && ch.get_cols()-1==cr.RightCol();
	}
	BOOL SelectionsHandler::IsSelectAll(CCellRange const& cr)const
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		return HEADER_ROW==cr.TopRow() && HEADER_COL==cr.LeftCol()
			&& cr.BottomRow()==rh.get_rows()-1 && cr.RightCol()==ch.get_cols()-1;
	}
	EMouseMode SelectionsHandler::BeginSelect(int row,int col)
	{
		EMouseMode emm=MOUSE_NOTHING;
		CCell const oldActiveCell=pSheet_->GetActiveCell();
		CCellRange const oldActiveCellRange=pSheet_->get_Selection();
		if (col < 0 && row<0){
			emm=MOUSE_SELECT_ALL;
			RowHeader& rh=pSheet_->get_RowHeader();
			ColHeader& ch=pSheet_->get_ColHeader();
			pSheet_->SetActiveCell(rh.get_TopVisScrollRow(),ch.get_LeftVisScrollCol());
			activeSelection_.set(HEADER_ROW,HEADER_COL,rh.get_rows()-1,ch.get_cols()-1);
			OnHeaderCornerClick();
		}else if(col<0){
			emm=MOUSE_SELECT_ROW;
			ColHeader& ch=pSheet_->get_ColHeader();
			pSheet_->SetActiveCell(row,ch.get_LeftVisScrollCol());
			activeSelection_.set(row,HEADER_COL,row,ch.get_cols()-1);
			OnRowHeaderClick(row);
		}else if (row < 0){
			emm=MOUSE_SELECT_COL;
			RowHeader& rh=pSheet_->get_RowHeader();
			pSheet_->SetActiveCell(rh.get_TopVisScrollRow(),col);
			activeSelection_.set(HEADER_ROW,col,rh.get_rows()-1,col);
			OnColHeaderClick(col);
		}else{
			emm=get_ListMode()? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
			pSheet_->SetActiveCell(row,col);
			const VisibleMergeCellMgr& vmc=pSheet_->GetVisibleMergeCellMgr();//NULL;
			const CMergeCell* pMergeCells=vmc.GetMergeCells(row,col);
			if(pMergeCells){
				activeSelection_=*pMergeCells;
			}else
				activeSelection_.set(row,col,row,col);
		}
		InvalidateWindow(oldActiveCell,oldActiveCellRange);
		pSheet_->put_MouseMode(emm);
		return emm;
	}
	*/
	//void SelectionsHandler::ExpandDirtyActiveSelection(CCellRange cr)
	//{
	//	pSheet_->ExpandDirtyActiveSelection(cr);
	//}
	//void SelectionsHandler::InvalidateWindow(CCell const& oldActiveCell,const Selections& oldSelections)//CCellRange const& oldActiveCellRange)
	//{
	//	//if(cell_equal(oldActiveCell,activeCell_) && CellRangeEqual(oldActiveCellRange,activeSelection_))
	//	//	return;
	//	//ExpandDirtyActiveSelection(oldActiveCellRange);
	//	//CCellRange const newSel=pSheet_->get_Selection();
	//	//if(oldActiveCell==pSheet_->GetActiveCell() && oldActiveCellRange==newSel)
	//	//	return;
	//	InvalidateHeaderCorner(oldSelections);
	//	//InvalidateHeader(oldActiveCell,oldSelections);
	//	//InvalidateColHeader(oldActiveCell,oldSelections);
	//	InvalidateContent(oldActiveCell,oldSelections);
	//	/*InvalidateContentӦ�ð������Ѿ�ע�Ͳ���
	//	ԭ����activeCellӦ�ð�����ѡ�񼸺���
	//	*/
	//	//const CMergeCell* pmerge=pSheet_->GetVisibleMergeCellMgr().GetMergeCells();
	//	
	//	pSheet_->ExpandDirtyActiveSelection(&oldSelections.GetActiveSelection(),&GetActiveSelection());

	//	pSheet_->UpdateWindow();
	//}
	//void SelectionsHandler::InvalidateDragBounds(const CCellRange& activeSelection)
	//{
	//	RECT rc=pSheet_->get_RangeRect(activeSelection);

	//}
//	void SelectionsHandler::SetActiveSelection(int leftCol,int topRow,int rightCol,int bottomRow)
//	{
//		//Selections* pCurSelections_=pSheet_->get_Selections();
//		SetActiveSelection(leftCol,topRow,rightCol,bottomRow);
//		/*
//#ifdef _DEBUG
//		_ASSERT(leftCol>=HEADER_COL);
//		_ASSERT(topRow>=HEADER_ROW);
//		ColHeader& ch=pSheet_->get_ColHeader();
//		int const col=ch.get_cols();
//		if(col>0)
//			_ASSERT(rightCol<pSheet_->get_ColHeader().get_cols());
//		if(pSheet_->get_RowHeader().get_rows()>0)
//			_ASSERT(bottomRow<pSheet_->get_RowHeader().get_rows());
//#endif
//		//vecSel_.clear();
//		CCell const oldActiveCell=pSheet_->GetActiveCell();
//		CCellRange const oldActiveSelection=activeSelection_;
//		activeSelection_.set(topRow,leftCol,bottomRow,rightCol);
//		if(!activeSelection_.Inside(pSheet_->GetActiveRow(),pSheet_->GetActiveCol()))
//		{
//			//activeCell_=activeSelection_.TopLeft();
//			pSheet_->SetActiveCell(activeSelection_.TopLeft());
//		}
//		if(pSheet_->IsWindow())
//			InvalidateWindow(oldActiveCell,oldActiveSelection);
//			*/
//	}
	//void SelectionsHandler::InvalidateContent(CCell const& oldActiveCell,const Selections& oldSelections,Int2Type<true>)
	//{
	//	InvalidateContent(oldActiveCell,oldSelections,Int2Type<false>);
	//	pSheet_->UpdateWindow();
	//}

	void SelectionsHandler::InvalidateContent(CCell const& oldActiveCell,const Selections& oldSelections,BOOL bUpdateWindow)const
	{
		if(oldSelections.IsSelectAll()!=IsSelectAll())
		{
			RECT const rc=pSheet_->raw_GetCellRect(CCell(IGNOR_ROW,IGNOR_COL));
			pSheet_->InvalidateRect(&rc,FALSE);
		}

		const bool bExpand=!(oldSelections.IsMultiSelectionMode()&&IsMultiSelectionMode());
		const static int nEXPAND_DELTA=3;
		CCellRange cr;
		CRgnLight rgn;
		if(pSheet_->GetScrollPart(cr)){
			//���±�ͷ�ػ���
			for(int r=cr.TopRow();r<=cr.BottomRow();++r){
				bool const bIn1=oldSelections.RowInSelections(r);
				bool const bIn2=baseClass::RowInSelections(r);
				//����ѡ�񼯺ϵ�����������������ѡ�񼯺�
				//���ཻ���䵫ǰ��״̬��һ����Ӧ�ػ�
				if((bIn1||bIn2) && !(bIn1 && bIn2)
					||(bIn1 && bIn2)&&IsFullColSelectedAtRow(r)!=oldSelections.IsFullColSelectedAtRow(r)
					)
				{
					pSheet_->InvalidateCell(CCell(r,HEADER_COL));
				}
			}
			for(int c=cr.LeftCol();c<=cr.RightCol();++c){
				bool const bIn1=oldSelections.ColInSelections(c);
				bool const bIn2=baseClass::ColInSelections(c);
				//����ѡ�񼯺ϵ�����������������ѡ�񼯺�
				//���ཻ���䵫ǰ��״̬��һ����Ӧ�ػ�
				if((bIn1||bIn2) && !(bIn1 && bIn2)
					||(bIn1 && bIn2)&&IsFullRowSelectedAtCol(c)!=oldSelections.IsFullRowSelectedAtCol(c)
					)
				{
					pSheet_->InvalidateCell(CCell(HEADER_ROW,c));
				}
			}
			//:~���±�ͷ�ػ���

			rgn.Clear();
			baseClass::Xor(oldSelections,rgn,&cr);
			for(LPCRECT lprc=rgn.GetFirst();lprc;lprc=rgn.GetNext(lprc)){
				RECT rc=*lprc;
				//if(bExpand){
				//	rc.left-=2;
				//	rc.top-=2;
				//	rc.right+=2;
				//	rc.bottom+=2;
				//}
				pSheet_->InvalidateRect(&rc,FALSE);
			}
		}
		if(pSheet_->GetFreezeRowsPart(cr)){
			//���±�ͷ�ػ���
			for(int r=cr.TopRow();r<=cr.BottomRow();++r){
				bool const bIn1=oldSelections.RowInSelections(r);
				bool const bIn2=baseClass::RowInSelections(r);
				//����ѡ�񼯺ϵ�����������������ѡ�񼯺�
				//���ཻ���䵫ǰ��״̬��һ����Ӧ�ػ�
				if((bIn1||bIn2) && !(bIn1 && bIn2)
					||(bIn1 && bIn2)&&IsFullColSelectedAtRow(r)!=oldSelections.IsFullColSelectedAtRow(r)
				)
				{
					pSheet_->InvalidateCell(CCell(r,HEADER_COL));
				}
			}
			//:~���±�ͷ�ػ���

			rgn.Clear();
			baseClass::Xor(oldSelections,rgn,&cr);
			for(LPCRECT lprc=rgn.GetFirst();lprc;lprc=rgn.GetNext(lprc)){
				RECT rc=*lprc;
				if(bExpand){
					::InflateRect(&rc,nEXPAND_DELTA,nEXPAND_DELTA);
				}
				pSheet_->InvalidateRect(&rc,FALSE);
			}
		}
		if(pSheet_->GetFreezeColsPart(cr)){
			//���±�ͷ�ػ���
			for(int c=cr.LeftCol();c<=cr.RightCol();++c){
				bool const bIn1=oldSelections.ColInSelections(c);
				bool const bIn2=baseClass::ColInSelections(c);
				//����ѡ�񼯺ϵ�����������������ѡ�񼯺�
				//���ཻ���䵫ǰ��״̬��һ����Ӧ�ػ�
				if((bIn1||bIn2) && !(bIn1 && bIn2)
					||(bIn1 && bIn2)&&IsFullRowSelectedAtCol(c)!=oldSelections.IsFullRowSelectedAtCol(c)
					)
				{
					pSheet_->InvalidateCell(CCell(HEADER_ROW,c));
				}
			}
			//:~���±�ͷ�ػ���

			rgn.Clear();
			baseClass::Xor(oldSelections,rgn,&cr);
			for(LPCRECT lprc=rgn.GetFirst();lprc;lprc=rgn.GetNext(lprc)){
				RECT rc=*lprc;
				if(bExpand){
					::InflateRect(&rc,nEXPAND_DELTA,nEXPAND_DELTA);
				}
				pSheet_->InvalidateRect(&rc,FALSE);
			}
		}
		if(pSheet_->GetFreezeAlthogonalPart(cr)){
			baseClass::Xor(oldSelections,rgn,&cr);
			for(LPCRECT lprc=rgn.GetFirst();lprc;lprc=rgn.GetNext(lprc)){
				RECT rc=*lprc;
				if(bExpand){
					::InflateRect(&rc,nEXPAND_DELTA,nEXPAND_DELTA);
				}
				pSheet_->InvalidateRect(&rc,FALSE);
			}
		}
		//invalidate DragCorner
		if(bExpand){
			const CCell oDragCornerCell=oldSelections.GetActiveSelection().RightBottom();
			const CCell nDragCornerCell=GetActiveSelection().RightBottom();
			if(!(oDragCornerCell==nDragCornerCell)){
				RECT rc=pSheet_->raw_GetCellRect(oDragCornerCell);
				SetRect(&rc,rc.right-5,rc.bottom-5,rc.right+2,rc.bottom+2);
				pSheet_->InvalidateRect(&rc,FALSE);
				rc=pSheet_->raw_GetCellRect(nDragCornerCell);
				SetRect(&rc,rc.right-5,rc.bottom-5,rc.right+2,rc.bottom+2);
				pSheet_->InvalidateRect(&rc,FALSE);
			}
		}
		//:~invalidate DragCorner

		const CCell newActiveCell=pSheet_->GetActiveCell();
		if(!(oldActiveCell==newActiveCell)||oldSelections.IsMultiSelectionMode()!=IsMultiSelectionMode()){
			RECT rcCell=pSheet_->GetVisibleCellRectEx(oldActiveCell);
			InflateRect(&rcCell,2,2);
			pSheet_->InvalidateRect(&rcCell,FALSE);
			rcCell=pSheet_->GetVisibleCellRectEx(newActiveCell);
			InflateRect(&rcCell,2,2);
			pSheet_->InvalidateRect(&rcCell,FALSE);
		}

		InvalidateActiveSelectionExpandBorder(oldSelections);
		//InvalidateActiveAdjoinEdges(oldSelections.GetActiveSelection(),GetActiveSelection());

		if(bUpdateWindow)
			pSheet_->UpdateWindow();
		/*
		const VisibleMergeCellMgr vmc=pSheet_->GetVisibleMergeCellMgr();
		vector<CMergeCell> const& mcs=vmc.GetMergeCells();
		for(vector<CMergeCell>::const_iterator it=mcs.begin();it!=mcs.end();++it)
		{
			_ASSERT(it->IsNormalize());
			RECT rc=pSheet_->get_RangeRect(it->TopRow(),it->LeftCol(),it->BottomRow(),it->RightCol());
			if(intersect(&rc,&rco) || intersect(&rc,&rcn))
				pSheet_->InvalidateRect(&rc,FALSE);
		}
		//pSheet_->GetMergeCells();
		*/
	}
	//�÷�����InvalidateContent����
	//void SelectionsHandler::InvalidateHeader(CCell const& oldActiveCell,const Selections& oldSelections)
	//{
	//	CCellRange cr;
	//	pSheet_->GetScrollPart(cr);
	//	for(int r=cr.TopRow();r<=cr.BottomRow();++r){
	//		bool const bIn1=oldSelections.RowInSelections(r);
	//		bool const bIn2=baseClass::RowInSelections(r);
	//		if((bIn1||bIn2) && !(bIn1 && bIn2)){//��ѡ�񼸺ε��������
	//			pSheet_->InvalidateCell(r,HEADER_COL);
	//		}
	//	}
	//	for(int c=cr.LeftCol();c<=cr.RightCol();++c){
	//		bool const bIn1=oldSelections.ColInSelections(c);
	//		bool const bIn2=baseClass::ColInSelections(c);
	//		if((bIn1||bIn2) && !(bIn1 && bIn2)){//��ѡ�񼸺ε��������
	//			pSheet_->InvalidateCell(HEADER_ROW,c);
	//		}
	//	}

	//	pSheet_->GetFreezeRowsPart(cr);
	//	for(int r=cr.TopRow();r<=cr.BottomRow();++r){
	//		bool const bIn1=oldSelections.RowInSelections(r);
	//		bool const bIn2=baseClass::RowInSelections(r);
	//		if((bIn1||bIn2) && !(bIn1 && bIn2)){//��ѡ�񼸺ε��������
	//			pSheet_->InvalidateCell(r,HEADER_COL);
	//		}
	//	}

	//	pSheet_->GetFreezeColsPart(cr);
	//	for(int c=cr.LeftCol();c<=cr.RightCol();++c){
	//		bool const bIn1=oldSelections.ColInSelections(c);
	//		bool const bIn2=baseClass::ColInSelections(c);
	//		if((bIn1||bIn2) && !(bIn1 && bIn2)){//��ѡ�񼸺ε��������
	//			pSheet_->InvalidateCell(HEADER_ROW,c);
	//		}
	//	}


	//	//oldSelections.get_RowsInSelections(
	//	/*
	//	CCellRange const newSel=pSheet_->get_Selection();
	//	int minr,maxr;
	//	MinMax<int>(oldActiveCellRange.TopRow(),oldActiveCellRange.BottomRow(),minr,maxr);
	//	const RECT rco=GetScrollRowHeaderRect(minr,maxr);
	//	const RECT rco1=GetFreezeRowHeaderRect(minr,maxr);
	//	MinMax<int>(newSel.TopRow(),newSel.BottomRow(),minr,maxr);
	//	const RECT rcn=GetScrollRowHeaderRect(minr,maxr);
	//	const RECT rcn1=GetFreezeRowHeaderRect(minr,maxr);
	//	BOOL bUnion=IsFullColSelected(oldActiveCellRange)!=IsFullColSelected(newSel);
	//	InvalidateRect(&rco,&rcn,bUnion);
	//	InvalidateRect(&rco1,&rcn1,bUnion);
	//	*/
	//}
		/*
		�÷�����InvalidateHeader������
	void SelectionsHandler::InvalidateColHeader(CCell const& oldActiveCell,const Selections& oldSelections)
	{
		int minc,maxc;
		MinMax<int>(oldActiveCellRange.LeftCol(),oldActiveCellRange.RightCol(),minc,maxc);
		RECT const rco=GetScrollColHeaderRect(minc,maxc);
		RECT const rco1=GetFreezeColHeaderRect(minc,maxc);

		CCellRange const newSel=pSheet_->get_Selection();
		MinMax<int>(newSel.LeftCol(),newSel.RightCol(),minc,maxc);
		RECT const rcn=GetScrollColHeaderRect(minc,maxc);
		RECT const rcn1=GetFreezeColHeaderRect(minc,maxc);
		BOOL const bUnion=IsFullRowSelected(oldActiveCellRange)!=IsFullRowSelected(newSel);
		InvalidateRect(&rco,&rcn,bUnion);
		InvalidateRect(&rco1,&rcn1,bUnion);
	}
		*/

	void SelectionsHandler::Selecting(int row,int col)
	{
		/*
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		CCell const oldActiveCell=pSheet_->GetActiveCell();//activeCell_;
		int const rows=rh.get_rows();
		int const cols=ch.get_cols();
		CCellRange const oldActiveCellRange=pSheet_->get_Selection();//activeSelection_;
		AtlTrace(_T("\nSelection::Selecting row=%d,col=%d"),row,col);
		if(HEADER_ROW==row && HEADER_COL==col){
			activeSelection_.set(HEADER_ROW,HEADER_COL,rows-1,cols-1);
			pSheet_->put_MouseMode(MOUSE_SELECT_ALL);
			OnHeaderCornerClick();
			pSheet_->RedrawWindow();
			return;
		}else if(HEADER_ROW==row){
			activeSelection_.set(HEADER_ROW,pSheet_->GetActiveCol(),rows-1,col);
		}else if(HEADER_COL==col){
				activeSelection_.set(pSheet_->GetActiveRow(),HEADER_COL,row,cols-1);
		}else{
			activeSelection_.RightBottom().set(row,col);
		}
		InvalidateHeaderCorner(oldActiveCellRange);
		InvalidateHeader(oldActiveCell,oldActiveCellRange);
		InvalidateColHeader(oldActiveCell,oldActiveCellRange);
		InvalidateContent(oldActiveCell,oldActiveCellRange);

		pSheet_->ExpandDirtyActiveSelection(oldActiveCellRange,activeSelection_);
		//ExpandDirtyActiveSelection(activeSelection_);

		pSheet_->UpdateWindow();
		*/
	}

/*
	//crClip [in,out]
	void SelectionsHandler::InvalidateSelectionBorder(const Selections& ss,CCellRange& crClip)
	{
		const CCellRange acr(ss.GetActiveSelection());
		acr.GetInterset(crClip,crClip);
		CRect rc=pSheet_->get_RangeRect(crClip);
		rc.InflateRect(3,3,3,3);
		if(crClip.LeftCol()>=acr.LeftCol()){
			const RECT _rc={rc.left,rc.top,rc.left+6,rc.bottom};
			InvalidateRect(pSheet_->m_hWnd,&_rc,FALSE);
		}
		if(crClip.TopRow()>=acr.TopRow()){
			const RECT _rc={rc.left,rc.top,rc.right,rc.top+6};
			InvalidateRect(pSheet_->m_hWnd,&_rc,FALSE);
		}
		if(crClip.RightCol()<=acr.RightCol()){
			const RECT _rc={rc.right-7,rc.top,rc.right+1,rc.bottom};
			InvalidateRect(pSheet_->m_hWnd,&_rc,FALSE);
		}
		if(crClip.BottomRow()<=acr.BottomRow()){
			const RECT _rc={rc.left,rc.bottom-6,rc.right,rc.bottom};
			InvalidateRect(pSheet_->m_hWnd,&_rc,FALSE);
		}
	}
		*/

	//void SelectionsHandler::InvalidateHeaderCorner(const Selections& oldSelections)
	//{
	//	if(oldSelections.IsSelectAll()!=IsSelectAll())
	//	{
	//		RECT const rc=pSheet_->raw_GetCellRect(IGNOR_ROW,IGNOR_COL);
	//		pSheet_->InvalidateRect(&rc,FALSE);
	//		//AtlTrace(_T("\nInvalidate HeaderCorner rect(%d,%d,%d,%d)"),rc.left,rc.top,rc.right,rc.bottom);
	//	}
	//}
	/*
	//RECT SelectionsHandler::GetScrollRowHeaderRect(CCellRange const& cr)const
	//ȡScrollRowHeader������[firstRow,lastRow]�ཻ�ķ�Χ
	RECT SelectionsHandler::GetScrollRowHeaderRect(int firstRow,int lastRow)const
	{
		_ASSERT(firstRow<=lastRow);
		RECT rc={0};
		const RowHeader& rh=pSheet_->get_RowHeader();
		//int const topRow=rh.get_TopVisScrollRow();
		//int const bottomRow=rh.get_BottomVisScrollRow();
		//const int minSelRow=min(cr.TopRow(),cr.BottomRow());
		//const int maxSelRow=max(cr.TopRow(),cr.BottomRow());
		const int minRow=max(rh.get_TopVisScrollRow(),firstRow);
		const int maxRow=min(rh.get_BottomVisScrollRow(),lastRow);
		if(minRow<=maxRow){
			const int height=rh.get_DiffHeights(minRow,maxRow+1);
			rc=pSheet_->raw_GetCellRect(minRow,IGNOR_COL);
			rc.bottom=rc.top+height;
		}
		return rc;
	}
	//RECT SelectionsHandler::GetFreezeRowHeaderRect(int firstRow,int lastRow)const
	//ȡFreezeRowHeader������[firstRow,lastRow]�ཻ�ķ�Χ
	RECT SelectionsHandler::GetFreezeRowHeaderRect(int firstRow,int lastRow)const
	{
		_ASSERT(firstRow<=lastRow);
		RECT rc={0};
		const RowHeader& rh=pSheet_->get_RowHeader();
		//int const topRow=rh.get_TopVisScrollRow();
		//int const bottomRow=rh.get_BottomVisScrollRow();
		//const int minSelRow=min(cr.TopRow(),cr.BottomRow());
		//const int maxSelRow=max(cr.TopRow(),cr.BottomRow());
		const int minRow=max(rh.get_FreezeTopRow(),firstRow);
		const int maxRow=min(rh.get_FreezeBottomRow(),lastRow);
		if(minRow<=maxRow){
			const int height=rh.get_DiffHeights(minRow,maxRow+1);
			rc=pSheet_->raw_GetCellRect(minRow,IGNOR_COL);
			rc.bottom=rc.top+height;
		}
		return rc;
	}
	//RECT SelectionsHandler::GetScrollColHeaderRect(CCellRange const& cr)
	//ȡScrollColHeader������[firstCol,lastCol]�ཻ�ķ�Χ��������ཻ�򷵻ط�Χ{0,0,0,0}
	RECT SelectionsHandler::GetScrollColHeaderRect(int firstCol,int lastCol)const
	{
		RECT rc={0};
		const ColHeader& ch=pSheet_->get_ColHeader();
		const int minCol=max(ch.get_LeftVisScrollCol(),firstCol);
		const int maxCol=min(ch.get_RightVisScrollCol(),lastCol);
		if(minCol<=maxCol){
			int width=ch.get_DiffWidths(minCol,maxCol+1);
			rc=pSheet_->raw_GetCellRect(IGNOR_ROW,minCol);
			rc.right=rc.left+width;
		}
		return rc;
	}
	//ȡFreezeColHeader������[firstCol,lastCol]�ཻ�ķ�Χ��������ཻ�򷵻ط�Χ{0,0,0,0}
	RECT SelectionsHandler::GetFreezeColHeaderRect(int firstCol,int lastCol)const
	{
		RECT rc={0};
		const ColHeader& ch=pSheet_->get_ColHeader();
		const int minCol=max(ch.get_FreezeLeftCol(),firstCol);
		const int maxCol=min(ch.get_FreezeRightCol(),lastCol);
		if(minCol<=maxCol){
			int width=ch.get_DiffWidths(minCol,maxCol+1);
			rc=pSheet_->raw_GetCellRect(IGNOR_ROW,minCol);
			rc.right=rc.left+width;
		}
		return rc;
	}
	*/
	//RECT SelectionsHandler::GetRect(CCellRange const& cr)
	//{
	//	int _min,_max;
	//	MinMax<int>(cr.TopRow(),cr.BottomRow(),_min,_max);
	//	RECT rc=GetFreezeRowHeaderRect(_min,_max);
	//	RECT const rc1=GetScrollRowHeaderRect(_min,_max);
	//	if(rc.top==rc.bottom)
	//		rc=rc1;
	//	else if(rc1.top!=rc1.bottom)
	//		rc.bottom=rc1.bottom;

	//	MinMax<int>(cr.LeftCol(),cr.RightCol(),_min,_max);
	//	RECT const rc2=GetFreezeColHeaderRect(_min,_max);
	//	rc.left=rc2.left;
	//	rc.right=rc2.right;
	//	RECT const rc3=GetScrollColHeaderRect(_min,_max);
	//	if(rc.left==rc.right){
	//		rc.left=rc3.left;
	//		rc.right=rc3.right;
	//	}else if(rc3.left!=rc3.right)
	//		rc.right=rc3.right;

	//	/*
	//	if(rc1.top!=rc1.bottom){
	//		rc.top=rc1.top;
	//		rc.bottom=rc1.bottom;
	//	}
	//	if(rc2.top!=rc2.bottom){
	//		if(rc.top==rc.bottom)
	//			rc.top=rc2.top;
	//		rc.bottom=rc2.bottom;
	//	}
	//	if(rc3.left!=rc3.right){
	//		rc.left=rc3.left;
	//		rc.right=rc3.right;
	//	}
	//	*/
	//	return rc;
	//}
	/*
	//Result of lprc1 - lprc2 store into address of prc,prc need at least 4 RECTs memory
	//return value repesents amount of valid RECTS the prc point to.
	int rect_diff(LPCRECT lprc1,LPCRECT lprc2,RECT* prc)
	{
		_ASSERT(rect_contain(lprc1,lprc2));
		if(lprc1->left == lprc2->left && lprc1->right == lprc2->right){
			prc->left=lprc1->left;
			prc->right=lprc1->right;
			if(lprc1->top==lprc2->top){
				prc->top=lprc2->bottom;
				prc->bottom=lprc1->bottom;
			}else{
				prc->top=lprc1->top;
				prc->bottom=lprc2->top;
			}
			return 1;
		}else if(lprc1->top==lprc2->top && lprc1->bottom==lprc2->bottom){
			prc->top=lprc1->top;
			prc->bottom=lprc1->bottom;
			if(lprc1->left==lprc2->left){
				prc->left=lprc2->right;
				prc->right=lprc1->right;
			}else{
				prc->left=lprc1->left;
				prc->right=lprc2->left;
			}
			return 1;
		}else{
			if(lprc1->left==lprc2->left && lprc1->top==lprc2->top){
				SetRect(prc,lprc1->left,lprc2->bottom,lprc1->right,lprc1->bottom);
				SetRect(prc+1,lprc2->right,lprc1->top,lprc1->right,lprc2->bottom);
			}else if(lprc1->right==lprc2->right && lprc1->top==lprc2->top){
				SetRect(prc,lprc1->left,lprc1->top,lprc2->left,lprc1->bottom);
				SetRect(prc+1,lprc2->left,lprc2->bottom,lprc1->right,lprc1->bottom);
			}else if(lprc1->left==lprc2->left && lprc1->bottom==lprc2->bottom){
				SetRect(prc  ,lprc1->left,lprc1->top,lprc1->right,lprc2->top);
				SetRect(prc+1,lprc2->right,lprc2->top,lprc1->right,lprc1->bottom);
			}else{
				SetRect(prc  ,lprc1->left,lprc1->top,lprc1->right,lprc2->top);
				SetRect(prc+1,lprc1->left,lprc2->top,lprc2->left,lprc1->bottom);
			}
			return 2;
		}
	}
	int rect_xor(LPCRECT lprc1,LPCRECT lprc2,RECT* prc)
	{
		int _min,_max;
		if(lprc1->left==lprc2->left && lprc1->top==lprc2->top){
			MinMax<int>(lprc1->bottom,lprc2->bottom,_min,_max);
			SetRect(prc,lprc1->left,_min,min(lprc1->right,lprc2->right),_max);
			MinMax<int>(lprc1->right,lprc2->right,_min,_max);
			SetRect(prc+1,_min,lprc1->top,_max,min(lprc1->bottom,lprc2->bottom));
		}else if(lprc1->right==lprc2->right && lprc1->top==lprc2->top){
			MinMax<int>(lprc1->left,lprc2->left,_min,_max);
			SetRect(prc,_min,lprc1->top,_max,min(lprc1->bottom,lprc2->bottom));
			MinMax<int>(lprc1->bottom,lprc2->bottom,_min,_max);
			SetRect(prc+1,max(lprc1->left,lprc2->left),_min,lprc1->right,_max);
		}else if(lprc1->right==lprc2->right && lprc1->bottom==lprc2->bottom){
			MinMax<int>(lprc1->left,lprc2->left,_min,_max);
			SetRect(prc,_min,max(lprc1->top,lprc2->top),_max,lprc1->bottom);
			MinMax<int>(lprc1->top,lprc2->top,_min,_max);
			SetRect(prc+1,max(lprc1->left,lprc2->left),_min,lprc1->right,_max);
		}else if(lprc1->left==lprc2->left && lprc1->bottom==lprc2->bottom){
			MinMax<int>(lprc1->top,lprc2->top,_min,_max);
			SetRect(prc,lprc1->left,_min,min(lprc1->right,lprc2->right),_max);
			MinMax<int>(lprc1->right,lprc2->right,_min,_max);
			SetRect(prc+1,_min,max(lprc1->top,lprc2->top),_max,lprc1->bottom);
		}else{
			*prc=*lprc1;
			prc[1]=*lprc2;
		}
		return 2;
	}
	void SelectionsHandler::InvalidateRect(LPCRECT lprc1,LPCRECT lprc2,BOOL bUnion)
	{
		if(bUnion){
			pSheet_->InvalidateRect(lprc1,FALSE);
			pSheet_->InvalidateRect(lprc2,FALSE);
		}else{
			CRgnLight rgn;
			rect_xor(lprc1,lprc2,rgn);
			for(LPCRECT lprc=rgn.GetFirst();lprc;lprc= CRgnLight::GetNext(lprc))
			{
				pSheet_->InvalidateRect(lprc,FALSE);
			}
		}
	}
	*/
	//{
	//	pSheet_->InvalidateRect(lprc1,FALSE);
	//	pSheet_->InvalidateRect(lprc2,FALSE);
	//	//if(!intersect(lprc1,lprc2)){
	//	//	pSheet_->InvalidateRect(lprc1,FALSE);
	//	//	//pSheet_->UpdateWindow();
	//	//	pSheet_->InvalidateRect(lprc2,FALSE);
	//	//	//pSheet_->UpdateWindow();
	//	//	return ;
	//	//}
	//	//if(!bSelecting/*intersect(lprc1,lprc2) || rect_adjoin(lprc1,lprc2)*/){
	//	//	RECT rc;
	//	//	UnionRect(&rc,lprc1,lprc2);
	//	//	pSheet_->InvalidateRect(&rc,FALSE);
	//	//	//pSheet_->UpdateWindow();
	//	//	return ;
	//	//}
	//	//RECT arc[4];
	//	//int nRect=0;
	//	//if(rect_contain(lprc1,lprc2))
	//	//	nRect=rect_diff(lprc1,lprc2,arc);
	//	//else if(rect_contain(lprc2,lprc1))
	//	//	nRect=rect_diff(lprc2,lprc1,arc);
	//	//else{
	//	//	nRect=rect_xor(lprc1,lprc2,arc);
	//	//	_ASSERT(nRect<=4);
	//	//}
	//	//for(int i=0;i<nRect;++i){
	//	//	pSheet_->InvalidateRect(&arc[i],FALSE);
	//	//	//pSheet_->UpdateWindow();
	//	//}
	//}
	void SelectionsHandler::SelectCells(CCell cell,const CCellRange& oldCR)
	{
		/*
		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();
		int const cols=ch.get_cols();
		int const rows=rh.get_rows();
		int autoScrollType_=0;
		if(cell.row>=bottomRow)
			autoScrollType_|=AS_DOWN;
		else if(cell.row<topRow){
			autoScrollType_|=AS_UP;
			if(0==topRow)
				return ;
			else if(cell.row<0)
				cell.row=topRow-1;
		}
		if(cell.col>=rightCol)
			autoScrollType_|=AS_RIGHT;
		else if(cell.col<leftCol){
			autoScrollType_|=AS_LEFT;
			if(0==leftCol)
				return;
			else if(cell.col<0)
				cell.col=leftCol-1;
		}
		if(HEADER_ROW==cell.row)
			cell.row=topRow>0?topRow-1:topRow;
		if(HEADER_COL==cell.col)
			cell.col=leftCol>0?leftCol-1:leftCol;
		if(cell.row>=bottomRow && cell.row<rows || cell.row<topRow
			|| cell.col>rightCol && cell.col<cols ||cell.col<leftCol
			){
				if(cell.col>=cols)
					cell.col=cols-1;
				if(cell.row>=rows)
					cell.row=rows-1;
				if(cell.row<0)
					cell.row=0;
				if(cell.col<0)
					cell.col=0;
				InvalidateWindow(pSheet_->GetActiveCell(),oldCR);
				//pSheet_->EnsureVisible(cell.row,cell.col);
				pSheet_->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
			}
			if(!(cell.row==activeSelection_.BottomRow()
				&& cell.col==activeSelection_.RightCol()))
				Selecting(cell.row,cell.col);
			pSheet_->EnsureVisible(cell.row,cell.col);
			*/
	}
	////����newActiveSelection Ӧ���Ѿ������ཻ��
	////�ϲ���Ԫ����н������˵ġ�
	//void SelectionsHandler::SetActiveSelection(const CCellRange& newActiveSelection)
	//{
	//	//const Selections& oss=this;
	//	//const CCellRange oldActiveSelection=GetActiveSelection();
	//	baseClass::SetActiveSelection(newActiveSelection);//.TopLeft(),newActiveSelection.RightBottom());
	//	//InvalidateActiveAdjoinEdges(oldActiveSelection,newActiveSelection);
	//	//InvalidateDirtyBorderOnFreezeLine(oldActiveSelection,newActiveSelection);
	//	//InvalidateActiveSelectionExpandBorder(oss);
	//	//InvalidateActiveSelectionExpandBorder(this);
	//	/*
	//	CCellRange cr(oldActiveSelection.TopRow(),oldActiveSelection.RightCol()+1,oldActiveSelection.BottomRow(),oldActiveSelection.RightCol()+1);
	//	RECT rc=pSheet_->get_RangeRect(cr);
	//	if(!IsRectEmpty(&rc)){
	//		SetRect(&rc,rc.left,rc.top-2,rc.left+2,rc.bottom+2);
	//		pSheet_->InvalidateRect(&rc,FALSE);
	//	}
	//	*/
	//}
	//���ѡ���������ʹ���border������Ч
	void SelectionsHandler::InvalidateActiveSelectionExpandBorder(const Selections& oss)const
	{
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		//int const rows=pSheet_->get_RowHeader().get_rows();
		//int const cols=pSheet_->get_ColHeader().get_cols();
		int const nLeftFreezeCol=ch.get_FreezeLeftCol();
		int const nRightFreezeCol=ch.get_FreezeRightCol();
		int const nTopFreezeRow=rh.get_FreezeTopRow();
		int const nBottomFreezeRow=rh.get_FreezeBottomRow();
		int const nLeftVisScrollCol=ch.get_LeftVisScrollCol();
		int const nTopVisScrollRow=rh.get_TopVisScrollRow();
		int const nRightVisScrollCol=ch.get_RightVisScrollCol();
		int const nBottomVisScrollRow=rh.get_BottomVisScrollRow();

		CCellRange cr;cr.SetNull();
		//const CCellRange oacr(oss.IsMultiSelectionMode()?cr:oss.GetActiveSelection());
		//const CCellRange nacr(IsMultiSelectionMode()?cr:GetActiveSelection());
		const CCellRange oacr(oss.GetActiveSelection());
		const CCellRange nacr(GetActiveSelection());
		vector<CCellRange> vec;
		oacr.Xor(nacr,vec);
		for(vector<CCellRange>::const_iterator it=vec.begin();it!=vec.end();++it){
			const CCellRange& acr=*it;
			pSheet_->InvalidateCellRange(&acr);//���в���ȥ��

			//int col=acr.RightCol()+1;
			int col=pSheet_->GetNextCol(acr.RightCol());
			if(col==acr.RightCol())
				++col;
			//��Ч��������Ͳ���
			if(col>=nLeftVisScrollCol && col<=nRightVisScrollCol 
				|| col>=nLeftFreezeCol && col<=nRightFreezeCol)
			{
				cr.set(acr.TopRow(),col,acr.BottomRow(),col);
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left,rc.top-2,rc.left+2,rc.bottom+2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч��������Ͳ���
			//col=acr.LeftCol()-1;
			col=pSheet_->GetPreCol(acr.LeftCol());
			if(col==acr.LeftCol())
				--col;
			if(col>=nLeftVisScrollCol && col<=nRightVisScrollCol 
				|| col>=nLeftFreezeCol && col<=nRightFreezeCol)
			{
				cr.set(acr.TopRow(),col,acr.BottomRow(),col);
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.right-3,rc.top-2,rc.right,rc.bottom+2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч���ڱ���������
			col=acr.RightCol();
			if(col>=nLeftVisScrollCol && col<=nRightVisScrollCol 
				|| col>=nLeftFreezeCol && col<=nRightFreezeCol)
			{
				cr.set(acr.TopRow(),col,acr.BottomRow(),col);
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.right-3,rc.top,rc.right,rc.bottom);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч���ڱ���������
			col=acr.LeftCol();
			if(col>=nLeftVisScrollCol && col<=nRightVisScrollCol 
				|| col>=nLeftFreezeCol && col<=nRightFreezeCol)
			{
				cr.set(acr.TopRow(),col,acr.BottomRow(),col);
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left,rc.top,rc.left+2,rc.bottom);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}

			//��Ч��������Ͳ���
			//int row=acr.TopRow()-1;
			int row=pSheet_->GetPreRow(acr.TopRow());
			if(row==acr.TopRow()) 
				--row;
			if(row>=nTopVisScrollRow && row<=nBottomVisScrollRow
				|| row>=nTopFreezeRow && row<=nBottomFreezeRow)
			{
				CCellRange cr(row,acr.LeftCol(),row,acr.RightCol());
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left-2,rc.bottom-3,rc.right+2,rc.bottom);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч��������Ͳ���
			//row=acr.BottomRow()+1;
			row=pSheet_->GetNextRow(acr.BottomRow());
			if(row==acr.BottomRow())
				++row;
			if(row>=nTopVisScrollRow && row<=nBottomVisScrollRow
				|| row>=nTopFreezeRow && row<=nBottomFreezeRow)
			{
				CCellRange cr(row,acr.LeftCol(),row,acr.RightCol());
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left-2,rc.top,rc.right+2,rc.top+2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч���ڱ���������
			row=acr.TopRow();
			if(row>=nTopVisScrollRow && row<=nBottomVisScrollRow
				|| row>=nTopFreezeRow && row<=nBottomFreezeRow)
			{
				CCellRange cr(row,acr.LeftCol(),row,acr.RightCol());
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left,rc.top,rc.right,rc.top+2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
			//��Ч���ڱ���������
			row=acr.BottomRow();
			if(row>=nTopVisScrollRow && row<=nBottomVisScrollRow
				|| row>=nTopFreezeRow && row<=nBottomFreezeRow)
			{
				CCellRange cr(row,acr.LeftCol(),row,acr.RightCol());
				RECT rc=pSheet_->get_RangeRect(cr);
				if(!IsRectEmpty(&rc)){
					SetRect(&rc,rc.left,rc.bottom-3,rc.right,rc.bottom);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}

		}
	}
	//void SelectionsHandler::SetActiveSelection(int leftCol,int topRow,int rightCol,int bottomRow)
	void Selections::SetActiveSelection(int leftCol,int topRow,int rightCol,int bottomRow)
	{
		CCellRange cr(topRow,leftCol,bottomRow,rightCol);
		pSheet_->AdjustSelection(cr.Normalize());
		SetActiveSelection(cr);
	}

	enum EMoveType
	{
		EMT_NOTOVERPART=0,				//û�п����ƶ�
		EMT_FREEZEROW2SCROLLROW,//�Ӷ������ƶ���������
		EMT_SCROLLROW2FREEZEROW,//�ӹ����е�������
		EMT_FREEZECOL2SCROLLCOL,//�Ӷ����е�������
		EMT_SCROLLCOL2FREEZECOL,//�ӹ����е�������
	};
	void SelectionsHandler::TrackMultiCellSelection(CCell cell,BOOL bAppendSelection,EMouseMode mouseMode)
	{
		const HWND hWnd=pSheet_->m_hWnd;
		SetCapture(hWnd);
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		//const bool bFreezeRowVisible=rh.IsFreezeRowVisible();
		//const bool bFreezeColVisible=ch.IsFreezeColVisible();
		const int rows=rh.get_rows();
		const int cols=ch.get_cols();
		const int nFreezeTopRow=rh.get_FreezeTopRow();
		const int nFreezeLeftCol=ch.get_FreezeLeftCol();
		const int nFreezeBottomRow=rh.get_FreezeBottomRow();
		const int nFreezeRightCol=ch.get_FreezeRightCol();
		const int nLeftScrollableCol=ch.get_LeftScrollableCol();
		const int nTopScrollableRow=rh.get_TopScrollableRow();
		//_ASSERT(cell.row<rows);
		//_ASSERT(cell.col<cols);
		if(cell.row>=rows||cell.row<HEADER_ROW||cell.col<HEADER_COL||cell.col>=cols)
			return;
		CCell oldA=pSheet_->GetActiveCell();
		//cell.set(max(0,cell.row),max(0,cell.col));
		Selections oss=this;
		if(bAppendSelection){
			/*
			if(!oss.IsMultiSelectionMode()){
				CCellRange cr;
				if(pSheet_->GetScrollPart(cr))
					InvalidateSelectionBorder(oss,cr);
				if(pSheet_->GetFreezeAlthogonalPart(cr))
					InvalidateSelectionBorder(oss,cr);
				if(pSheet_->GetFreezeRowsPart(cr))
					InvalidateSelectionBorder(oss,cr);
				if(pSheet_->GetFreezeColsPart(cr))
					InvalidateSelectionBorder(oss,cr);
			}
			*/
			switch(mouseMode)
			{
			case MOUSE_SELECT_ROW:
				AddSelection(pSheet_->AdjustSelection(CCellRange(cell.row,HEADER_COL,cell.row,cols-1)));
				cell.col=ch.IsFreezeColVisible()?ch.get_FreezeLeftCol():ch.get_LeftVisScrollCol();
				break;
			case MOUSE_SELECT_COL:
				AddSelection(pSheet_->AdjustSelection(CCellRange(HEADER_ROW,cell.col,rows-1,cell.col)));
				cell.row=rh.IsFreezeRowVisible()?rh.get_FreezeTopRow():rh.get_TopVisScrollRow();
				break;
			case MOUSE_SELECT_CELLS:
			default:
				AddSelection(pSheet_->AdjustSelection(CCellRange(cell)));
			}
		}else{
			switch(mouseMode)
			{
			case MOUSE_SELECT_ROW:
				SetActiveSelection(cell.col,cell.row,cols-1,cell.row);
				cell.col=ch.IsFreezeColVisible()?ch.get_FreezeLeftCol():ch.get_LeftVisScrollCol();
				break;
			case MOUSE_SELECT_COL:
				SetActiveSelection(cell.col,HEADER_ROW,cell.col,rows-1);
				cell.row=rh.IsFreezeRowVisible()?rh.get_FreezeTopRow():rh.get_TopVisScrollRow();
				break;
			default:
				baseClass::SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
			}
			/*
			if(oss.IsMultiSelectionMode())
			{
				CCellRange cr;
				if(pSheet_->GetScrollPart(cr)){
					InvalidateSelectionBorder(*this,cr);
				}
				if(pSheet_->GetFreezeAlthogonalPart(cr))
					InvalidateSelectionBorder(*this,cr);
				if(pSheet_->GetFreezeRowsPart(cr))
					InvalidateSelectionBorder(*this,cr);
				if(pSheet_->GetFreezeColsPart(cr))
					InvalidateSelectionBorder(*this,cr);
			}
			*/
		}
		pSheet_->SetActiveCell<false>(min(rows-1,max(0,cell.row)),min(cols-1,max(0,cell.col)));
		InvalidateContent(oldA,oss,TRUE);
		//oldA=cell;
		//oss=this;
		RECT rcContent=pSheet_->get_CellAxisInfo().get_ScrollRect();
		pSheet_->ClientToScreen(&rcContent);

		int autoScrollType=0;
		MSG msg;
		while((::GetCapture()==hWnd)&&(GetMessage(&msg, NULL, 0, 0))){
			//if(hWnd!=msg.hwnd){
			//	DispatchMessage(&msg);
			//	break;
			//}
			//const int bottomRow=rh.get_BottomVisScrollRow();
			//const int rightCol=ch.get_RightVisScrollCol();
			const int nLeftVisScrollCol=ch.get_LeftVisScrollCol();
			const int nTopVisScrollRow=rh.get_TopVisScrollRow();
#ifdef _DEBUG
			TCHAR buf[256];
			GetClassName(msg.hwnd,buf,256);
			AtlTrace(_T("\n"));
			AtlTrace(buf);
#endif
			switch(msg.message)
			{
			case WM_MOUSEMOVE:
				{
					KillTimer(hWnd,ID_TIMER_SCROLL);
					oldA=pSheet_->GetActiveCell();
					oss=this;
					autoScrollType=0;
					POINT pt={GET_X_LPARAM(msg.lParam),GET_Y_LPARAM(msg.lParam)};
					//GetCursorPos(&pt);
					//cell=pSheet_->GetCellByScreenPos(pt.x,pt.y);
					cell=pSheet_->GetCellByPos(pt.x,pt.y);
					pSheet_->ClientToScreen(&pt);

					if(cell.col<0){
						//cell.col=max(0,bFreezeColVisible?nFreezeLeftCol:nLeftVisScrollCol-1);
						cell.col=max(0,nFreezeLeftCol);
					}
					if(cell.col>=cols)
						cell.col=cols-1;
					if(cell.row<0){
						//cell.row=max(0,bFreezeRowVisible?nFreezeTopRow:nTopVisScrollRow-1);
						cell.row=max(0,nFreezeTopRow);
					}
					if(cell.row>=rows)
						cell.row=rows-1;


		//	EMT_FREEZEROW2SCROLLROW,//�Ӷ������ƶ���������
		//EMT_SCROLLROW2FREEZEROW,//�ӹ����е�������
		//EMT_FREEZECOL2SCROLLCOL,//�Ӷ����е�������
		//EMT_SCROLLCOL2FREEZECOL,//�ӹ����е�������
					EMoveType emt=EMT_NOTOVERPART;
					if(/*(MOUSE_SELECT_ROW==mouseMode
						||MOUSE_SELECT_CELLS==mouseMode)
						&& */
						nTopVisScrollRow>nTopScrollableRow
						//&& rh.IsFreezeRowVisible()
						)
					{
						if(cell.row>nFreezeBottomRow 
							&& oss.GetActiveSelection().BottomRow()<=nFreezeBottomRow)
						{//�Ӷ������ƶ���������
							emt=EMT_FREEZEROW2SCROLLROW;
						}else if(cell.row<=nFreezeBottomRow
							&& oss.GetActiveSelection().BottomRow()>nFreezeBottomRow
							)
						{//�ӹ������ƶ���������
							emt=EMT_SCROLLROW2FREEZEROW;
						}
					}
					if((MOUSE_SELECT_COL==mouseMode
						||MOUSE_SELECT_CELLS==mouseMode)
						&& nLeftVisScrollCol>nLeftScrollableCol
						&& ch.IsFreezeColVisible())
					{
						if(cell.col>nFreezeRightCol
							&& oss.GetActiveSelection().RightCol()<=nFreezeRightCol)
						{//�Ӷ������ƶ���������
							emt=EMT_FREEZECOL2SCROLLCOL;
						}else if(cell.col<=nFreezeRightCol
							&& oss.GetActiveSelection().RightCol()>nFreezeRightCol)
						{//�ӹ����е�������
							emt=EMT_SCROLLCOL2FREEZECOL;
						}
					}
					//�Ӷ������ƶ���������
					if(EMT_FREEZEROW2SCROLLROW==emt)
					{
						//oss=this;
						cell.row=nTopScrollableRow;
						CCellRange acr(oldA,cell);
						if(MOUSE_SELECT_ROW==mouseMode)
							acr.set(oldA.row,HEADER_COL,cell.row,cols-1);
						pSheet_->AdjustSelection(acr.Normalize());
						//pSheet_->GetVisibleMergeCellMgr().ReCalculate(acr);
						ChangeActiveSelection(acr);
						InvalidateContent(oldA,oss,FALSE);
						pSheet_->EnsureVisible(cell);
						break;
					}

					//:~�ӹ������ƶ���������


					//�Ӷ������ƶ���������
					if(EMT_FREEZECOL2SCROLLCOL==emt)
					{
						//oss=this;
						cell.col=nLeftScrollableCol;
						CCellRange acr(oldA,cell);
						if(MOUSE_SELECT_COL==mouseMode)
							acr.set(HEADER_ROW,oldA.col,rows-1,cell.col);
						pSheet_->AdjustSelection(acr.Normalize());
						//pSheet_->GetVisibleMergeCellMgr().ReCalculate(acr);
						ChangeActiveSelection(acr);
						InvalidateContent(oldA,oss,TRUE);
						pSheet_->EnsureVisible(cell);
						break;
					}
					//:~�Ӷ������ƶ���������
					if((/*cell.row==rows||*/pt.y>rcContent.bottom)
						&& (MOUSE_SELECT_ROW==mouseMode
						|| MOUSE_SELECT_CELLS==mouseMode))
					//if(pt.y>rcContent.bottom)
					{
						autoScrollType|=AS_DOWN;
						cell.row=min(rh.get_BottomVisScrollRow()+1,rows-1);
					}
					if((/*cell.col==cols||*/pt.x>rcContent.right)
						&& (MOUSE_SELECT_COL==mouseMode
						|| MOUSE_SELECT_CELLS==mouseMode))
					{
						autoScrollType|=AS_RIGHT;
						cell.col=min(ch.get_RightVisScrollCol()+1,cols-1);
					}
					//if(cell.row<nTopVisScrollRow && nTopVisScrollRow>nTopScrollableRow //&& oldA.row>=nTopVisScrollRow
					//	&& (MOUSE_SELECT_ROW==mouseMode
					//	|| MOUSE_SELECT_CELLS==mouseMode)
					//	||EMT_SCROLLROW2FREEZEROW==emt)
					//{
					//	autoScrollType|=AS_UP;
					//	cell.row=max(0,nTopVisScrollRow-1);
					//}
					if((MOUSE_SELECT_ROW==mouseMode
						|| MOUSE_SELECT_CELLS==mouseMode)
						&&nTopVisScrollRow>nTopScrollableRow
						&&cell.row<oss.GetActiveSelection().BottomRow() && cell.row<nTopVisScrollRow
						)
					{
						autoScrollType|=AS_UP;
						cell.row=max(0,nTopVisScrollRow-1);
					}
					
					//if(cell.col<nLeftVisScrollCol && nLeftVisScrollCol>nLeftScrollableCol// && oldA.col>=nLeftVisScrollCol
					//	&& (MOUSE_SELECT_COL==mouseMode
					//	|| MOUSE_SELECT_CELLS==mouseMode)
					//	||EMT_SCROLLCOL2FREEZECOL==emt)
					if((MOUSE_SELECT_COL==mouseMode
						||MOUSE_SELECT_CELLS==mouseMode)
							&&nLeftVisScrollCol>nLeftScrollableCol
							&&cell.col<oss.GetActiveSelection().RightCol()
							&& cell.col<nLeftVisScrollCol
							)
					{
						autoScrollType|=AS_LEFT;
						cell.col=max(0,nLeftVisScrollCol-1);
					}
					if(autoScrollType){
						pSheet_->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
					}
					/*
					if(cell.col<0){
						cell.col=max(0,ch.get_LeftVisScrollCol());
					}
					if(cell.col>=cols)
						cell.col=cols-1;
					if(cell.row<0){
						cell.row=max(0,rh.get_TopVisScrollRow()-1);
					}
					*/
					//oss=this;
					{
						CCellRange acr(oldA,cell);
						if(MOUSE_SELECT_ROW==mouseMode)
							acr.set(oldA.row,HEADER_COL,cell.row,cols-1);
						else if(MOUSE_SELECT_COL==mouseMode)
							acr.set(HEADER_ROW,oldA.col,rows-1,cell.col);
						pSheet_->AdjustSelection(acr.Normalize());
						//pSheet_->GetVisibleMergeCellMgr().ReCalculate(acr);
						ChangeActiveSelection(acr);
						InvalidateContent(oldA,oss,FALSE);
						if(autoScrollType){
							if(MOUSE_SELECT_ROW==mouseMode){
								pSheet_->EnsureVisible(cell.row,nLeftVisScrollCol,FALSE);
							}else if(MOUSE_SELECT_COL==mouseMode){
								pSheet_->EnsureVisible(nTopVisScrollRow,cell.col,FALSE);
							}else{
								pSheet_->EnsureVisible(cell,FALSE);
							}
						}
						UpdateWindow(pSheet_->m_hWnd);
					}
				}break;
			case WM_TIMER:
				if(ID_TIMER_SCROLL==msg.wParam){
					oldA=pSheet_->GetActiveCell();
					oss=this;
					const int oldRow=cell.row;
					if(autoScrollType&AS_DOWN){
						if(cell.row==rows-1)
							KillTimer(hWnd,ID_TIMER_SCROLL);
						else
							cell.row=min(cell.row+1,rows-1);
					}
					if(autoScrollType&AS_RIGHT){
						if(cell.col==cols-1)
							KillTimer(hWnd,ID_TIMER_SCROLL);
						else
							cell.col=min(cell.col+1,cols-1);
					}
					if(autoScrollType&AS_UP){
						if(nTopVisScrollRow==nTopScrollableRow){
							KillTimer(hWnd,ID_TIMER_SCROLL);
							const CCell mouseCell=pSheet_->GetMouseCell();
							cell.row=max(mouseCell.row,0);
						}else{
							//cell.row=max(0,cell.row-1);
							cell.row=max(0,nTopVisScrollRow-1);
						}
					}
					if(autoScrollType&AS_LEFT){
						if(nLeftVisScrollCol==nLeftScrollableCol){
							KillTimer(hWnd,ID_TIMER_SCROLL);
							const CCell mouseCell=pSheet_->GetMouseCell();
							cell.col=max(mouseCell.col,0);
						}else
							cell.col=max(0,cell.col-1);
					}

					CCellRange acr(oldA,cell);
					if(MOUSE_SELECT_ROW==mouseMode)
						acr.set(oldA.row,HEADER_COL,cell.row,cols-1);
					else if(MOUSE_SELECT_COL==mouseMode)
						acr.set(HEADER_ROW,oldA.col,rows-1,cell.col);
					//acr.Normalize();
					//pSheet_->GetVisibleMergeCellMgr().ReCalculate(acr);
					pSheet_->AdjustSelection(acr.Normalize());
					ChangeActiveSelection(acr);
					InvalidateContent(oldA,oss,FALSE);
					if(MOUSE_SELECT_ROW==mouseMode){
						pSheet_->EnsureVisible(cell.row,nLeftVisScrollCol,FALSE);
					}else if(MOUSE_SELECT_COL==mouseMode){
						pSheet_->EnsureVisible(nTopVisScrollRow,cell.col,FALSE);
					}else{
						pSheet_->EnsureVisible(cell,FALSE);
					}
					UpdateWindow(pSheet_->m_hWnd);
					//pSheet_->Scroll_ResetScrollBars(TRUE,TRUE);
				}break;
			case WM_LBUTTONUP:
				{
					::ReleaseCapture();
				}break;
			default:
				DispatchMessage(&msg);
			}
		}
		KillTimer(hWnd,ID_TIMER_SCROLL);
		::ReleaseCapture();
	}
	void SelectionsHandler::TrackSingleCellSelection(CCell cell)
	{
		const HWND hWnd=pSheet_->m_hWnd;
		SetCapture(hWnd);
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		const int rows=rh.get_rows();
		const int cols=ch.get_cols();

		CCell oldA=pSheet_->GetActiveCell();
		//CCellRange ocr=activeSelection_;
		//Selections* pCurSelections_=pSheet_->get_Selections();
		Selections oss=static_cast<Selections*>(this);
		//activeSelection_.TopLeft()=cell;
		//activeSelection_.RightBottom()=cell;
		//baseClass::clear();
		baseClass::SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
		pSheet_->SetActiveCell<false>(cell);
		InvalidateContent(oldA,oss,TRUE);

		RECT rcContent=pSheet_->get_CellAxisInfo().get_ScrollRect();
		pSheet_->ClientToScreen(&rcContent);

		int autoScrollType=0;
		MSG msg;
		while((::GetCapture()==hWnd)&&(GetMessage(&msg, NULL, 0, 0))){
			//if(hWnd!=msg.hwnd){
			//	DispatchMessage(&msg);
			//	break;
			//}
			const int nLeftVisScrollCol=ch.get_LeftVisScrollCol();
			const int nTopVisScrollRow=rh.get_TopVisScrollRow();
			const int nLeftScrollableCol=ch.get_LeftScrollableCol();
			const int nTopScrollableRow=rh.get_TopScrollableRow();
			switch(msg.message)
			{
			case WM_MOUSEMOVE:
				{
			//const int bottomRow=rh.get_BottomVisScrollRow();
			//const int rightCol=ch.get_RightVisScrollCol();
					autoScrollType=0;
					POINT pt;
					GetCursorPos(&pt);
					//cell=GetMouseCell(pSheet_,pt);
					cell=pSheet_->GetCellByScreenPos(pt.x,pt.y);
					//pSheet_->ScreenToClient(&pt);
					//_ASSERT(cell.row<rows);

					if(cell.row==rows||pt.y>rcContent.bottom){
						autoScrollType|=AS_DOWN;
						cell.row=min(rh.get_BottomVisScrollRow()+1,rows-1);
					}
					if(cell.col==cols||pt.x>rcContent.right){
						autoScrollType|=AS_RIGHT;
						cell.col=min(ch.get_RightVisScrollCol()+1,cols-1);
					}
					if(cell.row<nTopVisScrollRow && nTopVisScrollRow>nTopScrollableRow){
						autoScrollType|=AS_UP;
						cell.row=max(0,nTopVisScrollRow-1);
					}
					if(cell.col<nLeftVisScrollCol && nLeftVisScrollCol>nLeftScrollableCol){
						autoScrollType|=AS_LEFT;
						cell.col=max(0,nLeftVisScrollCol-1);
					}
					if(autoScrollType){
						pSheet_->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
					}
					if(cell.col<0)
						cell.col=0;
					if(cell.col>=cols)
						cell.col=cols-1;
					if(cell.row<0)
						cell.row=0;
					oldA=pSheet_->GetActiveCell();
					oss=static_cast<Selections*>(this);
					SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
					pSheet_->SetActiveCell<false>(cell.row,cell.col);
					InvalidateContent(oldA,oss,TRUE);
					if(autoScrollType)
						pSheet_->EnsureVisible(cell);
				}break;
			case WM_TIMER:
				{
					if(autoScrollType&AS_DOWN){
						if(cell.row==rows-1)
							KillTimer(hWnd,ID_TIMER_SCROLL);
						else
							cell.row=min(cell.row+1,rows-1);
					}
					if(autoScrollType&AS_RIGHT){
						if(cell.col==cols-1)
							KillTimer(hWnd,ID_TIMER_SCROLL);
						else
							cell.col=min(cell.col+1,cols-1);
					}
					if(autoScrollType&AS_UP){
						if(nTopVisScrollRow==nTopScrollableRow){
							KillTimer(hWnd,ID_TIMER_SCROLL);
							const CCell mouseCell=pSheet_->GetMouseCell();//GetMouseCell(pSheet_,pt);
							cell.row=max(mouseCell.row,0);
						}else
							cell.row=max(0,cell.row-1);
					}
					if(autoScrollType&AS_LEFT){
						if(nLeftVisScrollCol==nLeftScrollableCol){
							KillTimer(hWnd,ID_TIMER_SCROLL);
							const CCell mouseCell=pSheet_->GetMouseCell();//GetMouseCell(pSheet_,pt);
							cell.col=max(mouseCell.col,0);
						}else
							cell.col=max(0,cell.col-1);
					}

					/*CCell*/ oldA=pSheet_->GetActiveCell();
					//CCellRange ocr=activeSelection_;
					oss=static_cast<Selections*>(this);
					SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
					//activeSelection_.TopLeft()=cell;
					//activeSelection_.RightBottom()=cell;
					pSheet_->SetActiveCell<false>(cell);
					InvalidateContent(oldA,oss,TRUE);

					pSheet_->EnsureVisible(cell);
				}break;
			case WM_LBUTTONUP:
				{
					::ReleaseCapture();
					KillTimer(hWnd,ID_TIMER_SCROLL);
				}break;
			default:
				DispatchMessage(&msg);
			}
		}
		//pSheet_->EnsureVisible(cell.row,cell.col);
	}
	//LRESULT SelectionsHandler::OnLButtonDown(UINT,WPARAM wParam,LPARAM lParam,BOOL& bHandled)
	void SelectionsHandler::OnLButtonDown(const CELLHITTESTINFO& chi,WPARAM wParam)
	{
		//����HideCaret������SetFocus()����
		//SetFocus�������ڲ��༭�ؼ������٣�������
		//�����ٻ�ʹ����GetMessage/TranslateMessage��Ϣѭ��
		//��ijЩ����·������ҡ�����ʹ��HideCaret��������ص��
		//ExcelҲ�Dz������ع��ķ�ʽ��������ҵ�ԭ��
		//Ŀǰ�в������
		const HWND hWndFocus=GetFocus();
		::HideCaret(hWndFocus);

		ESelectionMode const esm=pSheet_->GetWorkbook()->get_SelectionMode();
		const bool bCtrlPressd=MK_CONTROL==(MK_CONTROL&wParam) && ESM_MULTISELECTION==esm/*pSheet_->get_AllowMultiSelectionMode()*/;
		POINT const point=chi.pt;//{LOWORD(lParam),HIWORD(lParam)};

		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		//ECellHitTestConstants hit;
		CCell const cell=chi.cell;//pSheet_->HitTest(point.x,point.y,hit);
		EMouseMode const mouseMode=(HEADER_ROW==cell.row && HEADER_COL==cell.col)?MOUSE_SELECT_ALL:(HEADER_ROW==cell.row?MOUSE_SELECT_COL:(HEADER_COL==cell.col?MOUSE_SELECT_ROW:MOUSE_SELECT_CELLS));
		switch(esm)
		{
		case ESM_SINGLECELL:
			if(MOUSE_SELECT_CELLS==mouseMode)
				TrackSingleCellSelection(cell);
			break;
		case ESM_SINGLELINE:
			break;
		case ESM_MULTILINE:
			break;
		case ESM_SINGLESELECTION:
		case ESM_MULTISELECTION:
			if(MOUSE_SELECT_ALL==mouseMode){
				SelectAll(bCtrlPressd);
			}else{
				const bool bShiftPressed=MK_SHIFT==(MK_SHIFT&wParam);
				if(bShiftPressed){
					const CCell acell=pSheet_->GetActiveCell();
					const Selections oss=this;
					CCellRange acr(acell,cell);
					if(MOUSE_SELECT_ROW==mouseMode){
						acr.set(acell.row,HEADER_COL,cell.row,ch.get_cols()-1);
					}else if(MOUSE_SELECT_COL==mouseMode){
						acr.set(HEADER_ROW,acell.col,rh.get_rows()-1,cell.col);
					}
					acr.Normalize();
					ChangeActiveSelection(pSheet_->AdjustSelection(acr));
					bSelectAll_=false;
					InvalidateContent(acell,oss,TRUE);
				}else{
					TrackMultiCellSelection(cell,bCtrlPressd,mouseMode);
				}
			}
			break;
		}
		//SetFocus�����ڲ��༭�ؼ����������¼���
		pSheet_->SetFocus();
	}

		/*
	LRESULT SelectionsHandler::OnMouseMove(UINT ,WPARAM nFlags,LPARAM lParam,BOOL& bHandled)
	{
		bHandled=FALSE;
		Worksheet* pSheet=pSheet_;
		HWND const hWnd=pSheet->m_hWnd;
		CCellRange const oldCR=activeSelection_;

		POINT const point={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
		EMouseMode const mouseMode=pSheet_->get_MouseMode();
		// If the left mouse button is down, then process appropriately
		if (nFlags & MK_LBUTTON) 
		{
			switch(mouseMode)
			{ 
			case MOUSE_SELECT_ALL:
				bHandled=TRUE;
				break;

			case MOUSE_SELECT_COL:
			case MOUSE_SELECT_ROW:    
			case MOUSE_SELECT_CELLS:    
				{
					bHandled=TRUE;
					ECellHitTestConstants hit;
					CCell cell=pSheet->HitTest(point.x,point.y,hit);
					switch(mouseMode)
					{
					case MOUSE_SELECT_COL:
						{
							cell.row=activeSelection_.BottomRow();
							autoScrollType_=0;
							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();
							int const cols=ch.get_cols();
							if(cell.col>=rightCol)
								autoScrollType_|=AS_RIGHT;
							else if(cell.col<leftCol)
								autoScrollType_|=AS_LEFT;
							if(HEADER_COL==cell.col)
								cell.col=leftCol>0?leftCol-1:leftCol;
							if(cell.col>=rightCol && cell.col<cols ||cell.col<leftCol){
								if(cell.col>=cols)
									cell.col=cols-1;
								if(cell.col<0)
									cell.col=0;
								InvalidateWindow(pSheet_->GetActiveCell(),oldCR);
								pSheet->EnsureVisible(topRow,cell.col);
								pSheet->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
							}
						}break;
					case MOUSE_SELECT_ROW:    
						{
							cell.col=activeSelection_.RightCol();
							autoScrollType_=0;
							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 rows=rh.get_rows();
							if(cell.row>=bottomRow)
								autoScrollType_|=AS_DOWN;
							else if(cell.row<topRow)
								autoScrollType_|=AS_UP;
							if(HEADER_ROW==cell.row)
								cell.row=topRow>0?topRow-1:topRow;
							if(cell.row>=bottomRow && cell.row<rows || cell.row<topRow){
								if(cell.row>=rows)
									cell.row=rows-1;
								if(cell.row<0)
									cell.row=0;
								InvalidateWindow(pSheet_->GetActiveCell(),oldCR);
								pSheet->EnsureVisible(cell.row,leftCol);
								pSheet->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
							}
						}break;
					case MOUSE_SELECT_CELLS:
						{
							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();
							int const cols=ch.get_cols();
							int const rows=rh.get_rows();
							autoScrollType_=0;
							if(cell.row>=bottomRow)
								autoScrollType_|=AS_DOWN;
							else if(cell.row<topRow)
								autoScrollType_|=AS_UP;
							if(cell.col>=rightCol)
								autoScrollType_|=AS_RIGHT;
							else if(cell.col<leftCol)
								autoScrollType_|=AS_LEFT;

							if(HEADER_ROW==cell.row)
								cell.row=topRow>0?topRow-1:topRow;
							if(HEADER_COL==cell.col)
								cell.col=leftCol>0?leftCol-1:leftCol;
							if(cell.row>=bottomRow && cell.row<rows || cell.row<topRow
								|| cell.col>rightCol && cell.col<cols ||cell.col<leftCol
								){
								if(cell.col>=cols)
									cell.col=cols-1;
								if(cell.row>=rows)
									cell.row=rows-1;
								if(cell.row<0)
									cell.row=0;
								if(cell.col<0)
									cell.col=0;
								InvalidateWindow(pSheet_->GetActiveCell(),oldCR);
								pSheet->EnsureVisible(cell.row,cell.col);
								pSheet->SetTimer(ID_TIMER_SCROLL,TIME_INTERVAL);
							}
						}break;
					default:
						_ASSERT(FALSE);
						//AtlTrace(_T("\nSelection::OnMouseMove mouseMode=%D"),mouseMode);
					}
					if(!(cell.row==activeSelection_.BottomRow()
						&& cell.col==activeSelection_.RightCol()))
						Selecting(cell.row,cell.col);
					break;
				}
				//#ifndef GRIDCONTROL_NO_DRAGDROP
				//			case MOUSE_PREPARE_DRAG:   
				//				OnBeginDrag();    
				//				break;
				//#endif
			}    
		}
		return 0;
	}
	LRESULT SelectionsHandler::OnLButtonUP(UINT uMsg,WPARAM wParam,LPARAM lParam,BOOL& bHandled)
	{
		bHandled=FALSE;
		pSheet_->KillTimer(ID_TIMER_SCROLL);
		return 0;
	}
		*/
//		RECT rect;
//		pSheet->GetClientRect(&rect);
//		POINT const point={GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam)};
//		//if(point.x>=rect.right || point.y>=rect.bottom)
//		//	return 0;
//		//#ifndef _WIN32_WCE_NO_CURSOR
//		//		ClipCursor(NULL);
//		//#endif
//		HWND const hWnd=pSheet->m_hWnd;
//		if (GetCapture() == hWnd)
//			ReleaseCapture();
//
//		ECellHitTestConstants hit;
//		CCell const cell=pSheet->HitTest(point.x,point.y,hit);
//		//POINT const LeftClickDownPoint=m_LeftClickDownPoint;
//		EMouseMode const mouseMode=pSheet->get_MouseMode();
//		switch(mouseMode)
//		{
//			// m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
//			// and then didn't move mouse before clicking up (releasing button)
//		case MOUSE_PREPARE_EDIT:
//			{
//				//OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
//			}break;
//#ifndef GRIDCONTROL_NO_DRAGDROP
//			// m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
//			// and then didn't move mouse before clicking up (releasing button)
//		case MOUSE_PREPARE_DRAG:
//			{
//				//ResetSelectedRange();
//			}break;
//#endif
//		}
//
//		pSheet->put_MouseMode(MOUSE_NOTHING);
//		//return pSheet->DefWindowProc(uMsg,wParam,lParam);
//		return 0;
//	}
	void SelectionsHandler::MoveHome()
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		int const nTopScrollableRow=rh.get_TopScrollableRow();
		int const nLeftScrollableCol=ch.get_LeftScrollableCol();
		CCell cell=pSheet_->GetActiveCell();
		if(nTopScrollableRow!=cell.row && nLeftScrollableCol!=cell.col){
			CCell const oldActiveCell=cell;
			const Selections oss=this;
			//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
			//activeCell_.set(0,0);
			//pSheet_->SetActiveCell(0,0);
			//Selections* pCurSelections_=pSheet_->get_Selections();
			cell=pSheet_->SetActiveCell<false>(nTopScrollableRow,nLeftScrollableCol);
			SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
			//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			pSheet_->EnsureVisible(cell);
			InvalidateContent(oldActiveCell,oss,TRUE);
		}else
			pSheet_->EnsureVisible(cell);
	}
	void SelectionsHandler::MoveEnd()
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		int const rows=rh.get_rows();
		int const cols=ch.get_cols();
		CCell cell=pSheet_->GetActiveCell();
		if(rows-1!=cell.row && cols-1!=cell.col){
			CCell const oldActiveCell=cell;
			//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
			//activeCell_.set(rows-1,cols-1);
			//Selections* pCurSelections_=pSheet_->get_Selections();
			const Selections oss=static_cast<Selections*>(this);
			SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell=pSheet_->SetActiveCell<false>(rows-1,cols-1))));
			//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			pSheet_->EnsureVisible(cell);
			InvalidateContent(oldActiveCell,oss,TRUE);
		}else
			pSheet_->EnsureVisible(cell);
	}
	void SelectionsHandler::MoveLineHome()
	{
		int const nLeftScrollableCol=pSheet_->get_ColHeader().get_LeftScrollableCol();
		CCell cell=pSheet_->GetActiveCell();
		if(nLeftScrollableCol!=cell.col){
			CCell const oldActiveCell=cell;
			//Selections* pCurSelections_=pSheet_->get_Selections();
			const Selections oss=static_cast<Selections*>(this);
			//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
			SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell=pSheet_->SetActiveCol(nLeftScrollableCol))));
			//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			//ColHeader& ch=pSheet_->get_ColHeader();
			pSheet_->EnsureVisible(cell);
			InvalidateContent(oldActiveCell,oss,TRUE);
		}else
			pSheet_->EnsureVisible(cell);
	}
	void SelectionsHandler::MoveLineEnd()
	{
		ColHeader& ch=pSheet_->get_ColHeader();
		int const cols=ch.get_cols()-1;
		CCell cell=pSheet_->GetActiveCell();
		if(cols!=cell.col){
			CCell const oldActiveCell=cell;//pSheet_->GetActiveCell();
			//Selections* pCurSelections_=pSheet_->get_Selections();
			const Selections oss=static_cast<Selections*>(this);
			//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
			SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell=pSheet_->SetActiveCol(cols))));
			//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			//ColHeader& ch=pSheet_->get_ColHeader();
			pSheet_->EnsureVisible(cell);
			InvalidateContent(oldActiveCell,oss,TRUE);
		}else
			pSheet_->EnsureVisible(cell);
	}
	void SelectionsHandler::MoveNextPage()
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		int const rows=rh.get_rows();
		int const topRow=rh.get_TopVisScrollRow();
		int bottomRow=rh.get_BottomVisScrollRow();
		if(pSheet_->IsRowFullVisible(bottomRow)&&bottomRow<rows){
			++bottomRow;
		}
		const CellAxisInfo& cai=pSheet_->get_CellAxisInfo();
		CRect const rc=cai.get_ScrollRect();
		int hi=0,height=rc.bottom-rc.top;
		int i=bottomRow;
		for(;i!=rows;++i){
			hi+=rh.get_RowHeight(i);
			if(hi>=height){
				CCell activeCell=pSheet_->SetActiveRow(pSheet_->GetActiveRow()+bottomRow-topRow);
				//int const diff=rh.get_DiffHeights(topRow,bottomRow);
				//int const nPos=pSheet_->GetScrollPos32(SB_VERT);
				//pSheet_->Scroll_SetScrollPos32(SB_VERT,nPos+diff);
				pSheet_->put_TopVisScrollRow(bottomRow);//,rc.Height()/*&rc*/);
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
				pSheet_->get_Selections()->SetActiveSelection(pSheet_->AdjustSelection(CCellRange(activeCell)));
				//pSheet_->RedrawWindow();
				const RECT rcDirty={0,cai.HFreezeAxis,cai.VClientAxis,cai.HClientAxis};
				pSheet_->InvalidateRect(&rcDirty,FALSE);

				if(pSheet_->IsRowFullVisible(rows-1)){
					//SCROLLINFO si={sizeof(SCROLLINFO),SIF_RANGE};//SIF_POS|SIF_RANGE|SIF_PAGE;
					//pSheet_->Scroll_GetVScrollInfo(/*SB_VERT,*/&si);
					//pSheet_->Scroll_SetVScrollPos32(/*SB_VERT,*/si.nMax);
					pSheet_->Scroll_ResetVScrollBar();///*SB_VERT,*/si.nMax);
				}
				pSheet_->UpdateWindow();
				return ;
			}
		}
		if(i==rows){
			if(!pSheet_->IsRowFullVisible(rows-1)){
				CCell const oldActiveCell=pSheet_->GetActiveCell();
				pSheet_->EnsureVisible(rows-1,oldActiveCell.col);
				//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
				//Selections* pCurSelections_=pSheet_->get_Selections();
				const Selections oss=static_cast<Selections*>(this);
				int const row=oldActiveCell.row+rows-rh.get_TopVisScrollRow();
				const CCell cell=row<rows?pSheet_->SetActiveRow(row):oldActiveCell;
				/*
				if(row<rows)
					cell=pSheet_->SetActiveRow(row);
				else
					pSheet_->GetActiveCell(cell.row,cell.col);
					*/
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
				
				InvalidateContent(oldActiveCell,oss,TRUE);
				pSheet_->EnsureVisible(cell);
			}
			SCROLLINFO si;
			si.cbSize = sizeof(SCROLLINFO);
			si.fMask = SIF_RANGE;//SIF_POS|SIF_RANGE|SIF_PAGE;
			pSheet_->Scroll_GetVScrollInfo(/*SB_VERT, */&si);
			//pSheet_->Scroll_SetVScrollPos32(/*SB_VERT,*/si.nMax);
			pSheet_->Scroll_ResetVScrollBar();
		}
	}
	void SelectionsHandler::MovePriorPage()
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		int topRow=rh.get_TopVisScrollRow();
		const CellAxisInfo& cai=pSheet_->get_CellAxisInfo();
		CRect const rc=cai.get_ScrollRect();
		int hi=0,height=rc.bottom-rc.top;
		for(;topRow>=rh.get_TopScrollableRow() && hi<=height;--topRow)
		{
			hi+=rh.get_RowHeight(topRow);
		}
		++topRow;
		if(hi>=height){
			//int const nPos=pSheet_->GetScrollPos32(SB_VERT);
			//pSheet_->Scroll_SetScrollPos32(SB_VERT,nPos-hi);
			pSheet_->put_TopVisScrollRow(topRow);//,rc.Height()/*&rc*/);
			CCell cell=pSheet_->GetActiveCell();
			cell=pSheet_->SetActiveRow(cell.row-(rh.get_BottomVisScrollRow()-topRow));
			pSheet_->get_Selections()->SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
			//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			//pSheet_->RedrawWindow();
			const RECT rcDirty={0,cai.HFreezeAxis,cai.VClientAxis,cai.HClientAxis};
			pSheet_->InvalidateRect(&rcDirty,FALSE);
			pSheet_->UpdateWindow();
		}else{
			CCell const oldActiveCell=pSheet_->GetActiveCell();
			if(!(pSheet_->IsCellFullVisible(topRow,oldActiveCell.col)
				&& pSheet_->IsCellFullVisible(oldActiveCell)))
			{
				pSheet_->EnsureVisible(topRow,oldActiveCell.col/*pSheet_->GetActiveCol()*/);
				//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
				//Selections* pCurSelections_=pSheet_->get_Selections();
				const Selections oss=static_cast<Selections*>(this);
				int const row=/*pSheet_->GetActiveRow()*/
					oldActiveCell.row-(rh.get_BottomVisScrollRow()-topRow);
				if(row>=0)
					pSheet_->SetActiveRow(row);
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(pSheet_->GetActiveCell())));
				InvalidateContent(oldActiveCell,oss,TRUE);
			}
		}
	}
	/**
	���ƻ��Ԫ��
	��������ƶ��򷵻�FALSE
	*/
	BOOL SelectionsHandler::MoveLeft()
	{
		//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
		ColHeader& ch=pSheet_->get_ColHeader();
		const Selections oss=this;
		//CCell newActiveCell=oldActiveCell;
		CCell cell=pSheet_->GetActiveCell();
		//������Թ�������������
		if(/*nLeftScrollableCol*/0!=cell.col){
			int const nLeftScrollableCol=ch.get_LeftScrollableCol();
			CCell const oldActiveCell=cell;
			//Selections* pCurSelections_=pSheet_->get_Selections();
			int const leftCol=ch.get_LeftVisScrollCol();
			const VisibleMergeCellMgr& vmc=pSheet_->GetVisibleMergeCellMgr();
			const CMergeCell* pMergeCells=vmc.GetMergeCells(pSheet_->GetActiveCell()/*GetActiveRow(),pSheet_->GetActiveCol()*/);
			_ASSERT(pMergeCells?pMergeCells->IsNormalize():TRUE);
			int newActiveCol=pSheet_->GetPreCol(pMergeCells?pMergeCells->LeftCol():oldActiveCell.col);
			if(ch.IsFreezeColVisible()&&newActiveCol<ch.get_FreezeLeftCol())
				newActiveCol=ch.get_FreezeLeftCol();
			cell=pSheet_->SetActiveCol(newActiveCol);
			//pMergeCells=vmc.GetMergeCells(cell);
			if(pMergeCells=vmc.GetMergeCells(cell)){
				_ASSERT(pMergeCells?pMergeCells->IsNormalize():TRUE);
				SetActiveSelection(*pMergeCells);//
				cell.col=pMergeCells->LeftCol();
			}else 
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));

			/*
			CCell _cell;
			bool const bOne=oss.IsOneCell(_cell);
			if(bOne && oldActiveCell.col==leftCol && _cell==oldActiveCell
				//&& oldSelection.TopLeft()==oldSelection.RightBottom()
				//&& oldSelection.TopLeft()==oldActiveCell 
				)
			{
				int const xDelta=(cell.col+1==oldActiveCell.col)?ch.get_ColWidth(cell.col):ch.get_DiffWidths(cell.col,oldActiveCell.col);
				int nPos=pSheet_->GetScrollPos32(SB_HORZ);
				pSheet_->Scroll_SetScrollPos32(SB_HORZ,max(0,nPos-xDelta));
				RECT const rcContent=pSheet_->get_CellAxisInfo().get_ScrollRect();
				int const newLeftCol=ch.put_LeftVisScrollCol(cell.col,&rcContent);
				if(newLeftCol!=leftCol){
					RECT rc=rcContent;
					rc.left+=ch.get_DiffWidths(oldActiveCell.col,oldActiveCell.col+2);//ch.get_ColWidth(oldActiveCell.col);
					rc.top=0;
					pSheet_->ScrollWindow(xDelta,0,&rc,&rc);
					rc.right=rc.left;//+xDelta;
					rc.left=rcContent.left;
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}//else
				//InvalidateWindow(oldActiveCell,oldSelection);
			if(ch.get_LeftScrollableCol()==cell.col)
				pSheet_->Scroll_SetScrollPos32(SB_HORZ,0);
				*/
			//InvalidateHeader(oldActiveCell,oss);
			////InvalidateColHeader(oldActiveCell,oss);
			InvalidateContent(oldActiveCell,oss);
		}
		pSheet_->EnsureVisible(cell);

		pSheet_->ExpandDirtyActiveSelection(&oss.GetActiveSelection(),&GetActiveSelection());
		//ExpandDirtyActiveSelection();
		pSheet_->UpdateWindow();
		return TRUE;
	}
	BOOL SelectionsHandler::MoveRight()
	{
		ColHeader& ch=pSheet_->get_ColHeader();
		//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
		int const cols=ch.get_cols();
		const Selections oss=this;
		CCell cell=pSheet_->GetActiveCell();
		if(cols-1!=cell.col/*pSheet_->GetActiveCol()*/){
			int const leftCol=ch.get_LeftVisScrollCol();
			int const rightCol=ch.get_RightVisScrollCol();
			CCell const oldActiveCell=cell;//pSheet_->GetActiveCell();
			//Selections* pCurSelections_=pSheet_->get_Selections();
			const VisibleMergeCellMgr& vmc=pSheet_->GetVisibleMergeCellMgr();
			const CMergeCell* pMergeCells=vmc.GetMergeCells(cell/*pSheet_->GetActiveRow(),pSheet_->GetActiveCol()*/);
			if(pMergeCells){
				_ASSERT(pMergeCells->IsNormalize());
				cell=pSheet_->SetActiveCol(pSheet_->GetNextCol(pMergeCells->RightCol()));
			}else{
				cell=pSheet_->SetActiveCol(pSheet_->GetNextCol(cell.col/*pSheet_->GetActiveCol()*/));
			}
			if(pMergeCells=vmc.GetMergeCells(cell)){
				SetActiveSelection(*pMergeCells);
				cell.col=pMergeCells->RightCol();
			}else{
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			}
			InvalidateContent(oldActiveCell,oss);
		}
		pSheet_->EnsureVisible(cell);//pSheet_->GetActiveRow(),pSheet_->GetActiveCol());

		pSheet_->ExpandDirtyActiveSelection(&oss.GetActiveSelection(),&GetActiveSelection());
		//ExpandDirtyActiveSelection(activeSelection_);
		pSheet_->UpdateWindow();

		AtlTrace(_T("SelectionsHandler::MoveRight leftCol=%d,rightcol=%d"),ch.get_LeftVisScrollCol(),ch.get_RightVisScrollCol());
		return TRUE;
	}

	BOOL SelectionsHandler::MoveUp()
	{
		//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
		RowHeader& rh=pSheet_->get_RowHeader();
		const Selections oss=this;
		CCell cell=pSheet_->GetActiveCell();
		//���Ͽ��Թ�������������
		if(/*nTopScrollableRow*/0!=cell.row/*pSheet_->GetActiveRow()*/){
			int const nTopScrollableRow=rh.get_TopScrollableRow();
			CCell const oldActiveCell=cell;//pSheet_->GetActiveCell();
			//Selections* pCurSelections_=pSheet_->get_Selections();

			const VisibleMergeCellMgr& vmc=pSheet_->GetVisibleMergeCellMgr();
			const CMergeCell* pMergeCells=vmc.GetMergeCells(cell);//pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			_ASSERT(pMergeCells?pMergeCells->IsNormalize():TRUE);
			//����ж�����ȷ�����Ϲ���������FreezeTopRow
			int newActiveRow=pSheet_->GetPreRow(pMergeCells?pMergeCells->TopRow():cell.row);
			if(rh.IsFreezeRowVisible()&&newActiveRow<rh.get_FreezeTopRow())
				newActiveRow=rh.get_FreezeTopRow();
			//:~����ж�����ȷ�����Ϲ���������FreezeTopRow
			cell=pSheet_->SetActiveRow(newActiveRow);
			if(pMergeCells=vmc.GetMergeCells(cell)){
				SetActiveSelection(*pMergeCells);
				cell.row=pMergeCells->TopRow();
			}else{
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());			
			}

			/*
			int const topRow=rh.get_TopVisScrollRow();
			CCell _cell;
			bool const bOneCell=oss.IsOneCell(_cell);
			if(bOneCell &&	oldActiveCell.row==topRow && _cell==oldActiveCell
				//&& oldSelection.TopLeft()==oldSelection.RightBottom()
				//&& oldSelection.TopLeft()==oldActiveCell
				)
			{
				const int yDelta=(pSheet_->GetActiveRow()+1==oldActiveCell.row)?rh.get_RowHeight(pSheet_->GetActiveRow()):rh.get_DiffHeights(pSheet_->GetActiveRow(),oldActiveCell.row);
				int nPos=pSheet_->GetScrollPos32(SB_VERT);
				pSheet_->Scroll_SetScrollPos32(SB_VERT,nPos-yDelta);
				RECT const rcContent=pSheet_->get_CellAxisInfo().get_ScrollRect();
				int const newTopRow=rh.put_TopVisScrollRow(cell.row,&rcContent);
				if(newTopRow!=topRow){
					RECT rc=rcContent;
					rc.top+=rh.get_DiffHeights(oldActiveCell.row,oldActiveCell.row+2);//rh.get_RowHeight(oldActiveCell.row);
					rc.left=0;
					pSheet_->ScrollWindow(0,yDelta,&rc,&rc);
					rc.bottom=rc.top;//+yDelta;
					rc.top=rcContent.top;
					pSheet_->InvalidateRect(&rc,FALSE);
				}
				//pSheet_->UpdateWindow();
			}//else
				//InvalidateWindow(oldActiveCell,oldSelection);
			if(rh.get_TopScrollableRow()==cell.row){
				pSheet_->Scroll_SetScrollPos32(SB_VERT,0);
			}
			*/
			//InvalidateColHeader(oldActiveCell,oss);
			//InvalidateHeader(oldActiveCell,oss);
			InvalidateContent(oldActiveCell,oss);
		}
		pSheet_->EnsureVisible(cell);//pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
		pSheet_->ExpandDirtyActiveSelection(&oss.GetActiveSelection(),&GetActiveSelection());
		//ExpandDirtyActiveSelection(activeSelection_);
		pSheet_->UpdateWindow();
		return TRUE;
	}
	BOOL SelectionsHandler::MoveDown()
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
		int const rows=rh.get_rows();
		const Selections oss=this;
		CCell cell=pSheet_->GetActiveCell();
		if(rows-1!=cell.row/*pSheet_->GetActiveRow()*/){
			int const topRow=rh.get_TopVisScrollRow();
			int const bottomRow=rh.get_BottomVisScrollRow();
			CCell const oldActiveCell=cell;//pSheet_->GetActiveCell();
			//Selections* pCurSelections_=pSheet_->get_Selections();

			const VisibleMergeCellMgr& vmc=pSheet_->GetVisibleMergeCellMgr();
			const CMergeCell* pMergeCells=vmc.GetMergeCells(cell);//pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
			if(pMergeCells){
				_ASSERT(pMergeCells->IsNormalize());
				cell=pSheet_->SetActiveRow(pSheet_->GetNextRow(pMergeCells->BottomRow()));
			}else{
				cell=pSheet_->SetActiveRow(pSheet_->GetNextRow(cell.row/*pSheet_->GetActiveRow()*/));
			}
			pMergeCells=vmc.GetMergeCells(cell);
			if(pMergeCells){
				//activeSelection_=*pMergeCells;
				SetActiveSelection(*pMergeCells);
				cell.row=pMergeCells->BottomRow();
			}else{
				SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
				//activeSelection_.set(pSheet_->GetActiveRow(),pSheet_->GetActiveCol(),pSheet_->GetActiveRow(),pSheet_->GetActiveCol());			
			}
			InvalidateContent(oldActiveCell,oss);
		}
		pSheet_->EnsureVisible(cell);//pSheet_->GetActiveRow(),pSheet_->GetActiveCol());
		pSheet_->ExpandDirtyActiveSelection(&oss.GetActiveSelection(),&GetActiveSelection());
		//ExpandDirtyActiveSelection(activeSelection_);
		//pSheet_->UpdateWindow();
		return TRUE;
	}
	void SelectionsHandler::OnEditCopy()
	{
		if(!IsMultiSelectionMode()){
			const CCellRange& acr=pSheet_->get_Selections()->GetActiveSelection();
			CCell const lt=acr.TopLeft();
			CCell const rb=acr.RightBottom();
			pSheet_->CopyToClipboard(lt.row,lt.col,rb.row,rb.col);
		}else{
			pSheet_->MessageBox(_T("���ܶԶ�������ʹ�ô����"),_T("mycell"),MB_OK|MB_ICONWARNING);
		}
	}
	LRESULT SelectionsHandler::OnKeyDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
	{
		UINT const nChar = (UINT) wParam;    // virtual-key code 
		//_DestroyInplaceWindow();
		if (IsCTRLpressed())
		{
			switch (nChar)
			{
			case 'A': 
				{
					/*
					RowHeader& rh=pSheet_->get_RowHeader();
					ColHeader& ch=pSheet_->get_ColHeader();
					//CCellRange oldSelection=pSheet_->get_Selection();//activeSelection_;
					//Selections* pCurSelections_=pSheet_->get_Selections();
					const Selections oss=static_cast<Selections*>(this);
					//activeSelection_.set(HEADER_ROW,HEADER_COL,rh.get_rows()-1,ch.get_cols()-1);
					SetActiveSelection(HEADER_ROW,HEADER_COL,rh.get_rows()-1,ch.get_cols()-1);
					//pSheet_->put_MouseMode(MOUSE_SELECT_ALL);
					//OnHeaderCornerClick();
					InvalidateWindow(pSheet_->GetActiveCell(),oss);
					*/
					SelectAll(false);
				}break;
	//#ifndef GRIDCONTROL_NO_CLIPBOARD
	//           case 'X': OnEditCut();        break;
	           case 'C': OnEditCopy();       break;
	//           case 'V': OnEditPaste();      break;
	//#endif
			}
		}
		switch(nChar)
		{
		case VK_RETURN:
			//if(!IsCTRLpressed())
			if(cellNextRow==get_EnterKeyMoveTo()){
				IsSHIFTpressed()?MoveUp():MoveDown();
				break;
			}
			//fall down
		case VK_TAB:
			{
				if(IsSHIFTpressed()){
					MoveLeft();
				}else{
					MoveRight();
				}
			}break;
		case VK_DOWN:	MoveDown();	break;
		case VK_UP:		MoveUp();	break;
		case VK_LEFT:
			{
				if(IsSHIFTpressed()){
				}else
					MoveLeft(); 
			}break;
		case VK_RIGHT:
			{
				if(IsSHIFTpressed()){
				}else
					MoveRight();
			}break;
		case VK_NEXT:	MoveNextPage();break;
		case VK_PRIOR:	MovePriorPage();break;
		case VK_HOME:
			IsCTRLpressed()?MoveHome():MoveLineHome();
			break;
		case VK_END:
			IsCTRLpressed()?MoveEnd():MoveLineEnd();
			break;
		}
		return 0;
	}
	//LRESULT SelectionsHandler::OnRButtonDown(UINT,WPARAM,LPARAM lParam,BOOL& bHandled)
	void SelectionsHandler::OnRButtonDown(const CELLHITTESTINFO& chi,WPARAM wParam)
	{
		//bHandled=FALSE;
		//SetFocus()�����ڲ��༭�ؼ����������¼���
		pSheet_->SetFocus();
		/*
		HitTestStruct hts;
		hts.pt.x=GET_X_LPARAM(lParam);
		hts.pt.y=GET_Y_LPARAM(lParam);
		const CCell cell=pSheet_->HitTest(hts.pt.x,hts.pt.y,hts.hit);
		*/
		const CCell cell=chi.cell;//pSheet_->GetCellByPos(GET_X_LPARAM(lParam),GET_Y_LPARAM(lParam));
		//Selections* pCurSelections_=pSheet_->get_Selections();
		if(CellInSelections(cell)){
			return ;
		}
		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();
		//const ESelectionMode esm=pSheet_->get_SelectionMode();
		//CCellRange const oldSelection=pSheet_->get_Selection();//activeSelection_;
		const Selections oss=this;
		CCell const oldActiveCell=pSheet_->GetActiveCell();
		if(cell.row>=topRow && cell.row<=bottomRow
			&& cell.col>=leftCol && cell.col<=rightCol)
		{
			pSheet_->SetActiveCell<false>(cell);
			SetActiveSelection(pSheet_->AdjustSelection(CCellRange(cell)));
		}else if(HEADER_ROW==cell.row && HEADER_COL==cell.col){
			const int row=rh.IsFreezeRowVisible()?rh.get_FreezeTopRow():topRow;
			const int col=ch.IsFreezeColVisible()?ch.get_FreezeLeftCol():leftCol;
			pSheet_->SetActiveCell<false>(row,col);
			//SetActiveSelection(HEADER_COL,HEADER_ROW,ch.get_cols()-1,rh.get_rows()-1);
			SelectAll();
		}else if(HEADER_ROW==cell.row){
			const int row=rh.IsFreezeRowVisible()?rh.get_FreezeTopRow():topRow;
			pSheet_->SetActiveCell<false>(row,cell.col);
			SetActiveSelection(cell.col,HEADER_ROW,cell.col,rh.get_rows()-1);
		}else if(HEADER_COL==cell.col){
			const int col=ch.IsFreezeColVisible()?ch.get_FreezeLeftCol():leftCol;
			pSheet_->SetActiveCell<false>(cell.row,col);
			SetActiveSelection(HEADER_COL,cell.row,ch.get_cols()-1,cell.row);
		}else{
			return ;
		}
		InvalidateContent(oldActiveCell,oss,TRUE);
		//pSheet_->SendNotifyMessageToListener(cell.row,cell.col,OCN_RBUTTONDOWN,(LPARAM)&hts);
		return ;
	}

	/*
	void SelectionsHandler::InvalidateDirtyBorderOnFreezeLine(const CCellRange& oldActiveSelection,const CCellRange& newActiveSelection)
	{
		const RowHeader& rh=pSheet_->get_RowHeader();
		const ColHeader& ch=pSheet_->get_ColHeader();
		if(rh.IsFreezeRowVisible()){
			const int topRow=oldActiveSelection.TopRow();
			const int nFreezeBottomRow=rh.get_FreezeBottomRow();
			if(topRow==nFreezeBottomRow+1 && topRow!=newActiveSelection.TopRow()
				||oldActiveSelection.BottomRow()==rh.get_TopVisScrollRow()-1
				)
			{
				const CCellRange cr(nFreezeBottomRow,
					max(oldActiveSelection.LeftCol(),ch.get_LeftVisScrollCol()),
					nFreezeBottomRow,
					min(oldActiveSelection.RightCol(),ch.get_RightVisScrollCol()));
				if(cr.LeftCol()<=cr.RightCol()){
					RECT rc=pSheet_->get_RangeRectPlain(cr);
					rc.top=rc.bottom;
					InflateRect(&rc,2,2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
		}
		if(ch.IsFreezeColVisible()){
			const int leftCol=oldActiveSelection.LeftCol();
			const int nFreezeRightCol=ch.get_FreezeRightCol();
			if(leftCol==nFreezeRightCol+1 && leftCol!=newActiveSelection.LeftCol()
				||oldActiveSelection.RightCol()==ch.get_LeftVisScrollCol()-1
				)
			{
				const CCellRange cr(
					max(oldActiveSelection.TopRow(),rh.get_TopVisScrollRow()),
					nFreezeRightCol,
					min(oldActiveSelection.BottomRow(),rh.get_BottomVisScrollRow()),
					nFreezeRightCol
					);
				if(cr.TopRow()<=cr.BottomRow()){
					RECT rc=pSheet_->get_RangeRectPlain(cr);
					rc.left=rc.right;
					InflateRect(&rc,2,2);
					pSheet_->InvalidateRect(&rc,FALSE);
				}
			}
		}
	}

	void SelectionsHandler::InvalidateActiveAdjoinEdges(const CCellRange& oldActiveSelection,const CCellRange& newActiveSelection)const
	{
		int const rows=pSheet_->get_RowHeader().get_rows();
		int const cols=pSheet_->get_ColHeader().get_cols();
		CCellRange cr1,cr2;
		vector<CCellRange> vec;
		oldActiveSelection.Xor(newActiveSelection,vec);
		for(vector<CCellRange>::const_iterator it=vec.begin();it!=vec.end();++it){
			//����������䲻��ȥ��
			pSheet_->InvalidateCellRange(&*it);

			int row=it->TopRow()-1;
			if(row>=0){
				cr1.set(row,it->LeftCol(),row,it->RightCol());
				if(cr1.GetInterset(oldActiveSelection,cr2)){
					pSheet_->InvalidateCellRangeBorder(&cr2);
				}
				if(cr1.GetInterset(newActiveSelection,cr1)){
					pSheet_->InvalidateCellRangeBorder(&cr1);
				}
			}
			row=it->BottomRow()+1;
			if(row<rows){
				cr1.set(row,it->LeftCol(),row,it->RightCol());
				if(cr1.GetInterset(oldActiveSelection,cr2)){
					pSheet_->InvalidateCellRangeBorder(&cr2);
				}
				if(cr1.GetInterset(newActiveSelection,cr1)){
					pSheet_->InvalidateCellRangeBorder(&cr1);
				}
			}
			int col=it->LeftCol()-1;
			if(col>=0){
				cr1.set(it->TopRow(),col,it->BottomRow(),col);
				if(cr1.GetInterset(oldActiveSelection,cr2)){
					pSheet_->InvalidateCellRangeBorder(&cr2);
				}
				if(cr1.GetInterset(newActiveSelection,cr1)){
					pSheet_->InvalidateCellRangeBorder(&cr1);
				}
			}
			col=it->RightCol()+1;
			if(col<cols){
				cr1.set(it->TopRow(),col,it->BottomRow(),col);
				if(cr1.GetInterset(oldActiveSelection,cr2)){
					pSheet_->InvalidateCellRangeBorder(&cr2);
				}
				if(cr1.GetInterset(newActiveSelection,cr1)){
					pSheet_->InvalidateCellRangeBorder(&cr1);
				}
			}
		}
	}
	*/

	////�޸Ļѡ�񼯣������ԭʼѡ�񼯺�
	//void SelectionsHandler::ChangeActiveSelection(const CCellRange& cr/*,const CCellRange* pClip*/)
	//{
	//	baseClass::ChangeActiveSelection(cr);
	//	InvalidateActiveAdjoinEdges(cr);
	//}
		/*
	LRESULT SelectionsHandler::OnTimer(UINT,WPARAM,LPARAM lParam,BOOL&)
	{
		RowHeader& rh=pSheet_->get_RowHeader();
		ColHeader& ch=pSheet_->get_ColHeader();
		RECT rcContent;
		pSheet_->GetClientRect(&rcContent);
		pSheet_->get_CellAxisInfo().get_ScrollRect(&rcContent);
		//CCellRange const oldCR=activeSelection_;
		//Selections* pCurSelections_=pSheet_->get_Selections();
		int const leftCol=ch.get_LeftVisScrollCol();
		int const rightCol=ch.get_RightVisScrollCol();
		int const topRow=rh.get_TopVisScrollRow();
		int const bottomRow=rh.get_BottomVisScrollRow();
		int const rows=rh.get_rows();
		int const cols=ch.get_cols();
		RECT const rcvScroll={0,rcContent.top,rcContent.right,rcContent.bottom};
		RECT const rchScroll={rcContent.left,0,rcContent.right,rcContent.bottom};
		if(autoScrollType_&AS_DOWN){
			if(bottomRow<rows-1){
				CCellRange acr=baseClass::GetActiveSelection();
				int acrBottomRow=acr.BottomRow();
				if(acrBottomRow<rows-1){
					acr.SetBottomRow(++acrBottomRow);
					SetActiveSelection(&acr);
				}
				//activeSelection_.SetBottomRow(bottomRow+1);
				rh.put_BottomVisScrollRow(acrBottomRow,&rcContent,TRUE);
				int const newTop=rh.get_TopVisScrollRow();
				int const yDelta=rh.get_DiffHeights(topRow,newTop);
				pSheet_->ScrollWindow(0,-yDelta,&rcvScroll,&rcvScroll);
				int const nScrollPos=pSheet_->GetScrollPos32(SB_VERT);
				pSheet_->Scroll_SetScrollPos32(SB_VERT,nScrollPos+yDelta);
			}else if(bottomRow==rows-1 && !pSheet_->IsCellFullVisible(bottomRow,HEADER_COL)){
				activeSelection_.SetBottomRow(bottomRow);
				pSheet_->EnsureVisible(bottomRow,leftCol);
			}
		}else if(autoScrollType_&AS_UP){
			if(topRow>0){
				//AtlTrace(_T("\nSelection::OnTimer topRow=%d"),topRow);
				CCellRange acr=baseClass::GetActiveSelection();
				int acrBottomRow=acr.BottomRow();
				if(acrBottomRow<
				activeSelection_.SetBottomRow(topRow-1);
				rh.put_TopVisScrollRow(activeSelection_.BottomRow(),&rcContent);
				int const newTop=rh.get_TopVisScrollRow();
				int const yDelta=rh.get_DiffHeights(newTop,topRow);
				pSheet_->ScrollWindow(0,yDelta,&rcvScroll,&rcvScroll);
				int const nScrollPos=pSheet_->GetScrollPos32(SB_VERT);
				pSheet_->Scroll_SetScrollPos32(SB_VERT,max(nScrollPos-yDelta,0));
			}
		}
		if(autoScrollType_&AS_RIGHT){
			if(rightCol<cols-1){
				activeSelection_.SetRightCol(rightCol+1);
				ch.put_RightVisScrollCol(activeSelection_.RightCol(),&rcContent,TRUE);
				int const newLeft=ch.get_LeftVisScrollCol();
				int const xDelta=ch.get_DiffWidths(leftCol,newLeft);
				pSheet_->ScrollWindow(-xDelta,0,&rchScroll,&rchScroll);
				int const nScrollPos=pSheet_->GetScrollPos32(SB_HORZ);
				pSheet_->Scroll_SetScrollPos32(SB_HORZ,nScrollPos+xDelta);
			}else if(rightCol==cols-1 && !pSheet_->IsCellFullVisible(HEADER_ROW,rightCol)){
				activeSelection_.SetRightCol(rightCol);
				pSheet_->EnsureVisible(rh.get_TopVisScrollRow(),rightCol);
			}
		}else if(autoScrollType_&AS_LEFT){
			if(leftCol>0){
				activeSelection_.SetRightCol(leftCol-1);
				ch.put_LeftVisScrollCol(activeSelection_.RightCol(),&rcContent);
				int const newLeft=ch.get_LeftVisScrollCol();
				int const xDelta=ch.get_DiffWidths(newLeft,leftCol);
				pSheet_->ScrollWindow(xDelta,0,&rchScroll,&rchScroll);
				int const nScrollPos=pSheet_->GetScrollPos32(SB_HORZ);
				pSheet_->Scroll_SetScrollPos32(SB_HORZ,max(nScrollPos-xDelta,0));
			}
		}
		InvalidateWindow(pSheet_->GetActiveCell(),oldCR);
		return 0;
	}
		*/
	//LRESULT SelectionsHandler::SendNotifyMessageToListener(int nRow, int nCol, int nNotifyCode,LPARAM lParam) const
	//{
	//	return pSheet_->SendDlgItemMessage(nRow,nCol,nNotifyCode,lParam);
	//}
}//namespace1

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