1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2015 - 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.
21 #include "ResizableDialog.h"
22 #include "TaskbarUUID.h"
25 #pragma comment(lib, "htmlhelp.lib")
27 #define DIALOG_BLOCKHORIZONTAL 1
28 #define DIALOG_BLOCKVERTICAL 2
31 * \ingroup TortoiseProc
33 * A template which can be used as the base-class of dialogs which form the main dialog
34 * of a 'dialog-style application'
35 * Just provides the boiler-plate code for dealing with application icons
37 * \remark Replace all references to CDialog or CResizableDialog in your dialog class with
38 * either CResizableStandAloneDialog, CStandAloneDialog or CStateStandAloneDialog, as appropriate
40 template <typename BaseType
> class CStandAloneDialogTmpl
: public BaseType
43 CStandAloneDialogTmpl(UINT nIDTemplate
, CWnd
* pParentWnd
= nullptr) : BaseType(nIDTemplate
, pParentWnd
)
45 m_hIcon
= AfxGetApp()->LoadIcon(IDR_MAINFRAME
);
50 virtual BOOL
OnInitDialog()
52 BaseType::OnInitDialog();
54 // Set the icon for this dialog. The framework does this automatically
55 // when the application's main window is not a dialog
56 SetIcon(m_hIcon
, TRUE
); // Set big icon
57 SetIcon(m_hIcon
, FALSE
); // Set small icon
61 m_height
= rect
.bottom
- rect
.top
;
62 m_width
= rect
.right
- rect
.left
;
64 m_tooltips
.Create(this);
69 virtual BOOL
PreTranslateMessage(MSG
* pMsg
)
71 m_tooltips
.RelayEvent(pMsg
, this);
72 if (pMsg
->message
== WM_KEYDOWN
)
74 int nVirtKey
= (int) pMsg
->wParam
;
76 if (nVirtKey
== 'A' && (GetKeyState(VK_CONTROL
) & 0x8000 ) )
79 ::GetClassName(pMsg
->hwnd
, buffer
,128);
81 if(_tcsnicmp(buffer
,_T("EDIT"),128) == 0)
83 ::PostMessage(pMsg
->hwnd
,EM_SETSEL
,0,-1);
88 return BaseType::PreTranslateMessage(pMsg
);
90 afx_msg
void OnPaint()
94 CPaintDC
dc(this); // device context for painting
96 SendMessage(WM_ICONERASEBKGND
, reinterpret_cast<WPARAM
>(dc
.GetSafeHdc()), 0);
98 // Center icon in client rectangle
99 int cxIcon
= GetSystemMetrics(SM_CXICON
);
100 int cyIcon
= GetSystemMetrics(SM_CYICON
);
102 GetClientRect(&rect
);
103 int x
= (rect
.Width() - cxIcon
+ 1) / 2;
104 int y
= (rect
.Height() - cyIcon
+ 1) / 2;
107 dc
.DrawIcon(x
, y
, m_hIcon
);
115 * Wrapper around the CWnd::EnableWindow() method, but
116 * makes sure that a control that has the focus is not disabled
117 * before the focus is passed on to the next control.
119 BOOL
DialogEnableWindow(UINT nID
, BOOL bEnable
)
121 CWnd
* pwndDlgItem
= GetDlgItem(nID
);
125 return pwndDlgItem
->EnableWindow(bEnable
);
126 if (GetFocus() == pwndDlgItem
)
128 SendMessage(WM_NEXTDLGCTL
, 0, FALSE
);
130 return pwndDlgItem
->EnableWindow(bEnable
);
134 * Adjusts the size of a checkbox or radio button control.
135 * Since we always make the size of those bigger than 'necessary'
136 * for making sure that translated strings can fit in those too,
137 * this method can reduce the size of those controls again to only
140 RECT
AdjustControlSize(UINT nID
)
142 CWnd
* pwndDlgItem
= GetDlgItem(nID
);
143 // adjust the size of the control to fit its content
144 CString sControlText
;
145 pwndDlgItem
->GetWindowText(sControlText
);
146 // next step: find the rectangle the control text needs to
149 CDC
* pDC
= pwndDlgItem
->GetWindowDC();
151 RECT controlrectorig
;
152 pwndDlgItem
->GetWindowRect(&controlrect
);
153 ::MapWindowPoints(nullptr, GetSafeHwnd(), (LPPOINT
)&controlrect
, 2);
154 controlrectorig
= controlrect
;
157 CFont
* font
= pwndDlgItem
->GetFont();
158 CFont
* pOldFont
= pDC
->SelectObject(font
);
159 if (pDC
->DrawText(sControlText
, -1, &controlrect
, DT_WORDBREAK
| DT_EDITCONTROL
| DT_EXPANDTABS
| DT_LEFT
| DT_CALCRECT
))
161 // now we have the rectangle the control really needs
162 if ((controlrectorig
.right
- controlrectorig
.left
) > (controlrect
.right
- controlrect
.left
))
164 // we're dealing with radio buttons and check boxes,
165 // which means we have to add a little space for the checkbox
166 // the value of 3 pixels added here is necessary in case certain visual styles have
167 // been disabled. Without this, the width is calculated too short.
168 const int checkWidth
= GetSystemMetrics(SM_CXMENUCHECK
) + 2*GetSystemMetrics(SM_CXEDGE
) + 3;
169 controlrectorig
.right
= controlrectorig
.left
+ (controlrect
.right
- controlrect
.left
) + checkWidth
;
170 pwndDlgItem
->MoveWindow(&controlrectorig
);
173 pDC
->SelectObject(pOldFont
);
176 return controlrectorig
;
180 * Adjusts the size of a static control.
181 * \param nID control ID
182 * \param rc the position of the control where this control shall
183 * be positioned next to on its right side.
184 * \param spacing number of pixels to add to rc.right
186 RECT
AdjustStaticSize(UINT nID
, RECT rc
, long spacing
)
188 CWnd
* pwndDlgItem
= GetDlgItem(nID
);
189 // adjust the size of the control to fit its content
190 CString sControlText
;
191 pwndDlgItem
->GetWindowText(sControlText
);
192 // next step: find the rectangle the control text needs to
195 CDC
* pDC
= pwndDlgItem
->GetWindowDC();
197 RECT controlrectorig
;
198 pwndDlgItem
->GetWindowRect(&controlrect
);
199 ::MapWindowPoints(nullptr, GetSafeHwnd(), (LPPOINT
)&controlrect
, 2);
200 controlrect
.right
+= 200; // in case the control needs to be bigger than it currently is (e.g., due to translations)
201 controlrectorig
= controlrect
;
203 long height
= controlrectorig
.bottom
-controlrectorig
.top
;
204 long width
= controlrectorig
.right
-controlrectorig
.left
;
205 controlrectorig
.left
= rc
.right
+ spacing
;
206 controlrectorig
.right
= controlrectorig
.left
+ width
;
207 controlrectorig
.bottom
= rc
.bottom
;
208 controlrectorig
.top
= controlrectorig
.bottom
- height
;
212 CFont
* font
= pwndDlgItem
->GetFont();
213 CFont
* pOldFont
= pDC
->SelectObject(font
);
214 if (pDC
->DrawText(sControlText
, -1, &controlrect
, DT_WORDBREAK
| DT_EDITCONTROL
| DT_EXPANDTABS
| DT_LEFT
| DT_CALCRECT
))
216 // now we have the rectangle the control really needs
217 controlrectorig
.right
= controlrectorig
.left
+ (controlrect
.right
- controlrect
.left
);
218 pwndDlgItem
->MoveWindow(&controlrectorig
);
220 pDC
->SelectObject(pOldFont
);
223 return controlrectorig
;
227 * Display a balloon with close button, anchored at a given edit control on this dialog.
229 void ShowEditBalloon(UINT nIdControl
, UINT nIdText
, UINT nIdTitle
, int nIcon
= TTI_WARNING
)
231 CString
text(MAKEINTRESOURCE(nIdText
));
232 CString
title(MAKEINTRESOURCE(nIdTitle
));
233 ShowEditBalloon(nIdControl
, text
, title
, nIcon
);
235 void ShowEditBalloon(UINT nIdControl
, const CString
& text
, const CString
& title
, int nIcon
= TTI_WARNING
)
238 bt
.cbStruct
= sizeof(bt
);
242 SendDlgItemMessage(nIdControl
, EM_SHOWBALLOONTIP
, 0, (LPARAM
)&bt
);
246 * Refreshes the cursor by forcing a WM_SETCURSOR message.
252 SetCursorPos(pt
.x
, pt
.y
);
255 void BlockResize(int block
)
257 m_nResizeBlock
= block
;
260 void EnableSaveRestore(LPCTSTR pszSection
, bool bRectOnly
= FALSE
)
262 // call the base method with the bHorzResize and bVertResize parameters
263 // figured out from the resize block flags.
264 BaseType::EnableSaveRestore(pszSection
, bRectOnly
, (m_nResizeBlock
& DIALOG_BLOCKHORIZONTAL
) == 0, (m_nResizeBlock
& DIALOG_BLOCKVERTICAL
) == 0);
268 CToolTips m_tooltips
;
273 DECLARE_MESSAGE_MAP()
276 HCURSOR
OnQueryDragIcon()
278 return static_cast<HCURSOR
>(m_hIcon
);
281 virtual void HtmlHelp(DWORD_PTR dwData
, UINT nCmd
= 0x000F)
283 CWinApp
* pApp
= AfxGetApp();
285 ASSERT(pApp
->m_pszHelpFilePath
);
286 // to call HtmlHelp the m_fUseHtmlHelp must be set in
287 // the application's constructor
288 ASSERT(pApp
->m_eHelpType
== afxHTMLHelp
);
293 // run the HTML Help engine
294 if (!::HtmlHelp(m_hWnd
, pApp
->m_pszHelpFilePath
, nCmd
, dwData
))
296 AfxMessageBox(AFX_IDP_FAILED_TO_LAUNCH_HELP
);
300 afx_msg LRESULT
OnTaskbarButtonCreated(WPARAM
/*wParam*/, LPARAM
/*lParam*/)
302 SetUUIDOverlayIcon(m_hWnd
);
309 class CStateDialog
: public CDialog
, public CResizableWndState
314 , m_bEnableSaveRestore(false)
317 CStateDialog(UINT nIDTemplate
, CWnd
* pParentWnd
= nullptr)
318 : CDialog(nIDTemplate
, pParentWnd
)
319 , m_bEnableSaveRestore(false)
322 CStateDialog(LPCTSTR lpszTemplateName
, CWnd
* pParentWnd
= nullptr)
323 : CDialog(lpszTemplateName
, pParentWnd
)
324 , m_bEnableSaveRestore(false)
327 virtual ~CStateDialog() {};
331 bool m_bEnableSaveRestore
;
335 CString m_sSection
; // section name (identifies a parent window)
338 // overloaded method, but since this dialog class is for non-resizable dialogs,
339 // the bHorzResize and bVertResize params are ignored and passed as false
340 // to the base method.
341 void EnableSaveRestore(LPCTSTR pszSection
, bool bRectOnly
= FALSE
, BOOL bHorzResize
= TRUE
, BOOL bVertResize
= TRUE
)
343 UNREFERENCED_PARAMETER(bHorzResize
);
344 UNREFERENCED_PARAMETER(bVertResize
);
345 m_sSection
= pszSection
;
347 m_bEnableSaveRestore
= true;
348 m_bRectOnly
= bRectOnly
;
350 // restore immediately
351 LoadWindowRect(pszSection
, bRectOnly
, false, false);
354 virtual CWnd
* GetResizableWnd() const
356 // make the layout know its parent window
357 return CWnd::FromHandle(m_hWnd
);
360 afx_msg
void OnDestroy()
362 if (m_bEnableSaveRestore
)
363 SaveWindowRect(m_sSection
, m_bRectOnly
);
364 CDialog::OnDestroy();
367 DECLARE_MESSAGE_MAP()
370 class CResizableStandAloneDialog
: public CStandAloneDialogTmpl
<CResizableDialog
>
373 CResizableStandAloneDialog(UINT nIDTemplate
, CWnd
* pParentWnd
= nullptr);
376 DECLARE_DYNAMIC(CResizableStandAloneDialog
)
379 afx_msg
void OnSizing(UINT fwSide
, LPRECT pRect
);
380 afx_msg
void OnMoving(UINT fwSide
, LPRECT pRect
);
381 afx_msg
void OnNcMButtonUp(UINT nHitTest
, CPoint point
);
382 afx_msg
void OnNcRButtonUp(UINT nHitTest
, CPoint point
);
383 afx_msg LRESULT
OnNcHitTest(CPoint point
);
385 DECLARE_MESSAGE_MAP()
390 CRect m_rcOrgWindowRect
;
393 class CStandAloneDialog
: public CStandAloneDialogTmpl
<CDialog
>
396 CStandAloneDialog(UINT nIDTemplate
, CWnd
* pParentWnd
= nullptr);
398 DECLARE_MESSAGE_MAP()
400 DECLARE_DYNAMIC(CStandAloneDialog
)
403 class CStateStandAloneDialog
: public CStandAloneDialogTmpl
<CStateDialog
>
406 CStateStandAloneDialog(UINT nIDTemplate
, CWnd
* pParentWnd
= nullptr);
408 DECLARE_MESSAGE_MAP()
410 DECLARE_DYNAMIC(CStateStandAloneDialog
)