Click here to Skip to main content
15,885,141 members
Articles / Desktop Programming / MFC

The Ultimate Toolbox - Updates and User Contributions

Rate me:
Please Sign up or sign in to vote.
4.79/5 (26 votes)
12 Feb 2013CPOL8 min read 254.7K   23.6K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
/*************************************************************************
				Class Implementation : CUGCellType
**************************************************************************
	Source file : UGCelTyp.cpp
// This software along with its related components, documentation and files ("The Libraries")
// is � 1994-2007 The Code Project (1612916 Ontario Limited) and use of The Libraries is
// governed by a software license agreement ("Agreement").  Copies of the Agreement are
// available at The Code Project (www.codeproject.com), as part of the package you downloaded
// to obtain this file, or directly from our office.  For a copy of the license governing
// this software, you may contact us at legalaffairs@codeproject.com, or by calling 416-849-8900.
*************************************************************************/
#include "stdafx.h"
#include "UGCtrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/***************************************************
CUGCellType - Constructor
	Setup the default properties for the cell type
	Cell types contain several member variables 
	that modify how the grid works with the cell type
	NOTE: New cell types must be registered with the
	grid before use.
****************************************************/
CUGCellType::CUGCellType()
{
	m_useThemes = true;
	m_drawThemesSet = false;
	m_canTextEdit = TRUE;
	m_drawLabelText = FALSE;
	m_canOverLap = TRUE;
	m_dScaleFactor = 1.0;
}

/***************************************************
~CUGCellType - Destructor
****************************************************/
CUGCellType::~CUGCellType()
{
}

/***************************************************
DrawTextOrLabel
	function is used to provide a cell type with information identifying
	if it should draw the string set by the SetText of SetLabelText.
Params:
	mode		- identifies text drawing mode
					FALSE (0)	- draw text
					TRUE (1)	- draw label text
Returns:
	UG_SUCCESS, this function will never fail.
*****************************************************/
int CUGCellType::DrawTextOrLabel(int mode)
{
	m_drawLabelText = mode;
	return UG_SUCCESS;
}

/***************************************************
SetID
	This function is called by the grid framework
	and assigns an ID number to be used by this
	cell type for the lifetime of 'this' instance
	of the grid. The ID number set by the grid
	for additional cell types depends on the order
	that the cells type were added.
Params:
	ID - ID number for the cell type to use
Returns:
	<none>
****************************************************/
void CUGCellType::SetID(int ID)
{
	m_ID = ID;
}

/***************************************************
GetID
	Returns the ID number of this cell type. This
	number will not change during the lifetime of 
	the grid's instance, but it may be different 
	the next time the grid is created.
Params:
	<none>
Returns:
	ID number of the cell
****************************************************/
int CUGCellType::GetID(){
	return m_ID;
}
/***************************************************
GetName
	Returns a readable name for the cell type.
	Returned value is used to help end-users
	to see what cell type are available.
Params:
	<none>
Return
	cell type name
****************************************************/
LPCTSTR CUGCellType::GetName()
{
	return _T("Normal Cell Type (default)");
}

/***************************************************
GetUGID
	Returns a GUID for the cell type, this number
	is unique for each cell type and never changes.
	This number can be used to find the cell types
	added to this instance of the Ultimate Grid.
Params:
	<none>
Returns:
	UGID (which is actually a GUID)	
****************************************************/
LPCUGID CUGCellType::GetUGID()
{
	static const UGID ugid = {0x78a705c1, 0xf3e9, 
							0x11d0, 0x9c, 0x7b, 
							0x0, 0x80, 0xc8, 0x3f, 
							0x71, 0x2f};

	return &ugid;
}

/***************************************************
GetEditArea
	Returns the editable area of a cell type.
	Some celltypes (i.e. drop list) require to
	have certain portion of the cell not covered
	by the edit control.  In case of the drop list
	the drop button should not be covered.
Params:
	rect - pointer to the cell rectangle, it can
		   be used to modify the edit area
Returns:
	UG_SUCCESS or UG_ERROR, currently the Utltimate
	Grid does not check the return value.
****************************************************/
int CUGCellType::GetEditArea(RECT *rect)
{
	UNREFERENCED_PARAMETER(*rect);
	return UG_SUCCESS;
}
/***************************************************
CanTextEdit
	The CanTextEdit function provides the grid
	with valuable information that it needs
	to determine if the user can start edit
	on given cell.

	This is often used on cell types that allow
	only visual user's interaction (progress bar,
	slider, etc)
Params:
	<none>
Return:
	TRUE - if the cell type allows editing
	FALSE - if the cell type does not allow editing
****************************************************/
BOOL CUGCellType::CanTextEdit()
{
	return m_canTextEdit;
}

/***************************************************
CanOverLap
	returns TRUE if this cell type can overlap
	other cells to the right if its text is too
	wide. Generally plain cell types allow overlapping
Params:
	<none>
Return:
	TRUE - if overlapping may occur
	FALSE - if overlapping is not allowed
****************************************************/
BOOL CUGCellType::CanOverLap(CUGCell *cell)
{
	if( cell->GetCellTypeEx() != 0 || cell->IsPropertySet(UGCELL_JOIN_SET) == TRUE )
		return 	FALSE;

	if( cell->IsPropertySet( UGCELL_ALIGNMENT_SET ) == TRUE )
	{
		long alignment = cell->GetAlignment();
		if( alignment & UG_ALIGNLEFT )
			return m_canOverLap;
		else
			return FALSE;
	}

	return FALSE;
}

/***************************************************
SetTextEditMode
	Is used to set the flag that identifies if
	the cell type can be editable.  This flag
	is then returned by the CanTextEdit function.
Params:
	mode - TRUE(on) or FALSE(off)
Return:
	UG_SUCCESS - success, this function will never fail.
****************************************************/
int CUGCellType::SetTextEditMode(int mode)
{
	if(mode == FALSE)
		m_canTextEdit = FALSE;
	else 
		m_canTextEdit = TRUE;

	return UG_SUCCESS;
}

/***************************************************
OnSystemChange
	This function is called for each cell type 
	when system settings change, such as screen
	resolution and or colors.
Params:
	none
Return:
	UG_SUCCESS - success
	UG_ERROR - error		
****************************************************/
int CUGCellType::OnSystemChange()
{
	return UG_SUCCESS;
}

/***************************************************
OnMessage
	This function is called when a windows message
	(UGCT_MESSAGE) was sent to this cell type.
	The wParam part of the message must contain the
	celltype ID (that is returned when a celltype
	is registered). 
Params:
	lParam - generic data, cell type dependant
			comes from the lParam paramenter of 
			a windows message
Return:
	Value is celltype dependant
****************************************************/
long CUGCellType::OnMessage(LPARAM lParam)
{
	UNREFERENCED_PARAMETER(lParam);
	return 0;
}

/***************************************************
OnCellTypeNotify
	This function is called whenever a celltype wants
	to fire a notification. By default this function
	calls through to CUGCtrl::OnCellTypeNotify, which
	developers generally override to handle the 
	notifications. However this function is useful
	to override when creating a customized cell type
	based off an existing cell type.
Params:
	ID - cell type ID
	col - column of the cell firing the notification
	row - row of the cell firing the notification
	msg - notification message
	param - notification dependant data
Return:
	Value is dependant on the notification being fired
****************************************************/
int CUGCellType::OnCellTypeNotify(long ID,int col,long row,long msg,LONG_PTR param){
	return m_ctrl->OnCellTypeNotify(ID,col,row,msg,param);
}

