Click here to Skip to main content
15,886,046 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.8K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
/*************************************************************************
				Class Implementation : CUGGrid
**************************************************************************
	Source file : UGGrid.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 <math.h>
#include "UGCtrl.h"
/*	define WM_HELPHITTEST and WM_COMMANDHELP messages
	required for the context sensitive help support*/
#include <afxpriv.h>

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

#ifndef WM_THEMECHANGED
#define WM_THEMECHANGED                 0x031A
#endif

/***************************************************
	Standard construction/desrtuction
***************************************************/
CUGGrid::CUGGrid()
{
	m_doubleBufferMode	= FALSE;
	m_keyRepeatCount	= 0;
	m_hasFocus			= FALSE;
	m_cellTypeCapture	= FALSE;
	m_bitmap			= NULL;
	m_tempDisableFocusRect = FALSE;
	m_bHandledMouseDown	= FALSE;
}

CUGGrid::~CUGGrid()
{
	if(m_bitmap != NULL)
		delete m_bitmap;
}

/********************************************
	Message handlers
*********************************************/
BEGIN_MESSAGE_MAP(CUGGrid, CWnd)
	//{{AFX_MSG_MAP(CUGGrid)
	ON_WM_PAINT()
	ON_WM_KEYDOWN()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	ON_WM_RBUTTONUP()
	ON_WM_CHAR()
	ON_WM_KILLFOCUS()
	ON_WM_SETFOCUS()
	ON_WM_MOUSEACTIVATE()
	ON_WM_SIZE()	
	ON_WM_SETCURSOR()
	ON_WM_KEYUP()
	ON_WM_GETDLGCODE()
	ON_WM_CREATE()
	ON_WM_RBUTTONDBLCLK()
	ON_WM_VSCROLL()
	ON_WM_HSCROLL()
	ON_WM_ERASEBKGND()
	ON_MESSAGE(WM_HELPHITTEST, OnHelpHitTest)
	ON_WM_HELPINFO()
	//}}AFX_MSG_MAP

	ON_NOTIFY_EX( TTN_NEEDTEXT, 0, ToolTipNeedText)

	#ifdef WM_MOUSEWHEEL
		ON_WM_MOUSEWHEEL()
	#endif

END_MESSAGE_MAP()

/***************************************************
OnCreate
	Please see MSDN for more details on this event
	handler.
Params:
	lpCreateStruct	- Points to a CREATESTRUCT structure
					  that contains information about the
					  CWnd object being created. 
Returns:
	OnCreate must return 0 to continue the creation of the
	CWnd object. If the application returns �1, the window
	will be destroyed.
*****************************************************/
int CUGGrid::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if(m_GI->m_enableHints)
		EnableToolTips(TRUE);

	return 0;
}

/***************************************************
ToolTipNeedText (TTN_NEEDTEXT)
	message handler will be called whenever a text is required for a tool tip.
	The Ultimate Grid uses the CUGCtrl::OnHint virtual function to obtain
	proper text to be displayed in the too tip.
Params:
		id			- Identifier of the control that sent the notification. Not
					  used. The control id is taken from the NMHDR structure.
		pTTTStruct	- A pointer to theNMTTDISPINFO structure. This structure is
					  also discussed further in The TOOLTIPTEXT Structure.
		pResult		- A pointer to result code you can set before you return.
					  TTN_NEEDTEXT handlers can ignore the pResult parameter.
Returns:
	<none>
*****************************************************/
BOOL CUGGrid::ToolTipNeedText( UINT id, NMHDR* pTTTStruct, LRESULT* pResult )
{
	UNREFERENCED_PARAMETER(id);
	UNREFERENCED_PARAMETER(*pResult);
	
	static CString string;
	int col;
	long row;
	// get mouse coordinates
	POINT point;
	GetCursorPos( &point );
	ScreenToClient( &point );

	// check if the mouse pointer is over a cell
	if ( m_ctrl->GetCellFromPoint( point.x, point.y, &col, &row ) == UG_SUCCESS )
	{
		if ( m_ctrl->OnHint( col, row, UG_GRID, &string ) == TRUE )
		{
			TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pTTTStruct;
			// Do this to Enable multiline ToolTips
			::SendMessage( pTTT->hdr.hwndFrom, TTM_SETMAXTIPWIDTH, 0, SHRT_MAX );
			::SendMessage( pTTT->hdr.hwndFrom, TTM_SETDELAYTIME, TTDT_AUTOPOP, SHRT_MAX );
			::SendMessage( pTTT->hdr.hwndFrom, TTM_SETDELAYTIME, TTDT_INITIAL, 200 );
			::SendMessage( pTTT->hdr.hwndFrom, TTM_SETDELAYTIME, TTDT_RESHOW, 200 );
			// set tool tip's string
			pTTT->lpszText = const_cast<LPTSTR>((LPCTSTR)string);

			return TRUE;
		}
	}
	return FALSE;
}

