Category : C++ Source Code
Archive   : MSTEXT2.ZIP
Filename : METRICS.CPP

 
Output of file : METRICS.CPP contained in archive : MSTEXT2.ZIP
//*************************************************************
//
// Description:
// Implementation file for CMetrics and derived classes.
//
// History: Date Author Comment
// 2/26/94 FJB Created
//
// Written by Microsoft Product Support Services, Windows Developer Support
// Copyright (c) 1994 Microsoft Corporation. All rights reserved.
//*************************************************************

#include "stdafx.h"
#include "textdoc.h"
#include "metrics.h"

//*************************************************************
//
// Class
// CMetrics
//
// Member Function:
// Construction:
// CMetrics - Initializes map mode,
//
// Attributes:
// IsValid - Indicates whether current computed metrics
// are valid.
// Operations:
// Compute - Recomputes metrics
// CreatePrinterDC - Creates a printer DC using current default
// printer.
// SetMapMode - Sets map mode for all CMetrics objects
// Invalidate - Invalidates current metrics.
//
// Description:
// This is the base class for several helper classes used by CTextView
// to compute and store metrics required for text output. Some examples
// of these metrics are:
//
// - Height and width of a line on the display
// - Height and width of a character on the display
// - Height and width of a line on the current printer
// - Height and width of a character on the current printer
// - Current user defined margins
// - Number of lines per page, on the current printer.
//
// To reduce the complexity of the CTextView class, these calculations
// were removed from the view and divided among three CMetrics derived
// classes: CViewMetrics, CPageMetrics, and CMargins.
//
//
// History: Date Author Comment
// 2/25/94 FJB Created
//
//*************************************************************

int CMetrics::m_nMapMode;

/////////////////////////////////////////////////////////////////////////////
// CMetrics operations

//*************************************************************
//
// Member Function:
// CMetrics::SetMapMode
//
// Purpose:
// Specifies the map mode for all CMetrics objects. Invalidates
// current metrics.
//
// Parameters:
// nMapMode - The desired map mode
//
// Comments:
// Since this is a static function, it changes the map mode for all
// CMetrics derived classes. However, it only invalidates the metrics
// for the CMetrics base class. Thus, it is important to call
// CMetrics::Invalidate for every CMetrics object after calling
// SetMapMode. Example:
//
// m_pSomeMetrics->Compute(); // compute metrics
// CMetrics::SetMapMode(MM_HIMETRIC);
// m_pSomeMetrics->Invalidate(); // map mode has changed,
// // must invalidate
//
// This won't be an issue except for applications that swap between
// mapping modes.
//
// History: Date Author Comment
// 2/26/94 FJB Created
//
//*************************************************************


void CMetrics::SetMapMode(int nMapMode)
{
ASSERT(nMapMode); // must specify a map mode

m_nMapMode = nMapMode;

// This isn't necessary, unless additional attributes are added to the
// base class.

// Invalidate();

}


CDC* CMetrics::CreatePrinterDC()
{
PRINTDLG PrtDlg;
HDC hDC;

if (!AfxGetApp()->GetPrinterDeviceDefaults(&PrtDlg))
{
TRACE("No default printer.\n");
// use screen DC for calculations
// It's OK to do this because this CDC will not be used for any
// output.
hDC = ::CreateDC("display",NULL,NULL,NULL);
}
else
{
CPrintDialog dlg(FALSE);

dlg.m_pd.hDevMode = PrtDlg.hDevMode;
dlg.m_pd.hDevNames = PrtDlg.hDevNames;

hDC = dlg.CreatePrinterDC();
}

CDC* pDC = CDC::FromHandle(hDC);
// This is a printer DC, so set m_bPrinting
// this is necessary so CScrollView::OnPrepareDC won't modify the
// ViewportOrg, and cause LPtoDP to return an inappropriate result.
pDC->m_bPrinting = TRUE;
return pDC;
}


//*************************************************************
//
// Class
// CViewMetrics
//
// Member Function:
// Construction:
// CMetrics - Initializes CTextDoc pointer,
//
// Attributes:
// GetLineSize - Returns the width and height of the longest line in
// document. Print information not available.
// GetCharSize - Returns the width and height of the average char.
// GetLogInch - Returns the size (in pixels) of a logical inch.
// GetExtLeading - Returns the tmExternalLeading value for the current
// font.
//
// Operations:
// SetFont - Specifies the font to be used as the basis for calcu-
// lations. Invalidates metrics.
// Compute - Recomputes metrics.
//
// Implementation
// ComputeScreenMetrics - Compute all screen metrics
// ComputePrintMetrics - Compute all printer metrics
//
// Description:
// CViewMetrics provides font based metrics, for both printer
// and screen.
//
// History: Date Author Comment
// 2/25/94 FJB Created
//
//*************************************************************