/***************************************************
OnLClicked
	This function is called when the left mouse 
	button is clicked over a cell using this cell
	type.
Params:
	col - column that was clicked in
	row - row that was clicked in
	updn - TRUE if the mouse button just went down
		 - FALSE if the mouse button just went up
	rect - rectangle of the cell that was clicked in
	point - point where the mouse was clicked
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnLClicked(int col,long row,int updn,RECT *rect,POINT *point)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(updn);
	UNREFERENCED_PARAMETER(*rect);
	UNREFERENCED_PARAMETER(*point);
	return FALSE;
}
/***************************************************
OnRClicked
	This function is called when the right mouse 
	button is clicked over a cell using this cell
	type.
Params:
	col - column that was clicked in
	row - row that was clicked in
	updn - TRUE if the mouse button just went down
		 - FALSE if the mouse button just went up
	rect - rectangle of the cell that was clicked in
	point - point where the mouse was clicked
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnRClicked(int col,long row,int updn,RECT *rect,POINT *point)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(updn);
	UNREFERENCED_PARAMETER(*rect);
	UNREFERENCED_PARAMETER(*point);
	return FALSE;
}
/***************************************************
OnDClicked
	This function is called when the left mouse 
	button is double clicked over a cell using this cell
	type.
Params:
	col - column that was clicked in
	row - row that was clicked in
	rect - rectangle of the cell that was clicked in
	point - point where the mouse was clicked
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnDClicked(int col,long row,RECT *rect,POINT *point)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*rect);
	UNREFERENCED_PARAMETER(*point);
	return FALSE;
}
/***************************************************
OnKeyDown
	This function is called when a cell of this type
	has focus and a key is pressed.(See WM_KEYDOWN)
Params:
	col - column that has focus
	row - row that has focus
	vcKey - pointer to the virtual key code, of the 
		key that was pressed
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnKeyDown(int col,long row,UINT *vcKey)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*vcKey);
	return FALSE;
}
/***************************************************
OnKeyUp
	This function is called when a cell of this type
	has focus and a key was unpressed.(See WM_KEYUP)
Params:
	col - column that has focus
	row - row that has focus
	vcKey - pointer to the virtual key code, of the 
		key that was unpressed
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnKeyUp(int col,long row,UINT *vcKey)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*vcKey);
	return FALSE;
}
/***************************************************
OnCharDown
	This function is called when a cell of this type
	has focus and a printable key is pressed.(WM_CHARDOWN)
Params:
	col - column that has focus
	row - row that has focus
	vcKey - pointer to the virtual key code, of the 
		key that was pressed
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnCharDown(int col,long row,UINT *vcKey)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*vcKey);
	return FALSE;
}
/***************************************************
OnMouseMove
	This function is called when the mouse  is over
	a cell of this celltype.
Params:
	col - column that the mouse is over
	row - row that the mouse is over
	point - point where the mouse is
	flags - mouse move flags (see WM_MOUSEMOVE)
Return:
	TRUE - if the event was processed
	FALSE - if the event was not
****************************************************/
BOOL CUGCellType::OnMouseMove(int col,long row,POINT *point,UINT flags)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*point);
	UNREFERENCED_PARAMETER(flags);
	return FALSE;
}

/***************************************************
OnChangedCellWidth
	This notification is sent to all visible
	cells is affected column when the user has
	changed width of a column.
Params:
	col - column that the mouse is over
	row - row that the mouse is over
	width - pointer to new column width
Return:
	<none>
****************************************************/
void CUGCellType::OnChangedCellWidth(int col, long row, int* width)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*width);
}

/***************************************************
OnChangingCellWidth
	This notification is sent to all visible
	cells is affected column while the user is 
	changing width of a column.
Params:
	col - column that the mouse is over
	row - row that the mouse is over
	width - pointer to new column width
Return:
	<none>
****************************************************/
void CUGCellType::OnChangingCellWidth(int col, long row, int* width)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*width);
}

/***************************************************
OnChangedCellHeight
	This notification is sent to all visible
	cells is affected row when the user has
	changed height of a column.
Params:
	col - column that the mouse is over
	row - row that the mouse is over
	height - pointer to new row height
Return:
	<none>
****************************************************/
void CUGCellType::OnChangedCellHeight(int col, long row, int* height)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*height);
}

/***************************************************
OnChangingCellHeight
	This notification is sent to all visible
	cells is affected row while the user is 
	changing height of a row.
Params
	col - column that the mouse is over
	row - row that the mouse is over
	height - pointer to new row height
Return
	<none>
****************************************************/
void CUGCellType::OnChangingCellHeight(int col, long row, int* height) 
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*height);
}

/***************************************************
SetOption
	This virtual function, although not implemented
	by default by any of cell types that are
	shipped with Ultimate Grid, was added
	to provide standard way to set additional
	properies of a cell.
Params:
	option - option ID number
	param - value for the specified option
Return:
	UG_NA - not implemented
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGCellType::SetOption(long option,long param)
{
	UNREFERENCED_PARAMETER(option);
	UNREFERENCED_PARAMETER(param);
	return UG_NA;
}
/***************************************************
GetOption
	This virtual function, although not implemented
	by default by any of cell types that are
	shipped with Ultimate Grid, was added
	to provide standard way to get additional
	properies of a cell.
Params:
	option - option ID number
	param - value for the specified option
Return:
	UG_NA - not implemented
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGCellType::GetOption(long option,long* param)
{
	UNREFERENCED_PARAMETER(option);
	UNREFERENCED_PARAMETER(*param);
	return UG_NA;
}
/***************************************************
OnSetFocus
	This function is called when a cell of this
	type receives focus.
Params
	col - column that just received focus
	row - row that just received focus
	cell - pointer to the cell object located at col/row
Return
	<none>
****************************************************/
void CUGCellType::OnSetFocus(int col,long row,CUGCell *cell)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*cell);
}
/***************************************************
OnKillFocus
	This function is called when a cell of this
	type loses focus.
Params
	col - column that just lost focus
	row - row that just lost focus
	cell - pointer to the cell object located at col/row
Return
	<none>
****************************************************/
void CUGCellType::OnKillFocus(int col,long row,CUGCell *cell)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*cell);
}

/***************************************************
OnDraw
	The Ultimate Grid calls this vistual function
	every time it is drawing a cell.  It is upto
	the individual cell type to properly draw itself.
Params:
	dc		- device context to draw the cell with
	rect	- rectangle to draw the cell in
	col		- column that is being drawn
	row		- row that is being drawn
	cell	- cell that is being drawn
	selected- TRUE if the cell is selected, otherwise FALSE
	current - TRUE if the cell is the current cell, otherwise FALSE
Return
	<none>
****************************************************/
void CUGCellType::OnDraw(CDC *dc,RECT *rect,int col,long row,CUGCell *cell,
						int selected,int current)
{
	if (!m_drawThemesSet)
		m_useThemes = cell->UseThemes();

#ifdef UG_ENABLE_PRINTING
	// If it is printing, call OnDrawPrint to draw the cell 
	if(dc->IsPrinting()){
		OnDrawPrint( dc, rect, col, row, cell, selected, current);
		return;
	}
#endif

	if(m_ctrl->m_GI->m_enableCellOverLap){
		if(CanOverLap(cell)){
			if(cell->GetTextLength() == 0){
				int overlapCol,offset;
				CUGCell overlapCell;
				offset = GetCellOverlapInfo(dc,col,row,&overlapCol,&overlapCell);
				if(offset != 0){
					DrawBorder(dc,rect,rect,cell);
					DrawText(dc,rect,offset,col,row,&overlapCell,selected,current);
					m_ctrl->m_CUGGrid->m_drawHint.AddHint(col+1,row);
					return;
				}
			}
			else{
				m_ctrl->m_CUGGrid->m_drawHint.AddHint(col+1,row);
			}
		}
	}

	DrawBorder(dc,rect,rect,cell);
	DrawText(dc,rect,0,col,row,cell,selected,current);
}