/***************************************************
OnToolHitTest
	The framework calls this member function to determine whether a point is in
	the bounding rectangle of the specified tool. If the point is in the
	rectangle, it retrieves information about the tool.
Params:
	point	- please see MSDN for more information on the parameters.
	pTI
Returns:
	If 1, the tooltip control was found; If -1, the tooltip control was not found.
*****************************************************/
// v7.2 - update 02 - 64-bit - changed from int to UGINTRET - see UG64Bit.h
UGINTRET CUGGrid::OnToolHitTest( CPoint point, TOOLINFO* pTI ) const
{
	int col;
	long row;
	static int lastCol = -2;
	static long lastRow = -2;
	
	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row) == UG_SUCCESS)
	{
		if(col != lastCol || row != lastRow)
		{
			lastCol = col;
			lastRow = row;
			CancelToolTips();
			return -1;
		}

		// v7.2 - update 03 - added TTF_TRANSPARENT flag. This prevents a 
		//        recursive flicker of large tooltips that are forced to 
		//        encroach on the mouse position. Reported by Kuerscht
		pTI->uFlags =  TTF_TRANSPARENT | TTF_NOTBUTTON | TTF_ALWAYSTIP |TTF_IDISHWND ;
		pTI->uId = (UINT_PTR)m_hWnd;
		pTI->hwnd = (HWND)m_hWnd;
		pTI->lpszText = LPSTR_TEXTCALLBACK;
		return 1;
	}
	return -1;
}
/***************************************************
OnPaint
	This routine is responsible for gathering the
	information to draw, get the selected state
	plus draw in an optomized fashion
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::OnPaint() 
{
	if ( m_GI->m_paintMode == FALSE )
		return;

	CClientDC dc(this);
	//redraw the cells in any invalid region
	CRect clipRect;

	if ( GetUpdateRect( clipRect ) == 0 )
		return;

	ValidateRect( NULL );

	//if( dc.GetClipBox( clipRect ) != NULLREGION )
	if ( clipRect.left == 0 && clipRect.right == 0 &&
		 clipRect.top == 0 && clipRect.bottom == 0 )
	{
		// redraw all cells in the grid.
		m_drawHint.AddHint(0,0,m_GI->m_numberCols,m_GI->m_numberRows);
	}
	else
	{
		int startCol	= 0,
			endCol		= m_GI->m_numberCols;
		long startRow	= 0,
			 endRow		= m_GI->m_numberRows;
		// determine the top-left and bottom-right cells of the clip rectangle
		m_ctrl->GetCellFromPoint( clipRect.left, clipRect.top, &startCol, &startRow );
		m_ctrl->GetCellFromPoint( clipRect.right, clipRect.bottom, &endCol, &endRow );
		// if the bottom right cell in the range is part of a join,
		// than get information on 'join end' cell.
		CUGCell cell;
		m_ctrl->GetCell( endCol, endRow, &cell );
		BOOL bOrigin;
		int stCol;
		long stRow;
		if ( cell.GetJoinInfo( &bOrigin, &stCol, &stRow ) == UG_SUCCESS )
		{
			endCol = endCol + stCol;
			endRow = endRow + stRow;
		}

		// redraw the region of cells that are affected by the invalid rect
		m_drawHint.AddHint( startCol, startRow, endCol, endRow );

		// if the current cell is not part of the clip region,
		// add the current cell to the draw hints
		if (!(startCol >= m_ctrl->GetCurrentCol() && endCol <= m_ctrl->GetCurrentCol() &&
			 startRow >= m_ctrl->GetCurrentRow() && endRow <= m_ctrl->GetCurrentRow()))
		{	
			if ( m_GI->m_highlightRowFlag == FALSE )
				m_drawHint.AddHint( m_ctrl->GetCurrentCol(), m_ctrl->GetCurrentRow());
			else
				m_drawHint.AddHint( 0, m_ctrl->GetCurrentRow(), m_GI->m_numberCols, m_ctrl->GetCurrentRow());
		}
	}

	//double buffering
	CDC * db_dc = NULL;
	if(m_doubleBufferMode)
	{
		db_dc = new CDC;
		db_dc->CreateCompatibleDC(NULL);
		db_dc->SelectObject(m_bitmap);
	}
	
	DrawCellsIntern(&dc,db_dc);
	m_drawHint.ClearHints();

	if(db_dc!= NULL)
		delete db_dc;
}

/***************************************************
PaintDrawHintsNow
	Redraws all of the cells in that have been added
	the the CUGDrawHints (m_drawHint).
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::PaintDrawHintsNow(LPCRECT invalidateRect){

	InvalidateRect(invalidateRect,FALSE);

	CPaintDC dc(this); // device context for painting

	//double buffering
	CDC * db_dc = NULL;
	if(m_doubleBufferMode){
		db_dc = new CDC;
		db_dc->CreateCompatibleDC(NULL);
		db_dc->SelectObject(m_bitmap);
	}
	
	DrawCellsIntern(&dc,db_dc);

	if(db_dc!= NULL)
		delete db_dc;
}

/***************************************************
DrawCellsIntern
	function is the key to the fast redraw functionality in the Ultimate Grid.
	This function is responsible for drawing cells within the grid area, it
	makes sure that only the cells that are marked as invalid
	(by calling CUGDrawHint::IsInvalid function) are redrawn.
Params:
	dc		- screen DC
	db_dc	- off-screen DC, used when double buffering is enabled.
Returns:
	<none>
*****************************************************/
void CUGGrid::DrawCellsIntern(CDC *dc,CDC *db_dc)
{
	RECT		rect = {0,0,0,0};
	RECT		cellRect;
	RECT		tempRect;
	
	CUGCell		cell,tempCell;
	CString		string;
	CSize		size;

	RECT		focusRect = {-1,-1,-1,-1};
	CUGCellType * cellType;

	int			rightBlank	= -1;
	int			bottomBlank = -1;

	int			col,x;
	long		row,y;

	int			selectBlock;

	int			dcID;
	CDC*		origDC = dc;

	//double buffering
	if(m_doubleBufferMode)
	{
		origDC = dc;
		dc =  db_dc;
		//get the default font to use
		if(m_GI->m_defFont != NULL){
			origDC->SelectObject(m_GI->m_defFont);
			dc->SelectObject(m_GI->m_defFont);
		}
	}
	else{
		//get the default font to use
		if(m_GI->m_defFont != NULL){
			dc->SelectObject(m_GI->m_defFont);
		}
	}
	
	m_ctrl->OnScreenDCSetup(origDC,db_dc,UG_GRID);
	
	//set the right and bottom vars to point to
	//the extremes, if the right or bottom is
	//sooner then they will be updated in the
	//main drawing loop
	m_GI->m_rightCol = m_GI->m_numberCols;
	m_GI->m_bottomRow = m_GI->m_numberRows;
	
	//main draw loop, this loop goes through all visible
	//cells and checks to see if they need redrawing
	//if they do then the cell is retrieved and drawn
	for(y = 0; y < m_GI->m_numberRows;y++)
	{
		//skip rows hidden under locked rows
		if(y == m_GI->m_numLockRows)
			y = m_GI->m_topRow;

		row = y;

		//calc the top bottom and right side of the rect 
		//for the current cell to be drawn
		rect.top = rect.bottom;

		if(m_GI->m_uniformRowHeightFlag)
			rect.bottom += m_GI->m_defRowHeight;
		else
			rect.bottom += m_GI->m_rowHeights[row];

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

		rect.right = 0;

		//check all visible cells in the current row to 
		//see if they need drawing
		for(x = 0;x < m_GI->m_numberCols;x++){

			//skip cols hidden under locked cols
			if(x == m_GI->m_numLockCols)
				x = m_GI->m_leftCol;

			row = y;
			col = x;

			//calc the left and right side of the rect
			rect.left = rect.right;
			rect.right  += m_GI->m_colInfo[col].width;

			if(rect.left == rect.right)
				continue;

			//check to see if the cell need to be redrawn
			if(m_drawHint.IsInvalid(col,row) != FALSE){
	
				//copy the rect, then use the cellRect from here
				//this is done since the cellRect may be modified
				CopyRect(&cellRect,&rect);

				//get the cell to draw
				m_ctrl->GetCellIndirect(col,row,&cell);

				//check to see if the cell is joined
				if(cell.IsPropertySet(UGCELL_JOIN_SET)){
					m_ctrl->GetCellRect(col,row,&cellRect);
					m_ctrl->GetJoinStartCell(&col,&row,&cell);
					if(m_drawHint.IsValid(col,row))
						continue;
					m_drawHint.SetAsValid(col,row);
				}

				//get the cell type to draw the cell
				if(cell.IsPropertySet(UGCELL_CELLTYPE_SET)){
					cellType = m_ctrl->GetCellType(cell.GetCellType());
				}
				else
				{
					cellType = m_ctrl->GetCellType(-1);
				}


				dcID = dc->SaveDC();

				//draw the cell, check to see if it is 'current' and/or selected
				CopyRect(&tempRect,&cellRect);
				if(row == m_GI->m_currentRow && ( col == m_GI->m_currentCol || m_GI->m_highlightRowFlag))
					cellType->OnDraw(dc,&cellRect,col,row,&cell,0,1);
				else{
					if(m_GI->m_multiSelect->IsSelected(col,row,&selectBlock))
						cellType->OnDraw(dc,&cellRect,col,row,&cell,selectBlock+1,0);
					else
						cellType->OnDraw(dc,&cellRect,col,row,&cell,0,0);
				}
				CopyRect(&cellRect,&tempRect);

				//draw a black line at the right edge of the locked columns
				if(m_GI->m_numLockCols >0){
					if(col == m_GI->m_leftCol){
						dc->SelectObject(GetStockObject(BLACK_PEN));
						dc->MoveTo(cellRect.left-1,cellRect.top);
						dc->LineTo(cellRect.left-1,cellRect.bottom+1);
					}
					else if(col == m_GI->m_numLockCols-1){
						dc->SelectObject(GetStockObject(BLACK_PEN));
						dc->MoveTo(cellRect.right-1,cellRect.top);
						dc->LineTo(cellRect.right-1,cellRect.bottom+1);
					}
				}
				//draw a black line at the bottom of the locked rows
				if(m_GI->m_numLockRows >0){
					if(row == m_GI->m_topRow ){
						dc->SelectObject(GetStockObject(BLACK_PEN));
						dc->MoveTo(cellRect.left,cellRect.top-1);
						dc->LineTo(cellRect.right+1,cellRect.top-1);
					}
					else if(row == m_GI->m_numLockRows-1){
						dc->SelectObject(GetStockObject(BLACK_PEN));
						dc->MoveTo(cellRect.left,cellRect.bottom-1);
						dc->LineTo(cellRect.right+1,cellRect.bottom-1);
					}
				}

				dc->RestoreDC(dcID);
			}

			//check to see if the focus rect should be drawn
			//this function should be called all the time
			//even if it is off screen
			if(row == m_GI->m_currentRow && (col == m_GI->m_currentCol || 
				m_GI->m_highlightRowFlag)){
				CopyRect(&focusRect,&cellRect);
			}

			//check to see if the right side of the rect is past the edge
			//of the grid drawing area, if so then break
			if(rect.right > m_GI->m_gridWidth){
				m_GI->m_rightCol = col;
				break;
			}
		
		}

		//check to see if there is blank space on the right side of the grid
		//drawing area
		if(rect.right < m_GI->m_gridWidth && m_GI->m_rightCol == m_GI->m_numberCols){
			rightBlank = rect.right;
		}

		//check to see if the bottom of the rect is past the bottom of the 
		//grid drawing area, if so then break
		if(rect.bottom > m_GI->m_gridHeight){
			m_GI->m_bottomRow = row;
			break;
		}

		//check for extra rows
		if(y >= (m_GI->m_numberRows-1)){
			long origNumRows = m_GI->m_numberRows;
			long newRow = y+1;
			m_ctrl->VerifyCurrentRow(&newRow);
			if(m_GI->m_numberRows > origNumRows){
				m_drawHint.AddHint(0,y+1,m_GI->m_numberCols-1,y+1);
			}
		}
	}

	//clear the draw hints
	m_drawHint.ClearHints();

	//check to see if there is blank space on the bottom of the grid
	//drawing area
	if(rect.bottom < m_GI->m_gridHeight && m_GI->m_bottomRow == m_GI->m_numberRows)
		bottomBlank = rect.bottom;
	
	//fill in the blank grid drawing areas
	if(rightBlank >=0 || bottomBlank >=0){
		CBrush brush(m_ctrl->OnGetDefBackColor(UG_GRID));
		GetClientRect(&rect);
		if(rightBlank >=0){
			rect.left = rightBlank;
			dc->FillRect(&rect,&brush);
		}
		if(bottomBlank >=0){
			rect.left = 0;
			rect.top = bottomBlank;
			dc->FillRect(&rect,&brush);
		}
	}

	//double buffering
	if(m_doubleBufferMode){
		dc = origDC;
		dc->BitBlt(0,0,m_GI->m_gridWidth,m_GI->m_gridHeight,db_dc,0,0,SRCCOPY);
	}	
	
	//draw the focus rect, if the flag was set above
	if(!m_tempDisableFocusRect){
		if((m_hasFocus || m_ctrl->m_findDialogRunning) && !m_ctrl->m_editInProgress)		
		{
			if(m_GI->m_highlightRowFlag)
			{
				focusRect.left = 0;

				if(rect.right < m_GI->m_gridWidth)
					focusRect.right = rect.right;
				else
				{
					if( m_GI->m_bExtend )
						focusRect.right = m_GI->m_gridWidth;
					else
					{
						int iStartCol = m_ctrl->GetLeftCol(), iEndCol = m_ctrl->GetNumberCols() - 1;
						int iWidth = 0;
						for( int iLoop = iStartCol ; iLoop <= iEndCol ; iLoop++ )
							iWidth += m_ctrl->GetColWidth( iLoop );

						focusRect.right = iWidth;
					}
				}
			}
			m_ctrl->OnDrawFocusRect(dc,&focusRect);
		}
	}

	//reset temporary flags
	m_tempDisableFocusRect = FALSE;
}

