1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2009, 2012-2013 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "LinkControl.h"
23 #define PROP_OBJECT_PTR MAKEINTATOM(ga.atom)
24 #define PROP_ORIGINAL_PROC MAKEINTATOM(ga.atom)
30 { atom
= GlobalAddAtom(_T("_LinkControl_Object_Pointer_")
31 _T("\\{62671D58-E5E8-46e0-A818-FD6547EC60B8}")); }
38 static CGlobalAtom ga
;
40 const UINT
CLinkControl::LK_LINKITEMCLICKED
41 = ::RegisterWindowMessage(_T("LK_LINKITEMCLICKED"));
44 HCURSOR
CLinkControl::g_hLinkCursor
= NULL
;
45 HFONT
CLinkControl::g_UnderlineFont
= NULL
;
46 HFONT
CLinkControl::g_NormalFont
= NULL
;
47 int CLinkControl::g_counter
= 0;
50 CLinkControl::CLinkControl(void)
51 : m_bOverControl(false)
52 , m_bMouseDownPressed(false)
54 , m_pfnOrigCtlProc(NULL
)
58 CLinkControl::~CLinkControl(void)
62 bool CLinkControl::ConvertStaticToLink(HWND hwndCtl
)
64 // Subclass the parent so we can draw the controls ourselves
65 HWND hwndParent
= GetParent(hwndCtl
);
68 WNDPROC pfnOrigProc
= (WNDPROC
) GetWindowLongPtr(hwndParent
, GWLP_WNDPROC
);
69 if (pfnOrigProc
!= _HyperlinkParentProc
)
71 if (SetProp(hwndParent
, PROP_ORIGINAL_PROC
, (HANDLE
)pfnOrigProc
))
72 SetWindowLongPtr(hwndParent
, GWLP_WNDPROC
, (LONG_PTR
)(WNDPROC
)_HyperlinkParentProc
);
76 // Make sure the control will send notifications.
78 LONG_PTR Style
= GetWindowLongPtr(hwndCtl
, GWL_STYLE
);
79 SetWindowLongPtr(hwndCtl
, GWL_STYLE
, Style
| SS_NOTIFY
);
81 // Create an updated font by adding an underline.
83 m_StdFont
= (HFONT
) SendMessage(hwndCtl
, WM_GETFONT
, 0, 0);
87 createGlobalResources();
89 SendMessage(hwndCtl
, WM_SETFONT
, (WPARAM
)CLinkControl::g_NormalFont
, FALSE
);
91 // Subclass the existing control.
93 m_pfnOrigCtlProc
= (WNDPROC
)GetWindowLongPtr(hwndCtl
, GWLP_WNDPROC
);
94 if (SetProp(hwndCtl
, PROP_OBJECT_PTR
, (HANDLE
)this))
95 SetWindowLongPtr(hwndCtl
, GWLP_WNDPROC
, (LONG_PTR
)(WNDPROC
)_HyperlinkProc
);
100 bool CLinkControl::ConvertStaticToLink(HWND hwndParent
, UINT uiCtlId
)
102 return ConvertStaticToLink(GetDlgItem(hwndParent
, uiCtlId
));
105 LRESULT CALLBACK
CLinkControl::_HyperlinkParentProc(HWND hwnd
, UINT message
,
106 WPARAM wParam
, LPARAM lParam
)
108 WNDPROC pfnOrigProc
= (WNDPROC
)GetProp(hwnd
, PROP_ORIGINAL_PROC
);
112 case WM_CTLCOLORSTATIC
:
114 //HDC hdc = (HDC)wParam;
115 HWND hwndCtl
= (HWND
)lParam
;
116 CLinkControl
*pHyperLink
= (CLinkControl
*)GetProp(hwndCtl
, PROP_OBJECT_PTR
);
120 LRESULT lr
= CallWindowProc(pfnOrigProc
, hwnd
, message
, wParam
, lParam
);
121 //::SetTextColor(hdc, GetSysColor(COLOR_HOTLIGHT));
128 SetWindowLongPtr(hwnd
, GWLP_WNDPROC
, (LONG_PTR
) pfnOrigProc
);
129 RemoveProp(hwnd
, PROP_ORIGINAL_PROC
);
133 return CallWindowProc(pfnOrigProc
, hwnd
, message
, wParam
, lParam
);
136 void CLinkControl::DrawFocusRect(HWND hwnd
)
138 HWND hwndParent
= ::GetParent(hwnd
);
142 // calculate where to draw focus rectangle, in screen coords
144 GetWindowRect(hwnd
, &rc
);
146 InflateRect(&rc
, 1, 1); // add one pixel all around
147 ::ScreenToClient(hwndParent
, (LPPOINT
)&rc
);
148 ::ScreenToClient(hwndParent
, ((LPPOINT
)&rc
) + 1);
149 HDC dcParent
= GetDC(hwndParent
);
150 ::DrawFocusRect(dcParent
, &rc
);
151 ReleaseDC(hwndParent
, dcParent
);
155 LRESULT CALLBACK
CLinkControl::_HyperlinkProc(HWND hwnd
, UINT message
,
156 WPARAM wParam
, LPARAM lParam
)
158 CLinkControl
*pHyperLink
= (CLinkControl
*)GetProp(hwnd
, PROP_OBJECT_PTR
);
164 if (pHyperLink
->m_bOverControl
)
167 GetClientRect(hwnd
, &rect
);
169 POINT pt
= { LOWORD(lParam
), HIWORD(lParam
) };
171 if (!PtInRect(&rect
, pt
))
176 pHyperLink
->m_bOverControl
= TRUE
;
177 SendMessage(hwnd
, WM_SETFONT
, (WPARAM
)CLinkControl::g_UnderlineFont
, FALSE
);
178 InvalidateRect(hwnd
, NULL
, FALSE
);
185 SetCursor(CLinkControl::g_hLinkCursor
);
189 case WM_CAPTURECHANGED
:
191 pHyperLink
->m_bOverControl
= FALSE
;
192 SendMessage(hwnd
, WM_SETFONT
, (WPARAM
)CLinkControl::g_NormalFont
, FALSE
);
193 InvalidateRect(hwnd
, NULL
, FALSE
);
198 if ((wParam
!= VK_SPACE
)&&(wParam
!= VK_RETURN
))
200 PostMessage(::GetParent(hwnd
), LK_LINKITEMCLICKED
, (WPARAM
)hwnd
, (LPARAM
)0);
205 PostMessage(::GetParent(hwnd
), LK_LINKITEMCLICKED
, (WPARAM
)hwnd
, (LPARAM
)0);
208 pHyperLink
->m_bMouseDownPressed
= true;
212 if (pHyperLink
->m_bMouseDownPressed
)
213 PostMessage(::GetParent(hwnd
), LK_LINKITEMCLICKED
, (WPARAM
)hwnd
, (LPARAM
)0);
214 pHyperLink
->m_bMouseDownPressed
= false;
219 LRESULT lres
= CallWindowProc(pHyperLink
->m_pfnOrigCtlProc
, hwnd
, message
, wParam
, lParam
);
220 // we want all keys to get the return key
221 lres
|= DLGC_WANTALLKEYS
;
223 // but we don't want the tab key since that should be used in dialogs
224 // to switch the focus
225 lres
&= ~DLGC_WANTTAB
;
226 lres
&= ~DLGC_STATIC
;
228 ((MSG
*)lParam
)->message
== WM_KEYDOWN
&&
229 ((MSG
*)lParam
)->wParam
== VK_TAB
)
231 lres
&= ~DLGC_WANTMESSAGE
;
240 CLinkControl::DrawFocusRect(hwnd
);
245 SetWindowLongPtr(hwnd
, GWLP_WNDPROC
, (LONG_PTR
)pHyperLink
->m_pfnOrigCtlProc
);
247 SendMessage(hwnd
, WM_SETFONT
, (WPARAM
)pHyperLink
->m_StdFont
, 0);
249 if (--CLinkControl::g_counter
<= 0)
250 destroyGlobalResources();
252 RemoveProp(hwnd
, PROP_OBJECT_PTR
);
257 return CallWindowProc(pHyperLink
->m_pfnOrigCtlProc
, hwnd
, message
,
261 void CLinkControl::createUnderlineFont(void)
264 GetObject(m_StdFont
, sizeof(lf
), &lf
);
265 lf
.lfWeight
= FW_BOLD
;
266 g_NormalFont
= CreateFontIndirect(&lf
);
268 lf
.lfUnderline
= TRUE
;
269 g_UnderlineFont
= CreateFontIndirect(&lf
);
272 void CLinkControl::createLinkCursor(void)
274 g_hLinkCursor
= ::LoadCursor(NULL
, IDC_HAND
); // Load Windows' hand cursor
275 if (!g_hLinkCursor
) // if not available, use the standard Arrow cursor
277 g_hLinkCursor
= ::LoadCursor(NULL
, IDC_ARROW
);