/***************************************************
OnDrawPrint
	The OnDrawPrint virtual function is identical
	in function to the OnDraw function.  However,
	this version of the OnDraw is called when the
	cell is drawn to printer device.
Params:
	dc		- device context to draw the cell with
	rect	- rectangle to draw the cell in
	col		- column that is being drawn
	row		- row that is being drawn
	cell	- cell that is being drawn
	selected- TRUE if the cell is selected, otherwise FALSE
	current - TRUE if the cell is the current cell, otherwise FALSE
Return
	<none>
****************************************************/
#ifdef UG_ENABLE_PRINTING
void CUGCellType::OnDrawPrint(CDC *dc,RECT *rect,int col,long row,CUGCell *cell,
							int selected,int current)
{
	CSize   size;
	RECT    rectOut;
	CRect   rectTmp(rect);
	int     nHeadColCount = 0;	
	float   fScale = m_ctrl->GetUGPrint()->GetPrintVScale(dc);
	int     nColCount = (int)m_ctrl->GetUGPrint()->m_ColRects.GetSize();
	CUGCell cellRight, cellLeft;

	if( m_ctrl->GetUGPrint()->PrintSideHeading() )
		nHeadColCount = m_ctrl->m_GI->m_numberSideHdgCols;

	// If the column is not overlapped by left cell
	// draw the left cell using new rect.

	if(m_ctrl->m_GI->m_enableCellOverLap){
		if(CanOverLap(cell)){
			if(cell->GetTextLength() == 0){
				int     overlapCol;
				CUGCell overlapCell;
				if( GetCellOverlapInfo(dc,col,row,&overlapCol,&overlapCell) != 0 )
					return;
			}
		}
	}

	// If the column is not wider enought to draw the text 
	// and the right cell can be overlapped.

	if( cell->IsPropertySet(UGCELL_FONT_SET) )
		dc->SelectObject(cell->GetFont());
	size = dc->GetOutputTextExtent(cell->GetText());
	if (size.cx > 0)
		size.cx += (int) (m_ctrl->m_GI->m_margin * fScale);

	// Caculate the right position of the cell rect.

	if( ( size.cx > (int) (m_ctrl->GetColWidth(col) * fScale) ) &&
		m_ctrl->GetCellType(cell->GetCellType())->CanOverLap(cell) ){
		for( int i = col + 1; i + nHeadColCount < nColCount; i++ ){
			m_ctrl->GetCellIndirect( i, row, &cellRight );
			if( NULL != cellRight.GetText() ) break;
			rectTmp.right = m_ctrl->GetUGPrint()->
				m_ColRects[i + nHeadColCount].right;
			if( rectTmp.right - rectTmp.left > size.cx ) break;
		}
	}

	// Draw the border and the text

	DrawBorder(dc,rectTmp,&rectOut,cell);
	DrawText(dc,&rectOut,0,col,row,cell,selected,current);
}
#endif
/***************************************************
OnDrawFocusRect
	In the default implementation of the 
	CUGCtrl::OnDrawFocusRect the Ultimate Grid provides
	the cell type of the current cell with a chance
	to draw its own focus rect.  If a cell type draws
	the focus rectangle, than it should return TRUE
	to inform the control class.
Params:
	dc		- device context to draw the cell with
	rect	- rectangle to draw the cell in
	col		- column that is being drawn
	row		- row that is being drawn
Return:
	TRUE	- if cell type processed this event
	FALSE	- if grid should 
****************************************************/
BOOL CUGCellType::OnDrawFocusRect(CDC *dc,RECT *rect,int col,int row)
{
	UNREFERENCED_PARAMETER(dc);
	UNREFERENCED_PARAMETER(rect);
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	return FALSE;
}