/***************************************************
RedrawCell
	function is called to redraw a single cell, it will add provided cell
	to draw hints (CUGDrawHint) and forces the window to update.
Params:
	col, row	- coordinates of cell to redraw
Returns:
	<none>
*****************************************************/
void CUGGrid::RedrawCell(int col,long row)
{
	m_drawHint.AddHint(col,row);
	Moved();
}

/***************************************************
RedrawRow
	function is called to redraw a single cell, it will add provided cells
	to draw hints (CUGDrawHint) and forces the window to update.
Params:
	row			- indicates the row number to update.
Returns:
	<none>
*****************************************************/
void CUGGrid::RedrawRow(long row)
{
	m_drawHint.AddHint(0,row,m_GI->m_numberCols-1,row);
	Moved();
}

/***************************************************
RedrawCol
	function is called to redraw a single cell, it will add provided cells
	to draw hints (CUGDrawHint) and forces the window to update.
Params:
	col			- indicates the column number to update.
Returns:
	<none>
*****************************************************/
void CUGGrid::RedrawCol(int col)
{
	m_drawHint.AddHint(col,0,col,m_GI->m_numberRows-1);
	Moved();
}

/***************************************************
RedrawRange
	function is called to redraw a single cell, it will add provided cells
	to draw hints (CUGDrawHint) and forces the window to update.
Params:
	startCol,	- parameters passed in indicate the range of cells to be redrawn
	startRow,	  the range's top-left corned is indicated by the StartCol and
	endCol,		  StartRow, and the bottom-right corner by the endCol and endRow.
	endRow
Returns:
	<none>
*****************************************************/
void CUGGrid::RedrawRange(int startCol,long startRow,int endCol,long endRow)
{
	m_drawHint.AddHint(startCol,startRow,endCol,endRow);
	Moved();
}

