⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dcprev.cpp

📁 vc6.0完整版
💻 CPP
📖 第 1 页 / 共 2 页
字号:
										int nTabOrigin, int nTabWidth)
{
	x -= nTabOrigin;        // normalize position to tab origin
	for (UINT i = 0; i < nTabStops; i++, lpnTabStops++)
	{
		if (*lpnTabStops > x)
			return *lpnTabStops + nTabOrigin;
	}
	return (x / nTabWidth + 1) * nTabWidth + nTabOrigin;
}

// Compute a character delta table for correctly positioning the screen
// font characters where the printer characters will appear on the page
CSize CPreviewDC::ComputeDeltas(int& x, LPCTSTR lpszString, UINT &nCount,
	BOOL bTabbed, UINT nTabStops, LPINT lpnTabStops, int nTabOrigin,
	LPTSTR lpszOutputString, int* pnDxWidths, int& nRightFixup)
{
	ASSERT_VALID(this);

	TEXTMETRIC tmAttrib;
	TEXTMETRIC tmScreen;
	::GetTextMetrics(m_hAttribDC, &tmAttrib);
	::GetTextMetrics(m_hDC, &tmScreen);

	CSize sizeExtent;
	::GetTextExtentPoint32A(m_hAttribDC, "A", 1, &sizeExtent);

	CPoint ptCurrent;
	UINT nAlignment = ::GetTextAlign(m_hAttribDC);
	BOOL bUpdateCP = (nAlignment & TA_UPDATECP) != 0;
	if (bUpdateCP)
	{
		::GetCurrentPositionEx(m_hDC, &ptCurrent);
		x = ptCurrent.x;
	}

	LPCTSTR lpszCurChar = lpszString;
	LPCTSTR lpszStartRun = lpszString;
	int* pnCurDelta = pnDxWidths;
	int nStartRunPos = x;
	int nCurrentPos = x;
	int nStartOffset = 0;

	int nTabWidth = 0;
	if (bTabbed)
	{
		if (nTabStops == 1)
		{
			nTabWidth = lpnTabStops[0];
		}
		else
		{
			// Get default size of a tab
			nTabWidth = LOWORD(::GetTabbedTextExtentA(m_hAttribDC,
				"\t", 1, 0, NULL));
		}
	}

	for (UINT i = 0; i < nCount; i++)
	{
		BOOL bSpace = ((_TUCHAR)*lpszCurChar == (_TUCHAR)tmAttrib.tmBreakChar);
		if (bSpace || (bTabbed && *lpszCurChar == '\t'))
		{
			// bSpace will be either TRUE (==1) or FALSE (==0).  For spaces
			// we want the space included in the GetTextExtent, for tabs we
			// do not want the tab included
			int nRunLength = (int)(lpszCurChar - lpszStartRun) + bSpace;

			CSize sizeExtent;
			::GetTextExtentPoint32(m_hAttribDC, lpszStartRun, nRunLength,
				&sizeExtent);
			int nNewPos = nStartRunPos + sizeExtent.cx
				- tmAttrib.tmOverhang;

			// now, if this is a Tab (!bSpace), compute the next tab stop
			if (!bSpace)
			{
				nNewPos = _AfxComputeNextTab(nNewPos, nTabStops, lpnTabStops,
								nTabOrigin, nTabWidth);
			}

			// Add this width to previous width
			if (pnCurDelta == pnDxWidths)
				nStartOffset += nNewPos - nCurrentPos;
			else
				*(pnCurDelta-1) += nNewPos - nCurrentPos;

			nCurrentPos = nNewPos;

			nStartRunPos = nCurrentPos;     // set start of run
			// *lpszCurChar must be SBC: tmBreakChar or '\t'
			lpszStartRun = lpszCurChar + 1;
		}
		else
		{
			// For the non-tabbed or non-tab-character case
			int cxScreen;
			if (_istlead(*lpszCurChar))
			{
				cxScreen = tmScreen.tmAveCharWidth;
				*pnCurDelta = tmAttrib.tmAveCharWidth;
			}
			else
			{
				::GetCharWidth(m_hDC, (_TUCHAR)*lpszCurChar,
					(_TUCHAR)*lpszCurChar, &cxScreen);
				if (!::GetCharWidth(m_hAttribDC, (_TUCHAR)*lpszCurChar,
					(_TUCHAR)*lpszCurChar, pnCurDelta))
				{
					// If printer driver fails the above call, use the average width
					*pnCurDelta = tmAttrib.tmAveCharWidth;
				}
			}
			*pnCurDelta -= tmAttrib.tmOverhang;
			cxScreen -= tmScreen.tmOverhang;
			nCurrentPos += *pnCurDelta;     // update current position

			// Center character in allotted space
			if (pnCurDelta != pnDxWidths)
			{
				int diff = (*pnCurDelta - cxScreen) / 2;
				*pnCurDelta -= diff;
				*(pnCurDelta - 1) += diff;
			}
			*lpszOutputString++ = *lpszCurChar;
			if (_istlead(*lpszCurChar))
			{
				*lpszOutputString++ = *(lpszCurChar+1); // copy trailing byte
				*(pnCurDelta + 1) = *pnCurDelta;        // double wide
				nCurrentPos += *pnCurDelta;
				pnCurDelta++;
				i++;
			}
			pnCurDelta++;
		}
		lpszCurChar = _tcsinc(lpszCurChar);
	}

	nAlignment &= TA_CENTER|TA_RIGHT;
	sizeExtent.cx = nCurrentPos - x;
	nRightFixup = 0;

	if (nAlignment == TA_LEFT)
		x += nStartOffset;      // Full left side adjustment
	else if (nAlignment == TA_CENTER)
		x += nStartOffset/2;    // Adjust Center by 1/2 left side adjustment
	else if (nAlignment == TA_RIGHT)
		nRightFixup = nStartOffset; // Right adjust needed later if TA_UPDATECP

	if (bUpdateCP)
		::MoveToEx(m_hDC, x, ptCurrent.y, NULL);

	nCount = (UINT)(pnCurDelta - pnDxWidths);   // number of characters output
	return sizeExtent;
}

