379 lines
9.3 KiB
C++
379 lines
9.3 KiB
C++
/*
|
|
* This is a part of the BugTrap package.
|
|
* Copyright (c) 2005-2009 IntelleSoft.
|
|
* All rights reserved.
|
|
*
|
|
* Description: Hyper-link control class.
|
|
* Author: Maksim Pyatkovskiy.
|
|
*
|
|
* This source code is only intended as a supplement to the
|
|
* BugTrap package reference and related electronic documentation
|
|
* provided with the product. See these sources for detailed
|
|
* information regarding the BugTrap package.
|
|
*/
|
|
|
|
#include "StdAfx.h"
|
|
#include "HyperLink.h"
|
|
#include "BugTrapUtils.h"
|
|
#include "Globals.h"
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
const COLORREF CHyperLink::m_rgbBlueColor = RGB(0x00, 0x00, 0xDD);
|
|
const COLORREF CHyperLink::m_rgbRedColor = RGB(0xDD, 0x00, 0x00);
|
|
|
|
CHyperLink::CHyperLink(void)
|
|
{
|
|
m_rgbCurrentColor = m_rgbBlueColor;
|
|
*m_szLinkURL = _T('\0');
|
|
m_hwnd = NULL;
|
|
m_pfnOldHyperLinkWndProc = NULL;
|
|
m_nPrevDefButtonID = -1;
|
|
}
|
|
|
|
/**
|
|
* @param pszLinkURL - new link URL.
|
|
*/
|
|
void CHyperLink::SetLinkURL(PCTSTR pszLinkURL)
|
|
{
|
|
if (pszLinkURL)
|
|
_tcscpy_s(m_szLinkURL, countof(m_szLinkURL), pszLinkURL);
|
|
else
|
|
*m_szLinkURL = _T('\0');
|
|
}
|
|
|
|
/**
|
|
* @param point - point coordinates.
|
|
* @return true if point appears in boundaries of hyper-link text.
|
|
*/
|
|
BOOL CHyperLink::HitTest(const POINT& point) const
|
|
{
|
|
RECT rect;
|
|
GetHyperLinkRect(rect);
|
|
return PtInRect(&rect, point);
|
|
}
|
|
|
|
/**
|
|
* @param x - point x-coordinate.
|
|
* @param y - point y-coordinate.
|
|
* @return true if point appears in boundaries of hyper-link text.
|
|
*/
|
|
BOOL CHyperLink::HitTest(int x, int y) const
|
|
{
|
|
POINT point;
|
|
point.x = x;
|
|
point.y = y;
|
|
return HitTest(point);
|
|
}
|
|
|
|
/**
|
|
* @param hdc - drawing context.
|
|
*/
|
|
void CHyperLink::DrawHyperLink(HDC hdc) const
|
|
{
|
|
TCHAR szLinkText[MAX_PATH];
|
|
GetWindowText(m_hwnd, szLinkText, countof(szLinkText));
|
|
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
|
|
_ASSERTE(g_pResManager != NULL);
|
|
HFONT hOldFont = g_pResManager->m_hUnderlinedFont ? SelectFont(hdc, g_pResManager->m_hUnderlinedFont) : NULL;
|
|
HWND hwndParent = GetParent(m_hwnd);
|
|
HBRUSH hBrush = hwndParent ? FORWARD_WM_CTLCOLORSTATIC(hwndParent, hdc, m_hwnd, SendMessage) : NULL;
|
|
if (! hBrush)
|
|
hBrush = g_pResManager->m_hbrButtonFaceBrush;
|
|
if (hBrush)
|
|
{
|
|
RECT rcClient;
|
|
GetClientRect(m_hwnd, &rcClient);
|
|
FillRect(hdc, &rcClient, hBrush);
|
|
}
|
|
SetTextColor(hdc, m_rgbCurrentColor);
|
|
TextOut(hdc, 1, 1, szLinkText, (int)_tcslen(szLinkText));
|
|
SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
|
|
if (hOldFont)
|
|
SelectFont(hdc, hOldFont);
|
|
if (GetFocus() == m_hwnd)
|
|
{
|
|
RECT rect;
|
|
GetHyperLinkRect(rect);
|
|
DrawFocusRect(hdc, &rect);
|
|
}
|
|
}
|
|
|
|
void CHyperLink::DoAction(void) const
|
|
{
|
|
if (*m_szLinkURL)
|
|
{
|
|
_ASSERTE(g_pResManager != NULL);
|
|
if (g_pResManager->m_hAppStartingCursor)
|
|
SetCursor(g_pResManager->m_hAppStartingCursor);
|
|
ShellExecute(NULL, _T("open"), m_szLinkURL, NULL, NULL, SW_SHOWDEFAULT);
|
|
}
|
|
else
|
|
{
|
|
HWND hwndParent = GetParent(m_hwnd);
|
|
if (hwndParent)
|
|
{
|
|
int nCtrlID = GetDlgCtrlID(m_hwnd);
|
|
FORWARD_WM_COMMAND(hwndParent, nCtrlID, m_hwnd, BN_CLICKED, PostMessage);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param hwnd - window handle.
|
|
* @param uMsg - message identifier.
|
|
* @param wParam - first message parameter.
|
|
* @param lParam - second message parameter.
|
|
*/
|
|
LRESULT CALLBACK CHyperLink::HyperLinkWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int x, y, nCtrlID;
|
|
POINT point;
|
|
HCURSOR hCursor;
|
|
COLORREF rgbNewColor;
|
|
PAINTSTRUCT ps;
|
|
HWND hwndParent, hwndCtrl;
|
|
LRESULT lResult;
|
|
DWORD dwResult;
|
|
HDC hdc;
|
|
|
|
CHyperLink* _this = (CHyperLink*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
|
|
_ASSERTE(_this != NULL);
|
|
switch(uMsg)
|
|
{
|
|
case WM_NCHITTEST:
|
|
return HTCLIENT;
|
|
case WM_SETCURSOR:
|
|
_ASSERTE(g_pResManager != NULL);
|
|
hCursor = g_pResManager->m_hArrowCursor;
|
|
if (g_pResManager->m_hHandCursor)
|
|
{
|
|
dwResult = GetMessagePos();
|
|
point.x = GET_X_LPARAM(dwResult);
|
|
point.y = GET_Y_LPARAM(dwResult);
|
|
ScreenToClient(hwnd, &point);
|
|
if (_this->HitTest(point))
|
|
hCursor = g_pResManager->m_hHandCursor;
|
|
}
|
|
if (hCursor)
|
|
{
|
|
SetCursor(hCursor);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
case WM_LBUTTONDOWN:
|
|
if (GetCapture() != hwnd)
|
|
{
|
|
x = GET_X_LPARAM(lParam);
|
|
y = GET_Y_LPARAM(lParam);
|
|
if (_this->HitTest(x, y))
|
|
{
|
|
_this->m_rgbCurrentColor = m_rgbRedColor;
|
|
SetCapture(hwnd);
|
|
if (GetFocus() == hwnd)
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
else
|
|
SetFocus(hwnd);
|
|
}
|
|
}
|
|
return 0;
|
|
case WM_MOUSEMOVE:
|
|
if (GetCapture() == hwnd)
|
|
{
|
|
x = GET_X_LPARAM(lParam);
|
|
y = GET_Y_LPARAM(lParam);
|
|
rgbNewColor = _this->HitTest(x, y) ? m_rgbRedColor : m_rgbBlueColor;
|
|
if (_this->m_rgbCurrentColor != rgbNewColor)
|
|
{
|
|
_this->m_rgbCurrentColor = rgbNewColor;
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
}
|
|
}
|
|
return 0;
|
|
case WM_LBUTTONUP:
|
|
if (GetCapture() == hwnd)
|
|
{
|
|
ReleaseCapture();
|
|
x = GET_X_LPARAM(lParam);
|
|
y = GET_Y_LPARAM(lParam);
|
|
if (_this->HitTest(x, y))
|
|
_this->DoAction();
|
|
}
|
|
return 0;
|
|
case WM_SETFOCUS:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
{
|
|
nCtrlID = GetDlgCtrlID(hwnd);
|
|
if (_this->m_nPrevDefButtonID < 0)
|
|
{
|
|
lResult = SendMessage(hwndParent, DM_GETDEFID, 0, 0);
|
|
_this->m_nPrevDefButtonID = HIWORD(lResult) == DC_HASDEFID && LOWORD(lResult) != nCtrlID ? LOWORD(lResult) : -1;
|
|
}
|
|
SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
|
|
if (_this->m_nPrevDefButtonID > 0)
|
|
{
|
|
// Sending a DM_SETDEFID message to change the default button will not always
|
|
// remove the default state border from the first push button. In these cases,
|
|
// the application should send a BM_SETSTYLE message to change the first push
|
|
// button border style.
|
|
hwndCtrl = GetDlgItem(hwndParent, _this->m_nPrevDefButtonID);
|
|
if (SendMessage(hwndCtrl, WM_GETDLGCODE, 0, 0) & DLGC_DEFPUSHBUTTON)
|
|
SendMessage(hwndCtrl, BM_SETSTYLE, BS_PUSHBUTTON, TRUE);
|
|
}
|
|
}
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
return 0;
|
|
case WM_KILLFOCUS:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent && wParam && IsChild(hwndParent, (HWND)wParam))
|
|
{
|
|
if (! (SendMessage((HWND)wParam, WM_GETDLGCODE, 0, 0) & (DLGC_DEFPUSHBUTTON | DLGC_UNDEFPUSHBUTTON)))
|
|
{
|
|
if (_this->m_nPrevDefButtonID > 0)
|
|
{
|
|
nCtrlID = _this->m_nPrevDefButtonID;
|
|
_this->m_nPrevDefButtonID = -1;
|
|
}
|
|
else
|
|
nCtrlID = IDOK;
|
|
hwndCtrl = GetDlgItem(hwndParent, nCtrlID);
|
|
if (hwndCtrl && IsWindowEnabled(hwndCtrl))
|
|
SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
|
|
}
|
|
else
|
|
{
|
|
_this->m_nPrevDefButtonID = -1;
|
|
nCtrlID = GetDlgCtrlID((HWND)wParam);
|
|
SendMessage(hwndParent, DM_SETDEFID, nCtrlID, 0);
|
|
}
|
|
}
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
return 0;
|
|
case WM_CAPTURECHANGED:
|
|
_this->m_rgbCurrentColor = m_rgbBlueColor;
|
|
InvalidateRect(hwnd, NULL, FALSE);
|
|
return 0;
|
|
case WM_ERASEBKGND:
|
|
return TRUE;
|
|
case WM_PAINT:
|
|
hdc = (HDC)wParam;
|
|
if (! hdc)
|
|
{
|
|
hdc = BeginPaint(hwnd, &ps);
|
|
if (hdc)
|
|
{
|
|
_this->DrawHyperLink(hdc);
|
|
EndPaint(hwnd, &ps);
|
|
}
|
|
}
|
|
else
|
|
_this->DrawHyperLink(hdc);
|
|
return 0;
|
|
case WM_PRINTCLIENT:
|
|
hdc = (HDC)wParam;
|
|
_this->DrawHyperLink(hdc);
|
|
return 0;
|
|
case WM_KEYDOWN:
|
|
switch (wParam)
|
|
{
|
|
case VK_RETURN:
|
|
_this->DoAction();
|
|
break;
|
|
case VK_TAB:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
{
|
|
BOOL bPrevCtrl = GetKeyState(VK_SHIFT) < 0;
|
|
FORWARD_WM_NEXTDLGCTL(hwndParent, bPrevCtrl, FALSE, PostMessage);
|
|
}
|
|
break;
|
|
case VK_LEFT:
|
|
case VK_UP:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
FORWARD_WM_NEXTDLGCTL(hwndParent, TRUE, FALSE, PostMessage);
|
|
break;
|
|
case VK_RIGHT:
|
|
case VK_DOWN:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
FORWARD_WM_NEXTDLGCTL(hwndParent, FALSE, FALSE, PostMessage);
|
|
break;
|
|
case VK_ESCAPE:
|
|
hwndParent = GetParent(hwnd);
|
|
if (hwndParent)
|
|
{
|
|
HWND hwndCtl = GetDlgItem(hwndParent, IDCANCEL);
|
|
if (! hwndCtl || IsWindowEnabled(hwndCtl))
|
|
FORWARD_WM_COMMAND(hwndParent, IDCANCEL, hwndCtl, BN_CLICKED, PostMessage);
|
|
}
|
|
break;
|
|
}
|
|
return 0;
|
|
case WM_GETDLGCODE:
|
|
return ((GetFocus() == hwnd ? DLGC_DEFPUSHBUTTON : DLGC_UNDEFPUSHBUTTON) | DLGC_WANTALLKEYS);
|
|
case BM_SETSTYLE:
|
|
return 0;
|
|
default:
|
|
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param hwnd - hyper-link window handle.
|
|
*/
|
|
void CHyperLink::Attach(HWND hwnd)
|
|
{
|
|
_ASSERTE(hwnd != NULL);
|
|
_ASSERTE(m_hwnd == NULL);
|
|
_ASSERTE(g_pResManager != NULL);
|
|
m_hwnd = hwnd;
|
|
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)this);
|
|
m_pfnOldHyperLinkWndProc = SubclassWindow(hwnd, HyperLinkWndProc);
|
|
InvalidateRect(hwnd, NULL, TRUE);
|
|
}
|
|
|
|
void CHyperLink::Detach(void)
|
|
{
|
|
if (m_pfnOldHyperLinkWndProc)
|
|
{
|
|
SubclassWindow(m_hwnd, m_pfnOldHyperLinkWndProc);
|
|
SetWindowLongPtr(m_hwnd, GWLP_USERDATA, NULL);
|
|
InvalidateRect(m_hwnd, NULL, TRUE);
|
|
m_pfnOldHyperLinkWndProc = NULL;
|
|
m_hwnd = NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param size - hyper-link size.
|
|
*/
|
|
void CHyperLink::GetHyperLinkSize(SIZE& size) const
|
|
{
|
|
HDC hdc = GetDC(m_hwnd);
|
|
_ASSERTE(g_pResManager != NULL);
|
|
HFONT hOldFont = NULL;
|
|
if (g_pResManager->m_hUnderlinedFont)
|
|
hOldFont = SelectFont(hdc, g_pResManager->m_hUnderlinedFont);
|
|
TCHAR szLinkText[MAX_PATH];
|
|
GetWindowText(m_hwnd, szLinkText, countof(szLinkText));
|
|
GetTextExtentPoint32(hdc, szLinkText, (int)_tcslen(szLinkText), &size);
|
|
if (hOldFont)
|
|
SelectFont(hdc, hOldFont);
|
|
ReleaseDC(m_hwnd, hdc);
|
|
}
|
|
|
|
/**
|
|
* @param rect - hyper-link rectangle.
|
|
*/
|
|
void CHyperLink::GetHyperLinkRect(RECT& rect) const
|
|
{
|
|
SIZE size;
|
|
GetHyperLinkSize(size);
|
|
rect.left = rect.top = 0;
|
|
rect.right = size.cx + 3;
|
|
rect.bottom = size.cy + 3;
|
|
}
|