/***************************************************
DrawText
	This function is the standard text drawing routine
	used by this cell type and used by many others.
Params:
	dc		- device context to draw the cell with
	rect	- rectangle to draw the cell in
	col		- column that is being drawn
	row		- row that is being drawn
	cell	- cell that is being drawn
	selected- TRUE if the cell is selected, otherwise FALSE
	current - TRUE if the cell is the current cell, otherwise FALSE
Return:
	<none>
****************************************************/
void CUGCellType::DrawText(CDC *dc,RECT *rect,int offset,int col,long row,CUGCell *cell,int selected,int current)
{
	int			left,top;
	SIZE		size;
	COLORREF	backcolor;
	LPCTSTR		string;
	int			stringLen;
	long		cellTypeEx;
	short		alignment;
	int			oldleft	= rect->left;
	long		properties = cell->GetPropertyFlags();
//	int			overLapCol = col;
	CFont		*pOldFont = NULL;

	// This is used by the theme drawing code.
	RECT offsetRect = *rect;
	offsetRect.left += offset;
	offsetRect.right -= offset;
	offsetRect.top += offset;
	offsetRect.bottom -= offset;

	UGXPThemeState state = UGXPThemes::GetState(selected>0, current>0);

	//get the extended style
	if(properties&UGCELL_CELLTYPEEX_SET){
		cellTypeEx = cell->GetCellTypeEx();
	}
	else
		cellTypeEx = 0;

	//get the string to draw
	if(!m_drawLabelText && !(cellTypeEx & UGCT_NORMALLABELTEXT) ){
		if(properties&UGCELL_STRING_SET){
			string  = cell->GetText();
			stringLen = cell->GetTextLength();
		}
		else{
			string = _T("");
			stringLen = 0;
		}
	}
	else{
		if(properties&UGCELL_LABEL_SET){
			string  = cell->GetLabelText();
			stringLen = lstrlen(string);
		}
		else{
			string = _T("");
			stringLen = 0;
		}
	}	

	//check for overlapping
/*	if(overLapCol != col)
	{
		cell->SetAlignment(olCell.GetAlignment());
		string  = olCell.GetText();
		stringLen = olCell.GetTextLength();
	}*/

	if(properties&UGCELL_ALIGNMENT_SET)
		alignment = cell->GetAlignment();
	else
		alignment = 0;

	
	//select the font
	if(properties&UGCELL_FONT_SET )
		pOldFont = dc->SelectObject(cell->GetFont());
	
	
	int style = 0;
	bool isDisabled = false;
	if( cell->IsPropertySet( UGCELL_CELLTYPEEX_SET ))
	{
		style = cell->GetCellTypeEx();
		isDisabled = (style & UGCT_CHECKBOXDISABLED) > 0;
	}

	if (isDisabled)
	{
		dc->SetTextColor(RGB(140, 140, 140));
		backcolor = cell->GetBackColor();
	}
	else
	//check the selected and current states
	if(selected || (current && m_ctrl->m_GI->m_currentCellMode&2))
	{
		dc->SetTextColor(cell->GetHTextColor());
		backcolor = cell->GetHBackColor();
	}
	else
	{
		dc->SetTextColor(cell->GetTextColor());
		backcolor = cell->GetBackColor();
	}

	// The button draws it's own background, so it can draw a pressed state
	if (cell->GetXPStyle() != XPCellTypeButton || !UGXPThemes::IsThemed())
		DrawBackground( dc, rect, backcolor, row, col, cell, (current != 0), (selected != 0) );
	
	//check for bitmaps
	if(properties&UGCELL_BITMAP_SET){
		oldleft = rect->left;
		if(offset != 0){
			int x;
			rect->left += offset;
			x= DrawBitmap(dc,cell->GetBitmap(),rect,backcolor);
			rect->left -= offset;
			offset += x;
			offsetRect.left += x;
		}
		else
		{
			int n = DrawBitmap(dc,cell->GetBitmap(),rect,backcolor);
			rect->left += n;
			offsetRect.left += n;
		}
	}

	GetTextExtentPoint(dc->m_hDC,string,stringLen,&size);

	// horizontal text alignment
	if(alignment&UG_ALIGNCENTER)
	{
		left = rect->left + (rect->right - rect->left - size.cx) /2;
	}
	else if(alignment&UG_ALIGNRIGHT)
	{
		left = rect->right - size.cx - m_ctrl->m_GI->m_margin;
	}
	else
	{
		left = rect->left + m_ctrl->m_GI->m_margin + offset;
	}	

	// vertical text alignment
	if(alignment & UG_ALIGNVCENTER)
	{
		GetTextExtentPoint(dc->m_hDC,string,stringLen,&size);
		top = rect->top + (rect->bottom - rect->top - size.cy) /2;
	}
	else if(alignment & UG_ALIGNBOTTOM)
	{
		top = rect->bottom - size.cy - 1;
	}
	else
	{
		top = rect->top + 1;
	}

	if(offset < 0)
		rect->left -= 1;

	// draw the text
	if(cellTypeEx&(UGCT_NORMALMULTILINE|UGCT_NORMALELLIPSIS))
	{
		if(cellTypeEx&UGCT_NORMALMULTILINE)
		{ // multiline

			CRect tempRect(rect);

			// set up a default format
			UINT format = DT_WORDBREAK | DT_NOPREFIX;

			// v7.2 - update 03 - changes here to respect bottom and center
			//        alignment settings for multi-line cells - 
			//        fix courtesy Allen Shiels
			// ..start
			// set the alignment format
			if (alignment & UG_ALIGNCENTER)	{
				format |= DT_CENTER;
			}
			else if	(alignment & UG_ALIGNRIGHT) {
				format |= DT_RIGHT;
			}
			else {
				// if no alignment has been specified, then default to left justified
				alignment |= UG_ALIGNLEFT;
				format |= DT_LEFT;
			}

			// adjust the left and right for alignment
			// if (format & (DT_CENTER|DT_RIGHT)) {
			if (alignment & (UG_ALIGNCENTER|UG_ALIGNRIGHT)) {
				tempRect.right -= m_ctrl->m_GI->m_margin + offset;
				offsetRect.right -= m_ctrl->m_GI->m_margin + offset;
			}
			
//			if (format & (DT_CENTER|DT_LEFT)) {
			if (alignment & (UG_ALIGNCENTER|UG_ALIGNLEFT)) {
				tempRect.left += m_ctrl->m_GI->m_margin + offset;
				offsetRect.left += m_ctrl->m_GI->m_margin + offset;
			}

			// adjust the top and bottom for alignment
			if (alignment & (UG_ALIGNBOTTOM|UG_ALIGNVCENTER)) {
				CRect calcRect(tempRect);
				int textHeight = dc->DrawText(string, -1, calcRect, format|DT_CALCRECT);
              
				if (alignment & UG_ALIGNVCENTER) {
					tempRect.top += (tempRect.bottom - tempRect.top - textHeight) / 2;
				}
				else {
					tempRect.top = (tempRect.bottom - textHeight);
				}
			}
			// .. end

//			// check alignment - multiline
//			if(alignment) {
//				if(alignment & UG_ALIGNCENTER) {
//					format |= DT_CENTER;
//				}
//				else if(alignment & UG_ALIGNRIGHT) {
//					format |= DT_RIGHT;
//					tempRect.right -= m_ctrl->m_GI->m_margin + offset;
//					offsetRect.right -= m_ctrl->m_GI->m_margin + offset;
//				}
//				else if(alignment & UG_ALIGNLEFT) {
//					format |= DT_LEFT;
//					tempRect.left += m_ctrl->m_GI->m_margin + offset;
//					offsetRect.left += m_ctrl->m_GI->m_margin + offset;
//				}
//			}
//			// if no alignment has been specified, then default to left justified
//			else
//			{
//				format |= DT_LEFT;
//				tempRect.left += m_ctrl->m_GI->m_margin + offset;
//				offsetRect.left += m_ctrl->m_GI->m_margin + offset;
//			}

			if (!m_useThemes || !DrawThemedText(*dc, tempRect.left, tempRect.top, &tempRect, string, stringLen, format, cell->GetXPStyle(), state))
			{
				dc->DrawText(string,-1,tempRect,format );			//draw the text			
			}
		}
		else
		{ // ellipsis

			rect->left += 3; //set margins
			rect->top = top;
 
			if (!m_useThemes || !DrawThemedText(*dc, left, top, &offsetRect, string, stringLen, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE, cell->GetXPStyle(), state))
			{
				dc->DrawText(string, rect, DT_NOPREFIX | DT_END_ELLIPSIS | DT_SINGLELINE);
			}

			// NOTE: To get the ellipsis type to display maximum text len, even
			//		 if a letter must be cut to do so.  Use following code.
			// CSize size = dc->GetTextExtent(string,stringLen);
			// if(size.cx + 6 > (rect->right - rect->left)){
			// 	size = dc->GetTextExtent(_T("..."),3);
			// 	rect->right -= size.cx + 3;
			// 	if(rect->right > rect->left)
			// 		dc->ExtTextOut(rect->left + 3,top,ETO_OPAQUE|ETO_CLIPPED,rect,string,stringLen,NULL);
			// 	rect->left = rect->right;
			// 	if(rect->left <= oldleft)
			// 		rect->left = oldleft + 1;
			// 	rect->right += size.cx + 3;
			// 	dc->ExtTextOut(rect->left+1,top,ETO_OPAQUE|ETO_CLIPPED,rect,_T("..."),3,NULL);
			// }
			// else{
			// 	dc->ExtTextOut(left,top,ETO_OPAQUE|ETO_CLIPPED,rect,string,stringLen,NULL);
			// }
		}
	}
	else
	{
/*		if(overLapCol != col)
		{
			//get the offset
			for( int loop = col -1;loop >= overLapCol; loop --)
			{
				left -= m_ctrl->GetColWidth(loop);
			}
			left += 1;
		}
*/
//		DrawBackground( dc, rect, backcolor, row, col, cell, (current != 0), (selected != 0));

		int mode = DT_LEFT | DT_NOPREFIX;
		int orgTop = top;

		if(alignment & UG_ALIGNBOTTOM)
		{
			top = offsetRect.top;
			mode |= DT_SINGLELINE | DT_BOTTOM;
		}

		if (!m_useThemes || !DrawThemedText(*dc, left, top, &offsetRect, string, stringLen, mode, cell->GetXPStyle(), state))
		{
			dc->ExtTextOut(left,orgTop,ETO_CLIPPED,rect,string,stringLen,NULL);
		}
	}

	//reset the rect
	rect->left = oldleft;

	if ( pOldFont )
		dc->SelectObject( pOldFont );
}