BOOL CPreviewDC::TextOut(int x, int y, LPCTSTR lpszString, int nCount)
{
	return ExtTextOut(x, y, 0, NULL, lpszString, nCount, NULL);
}

BOOL CPreviewDC::ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect,
	LPCTSTR lpszString, UINT nCount, LPINT lpDxWidths)
{
	ASSERT(m_hDC != NULL);
	ASSERT(m_hAttribDC != NULL);
	ASSERT(lpszString != NULL);
	ASSERT(lpDxWidths == NULL ||
			AfxIsValidAddress(lpDxWidths, sizeof(int) * nCount, FALSE));
	ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE));

	int* pDeltas = NULL;
	LPTSTR pOutputString = NULL;
	int nRightFixup = 0;

	if (lpDxWidths == NULL)
	{
		if (nCount == 0)    // Do nothing
			return TRUE;

		TRY
		{
			pDeltas = new int[nCount];
			pOutputString = new TCHAR[nCount];
		}
		CATCH_ALL(e)
		{
			delete[] pDeltas;  // in case it was allocated
			// Note: DELETE_EXCEPTION(e) not required
			return FALSE;   // Could not allocate buffer, cannot display
		}
		END_CATCH_ALL

		ComputeDeltas(x, (LPTSTR)lpszString, nCount, FALSE, 0, NULL, 0,
										pOutputString, pDeltas, nRightFixup);

		lpDxWidths = pDeltas;
		lpszString = pOutputString;
	}

	BOOL bSuccess = ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString,
														nCount, lpDxWidths);
	if (nRightFixup != 0 && bSuccess && (GetTextAlign() & TA_UPDATECP))
	{
		CPoint pt;
		::GetCurrentPositionEx(m_hDC, &pt);
		MoveTo(pt.x - nRightFixup, pt.y);
	}
	delete[] pDeltas;
	delete[] pOutputString;

	return bSuccess;
}

CSize CPreviewDC::TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount,
	int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin)
{
	ASSERT(m_hAttribDC != NULL);
	ASSERT(m_hDC != NULL);
	ASSERT(lpszString != NULL);
	ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE));
	ASSERT(lpnTabStopPositions == NULL ||
			AfxIsValidAddress(lpnTabStopPositions, sizeof(int) * nTabPositions,
				FALSE));

	if (nCount <= 0)
		return 0;         // nCount is zero, there is nothing to print

	int* pDeltas = NULL;
	LPTSTR pOutputString = NULL;
	int nRightFixup;

	TRY
	{
		pDeltas = new int[nCount];
		pOutputString = new TCHAR[nCount];
	}
	CATCH_ALL(e)
	{
		delete[] pDeltas;
		// Note: DELETE_EXCEPTION(e) not required
		return 0;           // signify error
	}
	END_CATCH_ALL

	UINT uCount = nCount;
	CSize sizeFinalExtent = ComputeDeltas(x, lpszString, uCount, TRUE,
							nTabPositions, lpnTabStopPositions, nTabOrigin,
							pOutputString, pDeltas, nRightFixup);

	BOOL bSuccess = ExtTextOut(x, y, 0, NULL, pOutputString, uCount, pDeltas);

	delete[] pDeltas;
	delete[] pOutputString;

	if (bSuccess && (GetTextAlign() & TA_UPDATECP))
	{
		CPoint pt;
		::GetCurrentPositionEx(m_hDC, &pt);
		MoveTo(pt.x - nRightFixup, pt.y);
	}

	return sizeFinalExtent;
}