/***************************************************
TempDisableFocusRect
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::TempDisableFocusRect(){
	m_tempDisableFocusRect = TRUE;
}


/***************************************************
Update
	function forces window update.
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::Update()
{
	InvalidateRect(NULL);
	UpdateWindow();
	return;
}

/***************************************************
Moved
	This routine recalcs the internal variables
	plus causes the grid to re-draw itself
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::Moved()
{
	int xScroll = 0;
	int yScroll = 0;
	int x;
	long y;
	CDC * pDC, *screenDC,*db_DC = NULL;

	if(GetUpdateRect(NULL)){
		UpdateWindow();
		return;
	}
	if(m_ctrl->m_findDialogRunning){
		Invalidate();
		UpdateWindow();
		return;
	}
	if(m_GI->m_enableVScrollHints || m_GI->m_enableHScrollHints){
		Invalidate();
		UpdateWindow();
		return;
	}

	/*	If the grid window is overlapped by other windows, 
		we should repaint the whole grid.*/
	HWND hPrevWnd, hNextWnd, hActiveWnd, hDtWnd;
	RECT rectGrid, rectOther, rectDest, rectSub, rectVisible;

	// Check if the grid window is overlapped by other windows
	GetWindowRect(&rectGrid);
	::CopyRect(&rectVisible, &rectGrid);
	for (hPrevWnd = m_hWnd; (hNextWnd = ::GetWindow(hPrevWnd, GW_HWNDPREV)) != NULL; hPrevWnd = hNextWnd){
	    ::GetWindowRect(hNextWnd, &rectOther);
		if (::IsWindowVisible(hNextWnd) && IntersectRect(&rectDest, &rectGrid, &rectOther)){
			::SubtractRect(&rectSub, &rectVisible, &rectDest);
			::CopyRect(&rectVisible, &rectSub);
		}
	}
	if ( !EqualRect(&rectVisible, &rectGrid) ) {
		Invalidate();
		UpdateWindow();
		return;
	}

	// Check if the grid is cliped by the active window (e.g. MDI frame window)
	hActiveWnd = ::GetActiveWindow();
	if ( (NULL != hActiveWnd) && (m_hWnd != hActiveWnd) ) {
		::GetWindowRect(hActiveWnd, &rectOther);
		if (::IsWindowVisible(hActiveWnd) && IntersectRect(&rectDest, &rectGrid, &rectOther)){
			if ( !EqualRect(&rectDest, &rectGrid) ) {
				Invalidate();
				UpdateWindow();
				return;
			}
		}
	}

	// Check if the grid is cliped by the desktop window
	hDtWnd = ::GetDesktopWindow();
	if ( (NULL != hDtWnd) && (m_hWnd != hDtWnd) ) {
		::GetWindowRect(hDtWnd, &rectOther);
		if (::IsWindowVisible(hDtWnd) && IntersectRect(&rectDest, &rectGrid, &rectOther)){
			if ( !EqualRect(&rectDest, &rectGrid) ) {
				Invalidate();
				UpdateWindow();
				return;
			}
		}
	}

	BOOL redrawAll = FALSE;

	//if the left col has changed then calc the scroll distance
	if(m_GI->m_leftCol != m_GI->m_lastLeftCol)
	{
		if(m_GI->m_leftCol > m_GI->m_lastLeftCol)
		{
			for(x = m_GI->m_lastLeftCol;x < m_GI->m_leftCol; x++)
			{
				xScroll += m_ctrl->GetColWidth(x);
				if(xScroll > m_GI->m_gridWidth)
				{
					redrawAll = TRUE;
					break;
				}
			}
		}
		else
		{
			for(x = m_GI->m_leftCol;x < m_GI->m_lastLeftCol; x++)
			{
				xScroll -= m_ctrl->GetColWidth(x);
				if(xScroll < -m_GI->m_gridWidth)
				{
					redrawAll = TRUE;
					break;
				}
			}
		}
		if(redrawAll)
		{
			xScroll = 0;
			//redraw the whole grid
			m_drawHint.AddHint(0,0,m_GI->m_numberCols,m_GI->m_numberRows);
		}
	}

	//if the top row has changed then calc the scroll distance
	if(m_GI->m_topRow != m_GI->m_lastTopRow)
	{
		if(m_GI->m_topRow > m_GI->m_lastTopRow)
		{
			for(y = m_GI->m_lastTopRow;y < m_GI->m_topRow; y++)
			{
				yScroll += m_ctrl->GetRowHeight(y);
				if(yScroll > m_GI->m_gridHeight)
				{
					redrawAll = TRUE;
					break;
				}
			}
		}
		else
		{
			for(y = m_GI->m_topRow;y < m_GI->m_lastTopRow; y++)
			{
				yScroll -= m_ctrl->GetRowHeight(y);
				if(yScroll < -m_GI->m_gridHeight)
				{
					redrawAll = TRUE;
					break;
				}
			}
		}
		if(redrawAll)
		{
			yScroll = 0;
			//redraw the whole grid
			m_drawHint.AddHint(0,0,m_GI->m_numberCols,m_GI->m_numberRows);
		}
	}

	//create the dc
	screenDC = GetDC();
	if(m_doubleBufferMode)
	{
		pDC = new CDC;
		pDC->CreateCompatibleDC(NULL);
		pDC->SelectObject(m_bitmap);
		db_DC = pDC;
	}
	else
	{
		pDC = screenDC;
	}

	//do scrolling of the window here
	if(xScroll != 0 || yScroll != 0)
	{
		RECT scrollRect;
		GetClientRect(&scrollRect);
		if(xScroll == 0)
			scrollRect.top += m_GI->m_lockRowHeight;
		if(yScroll == 0)
			scrollRect.left += m_GI->m_lockColWidth;
		pDC->ScrollDC(-xScroll,-yScroll,&scrollRect,&scrollRect,NULL,NULL);
		
		//add the draw hints for the area the was uncovered by the scroll
		if(xScroll >0)
			m_drawHint.AddHint(m_GI->m_rightCol,0,m_GI->m_numberCols,m_GI->m_numberRows);
		else if(xScroll < 0)
			m_drawHint.AddHint(0,0,m_GI->m_lastLeftCol,m_GI->m_numberRows);
		if(yScroll >0)
			m_drawHint.AddHint(0,m_GI->m_bottomRow,m_GI->m_numberCols,m_GI->m_numberRows);
		else if(yScroll < 0)
			m_drawHint.AddHint(0,0,m_GI->m_numberCols,m_GI->m_lastTopRow);
	}

	//add the last and current cells - add row support later
	if(m_GI->m_highlightRowFlag)
	{
		m_drawHint.AddHint(0,m_GI->m_lastRow,m_GI->m_numberCols,m_GI->m_lastRow);
		m_drawHint.AddHint(0,m_GI->m_currentRow,m_GI->m_numberCols,m_GI->m_currentRow);
	}
	else
	{
		m_drawHint.AddHint(m_GI->m_lastCol,m_GI->m_lastRow);
		m_drawHint.AddHint(m_GI->m_currentCol,m_GI->m_currentRow);
	}

	//call the grids main drawing routine
	DrawCellsIntern(screenDC,db_DC);

	//double buffering
	if(m_doubleBufferMode)
		delete db_DC;
	
	//close the device context
	ReleaseDC(screenDC);
}

