Click here to Skip to main content
15,896,111 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 256.3K   23.7K   170  
Updates and User Contributions for the Ultimate Toolbox Libraries
/*************************************************************************
				Class Implementation : CUGPrint
**************************************************************************
	Source file : ugprint.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

#ifdef UG_ENABLE_PRINTING

/***************************************************
	Standard construction/desrtuction
***************************************************/
CUGPrint::CUGPrint()
{
	m_pagesWide = 0;
	m_pagesHigh = 0;
	m_printList = NULL;

	m_printLeftMargin	= 25;	//margin in mm
	m_printTopMargin	= 25;	
	m_printRightMargin	= 25;
	m_printBottomMargin = 25;

	m_printFrame = TRUE;
	m_printCenter = FALSE;
	m_fitToPage = FALSE;
	m_printTopHeading = FALSE;
	m_printSideHeading = FALSE;

	m_virPixWidth = 7;
	m_bIsPreview = FALSE;

	m_printScale = 100;
}

/***************************************************
~CUGPrint- Destructor
****************************************************/
CUGPrint::~CUGPrint(){
	ClearPrintList();
}

/***************************************************
ClearPrintList - Private
	Clears the list of pages that are to be printed
Params
	<none>
Return
	<none>
****************************************************/
void CUGPrint::ClearPrintList()
{
	CUGPrintList* next;
	
	//delete all the items in the linked list
	while(m_printList != NULL)
	{
		next = m_printList->next;
		delete m_printList;
		m_printList = next;
	}
}
/***************************************************
AddPageToList - Private
	Adds a page to the print list, including the
	col/row range of the grid cells to print.
Params
	page	- page number
	startCol- leftmost column to print on the page
	endCol	- rightmost column to print on the page
	startRow- topmost row to print on the page
	endRow	- bottom most row to print on the page
Return
	UG_SUCCESS - success
	UG_ERROR - failure
****************************************************/
int	CUGPrint::AddPageToList(int page,int startCol,int endCol,long startRow,long endRow)
{
	CUGPrintList * item = NULL;	//new print list item

	//if the list is already empty then just return
	if(m_printList == NULL)
	{
		m_printList = new CUGPrintList;
		item = m_printList;
		item->next = NULL;
	}
	else
	{
		//find the last item in the list
		CUGPrintList* current = m_printList;
		while(current != NULL)
		{
			if(current->page == page)
			{
				item = current;
				break;
			}
			if(current->next==NULL)
			{
				item = new CUGPrintList;
				current->next = item;
				item->next = NULL;
				break;
			}
			current = current->next;
		}
	}

	if ( item != NULL )
	{
		item->page		= page;
		item->startCol	= startCol;
		item->endCol	= endCol;
		item->startRow	= startRow;
		item->endRow	= endRow;

		return UG_SUCCESS;
	}

	return UG_ERROR;
}
/***************************************************
GetPageFromList - Private
	Retrives the col/row range to be printed on a
	given page. The information is retrieved by
	page number
Params
	page	- page number to retrive the information for
	startCol- [out] leftmost column to print on the page
	endCol	- [out] rightmost column to print on the page
	startRow- [out] topmost row to print on the page
	endRow	- [out] bottom most row to print on the page
Return
	UG_SUCCESS - success
	UG_ERROR - failure
****************************************************/
int	CUGPrint::GetPageFromList(int page,int *startCol,int *endCol,long *startRow,long *endRow)
{
	//find the page
	CUGPrintList* next = m_printList;
	while(next != NULL)
	{
		if(next->page ==page)
			break;
		next = next->next;
	}

	//if the page was not found then return FALSE
	if(next == NULL)
		return UG_ERROR;
	
	//return the page information
	*startCol	= next->startCol;
	*endCol		= next->endCol;
	*startRow	= next->startRow;
	*endRow		= next->endRow;
	
	return UG_SUCCESS;
}
/***************************************************
PrintInit
	Initializes and sets up the data that needs to
	be calculated to perform the actual print. Such
	tasks include calcualating the number of pages
	required to print the given range, and the scale.
Params
	pDC - device context for the printer (or print preview)
	pPD - pointer to the print dialog information
	startCol- leftmost column to print on the page
	endCol	- rightmost column to print on the page
	startRow- topmost row to print on the page
	endRow	- bottom most row to print on the page
Return
	number of pages that will be printed
****************************************************/
int CUGPrint::PrintInit(CDC * pDC, CPrintDialog* pPD, int startCol,long startRow,
						int endCol,long endRow)
{
	UNREFERENCED_PARAMETER(pPD);

	ClearPrintList();

	//get a screen device context
	CDC	sDC;
	sDC.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
	
	//check to see if the request if for printing or print preview
	m_bIsPreview = FALSE;
	SIZE size;
	pDC->SetMapMode(MM_ANISOTROPIC);
	SetWindowExtEx(pDC->m_hDC,1,1,&size);
	if(size.cx != 1){
		m_bIsPreview = TRUE;
		SetWindowExtEx(pDC->m_hDC,size.cx,size.cy,&size);
	}
	
	//get the metrics for the printer
	float paperWidthPX		= (float)pDC->GetDeviceCaps(HORZRES);
	float paperHeightPX		= (float)pDC->GetDeviceCaps(VERTRES);
	float paperWidthMM		= (float)pDC->GetDeviceCaps(HORZSIZE);
	float paperHeightMM		= (float)pDC->GetDeviceCaps(VERTSIZE);
	int virtualWidthPX = (int)( 3.79 * (paperWidthMM - m_printLeftMargin - m_printRightMargin));
	int virtualHeightPX = (int)( 3.78 * (paperHeightMM - m_printTopMargin - m_printBottomMargin));

	//save the scaling values
	m_printVScale = ( (paperHeightPX/paperHeightMM) *
					(paperHeightMM - m_printTopMargin - m_printBottomMargin) ) /
					virtualHeightPX;
	m_printHScale = ( (paperWidthPX/paperWidthMM) *
					(paperWidthMM - m_printLeftMargin - m_printRightMargin) ) /
					virtualWidthPX;

	//save the margins
	m_printLeftMarginPX = (int)((paperWidthPX/paperWidthMM) * m_printLeftMargin);
	m_printTopMarginPX = (int)((paperHeightPX/paperHeightMM) * m_printTopMargin);
	m_printRightMarginPX = (int)(paperWidthPX - (paperWidthPX/paperWidthMM) * m_printRightMargin);
	m_printBottomMarginPX = (int)(paperHeightPX - (paperHeightPX/paperHeightMM) * m_printBottomMargin);
	m_paperWidthPX = (int)paperWidthPX;
	m_paperHeightPX = (int)paperHeightPX;

	//if not print preview, then addjust values by the virtual pixel width
	if(m_bIsPreview == FALSE)
	{
		m_virPixWidth = (int)paperWidthPX / 450;  //300
		m_printVScale /= m_virPixWidth;
		m_printHScale /= m_virPixWidth;
		m_printLeftMarginPX /= m_virPixWidth;
		m_printTopMarginPX /= m_virPixWidth;
		m_printRightMarginPX /= m_virPixWidth;
		m_printBottomMarginPX /= m_virPixWidth;
		m_paperWidthPX /= m_virPixWidth;
		m_paperHeightPX /= m_virPixWidth;
	}

	//get the number of pages wide
	int col,width=0,w;
	int scol = startCol;		//start col for a page
	m_pagesWide = 0;
	
	if(m_printSideHeading)
		width = m_ctrl->GetSH_Width();
	//find the number of pages wide and the number of columns
	//on each page
	for(col =startCol;col <= endCol;col++)
	{
		m_ctrl->GetColWidth(col,&w);		
		width += w;
	
		if(width > virtualWidthPX)
		{
			m_pagesWide++;
			if(m_printSideHeading)
				width = m_ctrl->GetSH_Width();
			else
				width = 0;

			if(w < virtualWidthPX)
				col--;

			//add the column info to the list
			AddPageToList(m_pagesWide,scol,col,0,0);
			scol = col+1;
		}
	}
	
	if(width >0)
	{
		m_pagesWide++;
		//add the column info to the list
		if(col > endCol)
			col = endCol;
		AddPageToList(m_pagesWide,scol,col,0,0);
	}

	//get the number of pages high
	long row;
	long srow = startRow;		//start row for page
	int height=0,h;
	m_pagesHigh = 0;
	
	if(m_printTopHeading)
		height = m_ctrl->GetTH_Height();

	//find the number of pages high and the number of rows
	//on each page
	for(row = startRow;row <=endRow;row++)
	{
		m_ctrl->GetRowHeight(row,&h);
		height += h;
		if(height > virtualHeightPX)
		{
			m_pagesHigh ++;
			if(m_printTopHeading)
				height = m_ctrl->GetTH_Height();
			else 
				height = 0;

			if(h < virtualHeightPX)
				row--;
			
			//add the page information to the list
			int c1,c2;
			long r1,r2;
			int page;
			for(col =1;col<=m_pagesWide;col++)
			{
				//get the col info
				GetPageFromList(col,&c1,&c2,&r1,&r2);
				//update the page info
				page = (m_pagesHigh-1)*m_pagesWide +col;
				AddPageToList(page,c1,c2,srow,row);
			}
			srow = row+1;
		}
	}
	if(height >0)
	{
		m_pagesHigh++;
		//add the page information to the list
		int c1,c2;
		long r1,r2;
		int page;
		for(col =1;col<=m_pagesWide;col++)
		{
			//get the col info
			GetPageFromList(col,&c1,&c2,&r1,&r2);
			//update the page info
			page = (m_pagesHigh-1)*m_pagesWide +col;
			if(row > endRow)
				row = endRow;
			AddPageToList(page,c1,c2,srow,row);
		}
	}

	//return the number of pages in total
	return (m_pagesWide * m_pagesHigh);
}
/***************************************************
PrintPage
	Performs the actual printing of the grid cells.
	PrintInit must be called first to setup the
	printing criteria.
Params
	pDC - device context of the printer (or print preview)
	pageNum - page number to print
Return
	UG_SUCCESS - success
	UG_ERROR - failure
****************************************************/
int CUGPrint::PrintPage(CDC * pDC, int pageNum)
{
	//TEST
	if(m_bIsPreview == FALSE)
	{
		SIZE size;
		pDC->SetMapMode(MM_ANISOTROPIC);
		SetWindowExtEx(pDC->m_hDC,1,1,&size);
		SetViewportExtEx(pDC->m_hDC,m_virPixWidth,m_virPixWidth,&size);
	}

	int  x,h,w,col,xx;
	long y,row,yy;
	int startCol,endCol;
	long startRow,endRow;
	RECT cellrect={0,0,0,0};
	RECT origCellRect;
	int leftMargin = m_printLeftMarginPX;
	int topMargin =  m_printTopMarginPX;

	//get the co-ords to print
	if(GetPageFromList(pageNum,&startCol,&endCol,&startRow,&endRow) != UG_SUCCESS)
		return UG_ERROR;

	//***********************************************************
	// Caculate the column width that will be used in drawing cells.
	//***********************************************************

	CRect ColRect;
	int   nColWidth, nFirstCol; 

	m_ColRects.RemoveAll();
	ColRect.left  = leftMargin;
	ColRect.right = ColRect.left;
	nFirstCol = startCol;
	if( m_printSideHeading )
		nFirstCol = 0 - m_GI->m_numberSideHdgCols;
	for( int i = nFirstCol; i <= endCol; i++ )
	{
		if( i < 0 )
		{
			//get the side heading co-ords
			ColRect.left = ColRect.right;
			ColRect.right += (int) (m_ctrl->m_CUGSideHdg->GetSHColWidth(i) * m_printHScale);
		}
		else 
		{
			//get the left,right co-ords
			ColRect.left = ColRect.right;
			m_ctrl->GetColWidth( i, &nColWidth );
			ColRect.right += (int) (nColWidth  * m_printHScale);
		}
		m_ColRects.Add(ColRect);
	}

	//*********************
	// draw the page
	//*********************

	//draw the grid
	cellrect.top = topMargin;
	cellrect.bottom = topMargin;

	//main grid row drawing loop
	yy = startRow;
	if(m_printTopHeading)
		yy = 0 - m_GI->m_numberTopHdgRows;

	for(y = yy; y <= endRow ; y++)
	{	
		//set up the rectangle for the row
		if(y < 0 )
		{
			//set up the rect for the top heading
			cellrect.top	= cellrect.bottom;
			cellrect.bottom+= (int)(m_ctrl->m_CUGTopHdg->GetTHRowHeight(y) * m_printVScale);
			cellrect.left	= leftMargin;
			cellrect.right  = cellrect.left;
		}
		else
		{
			if(yy < 0)
			{
				yy=0;
				y = startRow;
			}
			//set up the rect for the row to be drawn
			cellrect.top	= cellrect.bottom;
			m_ctrl->GetRowHeight(y,&h);		
			cellrect.bottom += (int)(h * m_printVScale);
			cellrect.left	= leftMargin ;
			cellrect.right  = cellrect.left;
		}	

		//dont draw the row if it is 0 pixels high		
		if(cellrect.top == cellrect.bottom)
			continue;

		//main column drawing loop
		xx =startCol;
		if(m_printSideHeading)
			xx = 0 - m_GI->m_numberSideHdgCols;
		for(x = xx; x <= endCol; x++)
		{
			if( x < 0 )
			{
				//get the side heading co-ords
				cellrect.left = cellrect.right;
				cellrect.right += (int)(m_ctrl->m_CUGSideHdg->GetSHColWidth(x) * m_printHScale);
			}
			else
			{
				if(xx < 0)
				{
					xx=0;
					x = startCol;
				}
				//get the left,right co-ords
				cellrect.left = cellrect.right;
				m_ctrl->GetColWidth(x,&w);		
				cellrect.right += (int)(w * m_printHScale);
			}
		
			//dont draw the column if it is 0 pixels wide
			if(cellrect.left == cellrect.right)
				continue;

			//store the original cell rect, incase it is modified below
			CopyRect(&origCellRect,&cellrect);
	
			col = x;
			row = y;

			//check to see if the cell is a joined cell
			if(m_ctrl->GetJoinStartCell(&col,&row)==UG_SUCCESS)
			{
				RECT tempRect;
				CUGCell sourceCell, targetCell;
				int  col2, tempCol, tempCol2;
				long row2, tempRow, tempRow2;

				tempCol  = col;
				tempRow  = row;
				m_ctrl->GetJoinRange(&col,&row,&col2,&row2);
				tempCol2 = col2;
				tempRow2 = row2;

				if ((y == startRow && x == col) || (x == startCol && y == row)
					|| (y == startRow && x == startCol))
				{
					m_ctrl->GetCell (col,row,&sourceCell);
					m_ctrl->SetCell (x,y,&sourceCell);
					m_ctrl->JoinCells (x,y,col2,row2);
					col = x;
					row = y;
					m_ctrl->GetJoinRange(&col,&row,&col2,&row2);
				}
				
				if(col == x && row == y)
				{
					CopyRect(&tempRect,&cellrect);

					if (col2 > endCol || row2 > endRow)
					{
						if (col2 > endCol)
							col2 = endCol;
						if (row2 > endRow)
							row2 = endRow;
						m_ctrl->JoinCells (col,row,col2,row2);
					}
					while(col2 > col)
					{
						if (col2 <= endCol)
						{
							m_ctrl->GetColWidth(col2,&w);		
							tempRect.right+=(int)(w* m_printHScale);
						}
						col2--;
					}

					while(row2 > row)
					{
						if (row2 <= endRow)
						{
							m_ctrl->GetRowHeight(row2,&h);		
							tempRect.bottom+=(int)(h* m_printVScale);
						}
						row2--;
					}
					InternPrintCell(pDC,&tempRect,col,row);
					m_ctrl->JoinCells (tempCol,tempRow,tempCol2,tempRow2);
				}
			}
			else
			{
				InternPrintCell(pDC,&cellrect,x,y);
			}
			
			//draw a section of the print frame if selected
			CopyRect(&cellrect,&origCellRect);
		}
	}

	if ( m_printFrame )
	{	// draw left border and top border.
		if ((( m_printTopHeading ) && ( m_GI->m_numberTopHdgRows > 0 )) ||
			( startRow <= endRow))
		{
			pDC->MoveTo(leftMargin,topMargin);
			pDC->LineTo(leftMargin,cellrect.bottom-1);
			pDC->MoveTo(leftMargin,topMargin);
			pDC->LineTo(cellrect.right-1, topMargin);
		}
	}

	return UG_SUCCESS;
}
/***************************************************
PrintSetMargin
	Sets the margin in mm (milli-meters)
Params
	whichMargin	- one of the following
					UG_PRINT_LEFTMARGIN
					UG_PRINT_RIGHTMARGIN
					UG_PRINT_TOPMARGIN
					UG_PRINT_BOTTOMMARGIN
	size - size of the margin in mm
return
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGPrint::PrintSetMargin(int whichMargin,int size)
{
	return PrintSetOption(whichMargin,(long)size);
}
/***************************************************
PrintSetScale
	Sets the overall printing scale, as a percentage. 
	The value defaults to 100% and can range from
	1 to 5000 percent
Params
	scalePercent - percentage to set the scale to
Return
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGPrint::PrintSetScale(int scalePercent)
{
	if(scalePercent < 1 || scalePercent > 5000)
		return UG_ERROR;

	m_printScale = scalePercent;

	return UG_SUCCESS;
}
/***************************************************
PrintSetOption
	Sets the up the printing options.
	
	 Note:When setting margins the param value is 
	 in mm (milli-meters)
Params
	option	- one of the following
				UG_PRINT_LEFTMARGIN
				UG_PRINT_RIGHTMARGIN
				UG_PRINT_TOPMARGIN
				UG_PRINT_BOTTOMMARGIN
				UG_PRINT_FRAME
				UG_PRINT_TOPHEADING
				UG_PRINT_SIDEHEADING
	param - if setting a margin:  size in mm
			if setting the frame: TRUE or FALSE
			if setting a heading: TRUE or FALSE
return
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGPrint::PrintSetOption(int option,long param)
{
	if(option == UG_PRINT_LEFTMARGIN)
		m_printLeftMargin = (int)param;
	if(option == UG_PRINT_RIGHTMARGIN)
		m_printRightMargin =  (int)param;
	if(option == UG_PRINT_TOPMARGIN)
		m_printTopMargin =  (int)param;
	if(option == UG_PRINT_BOTTOMMARGIN)
		m_printBottomMargin =  (int)param;
	if(option == UG_PRINT_FRAME)
	{
		if(param == FALSE)
			m_printFrame =  FALSE;
		else
			m_printFrame =  TRUE;
	}
	if(option == UG_PRINT_TOPHEADING)
	{
		m_printTopHeading = param;
	}
	if(option == UG_PRINT_SIDEHEADING)
	{
		m_printSideHeading = param;
	}
	
	return UG_SUCCESS;
}

/***************************************************
PrintGetOption
	Retrieves the margin in mm (milli-meters)
Params
	option	- one of the following
				UG_PRINT_LEFTMARGIN
				UG_PRINT_RIGHTMARGIN
				UG_PRINT_TOPMARGIN
				UG_PRINT_BOTTOMMARGIN
				UG_PRINT_FRAME
				UG_PRINT_TOPHEADING
				UG_PRINT_SIDEHEADING
	param - [out] if retrieving a margin:  size in mm
			[out] if retrieving the frame: TRUE or FALSE
			[out] if retrieving a heading: TRUE or FALSE
return
	UG_SUCCESS - success
	UG_ERROR - error
****************************************************/
int CUGPrint::PrintGetOption(int option,long *param)
{
	int retval = UG_SUCCESS;

	switch (option) 
	{
	case UG_PRINT_LEFTMARGIN:
		*param = m_printLeftMargin;
		break;
	case UG_PRINT_RIGHTMARGIN:
		*param = m_printRightMargin;
		break;
	case UG_PRINT_TOPMARGIN:
		*param = m_printTopMargin;
		break;
	case UG_PRINT_BOTTOMMARGIN:
		*param = m_printBottomMargin;
		break;
	case UG_PRINT_FRAME:
		*param = m_printFrame;
		break;
	case UG_PRINT_TOPHEADING:
		*param =  m_printTopHeading;
		break;
	case UG_PRINT_SIDEHEADING:
		*param =  m_printSideHeading;
		break;
	default:
		*param = 0;
		retval = UG_ERROR;
	}
	
	return retval;
}

