Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

500 lines
12 KiB

#ifndef __tmplrEdit_h
#define __tmplrEdit_h
#include <atlctrls.h>
#include <winuser.h>
/////////////////////////////////////////////////////////////////////////////
// CWindowImplHotlinkRichEdit
// Purpose - To display a hyperlink control (like Syslink in Whistler) using a rich edit ctrl
//
// Usage - CWindowImplHotlinkRichEdit<> m_Hotlink;
// CDialog::OnInitDialog(..)
// {
// ...
// m_Hotlink.SubClassWindow( GetDlgItem( IDC_RICHEDIT1 ));
// ::SendMessage (
// GetDlgItem(IDC_RICHEDIT1), WM_SETTEXT, 0 ,
// (LPARAM) _T("Click <A>here</A> to do something")
// );
// ...
// }
#define LINKSTARTTAG _T("<A>")
#define LINKENDTAG _T("</A>")
template <class T = CRichEditCtrl, class TBase = CWindow, class TWinTraits = CControlWinTraits>
class CWindowImplHotlinkRichEdit : public CWindowImpl< T, TBase, TWinTraits >
{
private:
int m_iLinkIndex;
RECT m_rect;
BOOL m_bHasFocus;
public:
CWindowImplHotlinkRichEdit() : m_iLinkIndex(-1), m_bHasFocus(FALSE)
{
ZeroMemory(&m_rect, sizeof(m_rect));
}
BEGIN_MSG_MAP(CWindowImplHotlinkRichEdit)
MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
MESSAGE_HANDLER(WM_SETTEXT, OnSetText)
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
MESSAGE_HANDLER(WM_CHAR, OnChar)
MESSAGE_HANDLER(WM_NCHITTEST, OnHitTest)
MESSAGE_HANDLER(WM_KEYDOWN, OnKey)
MESSAGE_HANDLER(WM_KEYUP, OnKey)
END_MSG_MAP()
HFONT CharFormatToHFont(CHARFORMAT * pcf)
{
// Create a font that matches the font specified by pcf
HFONT hFont = NULL;
HDC hDC = GetDC();
if (pcf)
{
LOGFONT lf;
ZeroMemory(&lf, sizeof(lf));
lf.lfCharSet = pcf->bCharSet;
lf.lfPitchAndFamily = pcf->bPitchAndFamily;
// yHeight is in twips.
lf.lfHeight = -1 * pcf->yHeight / 20.0 * GetDeviceCaps (hDC, LOGPIXELSY) / 72;
_tcsncpy(lf.lfFaceName, pcf->szFaceName, LF_FACESIZE);
lf.lfFaceName[LF_FACESIZE-1] = NULL;
hFont = CreateFontIndirect(&lf);
}
if (hDC)
{
ReleaseDC(hDC);
}
return hFont;
}
BOOL HFontToCharFormat(HFONT hFont, CHARFORMAT * pcf)
{
BOOL bRet = FALSE;
HDC hDC = GetDC();
if (hFont)
{
LOGFONT lf;
ZeroMemory(&lf, sizeof(lf));
if (GetObject(hFont, sizeof(lf), &lf))
{
pcf->bCharSet = lf.lfCharSet;
pcf->bPitchAndFamily = lf.lfPitchAndFamily;
// yHeight is in twips
pcf->yHeight = 20 * lf.lfHeight * 72.0 / GetDeviceCaps (hDC, LOGPIXELSY);
pcf->yHeight = pcf->yHeight < 0 ? -pcf->yHeight : pcf->yHeight;
_tcsncpy(pcf->szFaceName, lf.lfFaceName, LF_FACESIZE);
pcf->szFaceName[LF_FACESIZE-1] = NULL;
pcf->dwMask |= CFM_CHARSET | CFM_FACE | CFM_SIZE;
bRet = TRUE;
}
}
if (hDC)
{
ReleaseDC(hDC);
}
return bRet;
}
BOOL SubclassWindow(HWND hWnd)
{
BOOL bRC = FALSE;
if (::IsWindow(hWnd))
{
bRC = CWindowImpl< T, TBase, TWinTraits >::SubclassWindow( hWnd );
::SendMessage(hWnd, EM_SETSEL, -1, 0);
}
return bRC;
}
LRESULT OnPaint( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
DefWindowProc(uMsg, wParam, lParam);
::SendMessage(m_hWnd, EM_SETSEL, -1, 0);
HideCaret();
if (m_bHasFocus)
{
DrawHotlinkFocusRect();
}
bHandled = TRUE;
return 0;
}
LRESULT OnKey( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
if (VK_TAB == wParam || VK_SHIFT == wParam || VK_ESCAPE == wParam)
{
return DefWindowProc(uMsg, wParam, lParam);
}
bHandled = TRUE;
return 0;
}
LRESULT OnChar( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
if (VK_RETURN == wParam || VK_SPACE == wParam) // Enter and space when we have the focus...
{
HWND hWndParent;
hWndParent = ::GetParent(m_hWnd);
if (hWndParent)
{
NMHDR nmhdr;
ENLINK enlink;
nmhdr.hwndFrom = m_hWnd;
nmhdr.idFrom = ::GetDlgCtrlID(m_hWnd);
nmhdr.code = EN_LINK;
enlink.msg = uMsg;
enlink.lParam = lParam;
enlink.wParam = wParam;
enlink.nmhdr = nmhdr;
// DO NOT USE PostMessage for the notification, can cause AV
::SendMessage(hWndParent, WM_NOTIFY, ::GetDlgCtrlID(m_hWnd), (LPARAM) &enlink);
}
}
bHandled = TRUE;
return 0;
}
LRESULT OnHitTest( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
POINTS pts;
POINT pt;
pts = MAKEPOINTS(lParam);
POINTSTOPOINT(pt, pts);
::MapWindowPoints(NULL, m_hWnd, &pt, 1);
if (PtInRect(&m_rect, pt))
{
return DefWindowProc(uMsg, wParam, lParam);
}
return HTTRANSPARENT;
}
LRESULT OnKillFocus( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
DefWindowProc(uMsg, wParam, lParam);
if (TRUE == m_bHasFocus)
{
DrawHotlinkFocusRect();
m_bHasFocus = FALSE;
}
bHandled = TRUE;
return 0;
}
LRESULT OnFocus( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
// Each time we get WM_SETFOCUS we need to draw focus rect
// around the link
DefWindowProc(uMsg, wParam, lParam);
::SendMessage(m_hWnd, EM_SETSEL, -1, 0);
HideCaret();
if (FALSE == m_bHasFocus)
{
DrawHotlinkFocusRect();
m_bHasFocus = TRUE;
}
bHandled = TRUE;
return 0;
}
LRESULT OnSetText( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled )
{
TCHAR szLink[128];
TCHAR * szText = reinterpret_cast<LPTSTR> (lParam);
TCHAR * szActualText = NULL;
TCHAR * pLinkStart, * pLinkEnd, * pTemp;
int i,j;
// When we get WM_SETTEXT message, we will search the text for
// the link identified by <A> </A>
// After identifying the link we will strip off the tags and send the message
// to DefWindowProc
// Ex: "Click <A>here</A> to do something interesting"
if (szText)
{
pLinkStart = _tcsstr(szText, LINKSTARTTAG);
pLinkEnd = _tcsstr(szText, LINKENDTAG);
// Make sure that we have a link in the text
if (pLinkStart && pLinkEnd && pLinkStart < pLinkEnd)
{
// szActualText will hold the final text without the tags
szActualText = new TCHAR[_tcslen(szText) + 1];
if (szActualText)
{
i = j = 0;
pTemp = pLinkStart + _tcslen(LINKSTARTTAG); // pTemp = "here</A> to do something interesting"
while (pTemp < pLinkEnd)
{
szLink[i++] = *pTemp++;
}
szLink[i] = NULL; // szLink = "here"
while(szText < pLinkStart)
{
szActualText[j++] = *szText++;
}
szActualText[j] = NULL; // szActualText = "Click"
m_iLinkIndex = j;
_tcscat(szActualText, szLink); // szActualText = "Click here"
pTemp = pLinkEnd + _tcslen(LINKENDTAG); // pTemp = " to do something interesting"
_tcscat(szActualText, pTemp); // szActualText = "Click here to do something interesting"
}
}
}
bHandled = TRUE;
if (szActualText)
{
HWND hWndParent;
HFONT hFont;
CHARFORMAT cf;
ZeroMemory(&cf, sizeof(cf));
cf.cbSize = sizeof(cf);
hWndParent = ::GetParent(m_hWnd);
if (hWndParent)
{
// Stick to parent window's font...
hFont = reinterpret_cast<HFONT> (::SendMessage(hWndParent, WM_GETFONT, 0, 0));
if (hFont)
{
if (HFontToCharFormat(hFont, &cf))
{
::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_ALL, (LPARAM) &cf);
}
}
}
// Let the control display the text without the links
DefWindowProc(uMsg, wParam, (LPARAM) szActualText);
// Get current char format
::SendMessage(m_hWnd, EM_GETCHARFORMAT, SCF_DEFAULT, (LPARAM) &cf);
cf.dwEffects |= CFE_LINK; // For link style
// Select the link text
::SendMessage(m_hWnd, EM_SETSEL, m_iLinkIndex, m_iLinkIndex + _tcslen(szLink));
// Change the format of the link text
::SendMessage(m_hWnd, EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
// Get the rect that covers the link in logical units
// We will use this rect to draw focus rect around the link
GetLinkRect(szActualText, szLink);
return 0;
}
else
{
return DefWindowProc(uMsg, wParam, lParam);
}
}
BOOL GetLinkRect(LPTSTR szText, LPCTSTR szLink)
{
if (!szText || !szLink)
{
return FALSE;
}
BOOL bSuccess = FALSE;
if (-1 != m_iLinkIndex)
{
DWORD dwStart;
DWORD dwEnd;
dwStart = ::SendMessage(m_hWnd, EM_POSFROMCHAR, m_iLinkIndex, 0);
dwEnd = ::SendMessage(m_hWnd, EM_POSFROMCHAR, m_iLinkIndex + _tcslen(szLink), 0);
CHARFORMAT cf;
ZeroMemory(&cf, sizeof(cf));
cf.cbSize = sizeof(cf);
cf.dwMask |= CFM_CHARSET | CFM_FACE | CFM_SIZE;
::SendMessage(m_hWnd, EM_SETSEL, 0, -1);
::SendMessage(m_hWnd, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM) &cf);
HFONT hFont = CharFormatToHFont(&cf);
if (hFont)
{
HDC hDC = GetDC();
if (hDC)
{
SelectObject(hDC, hFont);
TEXTMETRIC tm;
ZeroMemory(&tm, sizeof(tm));
if (GetTextMetrics(hDC, &tm))
{
m_rect.left = LOWORD(dwStart);
m_rect.top = HIWORD(dwStart);
m_rect.right = LOWORD(dwEnd);
m_rect.bottom = m_rect.top + tm.tmHeight + tm.tmDescent;
bSuccess = TRUE;
}
ReleaseDC(hDC);
}
DeleteObject(hFont);
}
}
return bSuccess;
}
BOOL DrawHotlinkFocusRect()
{
BOOL bRet = FALSE;
if (-1 != m_iLinkIndex)
{
HDC hdc = GetDC();
bRet = DrawFocusRect(hdc, &m_rect);
ReleaseDC(hdc);
}
return bRet;
}
};
#endif // #ifndef __tmplEdit.h