/***************************************************
OnKeyDown
	Passes all keystrokes to a callback routine in CUGCtrl (OnKeyDown)
	then processes them.  The callback has ability to diallow further processing
	of the event.
Params:
	nChar		- please see MSDN for more information on the parameters.
	nRepCnt
	nFlags
Returns:
	<none>
*****************************************************/
void CUGGrid::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	UNREFERENCED_PARAMETER(nRepCnt);
	UNREFERENCED_PARAMETER(nFlags);

	m_GI->m_moveType = 0;	//key(default)

	int increment = 1; //default number of units to move

	if(m_GI->m_ballisticKeyMode > 0)
	{
		m_keyRepeatCount++;

		int value = (m_keyRepeatCount / m_GI->m_ballisticKeyMode);
		increment = value*value*value + 1;

		if( m_GI->m_ballisticKeyDelay > 0 )
		{
			if( value == 0 && m_keyRepeatCount > 1 )
				Sleep(m_GI->m_ballisticKeyDelay);
		}
	}

	//send a notify message to the cell type class
	BOOL processed = m_ctrl->GetCellType(m_GI->m_currentCol,m_GI->m_currentRow)->
		OnKeyDown(m_GI->m_currentCol,m_GI->m_currentRow,&nChar);

	//send a keydown notify message
	m_ctrl->OnKeyDown(&nChar,processed);

	int  curCol = m_GI->m_currentCol;
	long curRow = m_GI->m_currentRow;
	int  JoinCellStartCol, JoinCellEndCol, colOff, rowOff;
	long JoinCellStartRow, JoinCellEndRow;

	//process the keystroke
	if(nChar == VK_LEFT)
	{
		JoinCellStartCol = curCol - increment;
		JoinCellStartRow = curRow;
		if ( (JoinCellStartCol >= 0) && (m_ctrl->GetJoinStartCell(&JoinCellStartCol,&JoinCellStartRow) == UG_SUCCESS) )
		{
			m_ctrl->GotoCell(m_GI->m_dragCol - (curCol - JoinCellStartCol),
							 m_GI->m_dragRow - (curRow - JoinCellStartRow));
		}
		else
			m_ctrl->GotoCol(m_GI->m_dragCol - increment);
	}
	else if(nChar == VK_RIGHT)
	{
		JoinCellStartCol = curCol;
		JoinCellStartRow = curRow;
		colOff = increment;
		if ( m_ctrl->GetJoinRange(&JoinCellStartCol,&JoinCellStartRow, &JoinCellEndCol,&JoinCellEndRow) == UG_SUCCESS )
			colOff = (JoinCellEndCol - JoinCellStartCol) + increment;

		JoinCellStartRow = curRow;
		JoinCellStartCol = curCol + colOff;
		if (m_ctrl->GetJoinStartCell(&JoinCellStartCol,&JoinCellStartRow) == UG_SUCCESS)
		{
			m_ctrl->GotoCell(m_GI->m_dragCol - (curCol - JoinCellStartCol),
							 m_GI->m_dragRow - (curRow - JoinCellStartRow));
		}
		else
			m_ctrl->GotoCol(m_GI->m_dragCol + colOff);
	}
	else if(nChar == VK_UP)
	{
		JoinCellStartCol = curCol;
		JoinCellStartRow = curRow - increment;
		if ( (JoinCellStartRow >= 0) && (m_ctrl->GetJoinStartCell(&JoinCellStartCol,&JoinCellStartRow) == UG_SUCCESS) )
		{
			m_ctrl->GotoCell(m_GI->m_dragCol - (curCol - JoinCellStartCol),
							 m_GI->m_dragRow - (curRow - JoinCellStartRow));
		}
		else
			m_ctrl->GotoRow(m_GI->m_dragRow - increment);
	}
	else if(nChar == VK_DOWN)
	{
		JoinCellStartCol = curCol;
		JoinCellStartRow = curRow;
		rowOff = increment;
		if ( m_ctrl->GetJoinRange(&JoinCellStartCol,&JoinCellStartRow, &JoinCellEndCol,&JoinCellEndRow) == UG_SUCCESS )
			rowOff = (JoinCellEndRow - JoinCellStartRow) + increment;

		JoinCellStartCol = curCol;
		JoinCellStartRow = curRow + rowOff;
		if (m_ctrl->GetJoinStartCell(&JoinCellStartCol,&JoinCellStartRow) == UG_SUCCESS)
		{
			m_ctrl->GotoCell(m_GI->m_dragCol - (curCol - JoinCellStartCol),
							 m_GI->m_dragRow - (curRow - JoinCellStartRow));
		}
		else
			m_ctrl->GotoRow(m_GI->m_dragRow + rowOff);
	}
	else if(nChar == VK_PRIOR)
		m_ctrl->MoveCurrentRow(UG_PAGEUP);
	else if(nChar == VK_NEXT)
		m_ctrl->MoveCurrentRow(UG_PAGEDOWN);
	else if(nChar == VK_HOME){
		if(GetKeyState(VK_CONTROL) <0)
			m_ctrl->MoveCurrentRow(UG_TOP);
		else
			m_ctrl->MoveCurrentCol(UG_LEFT);
	}
	else if(nChar == VK_END)
	{
		if(GetKeyState(VK_CONTROL) <0)
			m_ctrl->MoveCurrentRow(UG_BOTTOM);
		else
			m_ctrl->MoveCurrentCol(UG_RIGHT);
	}
}

/***************************************************
OnLButtonDown
	Finds the cell that was clicked in, sends a notification
	updates the current cells position.
	It also sets mouse capture.
Params:
	nFlags		- please see MSDN for more information on the parameters.
	point
Returns:
	<none>
*****************************************************/
void CUGGrid::OnLButtonDown(UINT nFlags, CPoint point)
{
	if( GetFocus() != this )
		SetFocus();

	if(m_ctrl->m_editInProgress)
		return;

	int col = -1;
	long row = -1;
	RECT rect;
	BOOL processed = FALSE;

	SetCapture();

	//setup the move type flags
	m_GI->m_moveType = 1;	//lbutton
	m_GI->m_moveFlags = nFlags;

	//check to see what cell was clicked in, and move there
	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row,&rect) == UG_SUCCESS){
	
		m_ctrl->GotoCell(col,row);

		//send a notification to the cell type	
		processed = m_ctrl->GetCellType(col,row)->OnLClicked(col,row,1,&rect,&point);

		if(processed)
			m_cellTypeCapture = TRUE;
	}

	m_ctrl->OnLClicked(col,row,1,&rect,&point,processed);

	m_GI->m_moveType = 0;	//key(default)

	// indicate that this mouse button down event was handled by the grid,
	// allowing for the mouse button up to be processed.
	m_bHandledMouseDown = TRUE;
}

/***************************************************
OnLButtonUp
	Finds the cell that was clicked in
	Sends a notification to CUCtrl::OnLClicked
	Releases mouse capture
Params:
	nFlags		- please see MSDN for more information on the parameters.
	point
Returns:
	<none>
*****************************************************/
void CUGGrid::OnLButtonUp(UINT nFlags, CPoint point)
{
	UNREFERENCED_PARAMETER(nFlags);

	int col = -1;
	long row = -1;
	RECT rect;
	BOOL processed = FALSE;

	if ( m_bHandledMouseDown != TRUE )
		return;

	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row,&rect) == UG_SUCCESS){

		//send a notification to the cell type	
		processed = m_ctrl->GetCellType(col,row)->OnLClicked(col,row,0,&rect,&point);
	}

	m_ctrl->OnLClicked(col,row,0,&rect,&point,processed);

	ReleaseCapture();

	m_GI->m_dragCol = m_GI->m_currentCol;
	m_GI->m_dragRow = m_GI->m_currentRow;

	m_cellTypeCapture = FALSE;
	m_bHandledMouseDown = FALSE;
}

