xhtmlstatic.cpp

来自「管理项目进度工具的原代码」· C++ 代码 · 共 1,326 行 · 第 1/3 页

CPP
1,326
字号
// XHTMLStatic.cpp  Version 1.2
//
// Author:  Hans Dietrich
//          hdietrich2@hotmail.com
//
// History
//     Version 1.2 - 2004 June 12
//     - Changed APP: hyperlink to use HWND instead of GetParent();
//     - Added wParam to XHTMLSTATIC_APP_COMMAND struct
//     - Added function SetTextColor(LPCTSTR lpszColor)
//     - Added function SetLogFont(const LOGFONT * pLogFont)
//     - Added function SetWindowText() to call Init and RedrawWindow
//     - Fixed bug with XNamedColors in handling of "255,0,0" style 
//       in SetColorFromString()
//     - Fixed bug with descenders of large serif fonts
//
//     Version 1.1 - 2004 May 20
//     - Implemented SUB tag
//     - Implemented SUP tag
//     - Implemented BIG tag
//     - Implemented SMALL tag
//     - Implemented CODE tag
//     - Implemented HR tag
//     - Implemented APP: hyperlink
//     - Implemented common character entities
//     - Improved parsing performance
//     - Bug fixes
//
//     Version 1.0 - 2002 September 16
//     - Initial public release
//
// Acknowledgements:
//     Thanks to Charles Petzold for explaining how GetTextExtentPoint32()
//     works, in his excellent "Programming Windows", Fifth Edition:
//         http://www.bookpool.com/.x/6o8gzz6xw6/sm/157231995X
//
//     Thanks to Chris Maunder for showing how to set the cursor and receive 
//     mouse clicks for static controls, and for all the code that I used 
//     from his CHyperLink class:
//         http://www.codeproject.com/miscctrl/hyperlink.asp
//
// License:
//     This software is released into the public domain.  You are free to use
//     it in any way you like, except that you may not sell this source code.
//
//     This software is provided "as is" with no expressed or implied warranty.
//     I accept no liability for any damage or loss of business that this 
//     software may cause.
//
///////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "XHTMLStatic.h"

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

// some common character entities
XHTMLSTATIC_CHAR_ENTITIES CXHTMLStatic::m_aCharEntities[] = 
{
	{ _T("&"),		0,	_T('&') },		// ampersand
	{ _T("•"),		0,	_T('\x95') },	// bullet		NOT IN MS SANS SERIF
	{ _T("©"),		0,	_T('\xA9') },	// copyright
	{ _T("€"),		0,	_T('\x80') },	// euro sign
	{ _T(">"),		0,	_T('>') },		// greater than
	{ _T("¿"),	0,	_T('\xBF') },	// inverted question mark
	{ _T("&lt;"),		0,	_T('<') },		// less than
	{ _T("&nbsp;"),		0,	_T(' ') },		// nonbreaking space
	{ _T("&para;"),		0,	_T('\xB6') },	// paragraph sign
	{ _T("&pound;"),	0,	_T('\xA3') },	// pound sign
	{ _T("&quot;"),		0,	_T('"') },		// quotation mark
	{ _T("&reg;"),		0,	_T('\xAE') },	// registered trademark
	{ _T("&trade;"),	0,	_T('\x99') },	// trademark	NOT IN MS SANS SERIF
	{ NULL,				0,	0 }				// MUST BE LAST
};

///////////////////////////////////////////////////////////////////////////////
// CXHTMLStatic

#define WM_SHOWACCELERATORS 0x0128

BEGIN_MESSAGE_MAP(CXHTMLStatic, CStatic)
	//{{AFX_MSG_MAP(CXHTMLStatic)
	ON_WM_PAINT()
	ON_WM_TIMER()
	ON_WM_SETCURSOR()
	ON_WM_DESTROY()
	//}}AFX_MSG_MAP
    ON_CONTROL_REFLECT(STN_CLICKED, OnClicked)
	ON_MESSAGE(WM_SHOWACCELERATORS, OnShowAccelerators)
END_MESSAGE_MAP()

