/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2009 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "..\..\core\commonheaders.h" struct HyperlinkWndData { HFONT hEnableFont, hDisableFont; RECT rcText; COLORREF enableColor, disableColor, focusColor; BYTE flags; /* see HLKF_* */ }; /* flags */ #define HLKF_HASENABLECOLOR 0x1 /* dat->enableColor is not system default */ #define HLKF_HASDISABLECOLOR 0x2 /* dat->disableColor is not system default */ /* internal messages */ #define HLK_MEASURETEXT (WM_USER+1) #define HLK_INVALIDATE (WM_USER+2) static LRESULT CALLBACK HyperlinkWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { struct HyperlinkWndData *dat=(struct HyperlinkWndData*)GetWindowLongPtr(hwnd, 0); switch(msg) { case WM_NCCREATE: dat=(struct HyperlinkWndData*)mir_calloc(sizeof(struct HyperlinkWndData)); if (dat == NULL) return FALSE; /* fail creation */ SetWindowLongPtr(hwnd, 0, (LONG_PTR)dat); /* always succeeds */ /* fall thru */ case WM_SYSCOLORCHANGE: if ( !(dat->flags&HLKF_HASENABLECOLOR)) { if (GetSysColorBrush(COLOR_HOTLIGHT) == NULL) dat->enableColor=RGB(0, 0, 255); else dat->enableColor=GetSysColor(COLOR_HOTLIGHT); dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2); } if ( !(dat->flags&HLKF_HASDISABLECOLOR)) dat->disableColor=GetSysColor(COLOR_GRAYTEXT); break; case WM_SETFOCUS: case WM_KILLFOCUS: RedrawWindow(hwnd, NULL, NULL, RDW_INVALIDATE); break; case WM_MOUSEACTIVATE: SetFocus(hwnd); return MA_ACTIVATE; case WM_GETDLGCODE: { if (lParam) { MSG *msg = (MSG *) lParam; if (msg->message == WM_KEYDOWN) { if (msg->wParam == VK_TAB) return 0; if (msg->wParam == VK_ESCAPE) return 0; } else if (msg->message == WM_CHAR) { if (msg->wParam == '\t') return 0; if (msg->wParam == 27) return 0; } } return DLGC_WANTMESSAGE; } case WM_KEYDOWN: { switch (wParam) { case VK_SPACE: case VK_RETURN: SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), STN_CLICKED), (LPARAM)hwnd); break; } return 0; } case WM_LBUTTONDOWN: { POINT pt; POINTSTOPOINT(pt, MAKEPOINTS(lParam)); if ( !PtInRect(&dat->rcText, pt)) break; SendMessage(GetParent(hwnd), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(hwnd), STN_CLICKED), (LPARAM)hwnd); return 0; } case WM_SETFONT: { LOGFONT lf; HFONT hFont; if ((HFONT)wParam == NULL) { /* use default system color */ dat->hEnableFont=dat->hDisableFont=NULL; return 0; } if (GetObject((HFONT)wParam, sizeof(lf), &lf)) { lf.lfUnderline=1; hFont=CreateFontIndirect(&lf); if (hFont != NULL) { dat->hEnableFont=hFont; dat->hDisableFont=(HFONT)wParam; if (LOWORD(lParam)) SendMessage(hwnd, HLK_INVALIDATE, 0, 0); SendMessage(hwnd, HLK_MEASURETEXT, 0, 0); } } return 0; } case WM_ERASEBKGND: return TRUE; case WM_ENABLE: case HLK_INVALIDATE: { RECT rcWnd; POINT pt; HWND hwndParent; if ( !GetWindowRect(hwnd, &rcWnd)) break; pt.x=rcWnd.left; pt.y=rcWnd.top; hwndParent=GetParent(hwnd); if (hwndParent == NULL) hwndParent=hwnd; if ( !ScreenToClient(hwndParent, &pt)) break; rcWnd.right=pt.x+(rcWnd.right-rcWnd.left); rcWnd.bottom=pt.y+(rcWnd.bottom-rcWnd.top); rcWnd.left=pt.x; rcWnd.top=pt.y; InvalidateRect(hwndParent, &rcWnd, TRUE); return 0; } case WM_GETFONT: return (LRESULT)dat->hDisableFont; case WM_CREATE: case HLK_MEASURETEXT: { TCHAR szText[256]; if ( !GetWindowText(hwnd, szText, SIZEOF(szText))) return 0; lParam=(LPARAM)szText; /* fall thru */ case WM_SETTEXT: { HFONT hPrevFont = NULL; SIZE textSize; RECT rc; HDC hdc; LONG style; BOOL fMeasured=FALSE; hdc=GetDC(hwnd); if (hdc == NULL) return 0; /* text change failed */ if (dat->hEnableFont != NULL) hPrevFont=(HFONT)SelectObject(hdc, dat->hEnableFont); if (dat->hEnableFont == NULL || hPrevFont != NULL) /* select failed? */ if (GetTextExtentPoint32(hdc, (TCHAR*)lParam, lstrlen((TCHAR*)lParam), &textSize)) if (GetClientRect(hwnd, &rc)) { dat->rcText.top=0; dat->rcText.bottom=dat->rcText.top+textSize.cy; style=GetWindowLongPtr(hwnd, GWL_STYLE); if (style&SS_CENTER) dat->rcText.left=(rc.right-textSize.cx)/2; else if (style&SS_RIGHT) dat->rcText.left=rc.right-textSize.cx; else dat->rcText.left=0; dat->rcText.right=dat->rcText.left+textSize.cx; fMeasured=TRUE; } if (dat->hEnableFont != NULL && hPrevFont != NULL) SelectObject(hdc, hPrevFont); ReleaseDC(hwnd, hdc); if ( !fMeasured) return 0; /* text change failed */ SendMessage(hwnd, HLK_INVALIDATE, 0, 0); break; }} case WM_SETCURSOR: { POINT pt; HCURSOR hCursor; if ( !GetCursorPos(&pt)) return FALSE; if ( !ScreenToClient(hwnd, &pt)) return FALSE; if (PtInRect(&dat->rcText, pt)) { hCursor=(HCURSOR)GetClassLongPtr(hwnd, GCLP_HCURSOR); if (hCursor == NULL) hCursor=LoadCursor(NULL, IDC_HAND); /* Win2000+ */ } else hCursor=LoadCursor(NULL, IDC_ARROW); SetCursor(hCursor); return TRUE; } case HLK_SETENABLECOLOUR: { COLORREF prevColor=dat->enableColor; dat->enableColor=(COLORREF)wParam; dat->focusColor = RGB(GetRValue(dat->enableColor) / 2, GetGValue(dat->enableColor) / 2, GetBValue(dat->enableColor) / 2); dat->flags|=HLKF_HASENABLECOLOR; return (LRESULT)prevColor; } case HLK_SETDISABLECOLOUR: { COLORREF prevColor=dat->disableColor; dat->disableColor=(COLORREF)wParam; dat->flags|=HLKF_HASDISABLECOLOR; return (LRESULT)prevColor; } case WM_NCPAINT: return 0; case WM_PAINT: { HFONT hPrevFont; RECT rc; TCHAR szText[256]; UINT alignFlag; COLORREF textColor; PAINTSTRUCT ps; HDC hdc; hdc=BeginPaint(hwnd, &ps); if (hdc != NULL) { if (IsWindowEnabled(hwnd)) { hPrevFont=(HFONT)SelectObject(hdc, dat->hEnableFont); textColor = (GetFocus() == hwnd) ? dat->focusColor : dat->enableColor; } else { hPrevFont=(HFONT)SelectObject(hdc, dat->hDisableFont); textColor=dat->disableColor; } if (GetClientRect(hwnd, &rc) && GetWindowText(hwnd, szText, SIZEOF(szText))) { if (drawThemeParentBackground && IsWinVerXPPlus()) { BOOL fSmoothing; UINT fSmoothingType; SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fSmoothing, 0); SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &fSmoothingType, 0); if (fSmoothing && fSmoothingType == FE_FONTSMOOTHINGCLEARTYPE) drawThemeParentBackground(hwnd, hdc, &rc); } SetBkMode(hdc, TRANSPARENT); SetTextColor(hdc, textColor); alignFlag=(GetWindowLongPtr(hwnd, GWL_STYLE)&(SS_CENTER|SS_RIGHT|SS_LEFT)); DrawText(hdc, szText, -1, &rc, alignFlag|DT_NOPREFIX|DT_SINGLELINE|DT_TOP); } if (hPrevFont != NULL) SelectObject(hdc, hPrevFont); EndPaint(hwnd, &ps); } return 0; } case WM_NCDESTROY: if (dat->hEnableFont != NULL) DeleteObject(dat->hEnableFont); mir_free(dat); break; } return DefWindowProc(hwnd, msg, wParam, lParam); } int InitHyperlink(void) { WNDCLASS wcl; wcl.lpfnWndProc=HyperlinkWndProc; wcl.cbClsExtra=0; wcl.cbWndExtra=sizeof(struct HyperlinkWndData*); wcl.hInstance=hInst; if (IsWinVer2000Plus()) wcl.hCursor=NULL; else wcl.hCursor=LoadCursor(wcl.hInstance, MAKEINTRESOURCE(IDC_HYPERLINKHAND)); wcl.lpszClassName=WNDCLASS_HYPERLINK; wcl.hbrBackground=NULL; wcl.hIcon=NULL; wcl.lpszMenuName=NULL; wcl.style=CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS|CS_PARENTDC; RegisterClass(&wcl); /* automatically unregistered on exit */ return 0; }