www.pudn.com > RichTextEx.rar > HyperText.h
#ifndef MAQ_HYPERTEXT_H #define MAQ_HYPERTEXT_H #if _MSC_VER > 1000 #pragma once #endif #include#include
namespace HyperText { #define HTC_WORDWRAP 1 // word wrap text #define HTC_AUTO_SCROLL_BARS 2 // auto hide scroll bars #define HTC_UNDERLINE_LINKS 4 // underline links #define HTC_UNDERLINE_HOVER 8 // underline hover links #define HTC_ENABLE_TOOLTIPS 16 // enable hyperlink tool tips // -------------------------------------------------------------- // CHyperLink class CHyperLink { int m_iBegin; int m_iEnd; CString m_sTitle; enum LinkType { lt_Shell = 0, /* http:// mailto:*/ lt_Message = 1 /* WM_COMMAND */ } m_Type; // used for lt_Shell CString m_sCommand; CString m_sDirectory; // used for lt_Message HWND m_hWnd; UINT m_uMsg; WPARAM m_wParam; LPARAM m_lParam; public: CHyperLink(int iBegin, int iEnd, const CString& sTitle, const CString& sCommand, const CString& sDirectory) { m_Type = lt_Shell; m_iBegin = iBegin; m_iEnd = iEnd; m_sTitle = sTitle; m_sCommand = sCommand; m_sDirectory = sDirectory; } CHyperLink(int iBegin, int iEnd, const CString& sTitle, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { m_Type = lt_Message; m_iBegin = iBegin; m_iEnd = iEnd; m_sTitle = sTitle; m_hWnd = hWnd; m_uMsg = uMsg; m_wParam = wParam; m_lParam = lParam; } CHyperLink(const CHyperLink& Src) { m_Type = Src.m_Type; m_iBegin = Src.m_iBegin; m_iEnd = Src.m_iEnd; m_sTitle = Src.m_sTitle; m_sCommand = Src.m_sCommand; m_sDirectory = Src.m_sDirectory; m_hWnd = Src.m_hWnd; m_uMsg = Src.m_uMsg; m_wParam = Src.m_wParam; m_lParam = Src.m_lParam; } void Execute() { switch(m_Type) { case lt_Shell: ShellExecute(NULL, NULL, m_sCommand, NULL, m_sDirectory, SW_SHOWDEFAULT); break; case lt_Message: PostMessage(m_hWnd, m_uMsg, m_wParam, m_lParam); break; } } inline bool operator < (const CHyperLink& Arg) { return m_iEnd < Arg.m_iEnd; } inline int Begin() { return m_iBegin; } inline int End() { return m_iEnd; } inline int Len() { return m_iEnd - m_iBegin + 1; } inline CString Title() { return m_sTitle; } friend class CPreparedHyperText; }; class CPreparedHyperText { protected: CString m_sText; std::list m_Links; inline void RemoveLastSign(CString& sLink) { int len = sLink.GetLength(); if(len > 0) { TCHAR c = sLink[len-1]; switch(c) { case _T('.'): case _T(','): case _T(';'): case _T('\"'): case _T('\''): case _T('('): case _T(')'): case _T('['): case _T(']'): case _T('{'): case _T('}'): sLink.Delete(len -1, 1); break; } } } void PrepareText(const CString& sText) { m_sText = sText; m_Links.clear(); enum { unknown, space, http0, /* http:// */ http1, http2, http3, http4, http5, http6, ftp0, /* ftp:// */ ftp1, ftp2, ftp3, ftp4, ftp5, ftp, /* ftp. */ www0, /* www. */ www1, www2, www3, mailto0, /* mailto: */ mailto1, mailto2, mailto3, mailto4, mailto5, mailto6, mail /* xxx@yyy */ } state = space; int WordPos = 0; TCHAR sz[2]; TCHAR& c = sz[0]; sz[1] = 0; int last = m_sText.GetLength() -1; for(int i = 0; i <= last; i++) { c = m_sText[i]; _tcslwr(sz); switch(state) { case unknown: if(tspace(c)) state = space; else if(c == _T('@') && WordPos != i) state = mail; break; case space: WordPos = i; switch(c) { case _T('h'): state = http0; break; case _T('f'): state = ftp0; break; case _T('w'): state = www0; break; case _T('m'): state = mailto0; break; default: if(!tspace(c)) state = unknown; } break; /*----------------- http -----------------*/ case http0: if(c == _T('t')) state = http1; else if(tspace(c)) state = space; else state = unknown; break; case http1: if(c == _T('t')) state = http2; else if(tspace(c)) state = space; else state = unknown; break; case http2: if(c == _T('p')) state = http3; else if(tspace(c)) state = space; else state = unknown; break; case http3: if(c == _T(':')) state = http4; else if(tspace(c)) state = space; else state = unknown; break; case http4: if(c == _T('/')) state = http5; else if(tspace(c)) state = space; else state = unknown; break; case http5: if(c == _T('/')) state = http6; else if(tspace(c)) state = space; else state = unknown; break; case http6: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; /*----------------- ftp -----------------*/ case ftp0: if(c == _T('t')) state = ftp1; else if(tspace(c)) state = space; else state = unknown; break; case ftp1: if(c == _T('p')) state = ftp2; else if(tspace(c)) state = space; else state = unknown; break; case ftp2: if(c == _T(':')) state = ftp3; else if(c == _T('.')) state = ftp; else if(tspace(c)) state = space; else state = unknown; break; case ftp3: if(c == _T('/')) state = ftp4; else if(tspace(c)) state = space; else state = unknown; break; case ftp4: if(c == _T('/')) state = ftp5; else if(tspace(c)) state = space; else state = unknown; break; case ftp: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = CString(_T("ftp://")) + m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; case ftp5: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; /*----------------- www -----------------*/ case www0: if(c == _T('w')) state = www1; else if(tspace(c)) state = space; else state = unknown; break; case www1: if(c == _T('w')) state = www2; else if(tspace(c)) state = space; else state = unknown; break; case www2: if(c == _T('.')) state = www3; else if(tspace(c)) state = space; else state = unknown; break; case www3: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = CString(_T("http://")) + m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; /*----------------- mailto -----------------*/ case mailto0: if(c == _T('a')) state = mailto1; else if(tspace(c)) state = space; else state = unknown; break; case mailto1: if(c == _T('i')) state = mailto2; else if(tspace(c)) state = space; else state = unknown; break; case mailto2: if(c == _T('l')) state = mailto3; else if(tspace(c)) state = space; else state = unknown; break; case mailto3: if(c == _T('t')) state = mailto4; else if(tspace(c)) state = space; else state = unknown; break; case mailto4: if(c == _T('o')) state = mailto5; else if(tspace(c)) state = space; else state = unknown; break; case mailto5: if(c == _T(':')) state = mailto6; else if(tspace(c)) state = space; else state = unknown; break; case mailto6: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; /*----------------- mailto -----------------*/ case mail: if(tspace(c) || i == last) { int len = i == last ? i - WordPos + 1 : i - WordPos; CString s = CString(_T("mailto:")) + m_sText.Mid(WordPos, len); RemoveLastSign(s); m_Links.push_back(CHyperLink(WordPos, WordPos + len - 1, s, s, (LPCTSTR)NULL)); state = space; } break; } } m_Links.sort(); } bool tspace(TCHAR c) { return _istspace(c) || c < _T(' ') || c == _T(';') || c == _T(',') || c == _T('!'); } public: CPreparedHyperText() { } CPreparedHyperText(const CString& sText) { PrepareText(sText); } CPreparedHyperText(const CPreparedHyperText& src) { m_sText = src.m_sText; m_Links.assign(src.m_Links.begin(), src.m_Links.end()); } void Clear() { m_sText.Empty(); m_Links.erase(m_Links.begin(), m_Links.end()); } void SetText(const CString& sText) { Clear(); PrepareText(sText); } void AppendText(const CString& sText) { int len = m_sText.GetLength(); CPreparedHyperText ht(sText); m_sText+=sText; for(std::list ::iterator it = ht.m_Links.begin(); it != ht.m_Links.end(); it++) { CHyperLink hl = *it; hl.m_iBegin += len; hl.m_iEnd += len; m_Links.push_back(hl); } } void AppendHyperLink(const long lBegin, const long lEnd, const CString& sText, const CString& sTitle, const CString& sCommand, const CString& sDirectory) { ASSERT(sText.GetLength()>0); ASSERT(sCommand.GetLength()>0); int len = m_sText.GetLength(); m_sText+=sText; m_Links.push_back(CHyperLink(lBegin, lEnd, sTitle, sCommand, sDirectory)); } void AppendHyperLink(const CString& sText, const CString& sTitle, HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { ASSERT(sText.GetLength()>0); int len = m_sText.GetLength(); m_sText+=sText; m_Links.push_back(CHyperLink(len, len + sText.GetLength() - 1, sTitle, hWnd, uMsg, wParam, lParam)); } inline CString& GetText() { return m_sText; } inline std::list & GetLinks() { return m_Links; } //friend class CHyperTextCtrl; }; class CHyperTextCtrl { protected: class CLinePartInfo { public: int m_iBegin; int m_iEnd; CHyperLink* m_pHyperLink; inline CLinePartInfo(int iBegin, int iEnd, CHyperLink* pHyperLink = NULL) { m_iBegin = iBegin; m_iEnd = iEnd; m_pHyperLink = pHyperLink; } inline CLinePartInfo(const CLinePartInfo& Src) { m_iBegin = Src.m_iBegin; m_iEnd = Src.m_iEnd; m_pHyperLink = Src.m_pHyperLink; } inline int Begin() { return m_iBegin; } inline int End() { return m_iEnd; } inline int Len() { return m_iEnd - m_iBegin + 1; } }; class CLineInfo : public std::vector { public: int m_iBegin; int m_iEnd; inline CLineInfo(int iBegin, int iEnd) { m_iBegin = iBegin; m_iEnd = iEnd; } inline CLineInfo(const CLineInfo& Src) { m_iBegin = Src.m_iBegin; m_iEnd = Src.m_iEnd; assign(Src.begin(), Src.end()); } inline int Begin() { return m_iBegin; } inline int End() { return m_iEnd; } inline int Len() { return m_iEnd - m_iBegin + 1; } }; class CVisPart : public CLinePartInfo { public: CRect m_rcBounds; int m_iRealBegin; int m_iRealLen; CVisPart* m_pPrev; CVisPart* m_pNext; inline CVisPart( const CLinePartInfo& LinePartInfo, const CRect& rcBounds, int iRealBegin, int iRealLen, CVisPart* pPrev, CVisPart* pNext ) : CLinePartInfo(LinePartInfo) { m_rcBounds = rcBounds; m_iRealBegin = iRealBegin; m_iRealLen = iRealLen; m_pPrev = pPrev; m_pNext = pNext; } inline CVisPart(const CVisPart& Src) : CLinePartInfo(Src) { m_rcBounds = Src.m_rcBounds; m_iRealBegin = Src.m_iRealBegin; m_iRealLen = Src.m_iRealLen; m_pPrev = Src.m_pPrev; m_pNext = Src.m_pNext; } }; class CVisLine : public std::vector { }; CPreparedHyperText m_Text; std::vector m_Lines; CFont m_Font; COLORREF m_BkColor; COLORREF m_TextColor; COLORREF m_LinkColor; COLORREF m_HoverColor; HCURSOR m_LinkCursor; HCURSOR m_DefaultCursor; CToolTipCtrl m_tip; //temporary variables int m_iMaxWidth; // The maximum line width int m_iLineHeight; // Height of one line int m_iLinesHeight; // Sum of height of all lines bool m_bDontUpdateSizeInfo; // Used to prevent recursive call of the UpdateSize() method int m_iVertPos; // Vertical position in percents int m_iHorzPos; // Horizontal position in percents CFont m_DefaultFont; // This font is set by default CFont m_LinksFont; // Copied from main font to faster draw (link) CFont m_HoverFont; // Copied from main font to faster draw (hover link) std::vector m_VisLines; // Currently visible text CVisPart* m_pActivePart; // Active part of link (hovered) int m_iWheelDelta; // Mouse wheel scroll delta }; }; #endif