// This one is too complicated to do character-by-character output positioning
// All we really need to do here is mirror the current position
int CPreviewDC::DrawText(LPCTSTR lpszString, int nCount, LPRECT lpRect,
	UINT nFormat)
{
	ASSERT(m_hAttribDC != NULL);
	ASSERT(m_hDC != NULL);
	ASSERT(lpszString != NULL);
	ASSERT(lpRect != NULL);
	ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT)));
	ASSERT(nCount == -1 ?
		AfxIsValidString(lpszString) :
		AfxIsValidAddress(lpszString, nCount, FALSE));

	int retVal = ::DrawText(m_hDC, lpszString, nCount, lpRect, nFormat);

	CPoint pos;
	::GetCurrentPositionEx(m_hDC, &pos);
	::MoveToEx(m_hAttribDC, pos.x, pos.y, NULL);
	return retVal;
}

BOOL CPreviewDC::GrayString(CBrush*,
				BOOL (CALLBACK *)(HDC, LPARAM, int),
					LPARAM lpData, int nCount, int x, int y, int, int)
{
	TRACE0("TextOut() substituted for GrayString() in Print Preview.\n");
	return TextOut(x, y, (LPCTSTR)lpData, nCount);
}

int CPreviewDC::Escape(int nEscape, int nCount, LPCSTR lpszInData, void* lpOutData)
{
	// The tact here is to NOT allow any of the document control escapes
	// to be passed through.  Elimination of StartDoc and EndDoc should
	// eliminate anything actually going to the printer.  Also anything
	// that actually draws something will be filtered.

	ASSERT(m_hAttribDC != NULL);

	switch (nEscape)
	{
	case NEXTBAND:
	case SETCOLORTABLE:
	case GETCOLORTABLE:
	case FLUSHOUTPUT:
	case DRAFTMODE:
	case QUERYESCSUPPORT:
	case GETPHYSPAGESIZE:
	case GETPRINTINGOFFSET:
	case GETSCALINGFACTOR:
	case GETPENWIDTH:
	case SETCOPYCOUNT:
	case SELECTPAPERSOURCE:
	case GETTECHNOLOGY:
	case SETLINECAP:
	case SETLINEJOIN:
	case SETMITERLIMIT:
	case BANDINFO:
	case GETVECTORPENSIZE:
	case GETVECTORBRUSHSIZE:
	case ENABLEDUPLEX:
	case GETSETPAPERBINS:
	case GETSETPRINTORIENT:
	case ENUMPAPERBINS:
	case SETDIBSCALING:
	case ENUMPAPERMETRICS:
	case GETSETPAPERMETRICS:
	case GETEXTENDEDTEXTMETRICS:
	case GETEXTENTTABLE:
	case GETPAIRKERNTABLE:
	case GETTRACKKERNTABLE:
	case ENABLERELATIVEWIDTHS:
	case ENABLEPAIRKERNING:
	case SETKERNTRACK:
	case SETALLJUSTVALUES:
	case SETCHARSET:
	case SET_BACKGROUND_COLOR:
	case SET_SCREEN_ANGLE:
	case SET_SPREAD:
		return ::Escape(m_hAttribDC, nEscape, nCount, lpszInData, lpOutData);

	default:
		return 0;
	}
}