/***************************************************
OnLButtonDblClk
	Finds the cell that was clicked in
	Sends a notification to CUCtrl::OnDClicked
Params:
	<none>
Returns:
	<none>
*****************************************************/
void CUGGrid::OnLButtonDblClk(UINT nFlags, CPoint point)
{
	UNREFERENCED_PARAMETER(nFlags);

	int col = -1;
	long row = -1;
	RECT rect;
	BOOL processed = FALSE;
	
	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row,&rect) == UG_SUCCESS){

		//send a notification to the cell type	
		processed = m_ctrl->GetCellType(col,row)->OnDClicked(col,row,&rect,&point);
	}

	m_ctrl->OnDClicked(col,row,&rect,&point,processed);
}

/***************************************************
OnMouseMove
	Finds the cell that the mouse is over and if the left mouse button is down
	then the current cell postion is updated
	Sends optional notification messages
	Also scrolls the current cell if the mouse is outside the window area.
Params:
	nFlags		- please see MSDN for more information on the parameters.
	point
Returns:
	<none>
*****************************************************/
void CUGGrid::OnMouseMove(UINT nFlags, CPoint point)
{
	int col;
	long row;
	BOOL vertViewMove = FALSE,
		 horsViewMove = FALSE;

	if(m_ctrl->m_editInProgress)
		return;

	if(m_cellTypeCapture)
	{
		col = m_GI->m_currentCol;
		row = m_GI->m_currentRow;
		//send a notification to the cell type
		BOOL processed = m_ctrl->GetCellType(col,row)->OnMouseMove(col,row,&point,nFlags);
		//send a notification to the main grid class
		m_ctrl->OnMouseMove(col,row,&point,nFlags,processed);

		return;
	}


	m_GI->m_moveType = 3;	//mouse move
	m_GI->m_moveFlags = nFlags;

	//check to see if the mouse is over a cell
	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row) == UG_SUCCESS)
	{
		//send a notification to the cell type
		BOOL processed = m_ctrl->GetCellType(col,row)->OnMouseMove(col,row,&point,nFlags);
		//send a notification to the main grid class
		m_ctrl->OnMouseMove(col,row,&point,nFlags,processed);
	}

	if(nFlags & MK_LBUTTON)
	{
		// v7.2 - update 01 - the following loop was probably intended to 
		// optimize efficiency on slower cpus. With the loop and message 
		// pump removed, there is a noticable improvement in CPU usage.
		// This change should be monitored for any unwanted effects - code is
		// just commented out for now. Change suggested by lazymiken.
		
		// MSG msg;
		int moved = FALSE;

		//while(1)
		{
			if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row) == UG_SUCCESS)
			{
				if ( row == m_GI->m_bottomRow )
					vertViewMove = TRUE;
				if ( col == m_GI->m_rightCol )
					horsViewMove = TRUE;

				// The 'm_bScrollOnParialCells' flag controls the scrolling behavior
				// when the mouse is dragged over partially visible cell.  By default
				// we will treat this area same as area 'outside of the grid' meaning
				// that the grid will scroll using current ballistics settigs.
				// You can set this flag to FALSE if you do not want the grid to
				// scroll when user's mouse is over the partially visible cells,
				// the grid will only do that when mouse is moved outside of the view.
				if ( m_GI->m_bScrollOnParialCells == FALSE && ( vertViewMove == TRUE || horsViewMove == TRUE ))
					return;

				if ( m_bHandledMouseDown != TRUE )
					return;

				//send a notification to the cell type
				if(m_GI->m_numLockCols == 0 && m_GI->m_numLockRows == 0)
					m_ctrl->GotoCell(col,row);
				else
				{
					if(m_GI->m_dragCol > m_GI->m_numLockCols && col < m_GI->m_numLockCols)
						m_ctrl->MoveCurrentCol(UG_LINEUP);
					else
						m_ctrl->GotoCol(col);

					if(m_GI->m_dragRow > m_GI->m_numLockRows && row < m_GI->m_numLockRows)
						m_ctrl->MoveCurrentRow(UG_LINEUP);
					else
						m_ctrl->GotoRow(row);
				}	
			}
			//if the mouse is off the left side
			if(point.x < 0)
			{
				//if ballistic mode
				if(m_GI->m_ballisticMode)
				{
					int increment = (int)pow((double)((point.x * -1)/ m_GI->m_defColWidth +1), 
						m_GI->m_ballisticMode); 
					m_ctrl->GotoCol(m_GI->m_dragCol - increment);
					if(increment == 1)
						Sleep(m_GI->m_ballisticDelay);
				}
				else
					m_ctrl->MoveCurrentCol(UG_LINEUP);
				moved = TRUE;
			}
			//if the mouse is off the right side
			else if(point.x > m_GI->m_gridWidth || horsViewMove)
			{
				//if ballistic mode
				if(m_GI->m_ballisticMode)
				{
					int increment = (int)pow((double)(point.x - m_GI->m_gridWidth) / 
						m_GI->m_defColWidth +1, m_GI->m_ballisticMode); 
					m_ctrl->GotoCol(m_GI->m_dragCol + increment);
					if(increment == 1)
						Sleep(m_GI->m_ballisticDelay);
				}
				else
					m_ctrl->MoveCurrentCol(UG_LINEDOWN);
				moved = TRUE;
			}
			//if the mouse is above the top
			if(point.y < 0)
			{
				//if ballistic mode
				if(m_GI->m_ballisticMode)
				{
					long increment = (long)pow((double)((point.y* -1) / m_GI->m_defRowHeight +1), 
						m_GI->m_ballisticMode); 
					m_ctrl->GotoRow(m_GI->m_dragRow - increment);
					if(increment == 1)
						Sleep(m_GI->m_ballisticDelay);
				}
				else
					m_ctrl->MoveCurrentRow(UG_LINEUP);
				moved = TRUE;
			}
			//if the mouse is below the bottom
			else if(point.y > m_GI->m_gridHeight || vertViewMove)
			{
				//if ballistic mode
				if(m_GI->m_ballisticMode)
				{
					long increment = (long)pow((double)((point.y-m_GI->m_gridHeight) / 
						m_GI->m_defRowHeight +1), m_GI->m_ballisticMode); 
					m_ctrl->GotoRow(m_GI->m_dragRow + increment);
					if(increment == 1)
						Sleep(m_GI->m_ballisticDelay);
				}
				else
					m_ctrl->MoveCurrentRow(UG_LINEDOWN);
				moved = TRUE;
			}


			moved = FALSE;

			// v7.2 - update 01 - msg pump removed - see comments above

			//check for messages, if there are not then scroll some more
			//while(PeekMessage(&msg,NULL,0,0,PM_NOREMOVE))
			//{
			//	if(msg.message == WM_MOUSEMOVE || msg.message == WM_LBUTTONUP)
			//	{
			//		m_GI->m_moveType = 0;	//key(default)

			//		return;
			//	}
			//	GetMessage(&msg,NULL,0,0);
			//	TranslateMessage(&msg);
			//	DispatchMessage(&msg);
			//}
		}
	}

	m_GI->m_moveType = 0;	//key - default
}