/////////////////////////////////////////////////////////////////////////////
// CViewMetrics construction

CViewMetrics::CViewMetrics(CTextDoc* pDoc)
{
m_nMapMode = 0;
m_pFnt = NULL;
VERIFY (m_pDoc = pDoc);
}

/////////////////////////////////////////////////////////////////////////////
// CViewMetrics attributes

CSize CViewMetrics::GetLineSize(BOOL fWantPrint)
{
// line metrics are currently available only for screen
ASSERT (!fWantPrint);

Compute();

return m_sizeLine;
}


CSize CViewMetrics::GetCharSize(BOOL fWantPrint)
{
Compute();

return (fWantPrint) ? m_sizeCharPrt : m_sizeCharScn;
}


CSize CViewMetrics::GetLogInch()
{
Compute();

return m_sizeLogInch;
}


int CViewMetrics::GetExtLeading()
{
Compute();

return m_cyExtLeading;
}

/////////////////////////////////////////////////////////////////////////////
// CViewMetrics operations


void CViewMetrics::Compute()
{
if (!IsValid())
{
// call the base class to set m_fValid
CMetrics::Compute();

// For the purpose of code readability, screen calculations are
// separate from printing calculations
ComputeScreenMetrics();
ComputePrintMetrics();
}
}

void CViewMetrics::SetFont(CFont* pFnt)
{
ASSERT(pFnt);

m_pFnt = pFnt;
// View metrics are based on the selected font, and need to be
// recomputed
Invalidate();
}


/////////////////////////////////////////////////////////////////////////////
// CViewMetrics implementation

void CViewMetrics::ComputeScreenMetrics()
{
// get a CDC* for the screen
CDC* pDC = CDC::FromHandle(::GetDC(NULL));
// select the specified map mode
pDC->SetMapMode(m_nMapMode);
// select the specified font
CFont* pFnt = pDC->SelectObject(m_pFnt);
ASSERT(pFnt);

// First metric: get size of logical inch in pixels
m_sizeLogInch.cx = pDC->GetDeviceCaps(LOGPIXELSX);
m_sizeLogInch.cy = pDC->GetDeviceCaps(LOGPIXELSY);

TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);

// Store some useful text metrics
VERIFY(m_sizeCharScn.cy = tm.tmHeight + tm.tmExternalLeading);
m_sizeCharScn.cx = tm.tmAveCharWidth;
m_cyExtLeading = tm.tmExternalLeading;

m_sizeLine = CSize(0,0);

// loop through the document and find the longest line
for (int i = 0; i < m_pDoc->GetCLines(); i++)
{
CString str = m_pDoc->m_ary.GetAt(i);
CSize size = pDC->GetTextExtent(str,str.GetLength());
m_sizeLine.cx = max(size.cx,m_sizeLine.cx);
}

// line height is currently equal to character height
m_sizeLine.cy = m_sizeCharScn.cy;

// clean up
pDC->SelectObject(pFnt);
::ReleaseDC(NULL,pDC->GetSafeHdc());
}

void CViewMetrics::ComputePrintMetrics()
{
// get a printer CDC*
CDC* pDC = CreatePrinterDC();

ASSERT_VALID(pDC);
// select specified map mode
pDC->SetMapMode(m_nMapMode);
// select specified font
CFont* pFnt = pDC->SelectObject(m_pFnt);

ASSERT(pFnt);

TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);

// store useful text metrics
m_sizeCharPrt.cy = tm.tmHeight + tm.tmExternalLeading;
m_sizeCharPrt.cx = tm.tmAveCharWidth;

// clean up
pDC->SelectObject(pFnt);
::DeleteDC(pDC->GetSafeHdc());
}

//*************************************************************
//
// Class
// CPageMetrics
//
// Member Function:
// Construction:
// CPageMetrics - Initializes CTextDoc, CViewMetrics, and CMargins
// pointers. CPageMetrics requires these object to do
// its calculations
//
// Attributes:
// GetCPages - Returns the number of pages in the document.
// GetLinesPerPage - Returns the number of lines per page
// IsPageBreak - Returns true if the indicated line ends a page.
//
// Operations:
// Compute - Recomputes metrics
//
// Description:
// CPageMetrics calculates and provides page information about the
// document.
//
// History: Date Author Comment
// 2/25/94 FJB Created
//
//*************************************************************

