1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2016 - TortoiseGit
4 // Copyright (C) 2003-2006,2008, 2011, 2018 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "HyperLink.h"
22 #include "SmartHandle.h"
27 static char THIS_FILE
[] = __FILE__
;
33 CHyperLink::CHyperLink()
34 : m_hLinkCursor(nullptr)
35 , m_crLinkColor(GetSysColor(COLOR_HOTLIGHT
))
36 , m_crHoverColor(RGB(255, 0, 0)) // Red
37 , m_bOverControl(FALSE
)
38 , m_nUnderline(ulHover
)
43 CHyperLink::~CHyperLink()
45 m_UnderlineFont
.DeleteObject();
48 BOOL
CHyperLink::DestroyWindow()
50 KillTimer(m_nTimerID
);
52 return CStatic::DestroyWindow();
55 BOOL
CHyperLink::PreTranslateMessage(MSG
* pMsg
)
57 m_ToolTip
.RelayEvent(pMsg
);
58 return CStatic::PreTranslateMessage(pMsg
);
62 void CHyperLink::PreSubclassWindow()
64 // Enable notifications - CStatic has this disabled by default
65 ModifyStyle(0, SS_NOTIFY
);
67 // By default use the label text as the URL
68 if (m_strURL
.IsEmpty())
69 GetWindowText(m_strURL
);
72 GetWindowText(strWndText
);
73 if (strWndText
.IsEmpty())
75 SetWindowText(m_strURL
);
79 CFont
* pFont
= GetFont();
81 pFont
->GetObject(sizeof(lf
), &lf
);
84 NONCLIENTMETRICS metrics
= { 0 };
85 metrics
.cbSize
= sizeof(NONCLIENTMETRICS
);
86 SystemParametersInfo(SPI_GETNONCLIENTMETRICS
, 0, &metrics
, FALSE
);
87 memcpy_s(&lf
, sizeof(LOGFONT
), &metrics
.lfMessageFont
, sizeof(LOGFONT
));
89 m_StdFont
.CreateFontIndirect(&lf
);
90 lf
.lfUnderline
= (BYTE
) TRUE
;
91 m_UnderlineFont
.CreateFontIndirect(&lf
);
93 SetDefaultCursor(); // try loading a "hand" cursor
98 m_ToolTip
.Create(this);
99 m_ToolTip
.AddTool(this, m_strURL
, rect
, TOOLTIP_ID
);
101 CStatic::PreSubclassWindow();
104 BEGIN_MESSAGE_MAP(CHyperLink
, CStatic
)
105 ON_WM_CTLCOLOR_REFLECT()
110 ON_CONTROL_REFLECT(STN_CLICKED
, OnClicked
)
111 ON_WM_SYSCOLORCHANGE()
115 void CHyperLink::OnClicked()
117 if(!m_strURL
.IsEmpty())
123 ::SendMessage(this->GetParent()->m_hWnd
,WM_COMMAND
,this->GetDlgCtrlID(),0);
127 HBRUSH
CHyperLink::CtlColor(CDC
* pDC
, UINT
/*nCtlColor*/)
130 pDC
->SetTextColor(m_crHoverColor
);
132 pDC
->SetTextColor(m_crLinkColor
);
135 pDC
->SetBkMode(TRANSPARENT
);
136 return (HBRUSH
)GetStockObject(NULL_BRUSH
);
139 void CHyperLink::OnMouseMove(UINT nFlags
, CPoint point
)
143 m_bOverControl
= TRUE
;
145 if (m_nUnderline
== ulHover
)
146 SetFont(&m_UnderlineFont
);
149 SetTimer(m_nTimerID
, 100, nullptr);
151 CStatic::OnMouseMove(nFlags
, point
);
154 void CHyperLink::OnTimer(UINT_PTR nIDEvent
)
156 CPoint
p(GetMessagePos());
161 if (!rect
.PtInRect(p
))
163 m_bOverControl
= FALSE
;
164 KillTimer(m_nTimerID
);
166 if (m_nUnderline
!= ulAlways
)
169 InvalidateRect(rect
);
172 CStatic::OnTimer(nIDEvent
);
175 BOOL
CHyperLink::OnSetCursor(CWnd
* /*pWnd*/, UINT
/*nHitTest*/, UINT
/*message*/)
179 ::SetCursor(m_hLinkCursor
);
185 BOOL
CHyperLink::OnEraseBkgnd(CDC
* pDC
)
189 pDC
->FillSolidRect(rect
, ::GetSysColor(COLOR_3DFACE
));
194 void CHyperLink::SetURL(CString strURL
)
198 if (::IsWindow(GetSafeHwnd()))
200 m_ToolTip
.UpdateTipText(strURL
, this, TOOLTIP_ID
);
204 CString
CHyperLink::GetURL() const
209 void CHyperLink::SetColors(COLORREF crLinkColor
, COLORREF crHoverColor
)
211 m_crLinkColor
= crLinkColor
;
213 if (crHoverColor
== -1)
214 m_crHoverColor
= ::GetSysColor(COLOR_HIGHLIGHT
);
216 m_crHoverColor
= crHoverColor
;
218 if (::IsWindow(m_hWnd
))
222 COLORREF
CHyperLink::GetLinkColor() const
224 return m_crLinkColor
;
227 COLORREF
CHyperLink::GetHoverColor() const
229 return m_crHoverColor
;
232 void CHyperLink::SetUnderline(int nUnderline
/*=ulHover*/)
234 if (m_nUnderline
== nUnderline
)
237 if (::IsWindow(GetSafeHwnd()))
239 if (nUnderline
== ulAlways
)
240 SetFont(&m_UnderlineFont
);
247 m_nUnderline
= nUnderline
;
250 int CHyperLink::GetUnderline() const
255 // The following appeared in Paul DiLascia's Jan 1998 MSJ articles.
256 // It loads a "hand" cursor from the winhlp32.exe module
257 void CHyperLink::SetDefaultCursor()
261 // first try the windows hand cursor (not available on NT4)
263 # define OCR_HAND 32649
265 HCURSOR hHandCursor
= (HCURSOR
)::LoadImage(nullptr, MAKEINTRESOURCE(OCR_HAND
), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
| LR_SHARED
);
268 m_hLinkCursor
= hHandCursor
;
271 // windows cursor not available, so try to load it from winhlp32.exe
273 GetWindowsDirectory(CStrBuf(strWndDir
, MAX_PATH
), MAX_PATH
); // Explorer can't handle paths longer than MAX_PATH.
274 strWndDir
+= L
"\\winhlp32.exe";
275 // This retrieves cursor #106 from winhlp32.exe, which is a hand pointer
276 CAutoLibrary hModule
= LoadLibrary(strWndDir
);
278 HCURSOR hHandCursor2
= (HCURSOR
)::LoadImage(hModule
, MAKEINTRESOURCE(106), IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
280 m_hLinkCursor
= CopyCursor(hHandCursor2
);
285 HINSTANCE
CHyperLink::GotoURL(LPCTSTR url
)
287 return ShellExecute(nullptr, L
"open", url
, nullptr, nullptr, SW_SHOW
);
290 void CHyperLink::OnSysColorChange()
292 __super::OnSysColorChange();
293 m_crLinkColor
= GetSysColor(COLOR_HOTLIGHT
);