/***************************************************
OnRButtonDown
	Finds the cell that the mouse is in
	Sends series of notifications to the CUGCrtl
	Pops up a menu if enabled and populated.
Params:
	nFlags		- please see MSDN for more information on the parameters.
	point
Returns:
	<none>
*****************************************************/
void CUGGrid::OnRButtonDown(UINT nFlags, CPoint point)
{
	if(m_ctrl->m_editInProgress)
		return;

	int col = -1;
	long row = -1;
	BOOL processed = FALSE;
	RECT rect;

	m_GI->m_moveType = 2;	//2button
	m_GI->m_moveFlags = nFlags;

	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row,&rect) == UG_SUCCESS)
	{
		m_ctrl->GotoCell(col,row);
		//send a notification to the cell type	
		processed = m_ctrl->GetCellType(col,row)->OnRClicked(col,row,1,&rect,&point);
	}
	
	m_ctrl->OnRClicked(col,row,1,&rect,&point,processed);


	m_GI->m_moveType = 0;	//key(default)

	if(m_GI->m_enablePopupMenu)
	{
		ClientToScreen(&point);
		m_ctrl->StartMenu(col,row,&point,UG_GRID);
	}

	m_GI->m_moveType = 0;//key - default
	m_bHandledMouseDown = TRUE;
}

/***************************************************
OnRButtonUp
	Finds the cell that the mouse is in
	Sends a OnRClicked notification to the CUGCtrl.
Params:
	nFlags		- please see MSDN for more information on the parameters.
	point
Returns:
	<none>
*****************************************************/
void CUGGrid::OnRButtonUp(UINT nFlags, CPoint point)
{
	UNREFERENCED_PARAMETER(nFlags);

	int col = -1;
	long row = -1;
	RECT rect;
	BOOL processed = FALSE;

	if ( m_bHandledMouseDown != TRUE )
		return;

	if(m_ctrl->GetCellFromPoint(point.x,point.y,&col,&row,&rect) == UG_SUCCESS)
	{
		//send a notification to the cell type	
		processed = m_ctrl->GetCellType(col,row)->OnRClicked(col,row,0,&rect,&point);
	}

	m_ctrl->OnRClicked(col,row,0,&rect,&point,processed);

	m_GI->m_dragCol = m_GI->m_currentCol;
	m_GI->m_dragRow = m_GI->m_currentRow;
	m_bHandledMouseDown = FALSE;
}

/***************************************************
OnChar
	passed the handling of this event to the OnCharDown in both the cell's
	celltype and the CUGCtrl.
Params:
	nChar		- please see MSDN for more information on the parameters.
	nRepCnt
	nFlags
Returns:
	<none>
*****************************************************/
void CUGGrid::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	UNREFERENCED_PARAMETER(nRepCnt);
	UNREFERENCED_PARAMETER(nFlags);
	BOOL processed = FALSE;

	//send a notification to the cell type	
	processed = m_ctrl->GetCellType(m_GI->m_currentCol,m_GI->m_currentRow)->
		OnCharDown(m_GI->m_currentCol,m_GI->m_currentRow,&nChar);

	m_ctrl->OnCharDown(&nChar,processed);
}

/***************************************************
PreCreateWindow
	The Utlimate Grid overwrites this function to further customize the
	window that is created.
Params:
	cs			- please see MSDN for more information on the parameters.
Returns:
	Nonzero if the window creation should continue; 0 to indicate creation failure.
*****************************************************/
BOOL CUGGrid::PreCreateWindow(CREATESTRUCT& cs)
{
	cs.style = cs.style | WS_CLIPCHILDREN | WS_CLIPSIBLINGS;
	return CWnd::PreCreateWindow(cs);
}

/***************************************************
OnSetFocus
	The grid uses this event handler to setup internal variables and passes
	further processig to both the CWnd and CUGCtrl.
Params:
	pOldWnd		- pointer to window that lost the focus
Returns:
	<none>
*****************************************************/
void CUGGrid::OnSetFocus(CWnd* pOldWnd)
{
	m_hasFocus = TRUE;
	m_cellTypeCapture = FALSE;
	m_keyRepeatCount = 0;

	// pass the notification handling
	CWnd::OnSetFocus( pOldWnd );
	m_ctrl->OnSetFocus( UG_GRID );
	// redraw the current cell
	CRect cellRect;

	if ( m_GI->m_highlightRowFlag == TRUE )
	{
		m_ctrl->GetRangeRect( 0, m_GI->m_currentRow, m_GI->m_numberCols - 1, m_GI->m_currentRow, cellRect );
		m_drawHint.AddHint( 0, m_GI->m_currentRow, m_GI->m_numberCols - 1, m_GI->m_currentRow );
	}
	else
	{
		m_ctrl->GetCellRect( m_GI->m_currentCol, m_GI->m_currentRow, cellRect );
		m_drawHint.AddHint( m_GI->m_currentCol, m_GI->m_currentRow );
	}

	PaintDrawHintsNow( cellRect );
}

/***************************************************
OnKillFocus
	clears internal flag indicating that the grid no longer has focus
	and passes further processign to both the CWnd and CUGCtrl.
Params:
	pNewWnd		- pointer to window that is gaining the focus.
Returns:
	<none>
*****************************************************/
void CUGGrid::OnKillFocus(CWnd* pNewWnd)
{
	m_hasFocus = FALSE;

	CWnd::OnKillFocus(pNewWnd);
	// notify the grid that the grid lost focus
	m_ctrl->OnKillFocus(UG_GRID, pNewWnd);

	RedrawCell(m_GI->m_currentCol,m_GI->m_currentRow);
}

/***************************************************
OnMouseActivate
	The framework calls this member function when the cursor is in an inactive
	window and the user presses a mouse button.
Params:
	pDesktopWnd	- please see MSDN for more information on the parameters.
	nHitTest
	message
Returns:
	Specifies to activate the CWnd and to discard the mouse event.
*****************************************************/
int CUGGrid::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT message) 
{
	CWnd::OnMouseActivate( pDesktopWnd, nHitTest, message );
	return MA_ACTIVATE;
}

/***************************************************
SetDoubleBufferMode
	turns on and off the double buffer functionality.  When the double buffer
	mode is on then the grid will first is drawn to an off-screen DC before
	the results are copied over to the screen.
Params:
	mode		- double buffer mode (TRUE or FALSE)
Returns:
	UG_SUCCESS	- on success
	UG_ERROR	- if creation of off-screen buffer was unsuccessful
*****************************************************/
int CUGGrid::SetDoubleBufferMode(int mode)
{
	if(m_bitmap != NULL)
	{
		delete m_bitmap;
		m_bitmap = NULL;
	}

	m_doubleBufferMode = mode;

	if(mode == TRUE)
	{
		m_bitmap = new CBitmap;

		CDC * pDC = GetDC();
		RECT rect;
	
		GetClientRect(&rect);
		if(rect.right ==0)
			rect.right =1;
		if(rect.bottom ==0)
			rect.bottom =1;

		if(m_bitmap->CreateCompatibleBitmap(pDC,rect.right,rect.bottom) == 0)
		{
			delete m_bitmap;
			m_bitmap = NULL;
			m_doubleBufferMode = FALSE;
			return UG_ERROR;
		}

		//clear the bitmap
		CBitmap * oldbitmap = pDC->SelectObject(m_bitmap);
		if(oldbitmap)
			pDC->SelectObject(oldbitmap);

		ReleaseDC(pDC);
	}
	
	return UG_SUCCESS;
}

/***************************************************
OnSize
	The framework calls this member function after the window's size has changed.
	The Ultimate Grid takes this opportunity to reallocate the off-screen bitmap
	used by the double buffer mode.
Params:
	nType		- please see MSDN for more information on the parameters.
	cx
	cY
Returns:
	<none>
*****************************************************/
void CUGGrid::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);

	// reallocate the double buffer bitmap
	if( m_doubleBufferMode )
		SetDoubleBufferMode( m_doubleBufferMode );
}