bool CUGCellType::DrawThemedText(HDC dc, int left, int top,  RECT* rect, LPCTSTR string, int stringLen, DWORD textFormat, UGXPCellType cellType, UGXPThemeState state)
{
	bool success = false;

	if (m_useThemes && UGXPThemes::IsThemed())
	{
		RECT rcDraw = *rect;
		rcDraw.left = left;
		rcDraw.top = top;

		success = UGXPThemes::WriteText(NULL, dc, cellType, state, string, stringLen, textFormat, &rcDraw);
	}

	return success;
}

/***************************************************
DrawBackground
Params:
Return:
	<none>
****************************************************/
void CUGCellType::DrawBackground(CDC *dc,RECT *rect,COLORREF backcolor, int row, int col, CUGCell * cell, bool current, bool selected)
{
	bool isOwnerDraw = false;

	if (cell != NULL)
	{
		UGXPThemeState state = UGXPThemes::GetState(selected, current);

		if (m_useThemes)
		{
			RECT rcTheme = *rect;

			if (row != -1 && col != -1)
			{
				int overLapCol = 0;
				CUGCell olCell;
				int width = GetCellOverlapInfo(dc, col, row, &overLapCol, &olCell);

				// For some reason, GetCellOverlapInfo always returns 0 if the cell is on the left.
				if (overLapCol != col && width != 0)// && abs(overLapCol - col) == 1)
				{
					int step = 1;

					if (overLapCol < col) step = -1;

					for(int i = col + step; i != overLapCol + step; i += step)
					{
						RECT rcOverlap;

						m_ctrl->GetCellRect(i, row, &rcOverlap);

						int owidth = rcOverlap.right - rcOverlap.left;

						if (overLapCol > col)
						{
							rcTheme.right += owidth;
						}
						else
						{
							rcTheme.left -= owidth;
						}
					}
				}
			}

			isOwnerDraw = UGXPThemes::DrawBackground(NULL, *dc, cell->GetXPStyle(), state, &rcTheme, NULL);
	
			// If GetDrawBorderEdges returns true, we manually draw borders around the edge cells.
			if ((cell->GetXPStyle() == XPCellTypeTopCol ||
				cell->GetXPStyle() == XPCellTypeLeftCol ||
				cell->GetXPStyle() == XPCellTypeBorder) &&
				UGXPThemes::DrawBorderEdges())
			{
				isOwnerDraw &= (dc->DrawEdge(&rcTheme, EDGE_BUMP, BF_TOPRIGHT) > 0);
			}
			else
			{
				// DrawEdge fails for some cell types, but this is acceptable.
				UGXPThemes::DrawEdge(NULL, *dc, cell->GetXPStyle(), state, &rcTheme, cell->GetBorder(), 0, NULL);
			}
		}
	}

	if (!isOwnerDraw)
	{
		CBrush brush( backcolor );
		dc->FillRect( rect, &brush );
		dc->SetBkMode( TRANSPARENT );
	}
}

/***************************************************
OnPrint
	This function is called when the grid is going
	to be printed on a printer. This function should
	perform any setup required then call the celltypes
	OnDraw member
Params:
	dc		- device context to draw the cell with
	rect	- rectangle to draw the cell in
	bdrRect - outer retangle of the cells border
	col		- column that is being drawn
	row		- row that is being drawn
	cell	- cell that is being drawn
	overLapCol - column number of the cell to the left that
			is overlapping this cell. If this value is the same
			as 'col' then there is no overlapping
Return:
	<none>
****************************************************/
#ifdef UG_ENABLE_PRINTING
void CUGCellType::OnPrint(CDC *dc,RECT *rect,int col,long row,CUGCell *cell)
{
	int height, numRows, col1, col2;
	long row1, row2;
	CFont * font;
	
	col1 = col;
	row1 = row;

	if(row >=0)
		height = m_ctrl->GetRowHeight(row);
	else
		height = m_ctrl->m_GI->m_topHdgHeights[((row * -1) -1)];

	m_dScaleFactor = ((double)(rect->bottom - rect->top)) / ((double)height);
	
	if (cell->IsPropertySet (UGCELL_JOIN_SET)){
		m_ctrl->GetJoinRange (&col1, &row1, &col2, &row2);
		numRows = (row2 - row1) +1;
	
		if (numRows > 1)
			m_dScaleFactor = (((double)(rect->bottom - rect->top))/numRows)/((double)height);
	}
	else if ( col < 0 && row < 0 )
	{	// calculate the font scale factor when printing the corner button
		m_dScaleFactor = (((double)(rect->bottom - rect->top))/m_ctrl->m_GI->m_numberTopHdgRows)/((double)height);
	}

	if(cell->GetFont() != NULL)
		font = cell->GetFont();
	else
		font = m_ctrl->m_GI->m_defFont;
	LOGFONT lf;
	GetObject(font->m_hObject,sizeof(lf),&lf);

	CFont scaleFont;

	lf.lfHeight = (int)((double)lf.lfHeight * m_dScaleFactor);
	scaleFont.CreateFontIndirect(&lf);

	CFont * oldFont = dc->SelectObject(&scaleFont);
	cell->SetFont(&scaleFont);

	//TEST CODE
	CRect tempRect(rect);
	RECT tempRect2;

	OnDraw(dc,rect,col,row,cell,0,0);

	//TEST CODE
	DrawBorder(dc,tempRect,&tempRect2,cell);

	dc->SelectObject(oldFont);
}
#endif
/****************************************************
BitmapDisplay
	Draws a bitmap within the given rectangle. The bitmap
	is automatically resized to fit within rect. The bitmap
	is placed on the left side of the rect the with of the
	sized bitmap plus  a margin is returned
Params:
	hdc 		device context handle
	hbitmap 	bitmap handle
	rect 		bounding rectangle
	Margin 	top and bottom margins
Returns:
	returns the width of the area drawn in
*****************************************************/
int CUGCellType::DrawBitmap(CDC *dc,CBitmap * bitmap,RECT *rect,COLORREF backcolor)
{
	BITMAP bm;
	CBitmap * bmpOld;
	CDC dcMemory;
	long xin,yin,xout,yout;
	long ratio;
	int t;
	int resize = TRUE;
	int Margin = 2;

	//get the bitmaps co-ords
	bitmap->GetObject(sizeof(BITMAP), &bm);

	//calc the output co-ords , and maintain aspect ratio
	yout = (rect->bottom - rect->top - Margin*2)*100;
	yin =  bm.bmHeight;
	xin =  bm.bmWidth;
	ratio = yout /yin;
	xout = xin *ratio /100;
	yout /= 100;

	// printing the grid's content
#ifdef UG_ENABLE_PRINTING
	if( dc->IsPrinting())
	{	// adjust sizes of the bitmap and the margin to scale properly on the page
		Margin = (int)(Margin * m_dScaleFactor);
		yin = (int)(yin * m_dScaleFactor);
		xin = (int)(xin * m_dScaleFactor);
	}
#endif

	//if the height of the bitmap is less than the height of a row
	//then dont resize it
	if(yin <= (rect->bottom - rect->top - Margin *2) ){
		xout = xin;
		yout = yin;
		resize = FALSE;
	}
	if(xout >= rect->right - rect->left - Margin *2)
		xout = rect->right - rect->left - Margin *2;

	//create a compatible memory context
	dcMemory.CreateCompatibleDC(dc);
	bmpOld = (CBitmap *)dcMemory.SelectObject(bitmap);

	// If we're using themes, we draw the theme behind the bitmap - we can't do that here because we don't have a cell to pass in.
	if (!UGXPThemes::IsThemed())
	{
		//fill in background first
		t =rect->right;
		rect->right = rect->left+(int)xout+Margin*2;
		dc->SetBkColor(backcolor);
		DrawBackground( dc, rect, backcolor, NULL, false, false );
		rect->right = t;
	}

	//Draw the bitmap --- If the DC is printer, we have to 
	//convert the bitmap to DIB first, then print the DIB.
	if( dc->IsPrinting() )	// Print the bitmap	
	{
#ifdef UG_ENABLE_PRINTING
		LPSTR  pBuf;
		HANDLE hDib;
		LPBITMAPINFOHEADER lpbi;

		hDib = BitmapToDIB((HBITMAP) (bitmap->m_hObject), NULL);
	    lpbi = (LPBITMAPINFOHEADER) GlobalLock(hDib);

	    if( lpbi )
		{
			pBuf = (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi);
			t= (int)((rect->bottom - rect->top - yout)/2);
			StretchDIBits (dc->m_hDC,
				rect->left + Margin, rect->top + t,
				(int)xout,(int)yout, 0, 0,
				bm.bmWidth, bm.bmHeight,
				pBuf, (LPBITMAPINFO)lpbi,
                DIB_RGB_COLORS, SRCCOPY);
		}
		GlobalUnlock (hDib);
		GlobalFree (hDib);
#endif
	}

	else
	{	// Display the bitmap on screen
		if(resize)
		{
			dc->StretchBlt(rect->left+Margin,rect->top+Margin,(int)xout,(int)yout,
				&dcMemory,0,0, bm.bmWidth, bm.bmHeight,SRCCOPY);
		}
		else
		{
			t= (int)((rect->bottom - rect->top - yout)/2);
			dc->BitBlt(rect->left+Margin,rect->top+t,(int)xout,(int)yout,
				&dcMemory,0,0,SRCCOPY);
		}
	}

	//remove the compatible memory context
	dcMemory.SelectObject(bmpOld);

	return (Margin*2+(int)xout);
}

