/**
* This code is by OShah. all code will have the following licence.
* Copyright Shexec32. All code bears the following licence:
**/
/**
* Copyright Shexec32 2004-2005. All rights reserved.
*
* THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
**/
/** This file is the URL control presented at www.catch22.net that
* turns a static text label into a url link. The code has been
* slightly altered to work with FilePermsBox. The code is apparently
* public domain and comes with the following introductory notice:
*
* urlctrl - altered static text ctrl - bittmann 2004
*
* based upon "urlctrl" by jbrown
* please visit: http://www.catch22.net/tuts/
**/
#include "SecurityCore.h"
#include "UrlCtrl.h"
typedef struct tagURLCTRL
{
sized_array<TCHAR> szURL;//url!=display
WNDPROC oldproc;//old window proc
HCURSOR hcur;//cursor
HFONT hfont;//underlined font
COLORREF crUnvisited;//color unvisited
COLORREF crVisited;//color visited
BOOL fClicking;//internal state
DWORD dwFlags;//combination of UCF_xxx values
} URLCTRL;
BOOL util_url_draw(HWND, HDC, RECT*); //draw (LPRECT==NULL) OR calc (LPRECT!=NULL)
BOOL util_url_fit(HWND, BOOL); //resize window
BOOL util_url_open(HWND );//open url
LRESULT CALLBACK urlctrl_proc(HWND, UINT, WPARAM, LPARAM);
BOOL util_url_draw(HWND hwnd,HDC hdc,RECT *calcrect)
{/* calc OR draw */
if(::GetWindowLongPtr(hwnd, GWLP_WNDPROC) == reinterpret_cast<LONG_PTR>(urlctrl_proc) && hdc)
{/* is urlctrl and hdc? */
URLCTRL *url = reinterpret_cast<URLCTRL *>(::GetProp(hwnd, _T("UrlCtrl")));
if(url != NULL)
{
HANDLE hOld = NULL;
DWORD style = DT_SINGLELINE | DT_NOPREFIX;
RECT rc = {0};
int len = 2 + ::GetWindowTextLength(hwnd);
sized_array<TCHAR> szText(len);
::GetWindowText(hwnd, szText.get(), len);
if(url->dwFlags & UCF_TXT_RIGHT)
style |= DT_RIGHT;
else if(url->dwFlags & UCF_TXT_HCENTER)
style |= DT_CENTER;
if (url->dwFlags & UCF_TXT_BOTTOM)
style |= DT_BOTTOM;
else if(url->dwFlags & UCF_TXT_VCENTER)
style |= DT_VCENTER;
if(calcrect == NULL)
{/* draw! */
COLORREF crOldText = {0};
int iOldBkMode = 0;
::GetClientRect(hwnd, &rc);
::FillRect( hdc, &rc, reinterpret_cast<HBRUSH>(COLOR_3DFACE + 1) );
if(url->dwFlags & UCF_KBD)
{/* protect focus rect */
if(::GetFocus() == hwnd)
::DrawFocusRect(hdc, &rc);
++rc.left;
--rc.right;
++rc.top;
--rc.bottom;
}
crOldText = ::SetTextColor(hdc, (url->dwFlags & UCF_LNK_VISITED) ? (url->crVisited) : (url->crUnvisited));
iOldBkMode = ::SetBkMode(hdc, TRANSPARENT);
hOld = ::SelectObject(hdc, url->hfont);
::DrawText(hdc, szText.get(), -1, &rc, style);
::SelectObject(hdc, hOld);
::SetBkMode(hdc, iOldBkMode);
::SetTextColor(hdc, crOldText);
}
else
{/* just calc */
calcrect->left = calcrect->top = 0;
hOld = ::SelectObject(hdc, url->hfont);
calcrect->right = calcrect->bottom = 0x00007FFF;
/* some big value */
::DrawText(hdc, szText.get(), -1, calcrect, style | DT_CALCRECT);
hOld = ::SelectObject(hdc, hOld);
if(url->dwFlags & UCF_KBD)
{/* for focus rect */
calcrect->right += 2;
calcrect->bottom += 2;
}
}
return TRUE;
}
}
return FALSE;
}
BOOL util_url_fit(HWND hwnd, BOOL fRedraw /*= TRUE*/)
{
BOOL fResult = FALSE;
if( ::GetWindowLongPtr(hwnd, GWLP_WNDPROC) == reinterpret_cast<LONG_PTR>(urlctrl_proc) )
{/* is urlctrl? */
HDC hdc = ::GetDC(hwnd);
if(hdc != NULL)
{
RECT rc = {0};
fResult = util_url_draw(hwnd, hdc, &rc);
/* calc rect (does NOT draw) */
::ReleaseDC(hwnd, hdc); hdc = NULL;
if(fResult)
{/* apply rect */
UINT flags = SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE;
if(fRedraw == FALSE)
flags |= SWP_NOREDRAW;
fResult = ::SetWindowPos(hwnd, NULL, 0, 0, rc.right, rc.bottom, flags);
}
}
}
return fResult;
}
BOOL util_url_open(HWND hwnd)
{
BOOL fResult = FALSE;
if( ::GetWindowLongPtr(hwnd, GWLP_WNDPROC)== reinterpret_cast<LONG_PTR>(urlctrl_proc) )
{/* is urlctrl? */
URLCTRL *url = reinterpret_cast<URLCTRL *>(::GetProp(hwnd, _T("UrlCtrl")));
if(url)
{
::ShellExecute(NULL,_T("open"), url->szURL.get(), NULL, NULL, SW_SHOWNORMAL);
/* open browser */
url->dwFlags |= UCF_LNK_VISITED;
/* set visited */
::InvalidateRect(hwnd, NULL, TRUE);
::UpdateWindow(hwnd);
fResult = TRUE;
}
}
return fResult;
}
LRESULT CALLBACK urlctrl_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
URLCTRL *url = reinterpret_cast<URLCTRL *>(::GetProp(hwnd, _T("UrlCtrl")));
WNDPROC oldproc = url->oldproc;
switch(uMsg)
{
case WM_NCDESTROY:
{
::SetWindowLongPtr(hwnd, GWLP_WNDPROC, LONG_PTR2(reinterpret_cast<void *>(oldproc)));
if(url->hcur) ::DestroyCursor(url->hcur);
if(url->hfont) ::DeleteObject(url->hfont);
delete [] url; url = NULL;
::RemoveProp(hwnd, _T("UrlCtrl"));
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps = {0};
HDC hdc = reinterpret_cast<HDC>(wParam);
if(wParam == 0)
hdc = ::BeginPaint(hwnd, &ps);
if(hdc)
{
util_url_draw(hwnd, hdc, NULL);
if(wParam==0) ::EndPaint(hwnd, &ps);
}
return 0;
}
case WM_SETTEXT:
{
LRESULT result = ::CallWindowProc(oldproc, hwnd, uMsg, wParam, lParam);
if(url->dwFlags & UCF_FIT)
util_url_fit(hwnd, FALSE);
::InvalidateRect(hwnd, NULL, TRUE);
::UpdateWindow(hwnd);
return result;
}
case WM_SETCURSOR:
{
HCURSOR hcur = url->hcur;
if(hcur == NULL) hcur = ::LoadCursor(NULL, IDC_ARROW);
/* fall back */
::SetCursor(hcur);
return 1;
}
case WM_NCHITTEST:
{/* static returns HTTRANSPARENT (prevents receiving mouse msgs) */
return HTCLIENT;
}
case WM_SETFONT: //we always modify the font!
{
LOGFONT lf = {0};
HFONT hfont = reinterpret_cast<HFONT> (wParam);
if(hfont == NULL)
hfont = reinterpret_cast<HFONT>(::GetStockObject(SYSTEM_FONT));
::GetObject(hfont, sizeof(LOGFONT), &lf);
lf.lfUnderline = TRUE;
/* add underline */
if(url->hfont)
{/* delete old font */
::DeleteObject(url->hfont);
}
url->hfont = ::CreateFontIndirect(&lf);
/* create new font */
::CallWindowProc(oldproc, hwnd, uMsg, wParam, 0);
/* block redraw */
if(url->dwFlags & UCF_FIT)
util_url_fit(hwnd, FALSE);
if(LOWORD(lParam))
{/* redraw? */
::InvalidateRect(hwnd, NULL, TRUE);
::UpdateWindow(hwnd);
}
return 0;
}
case WM_LBUTTONDOWN:
{
if(url->dwFlags & UCF_KBD) ::SetFocus(hwnd);
::SetCapture(hwnd);
url->fClicking = TRUE;
break;
}
case WM_LBUTTONUP:
{
::ReleaseCapture();
if(url->fClicking)
{
POINT pt = {0};
RECT rc = {0};
url->fClicking = FALSE;
pt.x=static_cast<short>(LOWORD(lParam));
pt.y=static_cast<short>(HIWORD(lParam));
::ClientToScreen(hwnd, &pt);
::GetWindowRect(hwnd, &rc);
if(::PtInRect(&rc,pt))/* inside? */
util_url_open(hwnd);
}
break;
}
case WM_KEYDOWN:
{
if(url->dwFlags & UCF_KBD)
{
if(wParam == VK_SPACE)
{
util_url_open(hwnd);
return 0;
}
}
break;
}
case WM_KEYUP:
{
if(url->dwFlags & UCF_KBD)
{
if(wParam == VK_SPACE)
{
return 0;
}
}
break;
}
case WM_GETDLGCODE:
{
if(url->dwFlags & UCF_KBD)
return DLGC_WANTCHARS;
break;
}
case WM_SETFOCUS:
case WM_KILLFOCUS:
{
if(url->dwFlags & UCF_KBD)
{
::InvalidateRect(hwnd, NULL, TRUE);
::UpdateWindow(hwnd);
return 0;
}
break;
}
}
return ::CallWindowProc(oldproc, hwnd, uMsg, wParam, lParam);
}
BOOL urlctrl_set(HWND hwnd, const std::basic_string<TCHAR> &szURL,
COLORREF unvisited /*= RGB(0,0,255)*/, COLORREF visited /*= RGB(128,0,128)*/, DWORD dwFlags /*= UCF_KBD*/)
{
if(::IsWindow(hwnd))
{
URLCTRL *url = NULL;
if(::GetWindowLongPtr(hwnd, GWLP_WNDPROC) == LONG_PTR2(reinterpret_cast<void *>(urlctrl_proc)))
{/* update old */
throw STD(_T("Inited a URL control more than once"));
}
else
{/* create new */
url = new URLCTRL[1];
/* init once */
HFONT hfont = reinterpret_cast<HFONT>(::SendMessage(hwnd, WM_GETFONT, 0, 0));
url->oldproc = reinterpret_cast<WNDPROC>(static_cast<LONG_PTR>
(::SetWindowLongPtr(hwnd, GWLP_WNDPROC, LONG_PTR2(reinterpret_cast<void *>(urlctrl_proc)))));
::SetProp(hwnd, _T("UrlCtrl"), url);
/* store in control */
url->fClicking = FALSE;
url->hcur = ::LoadCursor(NULL, IDC_HAND);
/* modify current font */
::SendMessage(hwnd, WM_SETFONT, reinterpret_cast<WPARAM>(hfont), 0);
}
/* init always */
LONG style = ::GetWindowLong(hwnd, GWL_STYLE);
url->szURL.reset(szURL.size() + 2);
url->szURL = szURL;
//szURL.copy(url->szURL.get(), szURL.size(), 0);
url->crUnvisited = (unvisited);
url->crVisited = (visited);
url->dwFlags = dwFlags;
style &= ~(WS_BORDER | WS_TABSTOP);//remove
style |= SS_NOTIFY;//add
if(url->dwFlags & UCF_KBD)
style |= WS_TABSTOP;//add?
::SetWindowLong(hwnd, GWL_STYLE, style);
if(url->dwFlags & UCF_FIT)
util_url_fit(hwnd, FALSE);
::InvalidateRect(hwnd, NULL, TRUE);
::UpdateWindow(hwnd);
}
return TRUE;
}