///////////////////////////////////////////////////////////////////////////////
// ctor
CXHTMLStatic::CXHTMLStatic()
{
	memset(&m_lf, 0, sizeof(m_lf));

	m_bLogFont          = FALSE;
	m_hLinkCursor		= NULL;
	m_paAppCommands     = NULL;
	m_nAppCommands      = 0;
	m_nLeftMargin       = 0;
	m_nRightMargin      = 0;
	m_AnchorRectPtrs.RemoveAll();
	m_AnchorUrls.RemoveAll();

	// get hand cursor
    CString strWndDir;
    GetWindowsDirectory(strWndDir.GetBuffer(MAX_PATH), MAX_PATH);
    strWndDir.ReleaseBuffer();

    strWndDir += _T("\\winhlp32.exe");
    // This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
    HMODULE hModule = ::LoadLibrary(strWndDir);
    if (hModule) 
	{
        HCURSOR hHandCursor = ::LoadCursor(hModule, MAKEINTRESOURCE(106));
        if (hHandCursor)
            m_hLinkCursor = CopyCursor(hHandCursor);
    }
    ::FreeLibrary(hModule);

	InitCharEntities();

	Init();
}

///////////////////////////////////////////////////////////////////////////////
// dtor
CXHTMLStatic::~CXHTMLStatic()
{
	Init();

	if (m_hLinkCursor)
		::DestroyCursor(m_hLinkCursor);
	m_hLinkCursor = NULL;

	if (m_paAppCommands)
		delete [] m_paAppCommands;
	m_paAppCommands = NULL;
}

///////////////////////////////////////////////////////////////////////////////
// InitCharEntities
void CXHTMLStatic::InitCharEntities()
{
	for (int i = 0; m_aCharEntities[i].pszName != NULL; i++)
	{
		m_aCharEntities[i].cCode = (TCHAR) (i + 2);	// don't use 0 or 1
	}
}

///////////////////////////////////////////////////////////////////////////////
// InitCharEntities
TCHAR CXHTMLStatic::GetCharEntity(TCHAR cCode)
{
	TCHAR c = _T(' ');

	for (int i = 0; m_aCharEntities[i].pszName != NULL; i++)
	{
		if (cCode == m_aCharEntities[i].cCode)
		{
			c = m_aCharEntities[i].cSymbol;
			break;
		}
	}

	return c;
}

///////////////////////////////////////////////////////////////////////////////
// Init
void CXHTMLStatic::Init()
{
	m_crBackGround			= ::GetSysColor(COLOR_WINDOW);
	m_crText				= ::GetSysColor(COLOR_WINDOWTEXT);
	m_bUnderline			= FALSE;
	m_bBold					= FALSE;
	m_bItalic				= FALSE;
	m_bStrikeThrough		= FALSE;
	m_bSubscript			= FALSE;
	m_bSuperscript			= FALSE;
	m_bHorizontalRule		= FALSE;
	m_nHorizontalRuleSize	= 2;
	m_bHyperlinkTimer		= FALSE;
	m_bOnHyperlink			= FALSE;
	m_hPrevCursor			= NULL;
	m_bInAnchor				= FALSE;
	m_bGeneratedText		= FALSE;

	int n = m_AnchorRectPtrs.GetSize();

	for (int i = 0; i < n; i++)
	{
		CRect *pRect = (CRect *) m_AnchorRectPtrs[i];
		if (pRect)
			delete pRect;
	}

	m_AnchorRectPtrs.RemoveAll();
	m_AnchorUrls.RemoveAll();
}