/***************************************************
Draw Border
	Draws a border using the style set, possible
	styles are:
					   Left			   Top			   Right		   Bottom
				   |---------------|---------------|---------------|---------------
		Thin:		UG_BDR_LTHIN	UG_BDR_TTHIN	UG_BDR_RTHIN	UG_BDR_BTHIN
		Medium:		UG_BDR_LMEDIUM	UG_BDR_TMEDIUM	UG_BDR_RMEDIUM	UG_BDR_BMEDIUM
		Thick:		UG_BDR_LTHICK	UG_BDR_TTHICK	UG_BDR_RTHICK	UG_BDR_BTHICK
		3DRecess:	UG_BDR_RECESSED
		3DRaised:	UG_BDR_RAISED
Params:
	dc		- device context to draw on
	rect	- is the area to draw the border in
	rectout	- returns the area inside the border
	cell	- cell for which to draw the border for.
Returns:
	<none>
****************************************************/
void CUGCellType::DrawBorder(CDC *dc,RECT *rect,RECT *rectout,CUGCell * cell)
{
	if (!m_useThemes || !UGXPThemes::DrawEdge(NULL, *dc, cell->GetXPStyle(), ThemeStateNormal, rect, cell->GetBorder(), BF_RECT, rectout))
	{
		long props = cell->GetPropertyFlags();
		BOOL excelBdr = m_ctrl->m_GI->m_enableExcelBorders;

		if(( props & UGCELL_BORDERSTYLE_SET ) == 0 && !excelBdr)
		{
			CopyRect(rectout,rect);
			return;
		}

		int style = cell->GetBorder();
		CPen *pen = cell->GetBorderColor();
		CPen *origPen = NULL;

		if(style&UG_BDR_RAISED || style&UG_BDR_RECESSED)
			excelBdr = 0;

		int left=0,top=0,right=0,bottom=0;
		if(pen != NULL)
			dc->SelectObject(pen);
		else
			dc->SelectObject(m_ctrl->m_GI->m_defBorderPen);


		if(style&15 || excelBdr){ //thin lines
			
			if(style & 1){ //left
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->left,rect->bottom);
				left=1;
			}
			if(style & 2){ //top
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->right,rect->top);
				top=1;
			}
			if(style & 4 || excelBdr){ //right
				if((style&4) ==0)
					origPen = (CPen*)dc->SelectObject(m_ctrl->m_GI->m_defBorderPen);

				dc->MoveTo(rect->right-1,rect->top);
				dc->LineTo(rect->right-1,rect->bottom);
				right=-1;

				if((style&4) ==0)
					dc->SelectObject(origPen);
			}
			if(style & 8 || excelBdr){ //bottom
				if((style&8) ==0)
					origPen = (CPen*)dc->SelectObject(m_ctrl->m_GI->m_defBorderPen);

				dc->MoveTo(rect->left,rect->bottom-1);
				dc->LineTo(rect->right,rect->bottom-1);
				bottom=-1;

				if( origPen != NULL )
					// deselect the pen
					dc->SelectObject(origPen);
			}
		}
		if(style &240){ //medium lines
			if(style & 16){	//left
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->left,rect->bottom);
				dc->MoveTo(rect->left+1,rect->top);
				dc->LineTo(rect->left+1,rect->bottom);
				left=2;
			}
			if(style & 32){	//top
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->right,rect->top);
				dc->MoveTo(rect->left,rect->top+1);
				dc->LineTo(rect->right,rect->top+1);
				top=2;
			}
			if(style & 64){ //right
				dc->MoveTo(rect->right-1,rect->top);
				dc->LineTo(rect->right-1,rect->bottom);
				dc->MoveTo(rect->right-2,rect->top);
				dc->LineTo(rect->right-2,rect->bottom);
				right=-2;
			}
			if(style & 128){ //bottom
				dc->MoveTo(rect->left,rect->bottom-1);
				dc->LineTo(rect->right,rect->bottom-1);
				dc->MoveTo(rect->left,rect->bottom-2);
				dc->LineTo(rect->right,rect->bottom-2);
				bottom=-2;
			}
		}
		if(style &3840){ //thick lines
			if(style & 256){ //left
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->left,rect->bottom);
				dc->MoveTo(rect->left+1,rect->top);
				dc->LineTo(rect->left+1,rect->bottom);
				dc->MoveTo(rect->left+2,rect->top);
				dc->LineTo(rect->left+2,rect->bottom);
				left=3;
			}
			if(style & 512){ //top
				dc->MoveTo(rect->left,rect->top);
				dc->LineTo(rect->right,rect->top);
				dc->MoveTo(rect->left,rect->top+1);
				dc->LineTo(rect->right,rect->top+1);
				dc->MoveTo(rect->left,rect->top+2);
				dc->LineTo(rect->right,rect->top+2);
				top=3;
			}
			if(style & 1024){ //right
				dc->MoveTo(rect->right-1,rect->top);
				dc->LineTo(rect->right-1,rect->bottom);
				dc->MoveTo(rect->right-2,rect->top);
				dc->LineTo(rect->right-2,rect->bottom);
				dc->MoveTo(rect->right-3,rect->top);
				dc->LineTo(rect->right-3,rect->bottom);
				right=-3;
			}
			if(style & 2048){ //bottom
				dc->MoveTo(rect->left,rect->bottom-1);
				dc->LineTo(rect->right,rect->bottom-1);
				dc->MoveTo(rect->left,rect->bottom-2);
				dc->LineTo(rect->right,rect->bottom-2);
				dc->MoveTo(rect->left,rect->bottom-3);
				dc->LineTo(rect->right,rect->bottom-3);
				bottom=-3;
			}
		}
		if(style &4096){ //3D recessed

			int loop;
			//dark color
			dc->SelectObject((CPen *)&m_ctrl->m_threeDDarkPen);
			for(loop=0;loop<m_ctrl->m_GI->m_threeDHeight;loop++){
				dc->MoveTo(rect->left+loop,rect->bottom-loop-1);
				dc->LineTo(rect->left+loop,rect->top+loop);
				dc->LineTo(rect->right-loop-1,rect->top+loop);
			}
			//light color
			dc->SelectObject((CPen *)&m_ctrl->m_threeDLightPen);
			for(loop=0;loop<m_ctrl->m_GI->m_threeDHeight;loop++){
				dc->MoveTo(rect->right-loop-1,rect->top+loop);
				dc->LineTo(rect->right-loop-1,rect->bottom-loop-1);
				dc->LineTo(rect->left+loop,rect->bottom-loop-1);
			}
			left = m_ctrl->m_GI->m_threeDHeight;
			top = m_ctrl->m_GI->m_threeDHeight;
			right = -m_ctrl->m_GI->m_threeDHeight;
			bottom = -m_ctrl->m_GI->m_threeDHeight;

		}	

		if(style &8192){ //3D raised

			int loop;
			//light color
			dc->SelectObject((CPen *)&m_ctrl->m_threeDLightPen);
			for(loop=0;loop<m_ctrl->m_GI->m_threeDHeight;loop++){
				dc->MoveTo(rect->left+loop,rect->bottom-loop-1);
				dc->LineTo(rect->left+loop,rect->top+loop);
				dc->LineTo(rect->right-loop-1,rect->top+loop);
			}
			//dark color
			dc->SelectObject((CPen *)&m_ctrl->m_threeDDarkPen);
			for(loop=0;loop<m_ctrl->m_GI->m_threeDHeight;loop++){
				dc->MoveTo(rect->right-loop-1,rect->top+loop);
				dc->LineTo(rect->right-loop-1,rect->bottom-loop-1);
				dc->LineTo(rect->left+loop,rect->bottom-loop-1);
			}
			left = m_ctrl->m_GI->m_threeDHeight;
			top = m_ctrl->m_GI->m_threeDHeight;
			right = -m_ctrl->m_GI->m_threeDHeight;
			bottom = -m_ctrl->m_GI->m_threeDHeight;
		}	

		rectout->left	= rect->left + left;
		rectout->top	= rect->top + top;
		rectout->right	= rect->right + right;
		rectout->bottom = rect->bottom + bottom;
	}

	return;
}