/***************************************************
InternPrintCell - private
	This function is called by the PrintPage function
	to setup the drawing for an individual cell.
	Once setup then the cells specified celltype is
	called to perform the actual drawing
Params
	dc - device context to draw to
	rect - rectangle to draw the cell within
	col - column of the cell to draw
	row - row of the cell to draw
****************************************************/
void CUGPrint::InternPrintCell(CDC *dc,RECT * rect,int col,long row)
{
	CUGCellType * cellType;
	CUGCell cell,cell2;
	int leftMargin = m_printLeftMarginPX;
	int topMargin =  m_printTopMarginPX;

	//TEST
	CRgn rgn;
	if(m_bIsPreview == FALSE){
		rgn.CreateRectRgn((rect->left-0) * m_virPixWidth,
			(rect->top-0) * m_virPixWidth,
			(rect->right-0) * m_virPixWidth,
			(rect->bottom-0) * m_virPixWidth);

		dc->SelectClipRgn(NULL);
		dc->SelectClipRgn(&rgn);
	}

	if ( col < 0 && row < 0 )
	{
		rect->top = topMargin;
		rect->left = leftMargin;
		rect->right = (int)(leftMargin + (m_GI->m_sideHdgWidth * m_printHScale));
		rect->bottom = (int)(topMargin + (m_GI->m_topHdgHeight * m_printVScale)) - 1;

		col = -1;
		row = -1;
	}

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

	//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);

	//paint the cell
	int saveID = dc->SaveDC();
	cellType->OnPrint(dc,rect,col,row,&cell);
	dc->RestoreDC(saveID);

	//TEST
	if(m_bIsPreview == FALSE){
		dc->SelectClipRgn(NULL);
	}
}

#endif


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