void CPreviewDC::MirrorMappingMode(BOOL bCompute)
{
	ASSERT(m_hAttribDC != NULL);
	if (bCompute)
	{
		//
		// The following formula is used to compute the screen's viewport extent
		// From the printer and screen information and the Printer's Viewport
		// Extents.  (Note:  This formula is used twice, once for horizontal
		// and once for vertical)
		//
		// It is assumed that the Window Extents are maintained as equal.
		//
		//                  m * LogPixPerInch(Screen) * VpExt(Printer)
		// VpExt(Screen) = -------------------------------------------------
		//                          n * LogPixPerInch(Printer)
		//
		// Where m/n is the scaling factor.  (m/n > 1 is expansion)
		//

		VERIFY(::GetViewportExtEx(m_hAttribDC, &m_sizeVpExt));
		VERIFY(::GetWindowExtEx(m_hAttribDC, &m_sizeWinExt));

		while (m_sizeWinExt.cx > -0x4000 && m_sizeWinExt.cx < 0x4000 &&
			   m_sizeVpExt.cx  > -0x4000 && m_sizeVpExt.cx  < 0x4000)
		{
			m_sizeWinExt.cx <<= 1;
			m_sizeVpExt.cx  <<= 1;
		}

		while (m_sizeWinExt.cy > -0x4000 && m_sizeWinExt.cy < 0x4000 &&
			   m_sizeVpExt.cy  > -0x4000 && m_sizeVpExt.cy  < 0x4000)
		{
			m_sizeWinExt.cy <<= 1;
			m_sizeVpExt.cy  <<= 1;
		}

		long lTempExt = _AfxMultMultDivDiv(m_sizeVpExt.cx,
			m_nScaleNum, afxData.cxPixelsPerInch,
			m_nScaleDen, ::GetDeviceCaps(m_hAttribDC, LOGPIXELSX));

		ASSERT(m_sizeWinExt.cx != 0);
		m_sizeVpExt.cx = (int)lTempExt;

		lTempExt = _AfxMultMultDivDiv(m_sizeVpExt.cy,
			m_nScaleNum, afxData.cyPixelsPerInch,
			m_nScaleDen, ::GetDeviceCaps(m_hAttribDC, LOGPIXELSY));

		ASSERT(m_sizeWinExt.cy != 0);
		m_sizeVpExt.cy = (int)lTempExt;
	}

	if (m_hDC != NULL)
	{
		::SetMapMode(m_hDC, MM_ANISOTROPIC);
		::SetWindowExtEx(m_hDC, m_sizeWinExt.cx, m_sizeWinExt.cy, NULL);
		::SetViewportExtEx(m_hDC, m_sizeVpExt.cx, m_sizeVpExt.cy, NULL);

		// Now that the Logical Units are synchronized, we can set the Viewport Org
		MirrorViewportOrg();
	}
}

void CPreviewDC::MirrorViewportOrg()
{
	if (m_hAttribDC == NULL || m_hDC == NULL)
		return;

	CPoint ptVpOrg;
	VERIFY(::GetViewportOrgEx(m_hAttribDC, &ptVpOrg));
	PrinterDPtoScreenDP(&ptVpOrg);
	ptVpOrg += m_sizeTopLeft;
	::SetViewportOrgEx(m_hDC, ptVpOrg.x, ptVpOrg.y, NULL);

	CPoint ptWinOrg;
	VERIFY(::GetWindowOrgEx(m_hAttribDC, &ptWinOrg));
	::SetWindowOrgEx(m_hDC, ptWinOrg.x, ptWinOrg.y, NULL);
}

void CPreviewDC::SetTopLeftOffset(CSize sizeTopLeft)
{
	ASSERT(m_hAttribDC != NULL);
	m_sizeTopLeft = sizeTopLeft;
	MirrorViewportOrg();
}

void CPreviewDC::ClipToPage()
{
	ASSERT(m_hAttribDC != NULL);
	ASSERT(m_hDC != NULL);
	// Create a rect in Screen Device coordinates that is one pixel larger
	// on all sides than the actual page.  This is to hide the fact that
	// the printer to screen mapping mode is approximate and may result
	// in rounding error.

	CPoint pt(::GetDeviceCaps(m_hAttribDC, HORZRES),
				::GetDeviceCaps(m_hAttribDC, VERTRES));
	PrinterDPtoScreenDP(&pt);

	// Set the screen dc to MM_TEXT and no WindowOrg for the interesection

	::SetMapMode(m_hDC, MM_TEXT);
	::SetWindowOrgEx(m_hDC, 0, 0, NULL);
	::SetViewportOrgEx(m_hDC, m_sizeTopLeft.cx, m_sizeTopLeft.cy, NULL);
	::IntersectClipRect(m_hDC, -1, -1, pt.x + 2, pt.y + 2);

	// Resynchronize the mapping mode
	MirrorMappingMode(FALSE);
}

// these conversion functions can be used without an attached screen DC

void CPreviewDC::PrinterDPtoScreenDP(LPPOINT lpPoint) const
{
	ASSERT(m_hAttribDC != NULL);

	CSize sizePrinterVpExt;
	VERIFY(::GetViewportExtEx(m_hAttribDC, &sizePrinterVpExt));
	CSize sizePrinterWinExt;
	VERIFY(::GetWindowExtEx(m_hAttribDC, &sizePrinterWinExt));

	long xScreen = _AfxMultMultDivDiv(lpPoint->x,
		sizePrinterWinExt.cx, m_sizeVpExt.cx,
		sizePrinterVpExt.cx, m_sizeWinExt.cx);

	lpPoint->x = (int)xScreen;

	long yScreen = _AfxMultMultDivDiv(lpPoint->y,
		sizePrinterWinExt.cy, m_sizeVpExt.cy,
		sizePrinterVpExt.cy, m_sizeWinExt.cy);

	lpPoint->y = (int)yScreen;
}


#ifdef AFX_INIT_SEG
#pragma code_seg(AFX_INIT_SEG)
#endif

IMPLEMENT_DYNAMIC(CPreviewDC, CDC)

/////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -