Click here to Skip to main content
15,895,656 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 - version 1.1
// Written by Yanxueming <yanxm2003@hotmail.com>
// Copyright (C) 2006-2007
// All rights reserved.
//
// The code and information is provided "as-is" without
// warranty of any kind, either expressed or implied.
#include "stdafx.h"
#include "../include/Worksheet.h"
#include "../include/Workbook.h"
namespace mycell{
	//-------------------------------------------------------------------------------//
	//��������y���y��������[topRow,bottomRow)��
	//�ĵڼ���,��������������򷵻�INVALIDATE_ROW
	//heightΪ��ʼ��topRow����ڿͻ������˵ĸ߶�
	//��̽���ʵ����y>=0�����
	//-------------------------------------------------------------------------------//
	int HitTestRow(const RowHeader& rh,const int y,int topRow,int bottomRow,int& height)
	{
		_ASSERT(topRow<=bottomRow);
		_ASSERT(y>=height);
		for(int i=topRow;i!=bottomRow;++i){
			height+=rh.get_RowHeight(i);
			if(y<height)
				return i;
		}
		return INVALIDATE_ROW;
	}
	//-------------------------------------------------------------------------------//
	//��������x���x��������[leftCol,rightCol)��
	//�ĵڼ���,��������������򷵻�INVALIDATE_COL
	//widthΪ��ʼ��leftCol����ڿͻ�����˵Ŀ��
	//��̽���ʵ����x>=0�����
	//-------------------------------------------------------------------------------//
	int HitTestCol(const ColHeader& ch,const int x,int leftCol,int rightCol,int& width)
	{
		_ASSERT(leftCol<=rightCol);
		_ASSERT(x>=width);
		for(int i=leftCol;i!=rightCol;++i){
			width+=ch.get_ColWidth(i);
			if(x<width)
				return i;
		}
		return INVALIDATE_COL;
	}
	//x,y should be client coords
	CCell Worksheet::GetCellByPos(int const x,int const y)const
	{
		//const short x=(const short)_x;
		//const short y=(const short)_y;
		CCell cell(INVALIDATE_ROW,INVALIDATE_COL);
		const RowHeader& rh=get_RowHeader();
		const ColHeader& ch=get_ColHeader();
		const CellAxisInfo& cai=get_CellAxisInfo();
		int height=get_ShowColHeader()?ch.get_height():0;
		int width=get_ShowRowHeader()?rh.get_width():0;
		if(y<0){
			height=cai.HFreezeAxis;
			for(cell.row=rh.get_TopVisScrollRow()-1;cell.row>=0;){
				height-=rh.get_RowHeight(cell.row);
				if(height<y)
					break;
				--cell.row;
			}
			if(HEADER_ROW==cell.row)
				cell.row=INVALIDATE_ROW;
		}else if(y<height){
			cell.row=HEADER_ROW;
		}else{
			if(rh.IsFreezeRowVisible()){//�Ƿ����ڶ�����
				cell.row=HitTestRow(rh,y,rh.get_FreezeTopRow(),rh.get_FreezeBottomRow()+1,height);
			}
			if(INVALIDATE_ROW==cell.row){
				cell.row=HitTestRow(rh,y,rh.get_TopVisScrollRow(),rh.get_rows()/*get_BottomVisScrollRow()+1*/,height);
			}
			if(INVALIDATE_ROW==cell.row)
				cell.row=rh.get_rows();
		}
		if(x<0){
			//cell.col=-2;
			width=cai.VFreezeAxis;
			for(cell.col=rh.get_TopVisScrollRow()-1;cell.col>=0;){
				width-=rh.get_RowHeight(cell.col);
				if(width<x)
					break;
				--cell.col;
			}
			if(HEADER_COL==cell.col)
				cell.col=INVALIDATE_COL;
		}else if(x<width){
			cell.col=HEADER_COL;
		}else{
			if(ch.IsFreezeColVisible()){
				cell.col=HitTestCol(ch,x,ch.get_FreezeLeftCol(),ch.get_FreezeRightCol()+1,width);
			}
			if(INVALIDATE_COL==cell.col){
				cell.col=HitTestCol(ch,x,ch.get_LeftVisScrollCol(),ch.get_cols(),width);
			}
			if(INVALIDATE_COL==cell.col)
				cell.col=ch.get_cols();
		}
		return cell;
	}
	//CCell Worksheet::GetCellByScreenPos(int x,int y)const
	//{
	//}