/////////////////////////////////////////////////////////////////////////////
// CPageMetrics construction


CPageMetrics::CPageMetrics(CTextDoc* pDoc,
CMargins* pMar,
CViewMetrics* pVMet)
{
// CPageMetrics requires CMargins, CViewMetrics and CTextDoc objects
// For it's calculations

VERIFY(m_pDocument = pDoc);
VERIFY(m_pVMetrics = pVMet);
VERIFY(m_pMargins = pMar);
}

/////////////////////////////////////////////////////////////////////////////
// CPageMetrics attributes

int CPageMetrics::GetLinesPerPage()
{
Compute();

return m_nLinesPerPage;
}


int CPageMetrics::GetCPages()
{
Compute();

return m_cPages;
}

BOOL CPageMetrics::IsPageBreak(int nLine)
{
// if page metrics haven't been computed
// then don't do pagination. Pagination can be a lengthy process,
// it should only be done when explicitly asked for.
if (!IsValid())
return FALSE;

// if this line number divides evenly by the number of
// lines per page, this is a page break.
return !((nLine + 1) % m_nLinesPerPage);
}

/////////////////////////////////////////////////////////////////////////////
// CPageMetrics operations

void CPageMetrics::Compute()
{
// see if metrics have already been computed
if (IsValid())
return;
// call the base class to set m_fValid
CMetrics::Compute();

CDC* pDC = CreatePrinterDC();
ASSERT(pDC);

pDC->SetMapMode(m_nMapMode);

// get the dimensions of a printed character using current font
CPoint pt(m_pVMetrics->GetCharSize(TRUE));

// convert to device units to minimize round off error
pDC->LPtoDP(&pt,1);

// get the phsical page height in device units
int cyPage = m_pMargins->GetPhysSizeDev().cy;

// get current user margin offsets and covert to device units
CRect rectMargins = m_pMargins->GetUserMargins();
pDC->LPtoDP(&rectMargins);

// adjust page size by user margins offsets
cyPage -= (abs(rectMargins.top) + abs(rectMargins.bottom));

// compute first required metric
m_nLinesPerPage = abs(cyPage/pt.y);

ASSERT(m_nLinesPerPage);

// compute length of document in pages
m_cPages = m_pDocument->GetCLines() / m_nLinesPerPage;
if (m_pDocument->GetCLines() % m_nLinesPerPage)
m_cPages++;

ASSERT(m_cPages);

// cleanup
::DeleteDC(pDC->GetSafeHdc());
}

//*************************************************************
//
// Class
// CMargins
//
// Member Function:
// Construction:
// CMargins - Initializes default user margins to .5"
//
// Attributes:
// GetHardMargins - Returns a CRect that contains the hardware margins
// in MM_LOENGLISH units for the current printer.
// All margins are taken as positive offsets.
//
// GetUserMargins - Returns a CRect that contains the current user
// define marigins. See GetHardMargins for unit
// information.
//
// GetPrintableRect - Returns a CRect that describes the printable
// region, in MM_LOENGLISH units. The printable
// region is the usable portion of the page.
//
// GetPhysSizeDev - Returns a CSize that contains the physical page
// size, in device units.
//
// GetAdjustedRect - Returns a CRect that describes the page specified
// by the user defined margins.
//
// IsInvalid - Attempts to validate the specified user defined margins.
// Does two checks:
// 1. Ensures the user defined margins are >= the hardware
// margins for the current printer.
// 2. Checks to see if the user defined margins overlap.
//
// Operations:
// SetMargins - Specifies the user defined margins
// Compute - Recomputes metrics
//
// Description:
// CMargins calculates and maintains hardware margins, user defined
// margins.
//
// History: Date Author Comment
// 2/25/94 FJB Created
//
//*************************************************************

/////////////////////////////////////////////////////////////////////////////
// CMargins construction

CMargins::CMargins()
{
m_rectHardMargins = CRect(0,0,0,0);
// default .5" margins
m_rectUserMargins = CRect(50,50,50,50);

m_rectAdjusted = CRect(0,0,0,0);
m_rectPrintable = CRect(0,0,0,0);
}


/////////////////////////////////////////////////////////////////////////////
// CMargins attributes

//*************************************************************
//
// Member Function:
// CMargins::IsInvalid
//
// Description:
// Verifies the specified user defined margins
//
// Parameters:
// rectMargins - A CRect containing the user defined margins to verify.
// Margins are specified as positive offsets in
// MM_LOENGLISH units
//
// Returns:
// 0 - Margins were valid.
// CMargins:enMargins - The first margin determined to be invalid.
//
// History: Date Author Comment
// 2/26/94 FJB Created
//
//*************************************************************