/***************************************************
OnMouseWheel
	The framework calls this member function as a user rotates the mouse
	wheel and encounters the wheel's next notch.
Params:
	nFlags		- please see MSDN for more information on the parameters.
	zDelta
	pt
Returns:
	Nonzero if mouse wheel scrolling is enabled; otherwise 0.
*****************************************************/
#ifdef WM_MOUSEWHEEL
BOOL CUGGrid::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) 
{
	// TODO: Add your message handler code here and/or call default
	if(!m_ctrl->m_editInProgress) {
		int distance = zDelta / 120;
		m_GI->m_moveType = 4;
		m_ctrl->SetTopRow(m_GI->m_topRow - (distance * 3));
		m_ctrl->m_CUGSideHdg->Invalidate();
	}
	return CWnd::OnMouseWheel(nFlags, zDelta, pt);
}
#endif

/***************************************************
OnSetCursor
	The framework calls this member function if mouse input is not captured
	and the mouse causes cursor movement within the CWnd object.
Params:
	pWnd		- please see MSDN for more information on the parameters.
	nHitTest
	message
Returns:
	Nonzero to halt further processing, or 0 to continue.
*****************************************************/
BOOL CUGGrid::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	UNREFERENCED_PARAMETER(*pWnd);
	UNREFERENCED_PARAMETER(nHitTest);
	UNREFERENCED_PARAMETER(message);

	SetCursor(m_GI->m_arrowCursor);
	return TRUE;
}

/***************************************************
OnKeyUp
	The framework calls this member function when a nonsystem key is released,
	the grid passes this event to the cell type and CUGCtrl class for further
	processing.
Params:
	nChar		- please see MSDN for more information on the parameters.
	nRepCnt
	nFlags
Returns:
	<none>
*****************************************************/
void CUGGrid::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	UNREFERENCED_PARAMETER(nRepCnt);
	UNREFERENCED_PARAMETER(nFlags);
	m_keyRepeatCount = 0;	

	//send a notify message to the cell type class
	BOOL processed = m_ctrl->GetCellType(m_GI->m_currentCol,m_GI->m_currentRow)->
		OnKeyUp(m_GI->m_currentCol,m_GI->m_currentRow,&nChar);

	//send a keyup notify message
	m_ctrl->OnKeyUp(&nChar,processed);
}

/***************************************************
OnGetDlgCode
	The Ultimate Grid handles this event to ensure proper behavior when
	grid is placed on a dialog.
Params:
	<none>
Returns:
	Please see MSDN for complete list of valid return values.
*****************************************************/
UINT CUGGrid::OnGetDlgCode() 
{
	if(IsChild(GetFocus()))
		return DLGC_WANTALLKEYS|DLGC_WANTARROWS;
	else
		return CWnd::OnGetDlgCode() | DLGC_WANTARROWS | DLGC_WANTALLKEYS;
}

/***************************************************
GetScrollBarCtrl
	function is used to allow the grid to share its scrollbars with
	parent window.
Params:
	nBar		- scrollbar to return pointer to.
Returns:
	Pointer to a sibling scroll-bar control.
*****************************************************/
CScrollBar* CUGGrid::GetScrollBarCtrl(int nBar) const
{
	if(nBar==SB_HORZ)
		return m_ctrl->m_CUGHScroll;
	else
		return m_ctrl->m_CUGVScroll;
}

/***************************************************
OnVScroll
	The framework calls this member function when the user clicks the window's vertical scroll bar.
Params:
	nSBCode		- please see MSDN for more information on the parameters.
	nPos
	pScrollBar
Returns:
	<none>
*****************************************************/
void CUGGrid::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	m_ctrl->SendMessage(WM_VSCROLL,MAKEWPARAM(nSBCode,nPos),
		(LPARAM)(pScrollBar!=NULL ? pScrollBar->GetSafeHwnd() : NULL));
}

/***************************************************
OnHScroll
	The framework calls this member function when the user clicks the window's horizontal scroll bar.
Params:
	nSBCode		- please see MSDN for more information on the parameters.
	nPos
	pScrollBar
Returns:
	<none>
*****************************************************/
void CUGGrid::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
	m_ctrl->SendMessage(WM_HSCROLL,MAKEWPARAM(nSBCode,nPos),
		(LPARAM)(pScrollBar!=NULL ? pScrollBar->GetSafeHwnd() : NULL));
}

/***************************************************
OnHelpHitTest
	Sent as a result of context sensitive help
	being activated (with mouse) over main grid area
Params:
	WPARAM - not used
	LPARAM - x, y coordinates of the mouse event
Return:
	Context help ID to be displayed
*****************************************************/
LRESULT CUGGrid::OnHelpHitTest(WPARAM, LPARAM lParam)
{
	// this message is fired as result of mouse activated
	// context help being hit over the grid.
	int col;
	long row;
	CRect rect(0,0,0,0);
	int xPos = LOWORD(lParam),
		yPos = HIWORD(lParam);
	m_ctrl->GetCellFromPoint( xPos, yPos, &col, &row, &rect );
	// return context help ID to be looked up
	return m_ctrl->OnGetContextHelpID( col, row, UG_GRID );
}

/***************************************************
OnHelpInfo
	Sent as a result of context sensitive help
	being activated (with mouse) in main grid area
	if the grid is on the dialog
Params:
	HELPINFO - structure that contains information on selected help topic
Return:
	TRUE or FALSE to allow further processing of this message
*****************************************************/
BOOL CUGGrid::OnHelpInfo(HELPINFO* pHelpInfo) 
{
	if (pHelpInfo->iContextType == HELPINFO_WINDOW)
	{
		// this message is fired as result of mouse activated help in a dialog
		int col;
		long row;

		if ( GetKeyState( VK_F1 ) < 0 )
		{
			col = m_ctrl->GetCurrentCol();
			row = m_ctrl->GetCurrentRow();
		}
		else
		{
			CRect rect(0,0,0,0);
			CPoint point;
			point.x = pHelpInfo->MousePos.x;
			point.y = pHelpInfo->MousePos.y;

			ScreenToClient( &point );
			int xPos = point.x,
				yPos = point.y;
			m_ctrl->GetCellFromPoint( xPos, yPos, &col, &row, &rect );
		}

		DWORD dwTopicID = m_ctrl->OnGetContextHelpID( col, row, UG_GRID );
		if ( dwTopicID == 0 )
			return FALSE;

		// call context help with ID returned by the user notification
		AfxGetApp()->WinHelp( dwTopicID );
		// prevent further handling of this message
		return TRUE;
	}
	return FALSE;
}

LRESULT CUGGrid::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	switch (message)
	{
	case WM_THEMECHANGED:
		// This function closes all open handles, which will force them all to reload, using the new theme.
		UGXPThemes::CleanUp();
		return 0;
	default:
		return CWnd::WindowProc(message, wParam, lParam);
	}
}

BOOL CUGGrid::OnEraseBkgnd(CDC* pDC) 
{
	UNREFERENCED_PARAMETER(pDC);
	// Don't erase background when using themes.
	return UGXPThemes::IsThemed();
}

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