/****************************************************
GetBestSize
	Returns the best (nominal) size for a cell using
	this cell type, with the given cell properties.
Params:
	dc		- device context to use to calc the size on	
	size	- return the best size in this param
	cell	- pointer to a cell object to use for the calc.
Return:
	<none>
*****************************************************/
void CUGCellType::GetBestSize(CDC *dc,CSize *size,CUGCell *cell)
{
	//select the font
	CFont * oldFont = NULL;
	if(cell->IsPropertySet(UGCELL_FONT_SET))
		oldFont = (CFont *)dc->SelectObject(cell->GetFont());
	else if(m_ctrl->m_GI->m_defFont != NULL)
		oldFont = (CFont *)dc->SelectObject(m_ctrl->m_GI->m_defFont);

	//get the best size
	CSize s(0,0);
	int bitmapWidth = 0;
	double yin = 0, ratio = 0;

	if ( cell->IsPropertySet( UGCELL_BITMAP_SET ))
	{
		BITMAP bitmap;
		cell->GetBitmap()->GetBitmap( &bitmap );
		// calculate the size of the bitmap
		yin = bitmap.bmHeight;
		if ( yin > 0 )
			ratio = size->cy / yin;
		else
			ratio = 0;

		bitmapWidth = (int)( bitmap.bmWidth * ratio );
	}

	if(cell->IsPropertySet(UGCELL_TEXT_SET))
	{
		CRect rect(0,0,0,0);
		UINT style = DT_CALCRECT;

		if ( cell->GetCellTypeEx() == 0 )
			style |= DT_SINGLELINE;
		if ( cell->GetCellTypeEx() & UGCT_NORMALSINGLELINE )
			style |= DT_SINGLELINE;
		if ( cell->GetCellTypeEx() & UGCT_NORMALELLIPSIS )
			style |= DT_END_ELLIPSIS;

		dc->DrawText( cell->GetText(), rect, style );
		s.cx = rect.Width();
		s.cy = rect.Height();
	}

	//use margins
	s.cx += 6 + bitmapWidth;
	s.cy += 2;

	//select back the original font
	if(oldFont != NULL)
		dc->SelectObject(oldFont);
	
	*size = s;
}

/****************************************************
GetCellOverlapInfo
	Calculates cell overlap size and offset for the
	given cell.  This function will only work if
	the cell overlap is enabled.
Params:
	dc			- device context to use to perform calculations
	col, row	- coordinates of a cell to check
	overlapCol	- column at which the overlap started
	cell		- pointer to a cell that is overlapping
Return:
	offset for drawing the overlapped cell
*****************************************************/
int CUGCellType::GetCellOverlapInfo(CDC* dc,int col,long row,int *overlapCol,CUGCell *cell)
{
	int			overLappedCol;			//used by cell-overlapping calculations
	int			loop,prevCol,width;
	CSize		size;

	//if cell overlapping is enabled check to see if the
	//cell is overlapped
	overLappedCol = col;
	if(m_ctrl->m_GI->m_enableCellOverLap){
		//check to see if there is a prev cell in the col that is not blank
		prevCol = col;
		if(m_ctrl->m_GI->m_defDataSource->GetPrevNonBlankCol(&prevCol,row) == UG_SUCCESS){
	
			//check to see if the text in the cell that was found
			//is wider than the column that it is in
			m_ctrl->GetCellIndirect(prevCol,row,cell);
			// call GetBestSize for cell type set to this cell
			size.cx = m_ctrl->GetColWidth( prevCol );
			size.cy = m_ctrl->GetRowHeight( row );
			(m_ctrl->GetCellType( cell->GetCellType()))->GetBestSize( dc, &size, cell );

			//if the prev cell is wider than its column width
			//and the cell allows overlapping

			if(size.cx > m_ctrl->GetColWidth(prevCol) &&
				m_ctrl->GetCellType(cell->GetCellType())->
				CanOverLap(cell) != FALSE){

				//check to see how many columns wide it is
				width = 0;
				for(loop = prevCol;loop <col;loop++){
					width += m_ctrl->GetColWidth(loop);
					if(width > size.cx){
						break;
					}
				}
				//check to see if the current cell is within the string width
				if(col == loop){
					*overlapCol = prevCol;
					//if we're printing then use the font scale factor otherwise make it 1.0
					if( !dc->IsPrinting() )
						m_dScaleFactor = 1.0;
					return (int)( - (double)(width) * m_dScaleFactor );
				}
			}					
		}
	}
	return 0;
}

/****************************************************
OnScrolled
	This event is called for all celltypes currently added
	to the grid when the view area is scrolled.
Params:
	col, row	- cell coordinates identifying current cell
	cell		- pointer to current cell
Return:
	<none>
*****************************************************/
void CUGCellType::OnScrolled(int col,long row,CUGCell *cell)
{
	UNREFERENCED_PARAMETER(col);
	UNREFERENCED_PARAMETER(row);
	UNREFERENCED_PARAMETER(*cell);
}