///////////////////////////////////////////////////////////////////////////////
// OnPaint
void CXHTMLStatic::OnPaint() 
{
	CPaintDC dc(this); // device context for painting

	// get text from control
	CString strText = _T("");
	GetWindowText(strText);

	// replace character entity names with codes

	TCHAR ent[3] = { 0 };
	ent[0] = _T('\001');	// each entity name is replaced with a two-character
							// code that begins with \001

	for (int i = 0; m_aCharEntities[i].pszName != NULL; i++)
	{
		ent[1] = m_aCharEntities[i].cCode;
		strText.Replace(m_aCharEntities[i].pszName, ent);
	}

	CString str1 = _T("");
	int index = 0;

	// set text and background colors
	COLORREF crText = m_crText;
	COLORREF prev_crText = crText;

	COLORREF crBackground = m_crBackGround;
	COLORREF prev_crBackground = crBackground;

	CFont *pOldFont = dc.SelectObject(&m_font);
	int n = strText.GetLength();

	CRect rect;
	GetClientRect(&rect);

	dc.FillSolidRect(&rect, m_crBackGround);

	// allow for margins
	rect.left += m_nLeftMargin;
	rect.right -= m_nRightMargin;

	int nInitialXOffset = 0;//m_nLeftMargin;
	m_yStart = rect.top;

	LOGFONT lf, prev_lf;
	if (m_bLogFont)
	{
		memcpy(&lf, &m_lf, sizeof(lf));
	}
	else
	{
		CFont* cf = GetFont();
		if (cf)
			cf->GetObject(sizeof(lf), &lf);
		else
			GetObject(GetStockObject(SYSTEM_FONT), sizeof(lf), &lf);
	}
	memcpy(&prev_lf, &lf, sizeof(lf));

	CString strAnchorText = _T("");

	BOOL bSizeChange = FALSE;
	//BOOL bEndOfSizeChange = FALSE;
	TEXTMETRIC tm;
	dc.GetTextMetrics(&tm);

	while (n > 0)
	{
		///////////////////////////////////////////////////////////////////////
		if (_tcsnicmp(strText, _T("<B>"), 3) == 0)	// check for <b> or <B>
		{
			n -= 3;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			m_bBold++;// = TRUE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</B>"), 4) == 0)	// check for </B>
		{
			n -= 4;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (m_bBold)
				m_bBold--;// = FALSE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<I>"), 3) == 0)	// check for <I>
		{
			n -= 3;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			m_bItalic++;// = TRUE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</I>"), 4) == 0)	// check for </I>
		{
			n -= 4;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (m_bItalic)
				m_bItalic--;// = FALSE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<U>"), 3) == 0)		// check for <U>
		{
			n -= 3;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			m_bUnderline++;// = TRUE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</U>"), 4) == 0)	// check for </U>
		{
			n -= 4;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (m_bUnderline)
				m_bUnderline--;// = FALSE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<STRIKE>"), 8) == 0)	// check for <STRIKE>
		{
			n -= 8;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			m_bStrikeThrough++;// = TRUE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</STRIKE>"), 9) == 0)	// check for </STRIKE>
		{
			n -= 9;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (m_bStrikeThrough)
				m_bStrikeThrough--;// = FALSE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<BIG>"), 5) == 0)	// check for <BIG>
		{
			n -= 5;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (lf.lfHeight > 0)
				lf.lfHeight++;
			else
				lf.lfHeight--;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</BIG>"), 6) == 0)	// check for </BIG>
		{
			n -= 6;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (lf.lfHeight > 0)
				lf.lfHeight--;
			else
				lf.lfHeight++;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<SMALL>"), 7) == 0)	// check for <SMALL>
		{
			n -= 7;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (lf.lfHeight > 0)
				lf.lfHeight--;
			else
				lf.lfHeight++;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</SMALL>"), 8) == 0)	// check for </SMALL>
		{
			n -= 8;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (lf.lfHeight > 0)
				lf.lfHeight++;
			else
				lf.lfHeight--;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<SUB>"), 5) == 0)	// check for <SUB>
		{
			n -= 5;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			m_bSubscript++;// = TRUE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("</SUB>"), 6) == 0)	// check for </SUB>
		{
			n -= 6;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);
			if (m_bSubscript)
				m_bSubscript--;// = FALSE;
			continue;
		}
		///////////////////////////////////////////////////////////////////////
		else if (_tcsnicmp(strText, _T("<SUP>"), 5) == 0)	// check for <SUP>
		{
			n -= 5;
			index = strText.Find(_T('>'));
			if (index != -1)
				strText = strText.Mid(index+1);

⌨️ 快捷键说明

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