CMargins::enMargins CMargins::IsInvalid(CRect rectMargins)
{
LPINT lpnMargins = (LPINT) (LPRECT) &rectMargins;
LPINT lpnHardMargins = (LPINT) (LPRECT) &m_rectHardMargins;

CSize size = CSize(m_rectPrintable.Width(), m_rectPrintable.Height());
LPINT lpnPhysPage = (LPINT) (LPSIZE) &size;

for (int i = LEFT; i <= BOTTOM; i++)
{
// boundary check
if (lpnMargins[i-1] < lpnHardMargins[i-1])
return (CMargins::enMargins) i; // user defined margins must exceed
// hardware margins. Return error.

// determine complimentary margin (TOP/BOTTOM, LEFT/RIGHT)
int l = i + 2;
if (l > BOTTOM)
l -= BOTTOM;

// do margins overlap?
if (lpnMargins[i-1] + lpnMargins[l-1] >= abs(lpnPhysPage[!(i&1)]))
return (CMargins::enMargins) i; // Yes, return error
}
return (CMargins::enMargins) 0; // specified margins are OK
}


CRect CMargins::GetUserMargins()
{
Compute();

return m_rectUserMargins;
}


CRect CMargins::GetHardMargins()
{
Compute();

return m_rectHardMargins;
}


CRect CMargins::GetAdjustedMargins()
{
Compute();
// Adjusted margins are computed by subtracting hardware margin offsets
// from user defined margin offsets.

CRect rect(m_rectUserMargins.left - m_rectHardMargins.left,
m_rectUserMargins.top - m_rectHardMargins.top,
m_rectUserMargins.right - m_rectHardMargins.right,
m_rectUserMargins.bottom - m_rectHardMargins.bottom);
return rect;
}


CSize CMargins::GetPhysSizeDev()
{
Compute();

return m_sizePhysDev;
}

CRect CMargins::GetPrintableRect()
{
Compute();

return m_rectPrintable;
}

CRect CMargins::GetAdjustedRect()
{
Compute();

return m_rectAdjusted;
}


/////////////////////////////////////////////////////////////////////////////
// CMargins operations

void CMargins::SetMargins(CRect rectMargins)
{
ASSERT(!IsInvalid(rectMargins));

m_rectUserMargins = rectMargins;

// everything has to be recomputed now
Invalidate();
}


void CMargins::Compute()
{
if (IsValid())
return;

// call base class to set m_fValid
CMetrics::Compute();

CDC* pDC = CreatePrinterDC();
pDC->SetMapMode(m_nMapMode);

// Calculate margins. See article Q105444 in the Knowledge Base
// for a description of this method.

// 1. Get left/top hardware margins in device units
pDC->Escape(GETPRINTINGOFFSET,0,NULL,&m_rectHardMargins);

// 2, Get Physical page size in device units
pDC->Escape(GETPHYSPAGESIZE,0,NULL,&m_sizePhysDev);

// 3. Get Printable page size, in device units
// left and right are 0,0
m_rectPrintable.right = pDC->GetDeviceCaps(HORZRES);
m_rectPrintable.bottom = pDC->GetDeviceCaps(VERTRES);


// 4. Compute right/bottom hardware margins
m_rectHardMargins.right = m_sizePhysDev.cx - m_rectPrintable.Width()
- m_rectHardMargins.left;

m_rectHardMargins.bottom = m_sizePhysDev.cy - m_rectPrintable.Height()
- m_rectHardMargins.top;
// 5. Convert hardware margins to logical units
pDC->DPtoLP(&m_rectHardMargins);

// 6. Y coordinates will be negative (using MM_LOMETRIC)
// Margins are offsets so remove sign
m_rectHardMargins.top = abs(m_rectHardMargins.top);
m_rectHardMargins.bottom = abs(m_rectHardMargins.bottom);

// 7. Convert printable page size to logical units
pDC->DPtoLP(&m_rectPrintable);

// 8 Adjust printable page for user defined margins
m_rectAdjusted = GetAdjustedMargins();
m_rectAdjusted.right = m_rectPrintable.Width() -
m_rectAdjusted.right;

m_rectAdjusted.bottom = m_rectPrintable.Height() +
m_rectAdjusted.bottom;

m_rectAdjusted.top = -m_rectAdjusted.top;

::DeleteDC(pDC->GetSafeHdc());
}




  3 Responses to “Category : C++ Source Code
Archive   : MSTEXT2.ZIP
Filename : METRICS.CPP

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/