/****************************************************************************
BitmapToDIB
	This function creates a DIB from a bitmap using the specified palette. 
Params:
	HBITMAP hBitmap  - specifies the bitmap to convert 
	HPALETTE hPal    - specifies the palette to use with the bitmap 
Return:
	HANDLE            - identifies the device-dependent bitmap 
*****************************************************************************/
HANDLE CUGCellType::BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal) 
{ 
    BITMAP              bm;         // bitmap structure 
    BITMAPINFOHEADER    bi;         // bitmap header 
    LPBITMAPINFOHEADER  lpbi;       // pointer to BITMAPINFOHEADER 
    DWORD               dwLen;      // size of memory block 
    HANDLE              hDIB,		// handle to DIB
						tempHandle;	// temp handle 
    HDC                 hDC;        // handle to DC 
    DWORD               biBits;     // bits per pixel 
 
    // check if bitmap handle is valid  
    if (!hBitmap) return NULL; 
 
    // fill in BITMAP structure, return NULL if it didn't work 
    if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm)) 
        return NULL; 
 
    // if no palette is specified, use default palette 
    if (hPal == NULL) 
        hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE); 
 
    // calculate bits per pixel 
    biBits = bm.bmPlanes * bm.bmBitsPixel; 
 
    // make sure bits per pixel is valid  
    if (biBits <= 1) biBits = 1; 
    else if (biBits <= 4) biBits = 4; 
    else if (biBits <= 8) biBits = 8; 
    else // if greater than 8-bit, force to 24-bit 
        biBits = 24; 
 
    // initialize BITMAPINFOHEADER 
 
    bi.biSize = sizeof(BITMAPINFOHEADER); 
    bi.biWidth = bm.bmWidth; 
    bi.biHeight = bm.bmHeight; 
    bi.biPlanes = 1; 
    bi.biBitCount = (WORD)biBits; 
    bi.biCompression = BI_RGB; 
    bi.biSizeImage = 0; 
    bi.biXPelsPerMeter = 0; 
    bi.biYPelsPerMeter = 0; 
    bi.biClrUsed = 0; 
    bi.biClrImportant = 0; 
 
    // calculate size of memory block required to store BITMAPINFO 
    dwLen = bi.biSize + PaletteSize((LPSTR)&bi); 
 
    // get a DC 
    hDC = GetDC(NULL); 
 
    // select and realize our palette  
    hPal = SelectPalette(hDC, hPal, FALSE); 
    RealizePalette(hDC); 
 
    // alloc memory block to store our bitmap  
    hDIB = GlobalAlloc(GHND, dwLen); 
 
    // if we couldn't get memory block 
    if (!hDIB) 
    { 
      // clean up and return NULL  
      SelectPalette(hDC, hPal, TRUE); 
      RealizePalette(hDC); 
      ReleaseDC(NULL, hDC); 
      return NULL; 
    } 
 
    // lock memory and get pointer to it  
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
 
    /// use our bitmap info. to fill BITMAPINFOHEADER  
    *lpbi = bi; 
 
    // call GetDIBits with a NULL lpBits param, so it will calculate the 
    // biSizeImage field for us     
    GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 
        DIB_RGB_COLORS); 
 
    // get the info. returned by GetDIBits and unlock memory block  
    bi = *lpbi; 
    GlobalUnlock(hDIB); 
 
    // if the driver did not fill in the biSizeImage field, make one up  
    if (bi.biSizeImage == 0) 
        bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight; 
 
    // realloc the buffer big enough to hold all the bits  
    dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage; 
 
	tempHandle = GlobalReAlloc(hDIB, dwLen, 0);
    if (tempHandle != NULL ) 
        hDIB = tempHandle; 
    else 
    { 
        // clean up and return NULL  
        GlobalFree(hDIB); 
        hDIB = NULL; 
        SelectPalette(hDC, hPal, TRUE); 
        RealizePalette(hDC); 
        ReleaseDC(NULL, hDC); 
        return NULL; 
    } 
 
    // lock memory block and get pointer to it 
    lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 
 
    // call GetDIBits with a NON-NULL lpBits param, and actualy get the 
    // bits this time 
 
    if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPSTR)lpbi + 
            (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 
            DIB_RGB_COLORS) == 0) 
    { 
        // clean up and return NULL 
 
        GlobalUnlock(hDIB); 
        hDIB = NULL; 
        SelectPalette(hDC, hPal, TRUE); 
        RealizePalette(hDC); 
        ReleaseDC(NULL, hDC); 
        return NULL; 
    } 
 
    bi = *lpbi; 
 
    // clean up  
    GlobalUnlock(hDIB); 
    SelectPalette(hDC, hPal, TRUE); 
    RealizePalette(hDC); 
    ReleaseDC(NULL, hDC); 
 
    // return handle to the DIB 
    return hDIB; 
} 

/****************************************************************************
PaletteSize
	This function gets the size required to store the DIB's palette by 
	multiplying the number of colors by the size of an RGBQUAD (for a 
	Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2- 
	style DIB).
Params:
	LPSTR lpDIB      - pointer to packed-DIB memory block 
Return:
	WORD             - size of the color palette of the DIB 
*****************************************************************************/
DWORD CUGCellType::PaletteSize(LPSTR lpDIB) 
{ 
    // calculate the size required by the palette 
    if (IS_WIN30_DIB (lpDIB)) 
        return (DIBNumColors(lpDIB) * sizeof(RGBQUAD)); 
    else 
        return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE)); 
}

/****************************************************************************
DIBNumColors
	This function calculates the number of colors in the DIB's color table 
	by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style 
	DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, 
	if 24, no colors in color table. 
Params:
	LPSTR lpDIB      - pointer to packed-DIB memory block 
Return:
	WORD             - number of colors in the color table 
*****************************************************************************/
WORD CUGCellType::DIBNumColors(LPSTR lpDIB) 
{ 
    WORD wBitCount;  // DIB bit count 
 
    // If this is a Windows-style DIB, the number of colors in the 
    // color table can be less than the number of bits per pixel 
    // allows for (i.e. lpbi->biClrUsed can be set to some value). 
    // If this is the case, return the appropriate value.  
 
    if (IS_WIN30_DIB(lpDIB)) 
    { 
        DWORD dwClrUsed; 
         dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed; 
        if (dwClrUsed) return (WORD)dwClrUsed; 
    } 
 
    // Calculate the number of colors in the color table based on 
    // the number of bits per pixel for the DIB. 
     
    if (IS_WIN30_DIB(lpDIB)) 
        wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount; 
    else 
        wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; 
 
    // return number of colors based on bits per pixel 
 
    switch (wBitCount) 
    { 
        case 1: return 2; 
        case 4: return 16; 
        case 8: return 256; 
        default:return 0; 
    } 
} 

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
Canada Canada
In January 2005, David Cunningham and Chris Maunder created TheUltimateToolbox.com, a new group dedicated to the continued development, support and growth of Dundas Software’s award winning line of MFC, C++ and ActiveX control products.

Ultimate Grid for MFC, Ultimate Toolbox for MFC, and Ultimate TCP/IP have been stalwarts of C++/MFC development for a decade. Thousands of developers have used these products to speed their time to market, improve the quality of their finished products, and enhance the reliability and flexibility of their software.
This is a Organisation

476 members

Comments and Discussions