	//-------------------------------------------------------------------------//
	//���ؿͻ������꣬�÷���Ӧ��Ϊ�Ͳ�ε���
	//�������ǵ�Ԫ���Ƿ��ںϲ���Ԫ���ж�
	//���������ϲ���Ԫ��Χ�����⡣�����Ҫ
	//�õ������ϲ���Ԫ��ķ�Χ�������GetCellRectEx
	//������ֱ�ӵ���Worksheet��get_RangeRect����
	//˵����������raw_��ͷ�ķ����������Ǻϲ���Ԫ��������
	//-------------------------------------------------------------------------//
	RECT Worksheet::raw_GetCellRect(CCell cell/*int row,int col*/)const
	{
		//_ASSERT(row>=-1);
		//_ASSERT(col>=-1);
		RECT rc;
		if(cell.row<HEADER_ROW || cell.col<HEADER_COL)
		{
			SetRect(&rc,0,0,0,0);
			return rc;
		}
		//const RowHeader& rh=get_RowHeader();
		//const ColHeader& ch=get_ColHeader();
		int const topRow=rh_.get_TopVisScrollRow();
		int const leftCol=ch_.get_LeftVisScrollCol();
		if(HEADER_ROW==cell.row){
			rc.top=0;
			rc.bottom=ch_.get_height();
		}else{
			rc.top=get_ShowColHeader()?ch_.get_height():0;
			int const nFreezeTopRow=rh_.get_FreezeTopRow();
			int const nFreezeBottomRow=rh_.get_FreezeBottomRow();
			if(cell.row>=nFreezeTopRow && cell.row<=nFreezeBottomRow){
				rc.top+=rh_.get_DiffHeights(nFreezeTopRow,cell.row);
			}else{
				if(rh_.IsFreezeRowVisible())
					rc.top+=rh_.get_DiffHeights(nFreezeTopRow,nFreezeBottomRow+1);
				if(cell.row>topRow){
					rc.top+=rh_.get_DiffHeights(max(0,topRow),cell.row);
				}else if(cell.row<topRow){
					rc.top-=rh_.get_DiffHeights(cell.row,topRow);
				}
			}
			rc.bottom=rc.top+rh_.get_RowHeight(cell.row);
		}
		if(HEADER_COL==cell.col){
			rc.left=0;
			rc.right=rh_.get_width();
		}else{
			rc.left=get_ShowRowHeader()?rh_.get_width():0;
			int const nFreezeLeftCol=ch_.get_FreezeLeftCol();
			int const nFreezeRightCol=ch_.get_FreezeRightCol();
			if(cell.col>=nFreezeLeftCol && cell.col<=nFreezeRightCol){
				rc.left+=ch_.get_DiffWidths(nFreezeLeftCol,cell.col);
			}else{
				if(ch_.IsFreezeColVisible())
					rc.left+=ch_.get_DiffWidths(nFreezeLeftCol,nFreezeRightCol+1);
				if(cell.col>leftCol){
					rc.left+=ch_.get_DiffWidths(max(0,leftCol),cell.col);
				}else if(cell.col<leftCol){
					rc.left-=ch_.get_DiffWidths(cell.col,leftCol);
				}
			}
			rc.right=rc.left+ch_.get_ColWidth(cell.col);
			/*
			rc.left=get_ShowRowHeader()?rh_.get_width():0;
			if(ch_.IsFreezeColVisible())
				rc.left+=ch_.get_DiffWidths(ch_.get_FreezeLeftCol(),ch_.get_FreezeRightCol()+1);
			if(col>leftCol){
				rc.left+=ch_.get_DiffWidths(leftCol,col);
			}else if(col<leftCol){
				rc.left-=ch_.get_DiffWidths(col,leftCol);
			}
			rc.right=rc.left+ch_.get_ColWidth(col);
			*/
		}
		/*
		if(row<0){
			rc.top=0;
			rc.bottom=ch_.get_height();
		}else{
			int const topRow=rh_.get_TopVisScrollRow();

			if(!(row>=topRow && row<=rh_.get_BottomVisScrollRow())){
				SetRect(&rc,-1,-1,-1,-1);
				return rc;
			}

			rc.top=get_ShowColHeader()?ch_.get_height():0;
			for(int i=topRow;i!=row;++i){
				rc.top+=rh_.get_RowHeight(i);	
			}
			rc.bottom=rc.top+rh_.get_RowHeight(row);
		}
		if(col<0){
			rc.left=0;
			rc.right=rh_.get_width();
		}else{
			int const leftCol=ch_.get_LeftVisScrollCol();
			if(!(col>=leftCol && col<=ch_.get_RightVisScrollCol())){
				SetRect(&rc,-1,-1,-1,-1);
				return rc;
			}
			rc.left=get_ShowRowHeader()?rh_.get_width():0;
			for(int i=leftCol;i!=col;++i){
				rc.left+=ch_.get_ColWidth(i);
			}
			rc.right=rc.left+ch_.get_ColWidth(col);
		}
		*/
		return rc;
	}
	/*
	//Ӧ��ʹ��CELLHITTESTINFO Worksheet::HitTest(int x,int y)const
	//
	CCell Worksheet::HitTest(int const x, int const y,ECellHitTestConstants& hct)const
	{
		CCell cell=GetCellByPos(x,y);
		const Worksheet* pSheet=static_cast<const Worksheet*>(this);
		const RowHeader& rh=pSheet->get_RowHeader();
		const ColHeader& ch=pSheet->get_ColHeader();
		if(cell.col>=ch.get_cols() || cell.row>=rh.get_rows() || cell.row<-1 || cell.col<-1){
			hct=cellHTOuter;
			return cell;
		}

		int const delta=ResizeCaptureRange/2;
		RECT rcCell=raw_GetCellRect(cell.row,cell.col);
		if(x<rcCell.left-delta||x>rcCell.right+delta||y<rcCell.top-delta||y>rcCell.bottom+delta)
		{//Is out of Cell
			hct = cellHTOuter;
		}else if(x>=rcCell.right-delta-1){//�Ƿ����ұ�
			if(y<=rcCell.top+delta)
				hct = cellHTRightTop;
			else if(y>=rcCell.bottom-delta)
				hct = cellHTRightBottom;
			else
				hct = cellHTRight;
		}else if(x<=rcCell.left+delta){//�Ƿ������
			if(y<=rcCell.top+delta)//Is LeftTop
				hct = cellHTLeftTop;
			else if(y>=rcCell.bottom-delta)
				hct = cellHTLeftBottom;
			else
				hct = cellHTLeft;
		}else if(y>=rcCell.bottom-delta){//�Ƿ����±�
			hct = cellHTBottom;
		}else if(y<=rcCell.top+delta){//�Ƿ����ϱ�
			hct = cellHTTop;
		}else
			hct = cellHTInterior;
		return cell;
	}
	*/
	//------------------------------------------------------------------------------//
	//chi.pt must validate and chi.pt should be client coords.
	//��������Ļ��������̽�⣬̽�����chi.cell�����ڿɼ�
	//����Ҳ�����ڲ��ɼ����䡣
	//------------------------------------------------------------------------------//
	CELLHITTESTINFO& Worksheet::HitTest(CELLHITTESTINFO& chi)const
	{
		static int const delta=3;
		const CellAxisInfo& cai=get_CellAxisInfo();
		const int x=chi.pt.x;
		const int y=chi.pt.y;
		chi.flags=0;
		chi.cell=GetCellByPos(x,y);
		const int nLeftVisScrollCol=ch_.get_LeftVisScrollCol();
		const int nTopVisScrollRow=rh_.get_TopVisScrollRow();

		if(x>cai.VRemainAxis && x<=cai.VClientAxis || y>cai.HRemainAxis && y<=cai.HClientAxis)
		{
			chi.flags|=CHTC_IN_REMAIN_PART;
			if(x>cai.VRemainAxis && x<cai.VRemainAxis+delta){
				chi.flags|=CHTC_ON_VREMAIN_PART_LEFT;
				if(y<cai.HHeaderAxis && get_ColHeader().get_cols()>0){
					chi.flags|=CHTC_INCOLHEADER;
				}
			}
			if(y>cai.HRemainAxis && y<cai.HRemainAxis+delta){
				chi.flags|=CHTC_ON_HREMAIN_PART_TOP;
				if(x<cai.VHeaderAxis && get_RowHeader().get_rows()>0){
					chi.flags|=CHTC_ON_ROWDIVIDER;
				}
			}
		}
		if(CHTC_IN_REMAIN_PART&chi.flags){
			return chi;
		}

		const RECT rcCell=raw_GetCellRect(chi.cell);


		if(x<rcCell.left+delta){
			chi.flags|=CHTC_LEFT;
		} 
		if(y<=rcCell.top+delta){
			chi.flags|=CHTC_TOP;
		}
		if(x>=rcCell.right-delta-1){
			chi.flags|=CHTC_RIGHT;
		}
		if(y>=rcCell.bottom-delta){
			chi.flags|=CHTC_BOTTOM;
		}
		if(HEADER_ROW==chi.cell.row && HEADER_COL!=chi.cell.col){
			chi.flags|=CHTC_INCOLHEADER;
			if(((chi.flags&CHTC_LEFT)||(chi.flags&CHTC_RIGHT)) && !(/*0*/nLeftVisScrollCol==chi.cell.col && (chi.flags&CHTC_LEFT)))
				chi.flags|=CHTC_ON_COLDIVIDER;
		}
		if(HEADER_COL==chi.cell.col && HEADER_ROW!=chi.cell.row){
			chi.flags|=CHTC_INROWHEADER;
			if(((chi.flags&CHTC_TOP)||(chi.flags&CHTC_BOTTOM)) && !(nTopVisScrollRow==chi.cell.row&&(chi.flags&CHTC_TOP)))
				chi.flags|=CHTC_ON_ROWDIVIDER;
		}

		//CCell const acell=GetActiveCell();
		const ESelectionMode esm=GetWorkbook()->get_SelectionMode();
		if(ESM_SINGLESELECTION==esm/*ESM_MULTISELECTION==esm && !get_Selections()->IsMultiSelectionMode()*/)
		{
			const CCellRange acr=get_Selections()->GetActiveSelection();
			RECT rc=get_RangeRect(acr);
			InflateRect(&rc,1,1);
			if(PtInRect(&rc,chi.pt)){
				if(x>rc.left && x<rc.left+3 || x>rc.right-3 && x<rc.right
					|| y>rc.top && y<rc.top+3 && y>rc.bottom-3 && y<rc.bottom)
				{
					chi.flags|=CHTC_ON_DRAGBOUNDS;
				}
			}
			if(acr.RightBottom()==chi.cell){
				if(x>rcCell.right-5 && y>rcCell.bottom-3){
					chi.flags|=CHTC_ON_DRAGCORNER;
				}
			}else if(acr.RightCol()+1==chi.cell.col){
				if(acr.BottomRow()==chi.cell.row 
					&& x<rcCell.left+4 && y>rcCell.bottom-3
					||acr.BottomRow()+1==chi.cell.row 
					&& x<rcCell.left+4 && y<rcCell.top+4)
				{
					chi.flags|=CHTC_ON_DRAGCORNER;
				}
			}else if(acr.RightCol()==chi.cell.col){
				//AtlTrace(_T("\nx=%d,y=%d,cell.left=%d,cell.bottom=%d"),x,y,rcCell.left,rcCell.bottom);
				if(acr.BottomRow()==chi.cell.row && x>rcCell.right-5 && y>rcCell.bottom-3
					||acr.BottomRow()+1==chi.cell.row && x>rcCell.right-5&&y<rcCell.top+4
					)
				{
					chi.flags|=CHTC_ON_DRAGCORNER;
				}
			}
		}
		return chi;
	}
	//-------------------------------------------------------------------------//
	//���ؿͻ������ꡣ
	//�÷��������жϵ�Ԫ���Ƿ��ںϲ���Ԫ������
	//�У�����ǽ����������ϲ���Ԫ��ķ�Χ��
	//-------------------------------------------------------------------------//
	//RECT Worksheet::GetCellRectEx(int row,int col)const;
	//{
	//	const Worksheet* pSheet=static_cast<const Worksheet*>(this);
	//	CCellRange const* pmerge=pSheet->GetMergeCells(row,col);
	//	if(!pmerge)
	//		return raw_GetCellRect(row,col);
	//	return pSheet->get_RangeRect(*pmerge);
	//}
}//namespace mycell

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